diff options
Diffstat (limited to 'platform/windows/gl_manager_windows.cpp')
-rw-r--r-- | platform/windows/gl_manager_windows.cpp | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows.cpp index 1494e3ed1b..ad7c637a37 100644 --- a/platform/windows/gl_manager_windows.cpp +++ b/platform/windows/gl_manager_windows.cpp @@ -32,6 +32,11 @@ #if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED) +#include "core/config/project_settings.h" +#include "core/version.h" + +#include "thirdparty/nvapi/nvapi_minimal.h" + #include <dwmapi.h> #include <stdio.h> #include <stdlib.h> @@ -64,6 +69,171 @@ static String format_error_message(DWORD id) { return msg; } +const int OGL_THREAD_CONTROL_ID = 0x20C1221E; +const int OGL_THREAD_CONTROL_DISABLE = 0x00000002; +const int OGL_THREAD_CONTROL_ENABLE = 0x00000001; + +typedef int(__cdecl *NvAPI_Initialize_t)(); +typedef int(__cdecl *NvAPI_Unload_t)(); +typedef int(__cdecl *NvAPI_GetErrorMessage_t)(unsigned int, NvAPI_ShortString); +typedef int(__cdecl *NvAPI_DRS_CreateSession_t)(NvDRSSessionHandle *); +typedef int(__cdecl *NvAPI_DRS_DestroySession_t)(NvDRSSessionHandle); +typedef int(__cdecl *NvAPI_DRS_LoadSettings_t)(NvDRSSessionHandle); +typedef int(__cdecl *NvAPI_DRS_CreateProfile_t)(NvDRSSessionHandle, NVDRS_PROFILE *, NvDRSProfileHandle *); +typedef int(__cdecl *NvAPI_DRS_CreateApplication_t)(NvDRSSessionHandle, NvDRSProfileHandle, NVDRS_APPLICATION *); +typedef int(__cdecl *NvAPI_DRS_SaveSettings_t)(NvDRSSessionHandle); +typedef int(__cdecl *NvAPI_DRS_SetSetting_t)(NvDRSSessionHandle, NvDRSProfileHandle, NVDRS_SETTING *); +typedef int(__cdecl *NvAPI_DRS_FindProfileByName_t)(NvDRSSessionHandle, NvAPI_UnicodeString, NvDRSProfileHandle *); +NvAPI_GetErrorMessage_t NvAPI_GetErrorMessage__; + +static bool nvapi_err_check(char *msg, int status) { + if (status != 0) { + if (OS::get_singleton()->is_stdout_verbose()) { + NvAPI_ShortString err_desc = { 0 }; + NvAPI_GetErrorMessage__(status, err_desc); + print_verbose(vformat("%s: %s(code %d)", msg, err_desc, status)); + } + return false; + } + return true; +} + +// On windows we have to disable threaded optimization when using NVIDIA graphics cards +// to avoid stuttering, see https://github.com/microsoft/vscode-cpptools/issues/6592 +// also see https://github.com/Ryujinx/Ryujinx/blob/master/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs +void GLManager_Windows::_nvapi_disable_threaded_optimization() { + HMODULE nvapi = 0; +#ifdef _WIN64 + nvapi = LoadLibraryA("nvapi64.dll"); +#else + nvapi = LoadLibraryA("nvapi.dll"); +#endif + + if (nvapi == NULL) { + return; + } + + void *(__cdecl * NvAPI_QueryInterface)(unsigned int interface_id) = 0; + + NvAPI_QueryInterface = (void *(__cdecl *)(unsigned int))GetProcAddress(nvapi, "nvapi_QueryInterface"); + + if (NvAPI_QueryInterface == NULL) { + print_verbose("Error getting NVAPI NvAPI_QueryInterface"); + return; + } + + // Setup NVAPI function pointers + NvAPI_Initialize_t NvAPI_Initialize = (NvAPI_Initialize_t)NvAPI_QueryInterface(0x0150E828); + NvAPI_GetErrorMessage__ = (NvAPI_GetErrorMessage_t)NvAPI_QueryInterface(0x6C2D048C); + NvAPI_DRS_CreateSession_t NvAPI_DRS_CreateSession = (NvAPI_DRS_CreateSession_t)NvAPI_QueryInterface(0x0694D52E); + NvAPI_DRS_DestroySession_t NvAPI_DRS_DestroySession = (NvAPI_DRS_DestroySession_t)NvAPI_QueryInterface(0xDAD9CFF8); + NvAPI_Unload_t NvAPI_Unload = (NvAPI_Unload_t)NvAPI_QueryInterface(0xD22BDD7E); + NvAPI_DRS_LoadSettings_t NvAPI_DRS_LoadSettings = (NvAPI_DRS_LoadSettings_t)NvAPI_QueryInterface(0x375DBD6B); + NvAPI_DRS_CreateProfile_t NvAPI_DRS_CreateProfile = (NvAPI_DRS_CreateProfile_t)NvAPI_QueryInterface(0xCC176068); + NvAPI_DRS_CreateApplication_t NvAPI_DRS_CreateApplication = (NvAPI_DRS_CreateApplication_t)NvAPI_QueryInterface(0x4347A9DE); + NvAPI_DRS_SaveSettings_t NvAPI_DRS_SaveSettings = (NvAPI_DRS_SaveSettings_t)NvAPI_QueryInterface(0xFCBC7E14); + NvAPI_DRS_SetSetting_t NvAPI_DRS_SetSetting = (NvAPI_DRS_SetSetting_t)NvAPI_QueryInterface(0x577DD202); + NvAPI_DRS_FindProfileByName_t NvAPI_DRS_FindProfileByName = (NvAPI_DRS_FindProfileByName_t)NvAPI_QueryInterface(0x7E4A9A0B); + + if (!nvapi_err_check("NVAPI: Init failed", NvAPI_Initialize())) { + return; + } + + print_verbose("NVAPI: Init OK!"); + + NvDRSSessionHandle session_handle; + + if (!nvapi_err_check("NVAPI: Error creating DRS session", NvAPI_DRS_CreateSession(&session_handle))) { + NvAPI_Unload(); + return; + } + + if (!nvapi_err_check("NVAPI: Error loading DRS settings", NvAPI_DRS_LoadSettings(session_handle))) { + NvAPI_DRS_DestroySession(session_handle); + NvAPI_Unload(); + return; + } + + String app_executable_name = OS::get_singleton()->get_executable_path().get_file(); + String app_friendly_name = GLOBAL_GET("application/config/name"); + // We need a name anyways, so let's use the engine name if an application name is not available + // (this is used mostly by the Project Manager) + if (app_friendly_name.is_empty()) { + app_friendly_name = VERSION_NAME; + } + String app_profile_name = app_friendly_name + " Nvidia Profile"; + Char16String app_profile_name_u16 = app_profile_name.utf16(); + Char16String app_executable_name_u16 = app_executable_name.utf16(); + Char16String app_friendly_name_u16 = app_friendly_name.utf16(); + + NvDRSProfileHandle profile_handle = 0; + + int status = NvAPI_DRS_FindProfileByName(session_handle, (NvU16 *)(app_profile_name_u16.ptrw()), &profile_handle); + + if (status != 0) { + print_verbose("NVAPI: Profile not found, creating...."); + + NVDRS_PROFILE profile_info; + profile_info.version = NVDRS_PROFILE_VER; + profile_info.isPredefined = 0; + memcpy(profile_info.profileName, app_profile_name_u16.get_data(), sizeof(char16_t) * app_profile_name_u16.size()); + + if (!nvapi_err_check("NVAPI: Error creating profile", NvAPI_DRS_CreateProfile(session_handle, &profile_info, &profile_handle))) { + NvAPI_DRS_DestroySession(session_handle); + NvAPI_Unload(); + return; + } + + NVDRS_APPLICATION_V4 app; + app.version = NVDRS_APPLICATION_VER_V4; + app.isPredefined = 0; + app.isMetro = 1; + app.isCommandLine = 1; + memcpy(app.appName, app_executable_name_u16.get_data(), sizeof(char16_t) * app_executable_name_u16.size()); + memcpy(app.userFriendlyName, app_friendly_name_u16.get_data(), sizeof(char16_t) * app_friendly_name_u16.size()); + memcpy(app.launcher, L"", 1); + memcpy(app.fileInFolder, L"", 1); + + if (!nvapi_err_check("NVAPI: Error creating application", NvAPI_DRS_CreateApplication(session_handle, profile_handle, &app))) { + NvAPI_DRS_DestroySession(session_handle); + NvAPI_Unload(); + return; + } + } + + 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; + 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; + + if (!nvapi_err_check("NVAPI: Error calling NvAPI_DRS_SetSetting", NvAPI_DRS_SetSetting(session_handle, profile_handle, &setting))) { + NvAPI_DRS_DestroySession(session_handle); + NvAPI_Unload(); + return; + } + + if (!nvapi_err_check("NVAPI: Error saving settings", NvAPI_DRS_SaveSettings(session_handle))) { + NvAPI_DRS_DestroySession(session_handle); + NvAPI_Unload(); + return; + } + if (thread_control_val == OGL_THREAD_CONTROL_DISABLE) { + print_verbose("NVAPI: Disabled OpenGL threaded optimization successfully"); + } else { + print_verbose("NVAPI: Enabled OpenGL threaded optimization successfully"); + } + NvAPI_DRS_DestroySession(session_handle); +} + int GLManager_Windows::_find_or_create_display(GLWindow &win) { // find display NYI, only 1 supported so far if (_displays.size()) { @@ -295,6 +465,7 @@ void GLManager_Windows::swap_buffers() { } Error GLManager_Windows::initialize() { + _nvapi_disable_threaded_optimization(); return OK; } |