From e3753ed8b2c52e98e282e82ea5169bda0b34a2a6 Mon Sep 17 00:00:00 2001
From: "Karl Stiefvater (qarl)" <qarl@lindenlab.com>
Date: Fri, 21 May 2010 16:11:21 -0500
Subject: [PATCH] S3 feature/gpu table implementation.  reviewed by palmer and
 davep.

---
 indra/newview/app_settings/settings.xml |  11 ++
 indra/newview/llfeaturemanager.cpp      | 144 +++++++++++++++++++++---
 indra/newview/llfeaturemanager.h        |   6 +
 indra/newview/llstartup.cpp             |   9 ++
 indra/newview/llviewerwindow.cpp        |   1 +
 5 files changed, 156 insertions(+), 15 deletions(-)

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 418032c5546..a79e07bdb6f 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -4150,6 +4150,17 @@
         <key>Value</key>
             <integer>1</integer>
         </map>
+    <key>LastGPUClass</key>
+    <map>
+      <key>Comment</key>
+      <string>[DO NOT MODIFY] previous GPU class for tracking hardware changes</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>-1</integer>
+    </map>
     <key>LastFeatureVersion</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index 50b08f782a0..4fdb0101620 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -45,10 +45,13 @@
 #include "llsecondlifeurls.h"
 
 #include "llappviewer.h"
+#include "llhttpclient.h"
+#include "llnotificationsutil.h"
 #include "llviewercontrol.h"
 #include "llworld.h"
 #include "lldrawpoolterrain.h"
 #include "llviewertexturelist.h"
+#include "llversioninfo.h"
 #include "llwindow.h"
 #include "llui.h"
 #include "llcontrol.h"
@@ -62,15 +65,20 @@
 
 #if LL_DARWIN
 const char FEATURE_TABLE_FILENAME[] = "featuretable_mac.txt";
+const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_mac.%s.txt";
 #elif LL_LINUX
 const char FEATURE_TABLE_FILENAME[] = "featuretable_linux.txt";
+const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_linux.%s.txt";
 #elif LL_SOLARIS
 const char FEATURE_TABLE_FILENAME[] = "featuretable_solaris.txt";
+const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_solaris.%s.txt";
 #else
 const char FEATURE_TABLE_FILENAME[] = "featuretable.txt";
+const char FEATURE_TABLE_VER_FILENAME[] = "featuretable.%s.txt";
 #endif
 
 const char GPU_TABLE_FILENAME[] = "gpu_table.txt";
+const char GPU_TABLE_VER_FILENAME[] = "gpu_table.%s.txt";
 
 LLFeatureInfo::LLFeatureInfo(const std::string& name, const BOOL available, const F32 level)
 	: mValid(TRUE), mName(name), mAvailable(available), mRecommendedLevel(level)
@@ -215,22 +223,44 @@ BOOL LLFeatureManager::loadFeatureTables()
 	mSkippedFeatures.insert("RenderVBOEnable");
 	mSkippedFeatures.insert("RenderFogRatio");
 
-	std::string data_path = gDirUtilp->getAppRODataDir();
+	// first table is install with app
+	std::string app_path = gDirUtilp->getAppRODataDir();
+	app_path += gDirUtilp->getDirDelimiter();
+	app_path += FEATURE_TABLE_FILENAME;
 
-	data_path += gDirUtilp->getDirDelimiter();
+	// second table is downloaded with HTTP
+	std::string http_filename = llformat(FEATURE_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str());
+	std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename);
 
-	data_path += FEATURE_TABLE_FILENAME;
-	lldebugs << "Looking for feature table in " << data_path << llendl;
+	// use HTTP table if it exists
+	std::string path;
+	if (gDirUtilp->fileExists(http_path))
+	{
+		path = http_path;
+	}
+	else
+	{
+		path = app_path;
+	}
+
+	
+	return parseFeatureTable(path);
+}
+
+
+BOOL LLFeatureManager::parseFeatureTable(std::string filename)
+{
+	llinfos << "Looking for feature table in " << filename << llendl;
 
 	llifstream file;
 	std::string name;
 	U32		version;
 	
-	file.open(data_path); 	 /*Flawfinder: ignore*/
+	file.open(filename); 	 /*Flawfinder: ignore*/
 
 	if (!file)
 	{
-		LL_WARNS("RenderInit") << "Unable to open feature table!" << LL_ENDL;
+		LL_WARNS("RenderInit") << "Unable to open feature table " << filename << LL_ENDL;
 		return FALSE;
 	}
 
@@ -239,7 +269,7 @@ BOOL LLFeatureManager::loadFeatureTables()
 	file >> version;
 	if (name != "version")
 	{
-		LL_WARNS("RenderInit") << data_path << " does not appear to be a valid feature table!" << LL_ENDL;
+		LL_WARNS("RenderInit") << filename << " does not appear to be a valid feature table!" << LL_ENDL;
 		return FALSE;
 	}
 
@@ -302,24 +332,44 @@ BOOL LLFeatureManager::loadFeatureTables()
 
 void LLFeatureManager::loadGPUClass()
 {
-	std::string data_path = gDirUtilp->getAppRODataDir();
-
-	data_path += gDirUtilp->getDirDelimiter();
-
-	data_path += GPU_TABLE_FILENAME;
-
 	// defaults
 	mGPUClass = GPU_CLASS_UNKNOWN;
 	mGPUString = gGLManager.getRawGLString();
 	mGPUSupported = FALSE;
 
+	// first table is in the app dir
+	std::string app_path = gDirUtilp->getAppRODataDir();
+	app_path += gDirUtilp->getDirDelimiter();
+	app_path += GPU_TABLE_FILENAME;
+	
+	// second table is downloaded with HTTP
+	std::string http_filename = llformat(GPU_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str());
+	std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename);
+
+	// use HTTP table if it exists
+	std::string path;
+	if (gDirUtilp->fileExists(http_path))
+	{
+		path = http_path;
+	}
+	else
+	{
+		path = app_path;
+	}
+
+	parseGPUTable(path);
+}
+
+	
+void LLFeatureManager::parseGPUTable(std::string filename)
+{
 	llifstream file;
 		
-	file.open(data_path); 		 /*Flawfinder: ignore*/
+	file.open(filename);
 
 	if (!file)
 	{
-		LL_WARNS("RenderInit") << "Unable to open GPU table: " << data_path << "!" << LL_ENDL;
+		LL_WARNS("RenderInit") << "Unable to open GPU table: " << filename << "!" << LL_ENDL;
 		return;
 	}
 
@@ -403,6 +453,70 @@ void LLFeatureManager::loadGPUClass()
 	LL_WARNS("RenderInit") << "Couldn't match GPU to a class: " << gGLManager.getRawGLString() << LL_ENDL;
 }
 
+// responder saves table into file
+class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder
+{
+public:
+
+	LLHTTPFeatureTableResponder(std::string filename) :
+		mFilename(filename)
+	{
+	}
+
+	
+	virtual void completedRaw(U32 status, const std::string& reason,
+							  const LLChannelDescriptors& channels,
+							  const LLIOPipe::buffer_ptr_t& buffer)
+	{
+		if (isGoodStatus(status))
+		{
+			// write to file
+
+			llinfos << "writing feature table to " << mFilename << llendl;
+			
+			S32 file_size = buffer->countAfter(channels.in(), NULL);
+			if (file_size > 0)
+			{
+				// read from buffer
+				U8* copy_buffer = new U8[file_size];
+				buffer->readAfter(channels.in(), NULL, copy_buffer, file_size);
+
+				// write to file
+				LLAPRFile out(mFilename, LL_APR_WB);
+				out.write(copy_buffer, file_size);
+				out.close();
+			}
+		}
+		
+	}
+	
+private:
+	std::string mFilename;
+};
+
+void fetch_table(std::string table)
+{
+	const std::string base       = "http://viewer-settings.s3.amazonaws.com/";
+
+	const std::string filename   = llformat(table.c_str(), LLVersionInfo::getVersion().c_str());
+
+	const std::string url        = base + filename;
+
+	const std::string path       = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename);
+
+	llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl;
+	
+	LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path));
+}
+
+// fetch table(s) from a website (S3)
+void LLFeatureManager::fetchHTTPTables()
+{
+	fetch_table(FEATURE_TABLE_VER_FILENAME);
+	fetch_table(GPU_TABLE_VER_FILENAME);
+}
+
+
 void LLFeatureManager::cleanupFeatureTables()
 {
 	std::for_each(mMaskList.begin(), mMaskList.end(), DeletePairedPointer());
diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h
index dd218d428fa..c2ecede2c55 100644
--- a/indra/newview/llfeaturemanager.h
+++ b/indra/newview/llfeaturemanager.h
@@ -48,6 +48,7 @@ typedef enum EGPUClass
 	GPU_CLASS_3 = 3
 } EGPUClass; 
 
+
 class LLFeatureInfo
 {
 public:
@@ -144,8 +145,13 @@ class LLFeatureManager : public LLFeatureList, public LLSingleton<LLFeatureManag
 	// in the skip list if true
 	void applyFeatures(bool skipFeatures);
 
+	// load the dynamic GPU/feature table from a website
+	void fetchHTTPTables();
+	
 protected:
 	void loadGPUClass();
+	BOOL parseFeatureTable(std::string filename);
+	void parseGPUTable(std::string filename);
 	void initBaseMask();
 
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 0a464b3b6cc..b28377e5910 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -384,13 +384,22 @@ bool idle_startup()
 		{
 			LLNotificationsUtil::add("DisplaySetToRecommended");
 		}
+		else if ((gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass()) &&
+				 (gSavedSettings.getS32("LastGPUClass") != -1))
+		{
+			LLNotificationsUtil::add("DisplaySetToRecommended");
+		}
 		else if (!gViewerWindow->getInitAlert().empty())
 		{
 			LLNotificationsUtil::add(gViewerWindow->getInitAlert());
 		}
 			
 		gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion());
+		gSavedSettings.setS32("LastGPUClass", LLFeatureManager::getInstance()->getGPUClass());
 
+		// load dynamic GPU/feature tables from website (S3)
+		LLFeatureManager::getInstance()->fetchHTTPTables();
+		
 		std::string xml_file = LLUI::locateSkin("xui_version.xml");
 		LLXMLNodePtr root;
 		bool xml_ok = false;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index e0463e3c4a8..9fc7d6a56db 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1433,6 +1433,7 @@ LLViewerWindow::LLViewerWindow(
 
 	if (LLFeatureManager::getInstance()->isSafe()
 		|| (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion())
+		|| (gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass())
 		|| (gSavedSettings.getBOOL("ProbeHardwareOnStartup")))
 	{
 		LLFeatureManager::getInstance()->applyRecommendedSettings();
-- 
GitLab