Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3348,6 +3348,10 @@
- [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.
[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].
</member>
<member name="rendering/rendering_device/excluded_device_list" type="String" setter="" getter="" default="&quot;&quot;">
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.
[b]Note:[/b] The name must be an exact match of the full GPU model name (case-sensitive). Use [method RenderingDevice.get_device_name] to retrieve the device's name.
</member>
<member name="rendering/rendering_device/fallback_to_d3d12" type="bool" setter="" getter="" default="true">
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.
[b]Note:[/b] This setting is implemented only on Windows.
Expand Down
2 changes: 1 addition & 1 deletion drivers/d3d12/rendering_context_driver_d3d12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ Error RenderingContextDriverD3D12::initialize() {
err = _initialize_devices();
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);

return OK;
return _check_excluded_devices();
Comment thread
clayjohn marked this conversation as resolved.
}

const RenderingContextDriver::Device &RenderingContextDriverD3D12::device_get(uint32_t p_device_index) const {
Expand Down
2 changes: 1 addition & 1 deletion drivers/metal/rendering_context_driver_metal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Error RenderingContextDriverMetal::initialize() {
int version = (int)props.features.highestFamily - (int)MTL::GPUFamilyApple1 + 1;
device.name = vformat("%s (Apple%d)", metal_device->name()->utf8String(), version);

return OK;
return _check_excluded_devices();
}

const RenderingContextDriver::Device &RenderingContextDriverMetal::device_get(uint32_t p_device_index) const {
Expand Down
2 changes: 1 addition & 1 deletion drivers/vulkan/rendering_context_driver_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,7 @@ Error RenderingContextDriverVulkan::initialize() {
err = _initialize_devices();
ERR_FAIL_COND_V(err != OK, err);

return OK;
return _check_excluded_devices();
}

const RenderingContextDriver::Device &RenderingContextDriverVulkan::device_get(uint32_t p_device_index) const {
Expand Down
1 change: 1 addition & 0 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2391,6 +2391,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_vulkan", true);
GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_d3d12", true);
GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_opengl3", true);
GLOBAL_DEF_RST("rendering/rendering_device/excluded_device_list", "");
}

{
Expand Down
112 changes: 112 additions & 0 deletions servers/rendering/rendering_context_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@

#include "rendering_context_driver.h"

#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/os/os.h"

RenderingContextDriver::~RenderingContextDriver() {
}

Expand Down Expand Up @@ -158,6 +162,58 @@ void RenderingContextDriver::window_destroy(DisplayServerEnums::WindowID p_windo
window_surface_map.erase(p_window);
}

int32_t RenderingContextDriver::pick_device(SurfaceID p_surface, bool p_print_verbose) {
if (p_print_verbose) {
print_verbose("Devices:");
}

int32_t device_index = Engine::get_singleton()->get_gpu_index();
const uint32_t device_count = device_get_count();
const bool device_index_out_of_range = (device_index >= int32_t(device_count));
if (device_index_out_of_range) {
WARN_PRINT(vformat("The specified GPU index %d is out of range on this system (0-%d). Falling back to automatic device selection.", device_index, device_count - 1));
}

const bool detect_device = (device_index < 0) || device_index_out_of_range;
uint32_t device_type_score = 0;
for (uint32_t i = 0; i < device_count; i++) {
RenderingContextDriver::Device device_option = device_get(i);
String name = device_option.name;
String vendor = get_device_vendor_name(device_option);
String type = get_device_type_name(device_option);
bool present_supported = p_surface != 0 ? device_supports_present(i, p_surface) : false;
if (p_print_verbose) {
print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + type);
}

if (detect_device && (present_supported || p_surface == 0)) {
// If a window was specified, present must be supported by the device to be available as an option.
// Assign a score for each type of device and prefer the device with the higher score.
uint32_t option_score = get_device_type_score(device_option);
if (option_score > device_type_score) {
device_index = i;
device_type_score = option_score;
}
}
}

return device_index;
}

Error RenderingContextDriver::_check_excluded_devices() {
// Check if the picked device from the context is excluded from using RenderingDevice. The names must be an exact string match.
String device_list_string = GLOBAL_GET("rendering/rendering_device/excluded_device_list");
PackedStringArray device_list = device_list_string.split(",");
int32_t device_index = pick_device(0, false);
if (device_index >= 0 && device_index < (int32_t)(device_get_count())) {
const RenderingContextDriver::Device &device = device_get(device_index);
return device_list.has(device.name) ? ERR_CANT_CREATE : OK;
} else {
// No valid device was found, so just fail on this step instead.
return ERR_CANT_CREATE;
}
}

String RenderingContextDriver::get_driver_and_device_memory_report() const {
String report;

Expand Down Expand Up @@ -242,3 +298,59 @@ uint64_t RenderingContextDriver::get_device_memory_by_object_type(uint32_t) cons
uint64_t RenderingContextDriver::get_device_allocs_by_object_type(uint32_t) const {
return 0;
}

String RenderingContextDriver::get_device_vendor_name(const Device &p_device) {
switch (p_device.vendor) {
case RenderingContextDriver::Vendor::VENDOR_AMD:
return "AMD";
case RenderingContextDriver::Vendor::VENDOR_IMGTEC:
return "ImgTec";
case RenderingContextDriver::Vendor::VENDOR_APPLE:
return "Apple";
case RenderingContextDriver::Vendor::VENDOR_NVIDIA:
return "NVIDIA";
case RenderingContextDriver::Vendor::VENDOR_ARM:
return "ARM";
case RenderingContextDriver::Vendor::VENDOR_MICROSOFT:
return "Microsoft";
case RenderingContextDriver::Vendor::VENDOR_QUALCOMM:
return "Qualcomm";
case RenderingContextDriver::Vendor::VENDOR_INTEL:
return "Intel";
default:
return "Unknown";
}
}

String RenderingContextDriver::get_device_type_name(const Device &p_device) {
switch (p_device.type) {
case RenderingContextDriver::DEVICE_TYPE_INTEGRATED_GPU:
return "Integrated";
case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU:
return "Discrete";
case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU:
return "Virtual";
case RenderingContextDriver::DEVICE_TYPE_CPU:
return "CPU";
case RenderingContextDriver::DEVICE_TYPE_OTHER:
default:
return "Other";
}
}

uint32_t RenderingContextDriver::get_device_type_score(const Device &p_device) {
static const bool prefer_integrated = OS::get_singleton()->get_user_prefers_integrated_gpu();
switch (p_device.type) {
case RenderingContextDriver::DEVICE_TYPE_INTEGRATED_GPU:
return prefer_integrated ? 5 : 4;
case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU:
return prefer_integrated ? 4 : 5;
case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU:
return 3;
case RenderingContextDriver::DEVICE_TYPE_CPU:
return 2;
case RenderingContextDriver::DEVICE_TYPE_OTHER:
default:
return 1;
}
}
8 changes: 8 additions & 0 deletions servers/rendering/rendering_context_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class RenderingContextDriver {
private:
HashMap<DisplayServerEnums::WindowID, SurfaceID> window_surface_map;

protected:
Error _check_excluded_devices();

public:
SurfaceID surface_get_from_window(DisplayServerEnums::WindowID p_window) const;
Error window_create(DisplayServerEnums::WindowID p_window, const void *p_platform_data);
Expand Down Expand Up @@ -126,6 +129,7 @@ class RenderingContextDriver {
virtual void surface_destroy(SurfaceID p_surface) = 0;
virtual bool is_debug_utils_enabled() const = 0;

int32_t pick_device(SurfaceID p_surface, bool p_print_verbose);
String get_driver_and_device_memory_report() const;

virtual const char *get_tracked_object_name(uint32_t p_type_index) const;
Expand All @@ -140,4 +144,8 @@ class RenderingContextDriver {
virtual uint64_t get_device_allocation_count() const;
virtual uint64_t get_device_memory_by_object_type(uint32_t p_type) const;
virtual uint64_t get_device_allocs_by_object_type(uint32_t p_type) const;

static String get_device_vendor_name(const Device &p_device);
static String get_device_type_name(const Device &p_device);
static uint32_t get_device_type_score(const Device &p_device);
};
92 changes: 4 additions & 88 deletions servers/rendering/rendering_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,62 +60,6 @@
/**** HELPER FUNCTIONS ****/
/**************************/

static String _get_device_vendor_name(const RenderingContextDriver::Device &p_device) {
switch (p_device.vendor) {
case RenderingContextDriver::Vendor::VENDOR_AMD:
return "AMD";
case RenderingContextDriver::Vendor::VENDOR_IMGTEC:
return "ImgTec";
case RenderingContextDriver::Vendor::VENDOR_APPLE:
return "Apple";
case RenderingContextDriver::Vendor::VENDOR_NVIDIA:
return "NVIDIA";
case RenderingContextDriver::Vendor::VENDOR_ARM:
return "ARM";
case RenderingContextDriver::Vendor::VENDOR_MICROSOFT:
return "Microsoft";
case RenderingContextDriver::Vendor::VENDOR_QUALCOMM:
return "Qualcomm";
case RenderingContextDriver::Vendor::VENDOR_INTEL:
return "Intel";
default:
return "Unknown";
}
}

static String _get_device_type_name(const RenderingContextDriver::Device &p_device) {
switch (p_device.type) {
case RenderingContextDriver::DEVICE_TYPE_INTEGRATED_GPU:
return "Integrated";
case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU:
return "Discrete";
case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU:
return "Virtual";
case RenderingContextDriver::DEVICE_TYPE_CPU:
return "CPU";
case RenderingContextDriver::DEVICE_TYPE_OTHER:
default:
return "Other";
}
}

static uint32_t _get_device_type_score(const RenderingContextDriver::Device &p_device) {
static const bool prefer_integrated = OS::get_singleton()->get_user_prefers_integrated_gpu();
switch (p_device.type) {
case RenderingContextDriver::DEVICE_TYPE_INTEGRATED_GPU:
return prefer_integrated ? 5 : 4;
case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU:
return prefer_integrated ? 4 : 5;
case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU:
return 3;
case RenderingContextDriver::DEVICE_TYPE_CPU:
return 2;
case RenderingContextDriver::DEVICE_TYPE_OTHER:
default:
return 1;
}
}

static uint32_t _decode_hit_sbt_range_offset(RD::HitShaderBindingTableRange p_range) {
return uint32_t(uint64_t(p_range) & 0xFFFFFFFF);
}
Expand Down Expand Up @@ -7814,7 +7758,7 @@ void RenderingDevice::draw_command_end_label() {
}

String RenderingDevice::get_device_vendor_name() const {
return _get_device_vendor_name(device);
return RenderingContextDriver::get_device_vendor_name(device);
}

String RenderingDevice::get_device_name() const {
Expand Down Expand Up @@ -8308,36 +8252,8 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ
context = p_context;
driver = context->driver_create();

print_verbose("Devices:");
int32_t device_index = Engine::get_singleton()->get_gpu_index();
const uint32_t device_count = context->device_get_count();
const bool device_index_out_of_range = (device_index >= int32_t(device_count));
const bool detect_device = (device_index < 0) || device_index_out_of_range;

if (device_index_out_of_range) {
WARN_PRINT(vformat("The specified GPU index %d is out of range on this system (0-%d). Falling back to automatic device selection.", device_index, device_count - 1));
}

uint32_t device_type_score = 0;
for (uint32_t i = 0; i < device_count; i++) {
RenderingContextDriver::Device device_option = context->device_get(i);
String name = device_option.name;
String vendor = _get_device_vendor_name(device_option);
String type = _get_device_type_name(device_option);
bool present_supported = main_surface != 0 ? context->device_supports_present(i, main_surface) : false;
print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + type);
if (detect_device && (present_supported || main_surface == 0)) {
// If a window was specified, present must be supported by the device to be available as an option.
// Assign a score for each type of device and prefer the device with the higher score.
uint32_t option_score = _get_device_type_score(device_option);
if (option_score > device_type_score) {
device_index = i;
device_type_score = option_score;
}
}
}

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.");
int32_t device_index = context->pick_device(main_surface, true);
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.");

uint32_t frame_count = 1;
if (main_surface != 0) {
Expand All @@ -8361,7 +8277,7 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ
}

// Output our device version.
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));
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));
}

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