Skip to content

Commit 09d674b

Browse files
committed
Add user-defined exclusion list to RenderingDevice based on device names.
1 parent 542f8dd commit 09d674b

8 files changed

Lines changed: 125 additions & 89 deletions

doc/classes/ProjectSettings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3315,6 +3315,10 @@
33153315
- [code]d3d12[/code], Direct3D 12 from native drivers. If [member rendering/rendering_device/fallback_to_d3d12] is enabled, this is used as a fallback if Vulkan is not supported.
33163316
[b]Note:[/b] Starting with Godot 4.6, new projects are configured by default to use [code]d3d12[/code] on Windows. Projects created before Godot 4.6 keep [code]vulkan[/code] for compatibility reasons, but it is recommended to switch them manually to [code]d3d12[/code].
33173317
</member>
3318+
<member name="rendering/rendering_device/excluded_device_list" type="String" setter="" getter="" default="&quot;&quot;">
3319+
Comma-separated list of device names that should be excluded from initializing a RenderingDevice. When used in combination with [member rendering/rendering_device/fallback_to_opengl3], the compatibility renderer will be used instead if the platform supports it. This setting can be used to redirect users with underperforming or broken drivers to the Compatibility renderer.
3320+
[b]Note:[/b] The name must be an exact match. Use [method RenderingDevice.get_device_name] to retrieve the device's name.
3321+
</member>
33183322
<member name="rendering/rendering_device/fallback_to_d3d12" type="bool" setter="" getter="" default="true">
33193323
If [code]true[/code], the Forward+ renderer will fall back to Direct3D 12 if Vulkan is not supported. The fallback is always attempted regardless of this setting if Vulkan driver support was disabled at compile time.
33203324
[b]Note:[/b] This setting is implemented only on Windows.

drivers/d3d12/rendering_context_driver_d3d12.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ Error RenderingContextDriverD3D12::initialize() {
230230
err = _initialize_devices();
231231
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
232232

233-
return OK;
233+
return _check_excluded_devices();
234234
}
235235

236236
const RenderingContextDriver::Device &RenderingContextDriverD3D12::device_get(uint32_t p_device_index) const {

drivers/metal/rendering_context_driver_metal.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ - (void)setShouldMaximizeConcurrentCompilation:(BOOL)v;
7979
int version = (int)props.features.highestFamily - (int)MTLGPUFamilyApple1 + 1;
8080
device.name = vformat("%s (Apple%d)", metal_device.name.UTF8String, version);
8181

82-
return OK;
82+
return _check_excluded_devices();
8383
}
8484

8585
const RenderingContextDriver::Device &RenderingContextDriverMetal::device_get(uint32_t p_device_index) const {

drivers/vulkan/rendering_context_driver_vulkan.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ Error RenderingContextDriverVulkan::initialize() {
933933
err = _initialize_devices();
934934
ERR_FAIL_COND_V(err != OK, err);
935935

936-
return OK;
936+
return _check_excluded_devices();
937937
}
938938

939939
const RenderingContextDriver::Device &RenderingContextDriverVulkan::device_get(uint32_t p_device_index) const {

main/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2319,6 +2319,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
23192319
GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_vulkan", true);
23202320
GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_d3d12", true);
23212321
GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_opengl3", true);
2322+
GLOBAL_DEF_RST("rendering/rendering_device/excluded_device_list", "");
23222323
}
23232324

23242325
{

servers/rendering/rendering_context_driver.cpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030

3131
#include "rendering_context_driver.h"
3232

33+
#include "core/config/project_settings.h"
34+
3335
RenderingContextDriver::~RenderingContextDriver() {
3436
}
3537

@@ -84,6 +86,53 @@ void RenderingContextDriver::window_destroy(DisplayServer::WindowID p_window) {
8486
window_surface_map.erase(p_window);
8587
}
8688

89+
int32_t RenderingContextDriver::pick_device(SurfaceID p_surface, bool p_print_verbose) {
90+
if (p_print_verbose) {
91+
print_verbose("Devices:");
92+
}
93+
94+
int32_t device_index = Engine::get_singleton()->get_gpu_index();
95+
const uint32_t device_count = device_get_count();
96+
const bool detect_device = (device_index < 0) || (device_index >= int32_t(device_count));
97+
uint32_t device_type_score = 0;
98+
for (uint32_t i = 0; i < device_count; i++) {
99+
RenderingContextDriver::Device device_option = device_get(i);
100+
String name = device_option.name;
101+
String vendor = get_device_vendor_name(device_option);
102+
String type = get_device_type_name(device_option);
103+
bool present_supported = p_surface != 0 ? device_supports_present(i, p_surface) : false;
104+
if (p_print_verbose) {
105+
print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + type);
106+
}
107+
108+
if (detect_device && (present_supported || p_surface == 0)) {
109+
// If a window was specified, present must be supported by the device to be available as an option.
110+
// Assign a score for each type of device and prefer the device with the higher score.
111+
uint32_t option_score = get_device_type_score(device_option);
112+
if (option_score > device_type_score) {
113+
device_index = i;
114+
device_type_score = option_score;
115+
}
116+
}
117+
}
118+
119+
return device_index;
120+
}
121+
122+
Error RenderingContextDriver::_check_excluded_devices() {
123+
// Check if the picked device from the context is excluded from using RenderingDevice. The names must be an exact string match.
124+
String device_list_string = GLOBAL_GET("rendering/rendering_device/excluded_device_list");
125+
PackedStringArray device_list = device_list_string.split(",");
126+
int32_t device_index = pick_device(0, false);
127+
if (device_index >= 0 && device_index < (int32_t)(device_get_count())) {
128+
const RenderingContextDriver::Device &device = device_get(device_index);
129+
return device_list.has(device.name) ? ERR_CANT_CREATE : OK;
130+
} else {
131+
// No valid device was found, so just fail on this step instead.
132+
return ERR_CANT_CREATE;
133+
}
134+
}
135+
87136
String RenderingContextDriver::get_driver_and_device_memory_report() const {
88137
String report;
89138

@@ -168,3 +217,59 @@ uint64_t RenderingContextDriver::get_device_memory_by_object_type(uint32_t) cons
168217
uint64_t RenderingContextDriver::get_device_allocs_by_object_type(uint32_t) const {
169218
return 0;
170219
}
220+
221+
String RenderingContextDriver::get_device_vendor_name(const Device &p_device) {
222+
switch (p_device.vendor) {
223+
case RenderingContextDriver::Vendor::VENDOR_AMD:
224+
return "AMD";
225+
case RenderingContextDriver::Vendor::VENDOR_IMGTEC:
226+
return "ImgTec";
227+
case RenderingContextDriver::Vendor::VENDOR_APPLE:
228+
return "Apple";
229+
case RenderingContextDriver::Vendor::VENDOR_NVIDIA:
230+
return "NVIDIA";
231+
case RenderingContextDriver::Vendor::VENDOR_ARM:
232+
return "ARM";
233+
case RenderingContextDriver::Vendor::VENDOR_MICROSOFT:
234+
return "Microsoft";
235+
case RenderingContextDriver::Vendor::VENDOR_QUALCOMM:
236+
return "Qualcomm";
237+
case RenderingContextDriver::Vendor::VENDOR_INTEL:
238+
return "Intel";
239+
default:
240+
return "Unknown";
241+
}
242+
}
243+
244+
String RenderingContextDriver::get_device_type_name(const Device &p_device) {
245+
switch (p_device.type) {
246+
case RenderingContextDriver::DEVICE_TYPE_INTEGRATED_GPU:
247+
return "Integrated";
248+
case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU:
249+
return "Discrete";
250+
case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU:
251+
return "Virtual";
252+
case RenderingContextDriver::DEVICE_TYPE_CPU:
253+
return "CPU";
254+
case RenderingContextDriver::DEVICE_TYPE_OTHER:
255+
default:
256+
return "Other";
257+
}
258+
}
259+
260+
uint32_t RenderingContextDriver::get_device_type_score(const Device &p_device) {
261+
static const bool prefer_integrated = OS::get_singleton()->get_user_prefers_integrated_gpu();
262+
switch (p_device.type) {
263+
case RenderingContextDriver::DEVICE_TYPE_INTEGRATED_GPU:
264+
return prefer_integrated ? 5 : 4;
265+
case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU:
266+
return prefer_integrated ? 4 : 5;
267+
case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU:
268+
return 3;
269+
case RenderingContextDriver::DEVICE_TYPE_CPU:
270+
return 2;
271+
case RenderingContextDriver::DEVICE_TYPE_OTHER:
272+
default:
273+
return 1;
274+
}
275+
}

servers/rendering/rendering_context_driver.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ class RenderingContextDriver {
4141
private:
4242
HashMap<DisplayServer::WindowID, SurfaceID> window_surface_map;
4343

44+
protected:
45+
Error _check_excluded_devices();
46+
4447
public:
4548
SurfaceID surface_get_from_window(DisplayServer::WindowID p_window) const;
4649
Error window_create(DisplayServer::WindowID p_window, const void *p_platform_data);
@@ -104,6 +107,7 @@ class RenderingContextDriver {
104107
virtual void surface_destroy(SurfaceID p_surface) = 0;
105108
virtual bool is_debug_utils_enabled() const = 0;
106109

110+
int32_t pick_device(SurfaceID p_surface, bool p_print_verbose);
107111
String get_driver_and_device_memory_report() const;
108112

109113
virtual const char *get_tracked_object_name(uint32_t p_type_index) const;
@@ -118,4 +122,8 @@ class RenderingContextDriver {
118122
virtual uint64_t get_device_allocation_count() const;
119123
virtual uint64_t get_device_memory_by_object_type(uint32_t p_type) const;
120124
virtual uint64_t get_device_allocs_by_object_type(uint32_t p_type) const;
125+
126+
static String get_device_vendor_name(const Device &p_device);
127+
static String get_device_type_name(const Device &p_device);
128+
static uint32_t get_device_type_score(const Device &p_device);
121129
};

servers/rendering/rendering_device.cpp

Lines changed: 4 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -53,66 +53,6 @@
5353
#define ERR_RENDER_THREAD_GUARD() ERR_FAIL_COND_MSG(render_thread_id != Thread::get_caller_id(), ERR_RENDER_THREAD_MSG);
5454
#define ERR_RENDER_THREAD_GUARD_V(m_ret) ERR_FAIL_COND_V_MSG(render_thread_id != Thread::get_caller_id(), (m_ret), ERR_RENDER_THREAD_MSG);
5555

56-
/**************************/
57-
/**** HELPER FUNCTIONS ****/
58-
/**************************/
59-
60-
static String _get_device_vendor_name(const RenderingContextDriver::Device &p_device) {
61-
switch (p_device.vendor) {
62-
case RenderingContextDriver::Vendor::VENDOR_AMD:
63-
return "AMD";
64-
case RenderingContextDriver::Vendor::VENDOR_IMGTEC:
65-
return "ImgTec";
66-
case RenderingContextDriver::Vendor::VENDOR_APPLE:
67-
return "Apple";
68-
case RenderingContextDriver::Vendor::VENDOR_NVIDIA:
69-
return "NVIDIA";
70-
case RenderingContextDriver::Vendor::VENDOR_ARM:
71-
return "ARM";
72-
case RenderingContextDriver::Vendor::VENDOR_MICROSOFT:
73-
return "Microsoft";
74-
case RenderingContextDriver::Vendor::VENDOR_QUALCOMM:
75-
return "Qualcomm";
76-
case RenderingContextDriver::Vendor::VENDOR_INTEL:
77-
return "Intel";
78-
default:
79-
return "Unknown";
80-
}
81-
}
82-
83-
static String _get_device_type_name(const RenderingContextDriver::Device &p_device) {
84-
switch (p_device.type) {
85-
case RenderingContextDriver::DEVICE_TYPE_INTEGRATED_GPU:
86-
return "Integrated";
87-
case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU:
88-
return "Discrete";
89-
case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU:
90-
return "Virtual";
91-
case RenderingContextDriver::DEVICE_TYPE_CPU:
92-
return "CPU";
93-
case RenderingContextDriver::DEVICE_TYPE_OTHER:
94-
default:
95-
return "Other";
96-
}
97-
}
98-
99-
static uint32_t _get_device_type_score(const RenderingContextDriver::Device &p_device) {
100-
static const bool prefer_integrated = OS::get_singleton()->get_user_prefers_integrated_gpu();
101-
switch (p_device.type) {
102-
case RenderingContextDriver::DEVICE_TYPE_INTEGRATED_GPU:
103-
return prefer_integrated ? 5 : 4;
104-
case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU:
105-
return prefer_integrated ? 4 : 5;
106-
case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU:
107-
return 3;
108-
case RenderingContextDriver::DEVICE_TYPE_CPU:
109-
return 2;
110-
case RenderingContextDriver::DEVICE_TYPE_OTHER:
111-
default:
112-
return 1;
113-
}
114-
}
115-
11656
/**************************/
11757
/**** RENDERING DEVICE ****/
11858
/**************************/
@@ -6504,7 +6444,7 @@ void RenderingDevice::draw_command_end_label() {
65046444
}
65056445

65066446
String RenderingDevice::get_device_vendor_name() const {
6507-
return _get_device_vendor_name(device);
6447+
return RenderingContextDriver::get_device_vendor_name(device);
65086448
}
65096449

65106450
String RenderingDevice::get_device_name() const {
@@ -6953,30 +6893,8 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ
69536893
context = p_context;
69546894
driver = context->driver_create();
69556895

6956-
print_verbose("Devices:");
6957-
int32_t device_index = Engine::get_singleton()->get_gpu_index();
6958-
const uint32_t device_count = context->device_get_count();
6959-
const bool detect_device = (device_index < 0) || (device_index >= int32_t(device_count));
6960-
uint32_t device_type_score = 0;
6961-
for (uint32_t i = 0; i < device_count; i++) {
6962-
RenderingContextDriver::Device device_option = context->device_get(i);
6963-
String name = device_option.name;
6964-
String vendor = _get_device_vendor_name(device_option);
6965-
String type = _get_device_type_name(device_option);
6966-
bool present_supported = main_surface != 0 ? context->device_supports_present(i, main_surface) : false;
6967-
print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + type);
6968-
if (detect_device && (present_supported || main_surface == 0)) {
6969-
// If a window was specified, present must be supported by the device to be available as an option.
6970-
// Assign a score for each type of device and prefer the device with the higher score.
6971-
uint32_t option_score = _get_device_type_score(device_option);
6972-
if (option_score > device_type_score) {
6973-
device_index = i;
6974-
device_type_score = option_score;
6975-
}
6976-
}
6977-
}
6978-
6979-
ERR_FAIL_COND_V_MSG((device_index < 0) || (device_index >= int32_t(device_count)), ERR_CANT_CREATE, "None of the devices supports both graphics and present queues.");
6896+
int32_t device_index = context->pick_device(main_surface, true);
6897+
ERR_FAIL_COND_V_MSG((device_index < 0) || (device_index >= int32_t(context->device_get_count())), ERR_CANT_CREATE, "None of the devices supports both graphics and present queues.");
69806898

69816899
uint32_t frame_count = 1;
69826900
if (main_surface != 0) {
@@ -7000,7 +6918,7 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ
70006918
}
70016919

70026920
// Output our device version.
7003-
Engine::get_singleton()->print_header(vformat("%s %s - %s - Using Device #%d: %s - %s", get_device_api_name(), get_device_api_version(), rendering_method, device_index, _get_device_vendor_name(device), device.name));
6921+
Engine::get_singleton()->print_header(vformat("%s %s - %s - Using Device #%d: %s - %s", get_device_api_name(), get_device_api_version(), rendering_method, device_index, RenderingContextDriver::get_device_vendor_name(device), device.name));
70046922
}
70056923

70066924
// Pick the main queue family. It is worth noting we explicitly do not request the transfer bit, as apparently the specification defines

0 commit comments

Comments
 (0)