From 7491fbd677148e38898bb1a39d00ffd15e803ed4 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Mon, 19 Nov 2012 17:40:43 -0600
Subject: [PATCH] MAINT-1841 Use NVAPI to force NVIDIA GPU power management
 mode to prefer max performance

Reviewed by Simon.
---
 autobuild.xml                      |  24 ++++++
 indra/cmake/NVAPI.cmake            |  17 ++++
 indra/newview/CMakeLists.txt       |   2 +
 indra/newview/llappviewerwin32.cpp | 123 +++++++++++++++++++++++++++++
 4 files changed, 166 insertions(+)
 create mode 100644 indra/cmake/NVAPI.cmake

diff --git a/autobuild.xml b/autobuild.xml
index 05e0ac28ae..1bfc540eb9 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -1463,6 +1463,30 @@
           </map>
         </map>
       </map>
+      <key>nvapi</key>
+      <map>
+        <key>license</key>
+        <string>NVAPI</string>
+        <key>license_file</key>
+        <string>LICENSES/NVAPI_SDK_License_Agreement.pdf</string>
+        <key>name</key>
+        <string>nvapi</string>
+        <key>platforms</key>
+        <map>
+          <key>windows</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>baf519d36dffe4e4a59471450e391d01</string>
+              <key>url</key>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-nvapi/rev/267102/arch/CYGWIN/installer/nvapi-304-windows-20121116.tar.bz2</string>
+            </map>
+            <key>name</key>
+            <string>windows</string>
+          </map>
+        </map>
+      </map>
       <key>ogg-vorbis</key>
       <map>
         <key>license</key>
diff --git a/indra/cmake/NVAPI.cmake b/indra/cmake/NVAPI.cmake
new file mode 100644
index 0000000000..78989c408f
--- /dev/null
+++ b/indra/cmake/NVAPI.cmake
@@ -0,0 +1,17 @@
+# -*- cmake -*-
+include(Prebuilt)
+
+set(NVAPI ON CACHE BOOL "Use NVAPI.")
+
+if (NVAPI)
+  use_prebuilt_binary(nvapi)
+  
+  if (WINDOWS)
+    set(NVAPI_LIBRARY nvapi)
+  else (WINDOWS)
+    set(NVAPI_LIBRARY "")
+  endif (WINDOWS)
+else (NVAPI)
+  set(NVAPI_LIBRARY "")
+endif (NVAPI)
+
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 89def532c9..6d8b04c9f3 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -34,6 +34,7 @@ include(LLXML)
 include(LScript)
 include(Linking)
 include(NDOF)
+include(NVAPI)
 include(GooglePerfTools)
 include(TemplateCheck)
 include(UI)
@@ -1812,6 +1813,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${LLMATH_LIBRARIES}
     ${LLCOMMON_LIBRARIES}
     ${NDOF_LIBRARY}
+    ${NVAPI_LIBRARY}
     ${HUNSPELL_LIBRARY}
     ${viewer_LIBRARIES}
     ${BOOST_PROGRAM_OPTIONS_LIBRARY}
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 510ec47a31..23eb558755 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -46,6 +46,11 @@
 #include "llviewercontrol.h"
 #include "lldxhardware.h"
 
+#include "nvapi/nvapi.h"
+#include "nvapi/NvApiDriverSettings.h"
+
+#include <stdlib.h>
+
 #include "llweb.h"
 #include "llsecondlifeurls.h"
 
@@ -60,6 +65,7 @@
 #include "llwindebug.h"
 #endif
 
+
 // *FIX:Mani - This hack is to fix a linker issue with libndofdev.lib
 // The lib was compiled under VS2005 - in VS2003 we need to remap assert
 #ifdef LL_DEBUG
@@ -75,6 +81,20 @@ extern "C" {
 
 const std::string LLAppViewerWin32::sWindowClass = "Second Life";
 
+/*
+    This function is used to print to the command line a text message 
+    describing the nvapi error and quits
+*/
+void nvapi_error(NvAPI_Status status)
+{
+    NvAPI_ShortString szDesc = {0};
+	NvAPI_GetErrorMessage(status, szDesc);
+	llwarns << szDesc << llendl;
+
+	//should always trigger when asserts are enabled
+	llassert(status == NVAPI_OK);
+}
+
 // Create app mutex creates a unique global windows object. 
 // If the object can be created it returns true, otherwise
 // it returns false. The false result can be used to determine 
@@ -96,6 +116,79 @@ bool create_app_mutex()
 	return result;
 }
 
+void ll_nvapi_init(NvDRSSessionHandle hSession)
+{
+	// (2) load all the system settings into the session
+	NvAPI_Status status = NvAPI_DRS_LoadSettings(hSession);
+	if (status != NVAPI_OK) 
+	{
+		nvapi_error(status);
+		return;
+	}
+
+	NvAPI_UnicodeString profile_name;
+	std::string app_name = LLTrans::getString("APP_NAME");
+	llutf16string w_app_name = utf8str_to_utf16str(app_name);
+	wsprintf(profile_name, L"%s", w_app_name.c_str());
+	status = NvAPI_DRS_SetCurrentGlobalProfile(hSession, profile_name);
+	if (status != NVAPI_OK)
+	{
+		nvapi_error(status);
+		return;
+	}
+
+	// (3) Obtain the current profile. 
+	NvDRSProfileHandle hProfile = 0;
+	status = NvAPI_DRS_GetCurrentGlobalProfile(hSession, &hProfile);
+	if (status != NVAPI_OK) 
+	{
+		nvapi_error(status);
+		return;
+	}
+
+	// load settings for querying 
+	status = NvAPI_DRS_LoadSettings(hSession);
+	if (status != NVAPI_OK)
+	{
+		nvapi_error(status);
+		return;
+	}
+
+	//get the preferred power management mode for Second Life
+	NVDRS_SETTING drsSetting = {0};
+	drsSetting.version = NVDRS_SETTING_VER;
+	status = NvAPI_DRS_GetSetting(hSession, hProfile, PREFERRED_PSTATE_ID, &drsSetting);
+	if (status == NVAPI_SETTING_NOT_FOUND)
+	{ //only override if the user hasn't specifically set this setting
+		// (4) Specify that we want the VSYNC disabled setting
+		// first we fill the NVDRS_SETTING struct, then we call the function
+		drsSetting.version = NVDRS_SETTING_VER;
+		drsSetting.settingId = PREFERRED_PSTATE_ID;
+		drsSetting.settingType = NVDRS_DWORD_TYPE;
+		drsSetting.u32CurrentValue = PREFERRED_PSTATE_PREFER_MAX;
+		status = NvAPI_DRS_SetSetting(hSession, hProfile, &drsSetting);
+		if (status != NVAPI_OK) 
+		{
+			nvapi_error(status);
+			return;
+		}
+	}
+	else if (status != NVAPI_OK)
+	{
+		nvapi_error(status);
+		return;
+	}
+
+	
+
+	// (5) Now we apply (or save) our changes to the system
+	status = NvAPI_DRS_SaveSettings(hSession);
+	if (status != NVAPI_OK) 
+	{
+		nvapi_error(status);
+	}
+}
+
 //#define DEBUGGING_SEH_FILTER 1
 #if DEBUGGING_SEH_FILTER
 #	define WINMAIN DebuggingWinMain
@@ -165,6 +258,27 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
 		return -1;
 	}
 	
+	NvAPI_Status status;
+    
+	// Initialize NVAPI
+	status = NvAPI_Initialize();
+	NvDRSSessionHandle hSession = 0;
+
+    if (status == NVAPI_OK) 
+	{
+		// Create the session handle to access driver settings
+		status = NvAPI_DRS_CreateSession(&hSession);
+		if (status != NVAPI_OK) 
+		{
+			nvapi_error(status);
+		}
+		else
+		{
+			//override driver setting as needed
+			ll_nvapi_init(hSession);
+		}
+	}
+
 	// Have to wait until after logging is initialized to display LFH info
 	if (num_heaps > 0)
 	{
@@ -232,6 +346,15 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
 		LLAppViewer::sUpdaterInfo = NULL ;
 	}
 
+
+
+	// (NVAPI) (6) We clean up. This is analogous to doing a free()
+	if (hSession)
+	{
+		NvAPI_DRS_DestroySession(hSession);
+		hSession = 0;
+	}
+	
 	return 0;
 }
 
-- 
GitLab