Skip to content

Commit

Permalink
Fixed reggression in video rendering framerates on Nvidia (#552)
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
oomek authored and mickelson committed Mar 23, 2019
1 parent 9c2cacd commit 2060fd9
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 25 deletions.
97 changes: 75 additions & 22 deletions extlibs/nvapi/nvapi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ));
Expand All @@ -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;
}
Expand All @@ -64,38 +66,68 @@ 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);
NvAPI_DRS_SetSetting = (NvAPI_DRS_SetSetting_t) (*NvAPI_QueryInterface)(0x577DD202);
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;
NvAPI_Status status;

// 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 );

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 );

Expand All @@ -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 )
Expand Down Expand Up @@ -145,23 +170,51 @@ namespace {
}

// Set Triple Buffering
if ( enableTripleBuffering )
if ( disableTripleBuffering )
{
setting.version = NVDRS_SETTING_VER;
setting.settingId = OGL_TRIPLE_BUFFER_ID;
setting.settingType = NVDRS_DWORD_TYPE;
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;
Expand All @@ -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;
}
}
19 changes: 17 additions & 2 deletions extlibs/nvapi/nvapi_definitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -290,13 +299,16 @@ 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);
typedef NvAPI_Status (*NvAPI_DRS_SetSetting_t)(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_SETTING *pSetting);
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
Expand All @@ -305,13 +317,16 @@ 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;
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;

}
4 changes: 3 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 2060fd9

Please sign in to comment.