PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llfeaturemanager.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 817 lines | 609 code | 124 blank | 84 comment | 106 complexity | f5c3734e33a0291defdf55fbb876e65c MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llfeaturemanager.cpp
  3. * @brief LLFeatureManager class implementation
  4. *
  5. * $LicenseInfo:firstyear=2003&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include <iostream>
  28. #include <fstream>
  29. #include <boost/regex.hpp>
  30. #include "llfeaturemanager.h"
  31. #include "lldir.h"
  32. #include "llsys.h"
  33. #include "llgl.h"
  34. #include "llsecondlifeurls.h"
  35. #include "llappviewer.h"
  36. #include "llhttpclient.h"
  37. #include "llnotificationsutil.h"
  38. #include "llviewercontrol.h"
  39. #include "llworld.h"
  40. #include "lldrawpoolterrain.h"
  41. #include "llviewertexturelist.h"
  42. #include "llversioninfo.h"
  43. #include "llwindow.h"
  44. #include "llui.h"
  45. #include "llcontrol.h"
  46. #include "llboost.h"
  47. #include "llweb.h"
  48. #include "llviewershadermgr.h"
  49. #if LL_WINDOWS
  50. #include "lldxhardware.h"
  51. #endif
  52. #if LL_DARWIN
  53. const char FEATURE_TABLE_FILENAME[] = "featuretable_mac.txt";
  54. const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_mac.%s.txt";
  55. #elif LL_LINUX
  56. const char FEATURE_TABLE_FILENAME[] = "featuretable_linux.txt";
  57. const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_linux.%s.txt";
  58. #elif LL_SOLARIS
  59. const char FEATURE_TABLE_FILENAME[] = "featuretable_solaris.txt";
  60. const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_solaris.%s.txt";
  61. #else
  62. const char FEATURE_TABLE_FILENAME[] = "featuretable%s.txt";
  63. const char FEATURE_TABLE_VER_FILENAME[] = "featuretable%s.%s.txt";
  64. #endif
  65. const char GPU_TABLE_FILENAME[] = "gpu_table.txt";
  66. const char GPU_TABLE_VER_FILENAME[] = "gpu_table.%s.txt";
  67. LLFeatureInfo::LLFeatureInfo(const std::string& name, const BOOL available, const F32 level)
  68. : mValid(TRUE), mName(name), mAvailable(available), mRecommendedLevel(level)
  69. {
  70. }
  71. LLFeatureList::LLFeatureList(const std::string& name)
  72. : mName(name)
  73. {
  74. }
  75. LLFeatureList::~LLFeatureList()
  76. {
  77. }
  78. void LLFeatureList::addFeature(const std::string& name, const BOOL available, const F32 level)
  79. {
  80. if (mFeatures.count(name))
  81. {
  82. LL_WARNS("RenderInit") << "LLFeatureList::Attempting to add preexisting feature " << name << LL_ENDL;
  83. }
  84. LLFeatureInfo fi(name, available, level);
  85. mFeatures[name] = fi;
  86. }
  87. BOOL LLFeatureList::isFeatureAvailable(const std::string& name)
  88. {
  89. if (mFeatures.count(name))
  90. {
  91. return mFeatures[name].mAvailable;
  92. }
  93. LL_WARNS_ONCE("RenderInit") << "Feature " << name << " not on feature list!" << LL_ENDL;
  94. // changing this to TRUE so you have to explicitly disable
  95. // something for it to be disabled
  96. return TRUE;
  97. }
  98. F32 LLFeatureList::getRecommendedValue(const std::string& name)
  99. {
  100. if (mFeatures.count(name) && isFeatureAvailable(name))
  101. {
  102. return mFeatures[name].mRecommendedLevel;
  103. }
  104. LL_WARNS_ONCE("RenderInit") << "Feature " << name << " not on feature list or not available!" << LL_ENDL;
  105. return 0;
  106. }
  107. BOOL LLFeatureList::maskList(LLFeatureList &mask)
  108. {
  109. //llinfos << "Masking with " << mask.mName << llendl;
  110. //
  111. // Lookup the specified feature mask, and overlay it on top of the
  112. // current feature mask.
  113. //
  114. LLFeatureInfo mask_fi;
  115. feature_map_t::iterator feature_it;
  116. for (feature_it = mask.mFeatures.begin(); feature_it != mask.mFeatures.end(); ++feature_it)
  117. {
  118. mask_fi = feature_it->second;
  119. //
  120. // Look for the corresponding feature
  121. //
  122. if (!mFeatures.count(mask_fi.mName))
  123. {
  124. LL_WARNS("RenderInit") << "Feature " << mask_fi.mName << " in mask not in top level!" << LL_ENDL;
  125. continue;
  126. }
  127. LLFeatureInfo &cur_fi = mFeatures[mask_fi.mName];
  128. if (mask_fi.mAvailable && !cur_fi.mAvailable)
  129. {
  130. LL_WARNS("RenderInit") << "Mask attempting to reenabling disabled feature, ignoring " << cur_fi.mName << LL_ENDL;
  131. continue;
  132. }
  133. cur_fi.mAvailable = mask_fi.mAvailable;
  134. cur_fi.mRecommendedLevel = llmin(cur_fi.mRecommendedLevel, mask_fi.mRecommendedLevel);
  135. LL_DEBUGS("RenderInit") << "Feature mask " << mask.mName
  136. << " Feature " << mask_fi.mName
  137. << " Mask: " << mask_fi.mRecommendedLevel
  138. << " Now: " << cur_fi.mRecommendedLevel << LL_ENDL;
  139. }
  140. LL_DEBUGS("RenderInit") << "After applying mask " << mask.mName << std::endl;
  141. // Will conditionally call dump only if the above message will be logged, thanks
  142. // to it being wrapped by the LL_DEBUGS and LL_ENDL macros.
  143. dump();
  144. LL_CONT << LL_ENDL;
  145. return TRUE;
  146. }
  147. void LLFeatureList::dump()
  148. {
  149. LL_DEBUGS("RenderInit") << "Feature list: " << mName << LL_ENDL;
  150. LL_DEBUGS("RenderInit") << "--------------" << LL_ENDL;
  151. LLFeatureInfo fi;
  152. feature_map_t::iterator feature_it;
  153. for (feature_it = mFeatures.begin(); feature_it != mFeatures.end(); ++feature_it)
  154. {
  155. fi = feature_it->second;
  156. LL_DEBUGS("RenderInit") << fi.mName << "\t\t" << fi.mAvailable << ":" << fi.mRecommendedLevel << LL_ENDL;
  157. }
  158. LL_DEBUGS("RenderInit") << LL_ENDL;
  159. }
  160. LLFeatureList *LLFeatureManager::findMask(const std::string& name)
  161. {
  162. if (mMaskList.count(name))
  163. {
  164. return mMaskList[name];
  165. }
  166. return NULL;
  167. }
  168. BOOL LLFeatureManager::maskFeatures(const std::string& name)
  169. {
  170. LLFeatureList *maskp = findMask(name);
  171. if (!maskp)
  172. {
  173. LL_DEBUGS("RenderInit") << "Unknown feature mask " << name << LL_ENDL;
  174. return FALSE;
  175. }
  176. LL_INFOS("RenderInit") << "Applying GPU Feature list: " << name << LL_ENDL;
  177. return maskList(*maskp);
  178. }
  179. BOOL LLFeatureManager::loadFeatureTables()
  180. {
  181. // *TODO - if I or anyone else adds something else to the skipped list
  182. // make this data driven. Put it in the feature table and parse it
  183. // correctly
  184. mSkippedFeatures.insert("RenderAnisotropic");
  185. mSkippedFeatures.insert("RenderGamma");
  186. mSkippedFeatures.insert("RenderVBOEnable");
  187. mSkippedFeatures.insert("RenderFogRatio");
  188. // first table is install with app
  189. std::string app_path = gDirUtilp->getAppRODataDir();
  190. app_path += gDirUtilp->getDirDelimiter();
  191. std::string filename;
  192. std::string http_filename;
  193. #if LL_WINDOWS
  194. std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
  195. if (os_string.find("Microsoft Windows XP") == 0)
  196. {
  197. filename = llformat(FEATURE_TABLE_FILENAME, "_xp");
  198. http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "_xp", LLVersionInfo::getVersion().c_str());
  199. }
  200. else
  201. {
  202. filename = llformat(FEATURE_TABLE_FILENAME, "");
  203. http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "", LLVersionInfo::getVersion().c_str());
  204. }
  205. #else
  206. filename = FEATURE_TABLE_FILENAME;
  207. http_filename = llformat(FEATURE_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str());
  208. #endif
  209. app_path += filename;
  210. // second table is downloaded with HTTP
  211. std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename);
  212. // use HTTP table if it exists
  213. std::string path;
  214. if (gDirUtilp->fileExists(http_path))
  215. {
  216. path = http_path;
  217. }
  218. else
  219. {
  220. path = app_path;
  221. }
  222. return parseFeatureTable(path);
  223. }
  224. BOOL LLFeatureManager::parseFeatureTable(std::string filename)
  225. {
  226. llinfos << "Looking for feature table in " << filename << llendl;
  227. llifstream file;
  228. std::string name;
  229. U32 version;
  230. file.open(filename); /*Flawfinder: ignore*/
  231. if (!file)
  232. {
  233. LL_WARNS("RenderInit") << "Unable to open feature table " << filename << LL_ENDL;
  234. return FALSE;
  235. }
  236. // Check file version
  237. file >> name;
  238. file >> version;
  239. if (name != "version")
  240. {
  241. LL_WARNS("RenderInit") << filename << " does not appear to be a valid feature table!" << LL_ENDL;
  242. return FALSE;
  243. }
  244. mTableVersion = version;
  245. LLFeatureList *flp = NULL;
  246. while (file >> name)
  247. {
  248. char buffer[MAX_STRING]; /*Flawfinder: ignore*/
  249. if (name.substr(0,2) == "//")
  250. {
  251. // This is a comment.
  252. file.getline(buffer, MAX_STRING);
  253. continue;
  254. }
  255. if (name == "list")
  256. {
  257. if (flp)
  258. {
  259. //flp->dump();
  260. }
  261. // It's a new mask, create it.
  262. file >> name;
  263. if (mMaskList.count(name))
  264. {
  265. LL_ERRS("RenderInit") << "Overriding mask " << name << ", this is invalid!" << LL_ENDL;
  266. }
  267. flp = new LLFeatureList(name);
  268. mMaskList[name] = flp;
  269. }
  270. else
  271. {
  272. if (!flp)
  273. {
  274. LL_ERRS("RenderInit") << "Specified parameter before <list> keyword!" << LL_ENDL;
  275. return FALSE;
  276. }
  277. S32 available;
  278. F32 recommended;
  279. file >> available >> recommended;
  280. flp->addFeature(name, available, recommended);
  281. }
  282. }
  283. file.close();
  284. return TRUE;
  285. }
  286. void LLFeatureManager::loadGPUClass()
  287. {
  288. // defaults
  289. mGPUClass = GPU_CLASS_UNKNOWN;
  290. mGPUString = gGLManager.getRawGLString();
  291. mGPUSupported = FALSE;
  292. // first table is in the app dir
  293. std::string app_path = gDirUtilp->getAppRODataDir();
  294. app_path += gDirUtilp->getDirDelimiter();
  295. app_path += GPU_TABLE_FILENAME;
  296. // second table is downloaded with HTTP
  297. std::string http_filename = llformat(GPU_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str());
  298. std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename);
  299. // use HTTP table if it exists
  300. std::string path;
  301. if (gDirUtilp->fileExists(http_path))
  302. {
  303. path = http_path;
  304. }
  305. else
  306. {
  307. path = app_path;
  308. }
  309. parseGPUTable(path);
  310. }
  311. void LLFeatureManager::parseGPUTable(std::string filename)
  312. {
  313. llifstream file;
  314. file.open(filename);
  315. if (!file)
  316. {
  317. LL_WARNS("RenderInit") << "Unable to open GPU table: " << filename << "!" << LL_ENDL;
  318. return;
  319. }
  320. std::string rawRenderer = gGLManager.getRawGLString();
  321. std::string renderer = rawRenderer;
  322. for (std::string::iterator i = renderer.begin(); i != renderer.end(); ++i)
  323. {
  324. *i = tolower(*i);
  325. }
  326. bool gpuFound;
  327. U32 lineNumber;
  328. for (gpuFound = false, lineNumber = 0; !gpuFound && !file.eof(); lineNumber++)
  329. {
  330. char buffer[MAX_STRING]; /*Flawfinder: ignore*/
  331. buffer[0] = 0;
  332. file.getline(buffer, MAX_STRING);
  333. if (strlen(buffer) >= 2 && /*Flawfinder: ignore*/
  334. buffer[0] == '/' &&
  335. buffer[1] == '/')
  336. {
  337. // This is a comment.
  338. continue;
  339. }
  340. if (strlen(buffer) == 0) /*Flawfinder: ignore*/
  341. {
  342. // This is a blank line
  343. continue;
  344. }
  345. // setup the tokenizer
  346. std::string buf(buffer);
  347. std::string cls, label, expr, supported;
  348. boost_tokenizer tokens(buf, boost::char_separator<char>("\t\n"));
  349. boost_tokenizer::iterator token_iter = tokens.begin();
  350. // grab the label, pseudo regular expression, and class
  351. if(token_iter != tokens.end())
  352. {
  353. label = *token_iter++;
  354. }
  355. if(token_iter != tokens.end())
  356. {
  357. expr = *token_iter++;
  358. }
  359. if(token_iter != tokens.end())
  360. {
  361. cls = *token_iter++;
  362. }
  363. if(token_iter != tokens.end())
  364. {
  365. supported = *token_iter++;
  366. }
  367. if (label.empty() || expr.empty() || cls.empty() || supported.empty())
  368. {
  369. LL_WARNS("RenderInit") << "invald gpu_table.txt:" << lineNumber << ": '" << buffer << "'" << LL_ENDL;
  370. continue;
  371. }
  372. for (U32 i = 0; i < expr.length(); i++) /*Flawfinder: ignore*/
  373. {
  374. expr[i] = tolower(expr[i]);
  375. }
  376. // run the regular expression against the renderer
  377. boost::regex re(expr.c_str());
  378. if(boost::regex_search(renderer, re))
  379. {
  380. // if we found it, stop!
  381. gpuFound = true;
  382. mGPUString = label;
  383. mGPUClass = (EGPUClass) strtol(cls.c_str(), NULL, 10);
  384. mGPUSupported = (BOOL) strtol(supported.c_str(), NULL, 10);
  385. }
  386. }
  387. file.close();
  388. if ( gpuFound )
  389. {
  390. LL_INFOS("RenderInit") << "GPU '" << rawRenderer << "' recognized as '" << mGPUString << "'" << LL_ENDL;
  391. if (!mGPUSupported)
  392. {
  393. LL_INFOS("RenderInit") << "GPU '" << mGPUString << "' is not supported." << LL_ENDL;
  394. }
  395. }
  396. else
  397. {
  398. LL_WARNS("RenderInit") << "GPU '" << rawRenderer << "' not recognized" << LL_ENDL;
  399. }
  400. }
  401. // responder saves table into file
  402. class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder
  403. {
  404. public:
  405. LLHTTPFeatureTableResponder(std::string filename) :
  406. mFilename(filename)
  407. {
  408. }
  409. virtual void completedRaw(U32 status, const std::string& reason,
  410. const LLChannelDescriptors& channels,
  411. const LLIOPipe::buffer_ptr_t& buffer)
  412. {
  413. if (isGoodStatus(status))
  414. {
  415. // write to file
  416. llinfos << "writing feature table to " << mFilename << llendl;
  417. S32 file_size = buffer->countAfter(channels.in(), NULL);
  418. if (file_size > 0)
  419. {
  420. // read from buffer
  421. U8* copy_buffer = new U8[file_size];
  422. buffer->readAfter(channels.in(), NULL, copy_buffer, file_size);
  423. // write to file
  424. LLAPRFile out(mFilename, LL_APR_WB);
  425. out.write(copy_buffer, file_size);
  426. out.close();
  427. }
  428. }
  429. }
  430. private:
  431. std::string mFilename;
  432. };
  433. void fetch_feature_table(std::string table)
  434. {
  435. const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable");
  436. #if LL_WINDOWS
  437. std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
  438. std::string filename;
  439. if (os_string.find("Microsoft Windows XP") == 0)
  440. {
  441. filename = llformat(table.c_str(), "_xp", LLVersionInfo::getVersion().c_str());
  442. }
  443. else
  444. {
  445. filename = llformat(table.c_str(), "", LLVersionInfo::getVersion().c_str());
  446. }
  447. #else
  448. const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str());
  449. #endif
  450. const std::string url = base + "/" + filename;
  451. const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename);
  452. llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl;
  453. LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path));
  454. }
  455. void fetch_gpu_table(std::string table)
  456. {
  457. const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable");
  458. const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str());
  459. const std::string url = base + "/" + filename;
  460. const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename);
  461. llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl;
  462. LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path));
  463. }
  464. // fetch table(s) from a website (S3)
  465. void LLFeatureManager::fetchHTTPTables()
  466. {
  467. fetch_feature_table(FEATURE_TABLE_VER_FILENAME);
  468. fetch_gpu_table(GPU_TABLE_VER_FILENAME);
  469. }
  470. void LLFeatureManager::cleanupFeatureTables()
  471. {
  472. std::for_each(mMaskList.begin(), mMaskList.end(), DeletePairedPointer());
  473. mMaskList.clear();
  474. }
  475. void LLFeatureManager::init()
  476. {
  477. // load the tables
  478. loadFeatureTables();
  479. // get the gpu class
  480. loadGPUClass();
  481. // apply the base masks, so we know if anything is disabled
  482. applyBaseMasks();
  483. }
  484. void LLFeatureManager::applyRecommendedSettings()
  485. {
  486. // apply saved settings
  487. // cap the level at 2 (high)
  488. S32 level = llmax(GPU_CLASS_0, llmin(mGPUClass, GPU_CLASS_2));
  489. llinfos << "Applying Recommended Features" << llendl;
  490. setGraphicsLevel(level, false);
  491. gSavedSettings.setU32("RenderQualityPerformance", level);
  492. // now apply the tweaks to draw distance
  493. // these are double negatives, because feature masks only work by
  494. // downgrading values, so i needed to make a true value go to false
  495. // for certain cards, thus the awkward name, "Disregard..."
  496. if(!gSavedSettings.getBOOL("Disregard96DefaultDrawDistance"))
  497. {
  498. gSavedSettings.setF32("RenderFarClip", 96.0f);
  499. }
  500. else if(!gSavedSettings.getBOOL("Disregard128DefaultDrawDistance"))
  501. {
  502. gSavedSettings.setF32("RenderFarClip", 128.0f);
  503. }
  504. }
  505. void LLFeatureManager::applyFeatures(bool skipFeatures)
  506. {
  507. // see featuretable.txt / featuretable_linux.txt / featuretable_mac.txt
  508. #ifndef LL_RELEASE_FOR_DOWNLOAD
  509. dump();
  510. #endif
  511. // scroll through all of these and set their corresponding control value
  512. for(feature_map_t::iterator mIt = mFeatures.begin();
  513. mIt != mFeatures.end();
  514. ++mIt)
  515. {
  516. // skip features you want to skip
  517. // do this for when you don't want to change certain settings
  518. if(skipFeatures)
  519. {
  520. if(mSkippedFeatures.find(mIt->first) != mSkippedFeatures.end())
  521. {
  522. continue;
  523. }
  524. }
  525. // get the control setting
  526. LLControlVariable* ctrl = gSavedSettings.getControl(mIt->first);
  527. if(ctrl == NULL)
  528. {
  529. llwarns << "AHHH! Control setting " << mIt->first << " does not exist!" << llendl;
  530. continue;
  531. }
  532. // handle all the different types
  533. if(ctrl->isType(TYPE_BOOLEAN))
  534. {
  535. gSavedSettings.setBOOL(mIt->first, (BOOL)getRecommendedValue(mIt->first));
  536. }
  537. else if (ctrl->isType(TYPE_S32))
  538. {
  539. gSavedSettings.setS32(mIt->first, (S32)getRecommendedValue(mIt->first));
  540. }
  541. else if (ctrl->isType(TYPE_U32))
  542. {
  543. gSavedSettings.setU32(mIt->first, (U32)getRecommendedValue(mIt->first));
  544. }
  545. else if (ctrl->isType(TYPE_F32))
  546. {
  547. gSavedSettings.setF32(mIt->first, (F32)getRecommendedValue(mIt->first));
  548. }
  549. else
  550. {
  551. llwarns << "AHHH! Control variable is not a numeric type!" << llendl;
  552. }
  553. }
  554. }
  555. void LLFeatureManager::setGraphicsLevel(S32 level, bool skipFeatures)
  556. {
  557. LLViewerShaderMgr::sSkipReload = true;
  558. applyBaseMasks();
  559. switch (level)
  560. {
  561. case 0:
  562. maskFeatures("Low");
  563. break;
  564. case 1:
  565. maskFeatures("Mid");
  566. break;
  567. case 2:
  568. maskFeatures("High");
  569. break;
  570. case 3:
  571. maskFeatures("Ultra");
  572. break;
  573. default:
  574. maskFeatures("Low");
  575. break;
  576. }
  577. applyFeatures(skipFeatures);
  578. LLViewerShaderMgr::sSkipReload = false;
  579. LLViewerShaderMgr::instance()->setShaders();
  580. }
  581. void LLFeatureManager::applyBaseMasks()
  582. {
  583. // reapply masks
  584. mFeatures.clear();
  585. LLFeatureList* maskp = findMask("all");
  586. if(maskp == NULL)
  587. {
  588. LL_WARNS("RenderInit") << "AHH! No \"all\" in feature table!" << LL_ENDL;
  589. return;
  590. }
  591. mFeatures = maskp->getFeatures();
  592. // mask class
  593. if (mGPUClass >= 0 && mGPUClass < 4)
  594. {
  595. const char* class_table[] =
  596. {
  597. "Class0",
  598. "Class1",
  599. "Class2",
  600. "Class3"
  601. };
  602. LL_INFOS("RenderInit") << "Setting GPU Class to " << class_table[mGPUClass] << LL_ENDL;
  603. maskFeatures(class_table[mGPUClass]);
  604. }
  605. else
  606. {
  607. LL_INFOS("RenderInit") << "Setting GPU Class to Unknown" << LL_ENDL;
  608. maskFeatures("Unknown");
  609. }
  610. // now all those wacky ones
  611. if (!gGLManager.mHasFragmentShader)
  612. {
  613. maskFeatures("NoPixelShaders");
  614. }
  615. if (!gGLManager.mHasVertexShader || !mGPUSupported)
  616. {
  617. maskFeatures("NoVertexShaders");
  618. }
  619. if (gGLManager.mIsNVIDIA)
  620. {
  621. maskFeatures("NVIDIA");
  622. }
  623. if (gGLManager.mIsGF2or4MX)
  624. {
  625. maskFeatures("GeForce2");
  626. }
  627. if (gGLManager.mIsATI)
  628. {
  629. maskFeatures("ATI");
  630. }
  631. if (gGLManager.mHasATIMemInfo && gGLManager.mVRAM < 256)
  632. {
  633. maskFeatures("ATIVramLT256");
  634. }
  635. if (gGLManager.mATIOldDriver)
  636. {
  637. maskFeatures("ATIOldDriver");
  638. }
  639. if (gGLManager.mIsGFFX)
  640. {
  641. maskFeatures("GeForceFX");
  642. }
  643. if (gGLManager.mIsIntel)
  644. {
  645. maskFeatures("Intel");
  646. }
  647. if (gGLManager.mGLVersion < 1.5f)
  648. {
  649. maskFeatures("OpenGLPre15");
  650. }
  651. if (gGLManager.mGLVersion < 3.f)
  652. {
  653. maskFeatures("OpenGLPre30");
  654. }
  655. if (gGLManager.mNumTextureImageUnits <= 8)
  656. {
  657. maskFeatures("TexUnit8orLess");
  658. }
  659. if (gGLManager.mHasMapBufferRange)
  660. {
  661. maskFeatures("MapBufferRange");
  662. }
  663. // now mask by gpu string
  664. // Replaces ' ' with '_' in mGPUString to deal with inability for parser to handle spaces
  665. std::string gpustr = mGPUString;
  666. for (std::string::iterator iter = gpustr.begin(); iter != gpustr.end(); ++iter)
  667. {
  668. if (*iter == ' ')
  669. {
  670. *iter = '_';
  671. }
  672. }
  673. //llinfos << "Masking features from gpu table match: " << gpustr << llendl;
  674. maskFeatures(gpustr);
  675. // now mask cpu type ones
  676. if (gSysMemory.getPhysicalMemoryClamped() <= 256*1024*1024)
  677. {
  678. maskFeatures("RAM256MB");
  679. }
  680. #if LL_SOLARIS && defined(__sparc) // even low MHz SPARCs are fast
  681. #error The 800 is hinky. Would something like a LL_MIN_MHZ make more sense here?
  682. if (gSysCPU.getMHz() < 800)
  683. #else
  684. if (gSysCPU.getMHz() < 1100)
  685. #endif
  686. {
  687. maskFeatures("CPUSlow");
  688. }
  689. if (isSafe())
  690. {
  691. maskFeatures("safe");
  692. }
  693. }