From b8edc64379b3c4b5f2e7334468be65fd44a4980c Mon Sep 17 00:00:00 2001 From: Aitor Guevara <428243+aitorciki@users.noreply.github.com> Date: Sat, 29 Jun 2024 13:02:30 +0200 Subject: [PATCH] [Windows] Disable G-SYNC in windowed mode G-SYNC (NVIDIA's VRR) is known to be buggy on windowed mode in Windows. While the driver only enables G-SYNC for full screen mode by default, users can toggle it on for windowed mode too, resulting in unstable refresh rates during Editor usage. This patch extends Godot's NVIDIA profile to force the default full screen mode only G-SYNC with Godot. --- .../windows/gl_manager_windows_native.cpp | 43 ++++++++++++------- platform/windows/gl_manager_windows_native.h | 2 +- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/platform/windows/gl_manager_windows_native.cpp b/platform/windows/gl_manager_windows_native.cpp index c8d7534e269..f74aa4ced7d 100644 --- a/platform/windows/gl_manager_windows_native.cpp +++ b/platform/windows/gl_manager_windows_native.cpp @@ -76,6 +76,8 @@ static String format_error_message(DWORD id) { const int OGL_THREAD_CONTROL_ID = 0x20C1221E; const int OGL_THREAD_CONTROL_DISABLE = 0x00000002; const int OGL_THREAD_CONTROL_ENABLE = 0x00000001; +const int VRR_MODE_ID = 0x1194F158; +const int VRR_MODE_FULLSCREEN_ONLY = 0x1; typedef int(__cdecl *NvAPI_Initialize_t)(); typedef int(__cdecl *NvAPI_Unload_t)(); @@ -104,10 +106,12 @@ static bool nvapi_err_check(const char *msg, int status) { return true; } -// On windows we have to disable threaded optimization when using NVIDIA graphics cards -// to avoid stuttering, see https://stackoverflow.com/questions/36959508/nvidia-graphics-driver-causing-noticeable-frame-stuttering/37632948 -// also see https://github.com/Ryujinx/Ryujinx/blob/master/src/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs -void GLManagerNative_Windows::_nvapi_disable_threaded_optimization() { +// On windows we have to customize the NVIDIA application profile: +// * disable threaded optimization when using NVIDIA cards to avoid stuttering, see +// https://stackoverflow.com/questions/36959508/nvidia-graphics-driver-causing-noticeable-frame-stuttering/37632948 +// https://github.com/Ryujinx/Ryujinx/blob/master/src/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs +// * disable G-SYNC in windowed mode, as it results in unstable editor refresh rates +void GLManagerNative_Windows::_nvapi_setup_profile() { HMODULE nvapi = nullptr; #ifdef _WIN64 nvapi = LoadLibraryA("nvapi64.dll"); @@ -239,21 +243,29 @@ void GLManagerNative_Windows::_nvapi_disable_threaded_optimization() { } } - NVDRS_SETTING setting; - setting.version = NVDRS_SETTING_VER; - setting.settingId = OGL_THREAD_CONTROL_ID; - setting.settingType = NVDRS_DWORD_TYPE; - setting.settingLocation = NVDRS_CURRENT_PROFILE_LOCATION; - setting.isCurrentPredefined = 0; - setting.isPredefinedValid = 0; + NVDRS_SETTING ogl_thread_control_setting = { 0 }; + ogl_thread_control_setting.version = NVDRS_SETTING_VER; + ogl_thread_control_setting.settingId = OGL_THREAD_CONTROL_ID; + ogl_thread_control_setting.settingType = NVDRS_DWORD_TYPE; int thread_control_val = OGL_THREAD_CONTROL_DISABLE; if (!GLOBAL_GET("rendering/gl_compatibility/nvidia_disable_threaded_optimization")) { thread_control_val = OGL_THREAD_CONTROL_ENABLE; } - setting.u32CurrentValue = thread_control_val; - setting.u32PredefinedValue = thread_control_val; + ogl_thread_control_setting.u32CurrentValue = thread_control_val; - if (!nvapi_err_check("NVAPI: Error calling NvAPI_DRS_SetSetting", NvAPI_DRS_SetSetting(session_handle, profile_handle, &setting))) { + if (!nvapi_err_check("NVAPI: Error calling NvAPI_DRS_SetSetting", NvAPI_DRS_SetSetting(session_handle, profile_handle, &ogl_thread_control_setting))) { + NvAPI_DRS_DestroySession(session_handle); + NvAPI_Unload(); + return; + } + + NVDRS_SETTING vrr_mode_setting = { 0 }; + vrr_mode_setting.version = NVDRS_SETTING_VER; + vrr_mode_setting.settingId = VRR_MODE_ID; + vrr_mode_setting.settingType = NVDRS_DWORD_TYPE; + vrr_mode_setting.u32CurrentValue = VRR_MODE_FULLSCREEN_ONLY; + + if (!nvapi_err_check("NVAPI: Error calling NvAPI_DRS_SetSetting", NvAPI_DRS_SetSetting(session_handle, profile_handle, &vrr_mode_setting))) { NvAPI_DRS_DestroySession(session_handle); NvAPI_Unload(); return; @@ -270,6 +282,7 @@ void GLManagerNative_Windows::_nvapi_disable_threaded_optimization() { } else { print_verbose("NVAPI: Enabled OpenGL threaded optimization successfully"); } + print_verbose("NVAPI: Disabled G-SYNC for windowed mode successfully"); NvAPI_DRS_DestroySession(session_handle); } @@ -495,7 +508,7 @@ void GLManagerNative_Windows::swap_buffers() { } Error GLManagerNative_Windows::initialize() { - _nvapi_disable_threaded_optimization(); + _nvapi_setup_profile(); return OK; } diff --git a/platform/windows/gl_manager_windows_native.h b/platform/windows/gl_manager_windows_native.h index b4e2a3acdf5..532092ae743 100644 --- a/platform/windows/gl_manager_windows_native.h +++ b/platform/windows/gl_manager_windows_native.h @@ -78,7 +78,7 @@ private: int glx_minor, glx_major; private: - void _nvapi_disable_threaded_optimization(); + void _nvapi_setup_profile(); int _find_or_create_display(GLWindow &win); Error _create_context(GLWindow &win, GLDisplay &gl_display);