diff --git a/core/os/os.h b/core/os/os.h index 91e0ce93794..be8820eba9d 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -137,6 +137,7 @@ public: int get_display_driver_id() const { return _display_driver_id; } virtual Vector get_video_adapter_driver_info() const = 0; + virtual bool get_user_prefers_integrated_gpu() const { return false; } void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, Logger::ErrorType p_type = Logger::ERR_ERROR); void print(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index fb95c69b522..7316992b60d 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -616,6 +616,72 @@ Vector OS_Windows::get_video_adapter_driver_info() const { return info; } +bool OS_Windows::get_user_prefers_integrated_gpu() const { + // On Windows 10, the preferred GPU configured in Windows Settings is + // stored in the registry under the key + // `HKEY_CURRENT_USER\SOFTWARE\Microsoft\DirectX\UserGpuPreferences` + // with the name being the app ID or EXE path. The value is in the form of + // `GpuPreference=1;`, with the value being 1 for integrated GPU and 2 + // for discrete GPU. On Windows 11, there may be more flags, separated + // by semicolons. + + // If this is a packaged app, use the "application user model ID". + // Otherwise, use the EXE path. + WCHAR value_name[32768]; + bool is_packaged = false; + { + HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); + if (kernel32) { + using GetCurrentApplicationUserModelIdPtr = LONG(WINAPI *)(UINT32 * length, PWSTR id); + GetCurrentApplicationUserModelIdPtr GetCurrentApplicationUserModelId = (GetCurrentApplicationUserModelIdPtr)GetProcAddress(kernel32, "GetCurrentApplicationUserModelId"); + + if (GetCurrentApplicationUserModelId) { + UINT32 length = sizeof(value_name) / sizeof(value_name[0]); + LONG result = GetCurrentApplicationUserModelId(&length, value_name); + if (result == ERROR_SUCCESS) { + is_packaged = true; + } + } + } + } + if (!is_packaged && GetModuleFileNameW(nullptr, value_name, sizeof(value_name) / sizeof(value_name[0])) >= sizeof(value_name) / sizeof(value_name[0])) { + // Paths should never be longer than 32767, but just in case. + return false; + } + + LPCWSTR subkey = L"SOFTWARE\\Microsoft\\DirectX\\UserGpuPreferences"; + HKEY hkey = nullptr; + LSTATUS result = RegOpenKeyExW(HKEY_CURRENT_USER, subkey, 0, KEY_READ, &hkey); + if (result != ERROR_SUCCESS) { + return false; + } + + DWORD size = 0; + result = RegGetValueW(hkey, nullptr, value_name, RRF_RT_REG_SZ, nullptr, nullptr, &size); + if (result != ERROR_SUCCESS || size == 0) { + RegCloseKey(hkey); + return false; + } + + Vector buffer; + buffer.resize(size / sizeof(WCHAR)); + result = RegGetValueW(hkey, nullptr, value_name, RRF_RT_REG_SZ, nullptr, (LPBYTE)buffer.ptrw(), &size); + if (result != ERROR_SUCCESS) { + RegCloseKey(hkey); + return false; + } + + RegCloseKey(hkey); + const String flags = String::utf16((const char16_t *)buffer.ptr(), size / sizeof(WCHAR)); + + for (const String &flag : flags.split(";", false)) { + if (flag == "GpuPreference=1") { + return true; + } + } + return false; +} + OS::DateTime OS_Windows::get_datetime(bool p_utc) const { SYSTEMTIME systemtime; if (p_utc) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index b6a21ed42dd..9c7b98d7fdd 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -172,6 +172,7 @@ public: virtual String get_version() const override; virtual Vector get_video_adapter_driver_info() const override; + virtual bool get_user_prefers_integrated_gpu() const override; virtual void initialize_joypads() override {} diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 9e3ab5da495..a6612c0dc94 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -82,11 +82,12 @@ static String _get_device_type_name(const RenderingContextDriver::Device &p_devi } 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 4; + return prefer_integrated ? 5 : 4; case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU: - return 5; + return prefer_integrated ? 4 : 5; case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU: return 3; case RenderingContextDriver::DEVICE_TYPE_CPU: