diff options
Diffstat (limited to 'indra/newview/llfeaturemanager.cpp')
-rw-r--r-- | indra/newview/llfeaturemanager.cpp | 349 |
1 files changed, 248 insertions, 101 deletions
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index e6fcfb6d40..ca2ef5f5b8 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -2,38 +2,33 @@ * @file llfeaturemanager.cpp * @brief LLFeatureManager class implementation * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ +#include "llviewerprecompiledheaders.h" + #include <iostream> #include <fstream> -#include "llviewerprecompiledheaders.h" - #include <boost/regex.hpp> #include "llfeaturemanager.h" @@ -43,10 +38,14 @@ #include "llgl.h" #include "llsecondlifeurls.h" +#include "llappviewer.h" +#include "llhttpclient.h" +#include "llnotificationsutil.h" #include "llviewercontrol.h" #include "llworld.h" #include "lldrawpoolterrain.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" +#include "llversioninfo.h" #include "llwindow.h" #include "llui.h" #include "llcontrol.h" @@ -57,75 +56,71 @@ #include "lldxhardware.h" #endif -// -// externs -// -extern LLMemoryInfo gSysMemory; -extern LLCPUInfo gSysCPU; #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_FILENAME[] = "featuretable%s.txt"; +const char FEATURE_TABLE_VER_FILENAME[] = "featuretable%s.%s.txt"; #endif const char GPU_TABLE_FILENAME[] = "gpu_table.txt"; +const char GPU_TABLE_VER_FILENAME[] = "gpu_table.%s.txt"; -LLFeatureManager *gFeatureManagerp = NULL; - -LLFeatureInfo::LLFeatureInfo(const char *name, const BOOL available, const F32 level) : mValid(TRUE) +LLFeatureInfo::LLFeatureInfo(const std::string& name, const BOOL available, const F32 level) + : mValid(TRUE), mName(name), mAvailable(available), mRecommendedLevel(level) { - mName = name; - mAvailable = available; - mRecommendedLevel = level; } -LLFeatureList::LLFeatureList(const char *name) +LLFeatureList::LLFeatureList(const std::string& name) + : mName(name) { - mName = name; } LLFeatureList::~LLFeatureList() { } -void LLFeatureList::addFeature(const char *name, const BOOL available, const F32 level) +void LLFeatureList::addFeature(const std::string& name, const BOOL available, const F32 level) { if (mFeatures.count(name)) { - llwarns << "LLFeatureList::Attempting to add preexisting feature " << name << llendl; + LL_WARNS("RenderInit") << "LLFeatureList::Attempting to add preexisting feature " << name << LL_ENDL; } LLFeatureInfo fi(name, available, level); mFeatures[name] = fi; } -BOOL LLFeatureList::isFeatureAvailable(const char *name) +BOOL LLFeatureList::isFeatureAvailable(const std::string& name) { if (mFeatures.count(name)) { return mFeatures[name].mAvailable; } - llwarns << "Feature " << name << " not on feature list!" << llendl; + LL_WARNS("RenderInit") << "Feature " << name << " not on feature list!" << LL_ENDL; // changing this to TRUE so you have to explicitly disable // something for it to be disabled return TRUE; } -F32 LLFeatureList::getRecommendedValue(const char *name) +F32 LLFeatureList::getRecommendedValue(const std::string& name) { if (mFeatures.count(name) && isFeatureAvailable(name)) { return mFeatures[name].mRecommendedLevel; } - llwarns << "Feature " << name << " not on feature list or not available!" << llendl; + LL_WARNS("RenderInit") << "Feature " << name << " not on feature list or not available!" << LL_ENDL; return 0; } @@ -148,49 +143,49 @@ BOOL LLFeatureList::maskList(LLFeatureList &mask) // if (!mFeatures.count(mask_fi.mName)) { - llwarns << "Feature " << mask_fi.mName << " in mask not in top level!" << llendl; + LL_WARNS("RenderInit") << "Feature " << mask_fi.mName << " in mask not in top level!" << LL_ENDL; continue; } LLFeatureInfo &cur_fi = mFeatures[mask_fi.mName]; if (mask_fi.mAvailable && !cur_fi.mAvailable) { - llwarns << "Mask attempting to reenabling disabled feature, ignoring " << cur_fi.mName << llendl; + LL_WARNS("RenderInit") << "Mask attempting to reenabling disabled feature, ignoring " << cur_fi.mName << LL_ENDL; continue; } cur_fi.mAvailable = mask_fi.mAvailable; cur_fi.mRecommendedLevel = llmin(cur_fi.mRecommendedLevel, mask_fi.mRecommendedLevel); -#ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Feature mask " << mask.mName + LL_DEBUGS("RenderInit") << "Feature mask " << mask.mName << " Feature " << mask_fi.mName << " Mask: " << mask_fi.mRecommendedLevel - << " Now: " << cur_fi.mRecommendedLevel << llendl; -#endif + << " Now: " << cur_fi.mRecommendedLevel << LL_ENDL; } -#if 0 && !LL_RELEASE_FOR_DOWNLOAD - llinfos << "After applying mask " << mask.mName << llendl; - dump(); -#endif + LL_DEBUGS("RenderInit") << "After applying mask " << mask.mName << std::endl; + // Will conditionally call dump only if the above message will be logged, thanks + // to it being wrapped by the LL_DEBUGS and LL_ENDL macros. + dump(); + LL_CONT << LL_ENDL; + return TRUE; } void LLFeatureList::dump() { - llinfos << "Feature list: " << mName << llendl; - llinfos << "--------------" << llendl; + LL_DEBUGS("RenderInit") << "Feature list: " << mName << LL_ENDL; + LL_DEBUGS("RenderInit") << "--------------" << LL_ENDL; LLFeatureInfo fi; feature_map_t::iterator feature_it; for (feature_it = mFeatures.begin(); feature_it != mFeatures.end(); ++feature_it) { fi = feature_it->second; - llinfos << fi.mName << "\t\t" << fi.mAvailable << ":" << fi.mRecommendedLevel << llendl; + LL_DEBUGS("RenderInit") << fi.mName << "\t\t" << fi.mAvailable << ":" << fi.mRecommendedLevel << LL_ENDL; } - llinfos << llendl; + LL_DEBUGS("RenderInit") << LL_ENDL; } -LLFeatureList *LLFeatureManager::findMask(const char *name) +LLFeatureList *LLFeatureManager::findMask(const std::string& name) { if (mMaskList.count(name)) { @@ -200,15 +195,15 @@ LLFeatureList *LLFeatureManager::findMask(const char *name) return NULL; } -BOOL LLFeatureManager::maskFeatures(const char *name) +BOOL LLFeatureManager::maskFeatures(const std::string& name) { LLFeatureList *maskp = findMask(name); if (!maskp) { -// llwarns << "Unknown feature mask " << name << llendl; + LL_DEBUGS("RenderInit") << "Unknown feature mask " << name << LL_ENDL; return FALSE; } - llinfos << "Applying Feature Mask: " << name << llendl; + LL_DEBUGS("RenderInit") << "Applying Feature Mask: " << name << LL_ENDL; return maskList(*maskp); } @@ -222,62 +217,100 @@ 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(); - data_path += gDirUtilp->getDirDelimiter(); + std::string filename; + std::string http_filename; +#if LL_WINDOWS + std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); + if (os_string.find("Microsoft Windows XP") == 0) + { + filename = llformat(FEATURE_TABLE_FILENAME, "_xp"); + http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "_xp", LLVersionInfo::getVersion().c_str()); + } + else + { + filename = llformat(FEATURE_TABLE_FILENAME, ""); + http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "", LLVersionInfo::getVersion().c_str()); + } +#else + filename = FEATURE_TABLE_FILENAME; + http_filename = llformat(FEATURE_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str()); +#endif - data_path += FEATURE_TABLE_FILENAME; + app_path += filename; + + // second table is downloaded with HTTP + 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; + } + + + return parseFeatureTable(path); +} - char name[MAX_STRING+1]; /*Flawfinder: ignore*/ + +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.c_str()); /*Flawfinder: ignore*/ + file.open(filename); /*Flawfinder: ignore*/ if (!file) { - llwarns << "Unable to open feature table!" << llendl; + LL_WARNS("RenderInit") << "Unable to open feature table " << filename << LL_ENDL; return FALSE; } // Check file version file >> name; file >> version; - if (strcmp(name, "version")) + if (name != "version") { - llwarns << data_path << " does not appear to be a valid feature table!" << llendl; + LL_WARNS("RenderInit") << filename << " does not appear to be a valid feature table!" << LL_ENDL; return FALSE; } mTableVersion = version; LLFeatureList *flp = NULL; - while (!file.eof()) + while (!file.eof() && file.good()) { char buffer[MAX_STRING]; /*Flawfinder: ignore*/ - name[0] = 0; file >> name; - if (strlen(name) >= 2 && /*Flawfinder: ignore*/ - name[0] == '/' && - name[1] == '/') + if (name.substr(0,2) == "//") { // This is a comment. file.getline(buffer, MAX_STRING); continue; } - if (strlen(name) == 0) /*Flawfinder: ignore*/ + if (name.empty()) { // This is a blank line file.getline(buffer, MAX_STRING); continue; } - if (!strcmp(name, "list")) + if (name == "list") { if (flp) { @@ -287,7 +320,7 @@ BOOL LLFeatureManager::loadFeatureTables() file >> name; if (mMaskList.count(name)) { - llerrs << "Overriding mask " << name << ", this is invalid!" << llendl; + LL_ERRS("RenderInit") << "Overriding mask " << name << ", this is invalid!" << LL_ENDL; } flp = new LLFeatureList(name); @@ -297,7 +330,8 @@ BOOL LLFeatureManager::loadFeatureTables() { if (!flp) { - llerrs << "Specified parameter before <list> keyword!" << llendl; + LL_ERRS("RenderInit") << "Specified parameter before <list> keyword!" << LL_ENDL; + return FALSE; } S32 available; F32 recommended; @@ -312,24 +346,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.c_str()); /*Flawfinder: ignore*/ + file.open(filename); if (!file) { - llwarns << "Unable to open GPU table: " << data_path << "!" << llendl; + LL_WARNS("RenderInit") << "Unable to open GPU table: " << filename << "!" << LL_ENDL; return; } @@ -400,7 +454,7 @@ void LLFeatureManager::loadGPUClass() { // if we found it, stop! file.close(); - llinfos << "GPU is " << label << llendl; + LL_INFOS("RenderInit") << "GPU is " << label << llendl; mGPUString = label; mGPUClass = (EGPUClass) strtol(cls.c_str(), NULL, 10); mGPUSupported = (BOOL) strtol(supported.c_str(), NULL, 10); @@ -410,9 +464,101 @@ void LLFeatureManager::loadGPUClass() } file.close(); - llwarns << "Couldn't match GPU to a class: " << gGLManager.getRawGLString() << llendl; + 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_feature_table(std::string table) +{ + const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable"); + +#if LL_WINDOWS + std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); + std::string filename; + if (os_string.find("Microsoft Windows XP") == 0) + { + filename = llformat(table.c_str(), "_xp", LLVersionInfo::getVersion().c_str()); + } + else + { + filename = llformat(table.c_str(), "", LLVersionInfo::getVersion().c_str()); + } +#else + const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str()); +#endif + + 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)); +} + +void fetch_gpu_table(std::string table) +{ + const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable"); + + 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_feature_table(FEATURE_TABLE_VER_FILENAME); + fetch_gpu_table(GPU_TABLE_VER_FILENAME); +} + + void LLFeatureManager::cleanupFeatureTables() { std::for_each(mMaskList.begin(), mMaskList.end(), DeletePairedPointer()); @@ -441,7 +587,6 @@ void LLFeatureManager::applyRecommendedSettings() setGraphicsLevel(level, false); gSavedSettings.setU32("RenderQualityPerformance", level); - gSavedSettings.setBOOL("RenderCustomSettings", FALSE); // now apply the tweaks to draw distance // these are double negatives, because feature masks only work by @@ -455,8 +600,6 @@ void LLFeatureManager::applyRecommendedSettings() { gSavedSettings.setF32("RenderFarClip", 128.0f); } - - } void LLFeatureManager::applyFeatures(bool skipFeatures) @@ -493,19 +636,19 @@ void LLFeatureManager::applyFeatures(bool skipFeatures) // handle all the different types if(ctrl->isType(TYPE_BOOLEAN)) { - gSavedSettings.setBOOL(mIt->first, (BOOL)getRecommendedValue(mIt->first.c_str())); + gSavedSettings.setBOOL(mIt->first, (BOOL)getRecommendedValue(mIt->first)); } else if (ctrl->isType(TYPE_S32)) { - gSavedSettings.setS32(mIt->first, (S32)getRecommendedValue(mIt->first.c_str())); + gSavedSettings.setS32(mIt->first, (S32)getRecommendedValue(mIt->first)); } else if (ctrl->isType(TYPE_U32)) { - gSavedSettings.setU32(mIt->first, (U32)getRecommendedValue(mIt->first.c_str())); + gSavedSettings.setU32(mIt->first, (U32)getRecommendedValue(mIt->first)); } else if (ctrl->isType(TYPE_F32)) { - gSavedSettings.setF32(mIt->first, (F32)getRecommendedValue(mIt->first.c_str())); + gSavedSettings.setF32(mIt->first, (F32)getRecommendedValue(mIt->first)); } else { @@ -548,7 +691,7 @@ void LLFeatureManager::applyBaseMasks() LLFeatureList* maskp = findMask("all"); if(maskp == NULL) { - llwarns << "AHH! No \"all\" in feature table!" << llendl; + LL_WARNS("RenderInit") << "AHH! No \"all\" in feature table!" << LL_ENDL; return; } @@ -565,12 +708,12 @@ void LLFeatureManager::applyBaseMasks() "Class3" }; - llinfos << "Setting GPU Class to " << class_table[mGPUClass] << llendl; + LL_INFOS("RenderInit") << "Setting GPU Class to " << class_table[mGPUClass] << LL_ENDL; maskFeatures(class_table[mGPUClass]); } else { - llinfos << "Setting GPU Class to Unknown" << llendl; + LL_INFOS("RenderInit") << "Setting GPU Class to Unknown" << LL_ENDL; maskFeatures("Unknown"); } @@ -595,6 +738,10 @@ void LLFeatureManager::applyBaseMasks() { maskFeatures("ATI"); } + if (gGLManager.mATIOldDriver) + { + maskFeatures("ATIOldDriver"); + } if (gGLManager.mIsGFFX) { maskFeatures("GeForceFX"); @@ -620,7 +767,7 @@ void LLFeatureManager::applyBaseMasks() } //llinfos << "Masking features from gpu table match: " << gpustr << llendl; - maskFeatures(gpustr.c_str()); + maskFeatures(gpustr); // now mask cpu type ones if (gSysMemory.getPhysicalMemoryClamped() <= 256*1024*1024) @@ -630,9 +777,9 @@ void LLFeatureManager::applyBaseMasks() #if LL_SOLARIS && defined(__sparc) // even low MHz SPARCs are fast #error The 800 is hinky. Would something like a LL_MIN_MHZ make more sense here? - if (gSysCPU.getMhz() < 800) + if (gSysCPU.getMHz() < 800) #else - if (gSysCPU.getMhz() < 1100) + if (gSysCPU.getMHz() < 1100) #endif { maskFeatures("CPUSlow"); |