From b5d4cd8b344b8340ffb1b73451526466e0454ea6 Mon Sep 17 00:00:00 2001 From: Radek Dutkiewicz Date: Tue, 19 Mar 2019 01:28:01 +0000 Subject: [PATCH] Fixed reggression in video rendering framerates on Nvidia - Replacing triple buffering with frame queue seems to do much better job in ensuring the videos are playing smoothly. The unusual low framerate of videos was manifesting in some edge cases after the commit that fixed high cpu usage on playing videos and when triple buffering was added. - Refactored nvapi profile management to better handle situations when the user manually created a profile for Attract Mode. --- extlibs/nvapi/nvapi.hpp | 97 ++++++++++++++++++++++------- extlibs/nvapi/nvapi_definitions.hpp | 19 +++++- src/main.cpp | 4 +- 3 files changed, 95 insertions(+), 25 deletions(-) diff --git a/extlibs/nvapi/nvapi.hpp b/extlibs/nvapi/nvapi.hpp index 957041a2e..4259a11c9 100644 --- a/extlibs/nvapi/nvapi.hpp +++ b/extlibs/nvapi/nvapi.hpp @@ -33,12 +33,15 @@ namespace { int nvapi_init() { const bool disableThreadedOptimizations = true; - const bool maximumPerformance = true; - const bool enableTripleBuffering = true; + const bool setMaximumPerformance = true; + const bool disableTripleBuffering = true; + const bool setPrerenderedFrames = true; - const wchar_t* profileName = L"Attract Mode2"; + const wchar_t* profileName = L"Attract Mode"; const wchar_t* appName = L""; + int return_code = 0; + std::wstring file_name; wchar_t result[MAX_PATH]; file_name = std::wstring( result, GetModuleFileNameW( NULL, result, MAX_PATH )); @@ -49,7 +52,6 @@ namespace { HMODULE hmod = LoadLibrary( NVAPI_DLL ); if ( hmod == NULL ) { - //FeLog remove FeDebug() << "NvAPI: " << NVAPI_DLL << " not found" << std::endl; return 0; } @@ -64,6 +66,7 @@ namespace { NvAPI_EnumPhysicalGPUs = (NvAPI_EnumPhysicalGPUs_t) (*NvAPI_QueryInterface)(0xE5AC921F); NvAPI_GPU_GetUsages = (NvAPI_GPU_GetUsages_t) (*NvAPI_QueryInterface)(0x189A1FDF); NvAPI_DRS_CreateProfile = (NvAPI_DRS_CreateProfile_t) (*NvAPI_QueryInterface)(0xCC176068); + NvAPI_DRS_DeleteProfile = (NvAPI_DRS_DeleteProfile_t) (*NvAPI_QueryInterface)(0x17093206); NvAPI_DRS_CreateSession = (NvAPI_DRS_CreateSession_t) (*NvAPI_QueryInterface)(0x0694D52E); NvAPI_DRS_LoadSettings = (NvAPI_DRS_LoadSettings_t) (*NvAPI_QueryInterface)(0x375DBD6B); NvAPI_DRS_CreateApplication = (NvAPI_DRS_CreateApplication_t) (*NvAPI_QueryInterface)(0x4347A9DE); @@ -71,6 +74,8 @@ namespace { NvAPI_DRS_SaveSettings = (NvAPI_DRS_SaveSettings_t) (*NvAPI_QueryInterface)(0xFCBC7E14); NvAPI_DRS_DestroySession = (NvAPI_DRS_DestroySession_t) (*NvAPI_QueryInterface)(0x0DAD9CFF8); NvAPI_DRS_FindProfileByName = (NvAPI_DRS_FindProfileByName_t) (*NvAPI_QueryInterface)(0x7E4A9A0B); + NvAPI_DRS_FindApplicationByName = (NvAPI_DRS_FindApplicationByName_t) (*NvAPI_QueryInterface)(0xEEE566B2); + NvAPI_DRS_GetProfileInfo = (NvAPI_DRS_GetProfileInfo_t) (*NvAPI_QueryInterface)(0x61CD6FD6); NvAPI_GetErrorMessage = (NvAPI_GetErrorMessage_t) (*NvAPI_QueryInterface)(0x6C2D048C); NvDRSSessionHandle hSession; @@ -78,9 +83,9 @@ namespace { // Initialize NvAPI status = NvAPI_Initialize(); - FeDebug() << "NvAPI: Initialize: " << nvapi_get_error_msg( status ); - if ( status != NVAPI_OK ) - return 0; + FeDebug() << "NvAPI: Initialize: " << nvapi_get_error_msg( status ); + if ( status != NVAPI_OK ) + return 0; status = NvAPI_DRS_CreateSession( &hSession ); FeDebug() << "NvAPI: CreateSession: " << nvapi_get_error_msg( status ); @@ -88,14 +93,41 @@ namespace { status = NvAPI_DRS_LoadSettings( hSession ); FeDebug() << "NvAPI: LoadSettings: " << nvapi_get_error_msg( status ); - // Fill profile info + // Fill application info + NVDRS_APPLICATION app; + app.version = NVDRS_APPLICATION_VER; + app.isPredefined = 0; + nvapi_set_ustring( app.appName, appName ); + nvapi_set_ustring( app.launcher, L"" ); + + NvDRSProfileHandle hProfile; + + status = NvAPI_DRS_FindApplicationByName(hSession, app.appName, &hProfile, &app); + if ( status != NVAPI_OK ) + return_code = 1; + NVDRS_PROFILE profileInfo; profileInfo.version = NVDRS_PROFILE_VER; profileInfo.isPredefined = 0; + + NvAPI_DRS_GetProfileInfo(hSession, hProfile, &profileInfo); + + if ( status == NVAPI_OK ) + { + if ( std::wcscmp((wchar_t*)profileInfo.profileName, profileName) != 0 ) + { + FeDebug() << "NvAPI: " << nowide::narrow( file_name ) << " is already assigned in profile " << + nowide::narrow((wchar_t*)profileInfo.profileName) << std::endl; + status = NvAPI_DRS_DeleteProfile( hSession, hProfile ); + FeDebug() << "NvAPI: Deleting Nvidia profile: " << nvapi_get_error_msg( status ); + return_code = 1; + } + } + + // Fill profile info nvapi_set_ustring( profileInfo.profileName, profileName ); // Open profile or create if not found - NvDRSProfileHandle hProfile; status = NvAPI_DRS_FindProfileByName( hSession, profileInfo.profileName, &hProfile ); FeDebug() << "NvAPI: FindProfileByName: " << nvapi_get_error_msg( status ); @@ -105,13 +137,6 @@ namespace { FeDebug() << "NvAPI: CreateProfile: " << nvapi_get_error_msg( status ); } - // Fill application info - NVDRS_APPLICATION app; - app.version = NVDRS_APPLICATION_VER; - app.isPredefined = 0; - nvapi_set_ustring( app.appName, appName ); - nvapi_set_ustring( app.launcher, L"" ); - // Create application status = NvAPI_DRS_CreateApplication( hSession, hProfile, &app ); if ( status != NVAPI_ERROR ) @@ -145,7 +170,7 @@ namespace { } // Set Triple Buffering - if ( enableTripleBuffering ) + if ( disableTripleBuffering ) { setting.version = NVDRS_SETTING_VER; setting.settingId = OGL_TRIPLE_BUFFER_ID; @@ -153,15 +178,43 @@ namespace { setting.settingLocation = NVDRS_CURRENT_PROFILE_LOCATION; setting.isCurrentPredefined = 0; setting.isPredefinedValid = 0; - setting.u32CurrentValue = OGL_TRIPLE_BUFFER_ENABLED; - setting.u32PredefinedValue = OGL_TRIPLE_BUFFER_ENABLED; + setting.u32CurrentValue = OGL_TRIPLE_BUFFER_DISABLED; + setting.u32PredefinedValue = OGL_TRIPLE_BUFFER_DISABLED; + + status = NvAPI_DRS_SetSetting( hSession, hProfile, &setting ); + FeDebug() << "NvAPI: Triple Buffering OFF: " << nvapi_get_error_msg( status ); + } + + // Set Prerendered Frames + if ( setPrerenderedFrames ) + { + setting.version = NVDRS_SETTING_VER; + setting.settingId = PRERENDERLIMIT_ID; + setting.settingType = NVDRS_DWORD_TYPE; + setting.settingLocation = NVDRS_CURRENT_PROFILE_LOCATION; + setting.isCurrentPredefined = 0; + setting.isPredefinedValid = 0; + setting.u32CurrentValue = 0x04; + setting.u32PredefinedValue = 0x04; + + status = NvAPI_DRS_SetSetting( hSession, hProfile, &setting ); + FeDebug() << "NvAPI: Prendered Frames set to 4: " << nvapi_get_error_msg( status ); + + setting.version = NVDRS_SETTING_VER; + setting.settingId = OGL_MAX_FRAMES_ALLOWED_ID; + setting.settingType = NVDRS_DWORD_TYPE; + setting.settingLocation = NVDRS_CURRENT_PROFILE_LOCATION; + setting.isCurrentPredefined = 0; + setting.isPredefinedValid = 0; + setting.u32CurrentValue = 0x04; + setting.u32PredefinedValue = 0x04; status = NvAPI_DRS_SetSetting( hSession, hProfile, &setting ); - FeDebug() << "NvAPI: Triple Buffering ON: " << nvapi_get_error_msg( status ); + FeDebug() << "NvAPI: Maximum frames allowed set to 4: " << nvapi_get_error_msg( status ); } // Set Power State - if ( maximumPerformance ) + if ( setMaximumPerformance ) { setting.version = NVDRS_SETTING_VER; setting.settingId = PREFERRED_PSTATE_ID; @@ -184,6 +237,6 @@ namespace { status = NvAPI_DRS_DestroySession( hSession ); FeDebug() << "NvAPI: Closing Nvidia session: " << nvapi_get_error_msg( status ); - return 0; + return return_code; } } diff --git a/extlibs/nvapi/nvapi_definitions.hpp b/extlibs/nvapi/nvapi_definitions.hpp index c4419a94d..ca7219cd8 100644 --- a/extlibs/nvapi/nvapi_definitions.hpp +++ b/extlibs/nvapi/nvapi_definitions.hpp @@ -9,8 +9,9 @@ namespace { enum Esetting { OGL_THREAD_CONTROL_ID = 0x20C1221E, OGL_TRIPLE_BUFFER_ID = 0x20FDD1F9, - PREFERRED_PSTATE_ID = 0x1057EB71 - + PREFERRED_PSTATE_ID = 0x1057EB71, + PRERENDERLIMIT_ID = 0x007BA09E, + OGL_MAX_FRAMES_ALLOWED_ID = 0x208E55E3 }; enum EValues_OGL_THREAD_CONTROL { @@ -40,6 +41,14 @@ enum EValues_PREFERRED_PSTATE { PREFERRED_PSTATE_DEFAULT = PREFERRED_PSTATE_OPTIMAL_POWER }; +enum EValues_PRERENDERLIMIT { + PRERENDERLIMIT_MIN = 0x00, + PRERENDERLIMIT_MAX = 0xff, + PRERENDERLIMIT_APP_CONTROLLED = 0x00, + PRERENDERLIMIT_NUM_VALUES = 3, + PRERENDERLIMIT_DEFAULT = PRERENDERLIMIT_APP_CONTROLLED +}; + typedef enum _NvAPI_Status { NVAPI_OK = 0, //!< Success. Request is completed. @@ -290,6 +299,7 @@ typedef NvAPI_Status (*NvAPI_Initialize_t)(); typedef NvAPI_Status (*NvAPI_EnumPhysicalGPUs_t)(int **handles, int *count); typedef NvAPI_Status (*NvAPI_GPU_GetUsages_t)(int *handle, unsigned int *usages); typedef NvAPI_Status (*NvAPI_DRS_CreateProfile_t)(NvDRSSessionHandle hSession, NVDRS_PROFILE *pProfileInfo, NvDRSProfileHandle *phProfile); +typedef NvAPI_Status (*NvAPI_DRS_DeleteProfile_t)(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile); typedef NvAPI_Status (*NvAPI_DRS_CreateSession_t)(NvDRSSessionHandle *phSession); typedef NvAPI_Status (*NvAPI_DRS_LoadSettings_t)(NvDRSSessionHandle hSession); typedef NvAPI_Status (*NvAPI_DRS_CreateApplication_t)(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_APPLICATION *pApplication); @@ -297,6 +307,8 @@ typedef NvAPI_Status (*NvAPI_DRS_SetSetting_t)(NvDRSSessionHandle hSession, NvDR typedef NvAPI_Status (*NvAPI_DRS_SaveSettings_t)(NvDRSSessionHandle hSession); typedef NvAPI_Status (*NvAPI_DRS_DestroySession_t)(NvDRSSessionHandle hSession); typedef NvAPI_Status (*NvAPI_DRS_FindProfileByName_t)(NvDRSSessionHandle hSession, NvAPI_UnicodeString profileName, NvDRSProfileHandle* phProfile); +typedef NvAPI_Status (*NvAPI_DRS_FindApplicationByName_t)(NvDRSSessionHandle hSession, NvAPI_UnicodeString appName, NvDRSProfileHandle* phProfile, NVDRS_APPLICATION* pApplication); +typedef NvAPI_Status (*NvAPI_DRS_GetProfileInfo_t)(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_PROFILE* pProfileInfo); typedef NvAPI_Status (*NvAPI_GetErrorMessage_t)(NvAPI_Status nr,NvAPI_ShortString szDesc); // nvapi.dll internal function pointers @@ -305,6 +317,7 @@ NvAPI_Initialize_t NvAPI_Initialize = NULL; NvAPI_EnumPhysicalGPUs_t NvAPI_EnumPhysicalGPUs = NULL; NvAPI_GPU_GetUsages_t NvAPI_GPU_GetUsages = NULL; NvAPI_DRS_CreateProfile_t NvAPI_DRS_CreateProfile = NULL; +NvAPI_DRS_DeleteProfile_t NvAPI_DRS_DeleteProfile = NULL; NvAPI_DRS_CreateSession_t NvAPI_DRS_CreateSession = NULL; NvAPI_DRS_LoadSettings_t NvAPI_DRS_LoadSettings = NULL; NvAPI_DRS_CreateApplication_t NvAPI_DRS_CreateApplication = NULL; @@ -312,6 +325,8 @@ NvAPI_DRS_SetSetting_t NvAPI_DRS_SetSetting = NULL; NvAPI_DRS_SaveSettings_t NvAPI_DRS_SaveSettings = NULL; NvAPI_DRS_DestroySession_t NvAPI_DRS_DestroySession = NULL; NvAPI_DRS_FindProfileByName_t NvAPI_DRS_FindProfileByName = NULL; +NvAPI_DRS_FindApplicationByName_t NvAPI_DRS_FindApplicationByName = NULL; +NvAPI_DRS_GetProfileInfo_t NvAPI_DRS_GetProfileInfo = NULL; NvAPI_GetErrorMessage_t NvAPI_GetErrorMessage = NULL; } diff --git a/src/main.cpp b/src/main.cpp index f446b5cc7..e2682ece4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -112,7 +112,9 @@ int main(int argc, char *argv[]) #ifdef SFML_SYSTEM_WINDOWS // Detect an nvidia card and if it's found create an nvidia profile // for Attract Mode with optimizations - nvapi_init(); + if ( nvapi_init() > 0 ) + FeLog() << "Nvidia GPU detected. Attract Mode profile was not found so it has been created.\n" + << "In order for the changes to take effect, please restart Attract Mode\n" << std::endl; FeDebug() << std::endl; #endif