llviewertexturelist.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:45k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llviewertexturelist.cpp
  3.  * @brief Object for managing the list of images within a region
  4.  *
  5.  * $LicenseInfo:firstyear=2000&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2000-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include <sys/stat.h>
  34. #include "llviewertexturelist.h"
  35. #include "imageids.h"
  36. #include "llgl.h" // fot gathering stats from GL
  37. #include "llimagegl.h"
  38. #include "llimagebmp.h"
  39. #include "llimagej2c.h"
  40. #include "llimagetga.h"
  41. #include "llimagejpeg.h"
  42. #include "llimagepng.h"
  43. #include "llimageworker.h"
  44. #include "llsdserialize.h"
  45. #include "llsys.h"
  46. #include "llvfs.h"
  47. #include "llvfile.h"
  48. #include "llvfsthread.h"
  49. #include "llxmltree.h"
  50. #include "message.h"
  51. #include "lltexturecache.h"
  52. #include "lltexturefetch.h"
  53. #include "llviewercontrol.h"
  54. #include "llviewertexture.h"
  55. #include "llviewermedia.h"
  56. #include "llviewerregion.h"
  57. #include "llviewerstats.h"
  58. #include "pipeline.h"
  59. #include "llappviewer.h"
  60. #include "llxuiparser.h"
  61. ////////////////////////////////////////////////////////////////////////////
  62. void (*LLViewerTextureList::sUUIDCallback)(void **, const LLUUID&) = NULL;
  63. U32 LLViewerTextureList::sTextureBits = 0;
  64. U32 LLViewerTextureList::sTexturePackets = 0;
  65. S32 LLViewerTextureList::sNumImages = 0;
  66. LLStat LLViewerTextureList::sNumImagesStat(32, TRUE);
  67. LLStat LLViewerTextureList::sNumRawImagesStat(32, TRUE);
  68. LLStat LLViewerTextureList::sGLTexMemStat(32, TRUE);
  69. LLStat LLViewerTextureList::sGLBoundMemStat(32, TRUE);
  70. LLStat LLViewerTextureList::sRawMemStat(32, TRUE);
  71. LLStat LLViewerTextureList::sFormattedMemStat(32, TRUE);
  72. LLViewerTextureList gTextureList;
  73. static LLFastTimer::DeclareTimer FTM_PROCESS_IMAGES("Process Images");
  74. ///////////////////////////////////////////////////////////////////////////////
  75. LLViewerTextureList::LLViewerTextureList() 
  76. : mForceResetTextureStats(FALSE),
  77. mUpdateStats(FALSE),
  78. mMaxResidentTexMemInMegaBytes(0),
  79. mMaxTotalTextureMemInMegaBytes(0)
  80. {
  81. }
  82. void LLViewerTextureList::init()
  83. {
  84. sNumImages = 0;
  85. mMaxResidentTexMemInMegaBytes = 0;
  86. mMaxTotalTextureMemInMegaBytes = 0 ;
  87. if (gNoRender)
  88. {
  89. // Don't initialize GL stuff if we're not rendering.
  90. return;
  91. }
  92. mUpdateStats = TRUE;
  93. // Update how much texture RAM we're allowed to use.
  94. updateMaxResidentTexMem(0); // 0 = use current
  95. doPreloadImages();
  96. }
  97. void LLViewerTextureList::doPreloadImages()
  98. {
  99. LL_DEBUGS("ViewerImages") << "Preloading images..." << LL_ENDL;
  100. // Set the "missing asset" image
  101. LLViewerFetchedTexture::sMissingAssetImagep = LLViewerTextureManager::getFetchedTextureFromFile("missing_asset.tga", MIPMAP_NO, LLViewerFetchedTexture::BOOST_UI);
  102. // Set the "white" image
  103. LLViewerFetchedTexture::sWhiteImagep = LLViewerTextureManager::getFetchedTextureFromFile("white.tga", MIPMAP_NO, LLViewerFetchedTexture::BOOST_UI);
  104. LLUIImageList* image_list = LLUIImageList::getInstance();
  105. image_list->initFromFile();
  106. // turn off clamping and bilinear filtering for uv picking images
  107. //LLViewerFetchedTexture* uv_test = preloadUIImage("uv_test1.tga", LLUUID::null, FALSE);
  108. //uv_test->setClamp(FALSE, FALSE);
  109. //uv_test->setMipFilterNearest(TRUE, TRUE);
  110. //uv_test = preloadUIImage("uv_test2.tga", LLUUID::null, FALSE);
  111. //uv_test->setClamp(FALSE, FALSE);
  112. //uv_test->setMipFilterNearest(TRUE, TRUE);
  113. // prefetch specific UUIDs
  114. LLViewerTextureManager::getFetchedTexture(IMG_SHOT, TRUE);
  115. LLViewerTextureManager::getFetchedTexture(IMG_SMOKE_POOF, TRUE);
  116. LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTextureFromFile("silhouette.j2c", MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI);
  117. if (image) 
  118. {
  119. image->setAddressMode(LLTexUnit::TAM_WRAP);
  120. mImagePreloads.insert(image);
  121. }
  122. image = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryLines.png", MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI);
  123. if (image) 
  124. {
  125. image->setAddressMode(LLTexUnit::TAM_WRAP);
  126. mImagePreloads.insert(image);
  127. }
  128. image = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryPassLines.png", MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI);
  129. if (image) 
  130. {
  131. image->setAddressMode(LLTexUnit::TAM_WRAP);
  132. mImagePreloads.insert(image);
  133. }
  134. image = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI);
  135. if (image) 
  136. {
  137. image->setAddressMode(LLTexUnit::TAM_WRAP);
  138. mImagePreloads.insert(image);
  139. }
  140. image = LLViewerTextureManager::getFetchedTextureFromFile("transparent.j2c", MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE,
  141. 0,0,LLUUID("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"));
  142. if (image) 
  143. {
  144. image->setAddressMode(LLTexUnit::TAM_WRAP);
  145. mImagePreloads.insert(image);
  146. }
  147. }
  148. static std::string get_texture_list_name()
  149. {
  150. return std::string("texture_list_") + gSavedSettings.getString("LoginLocation") + ".xml";
  151. }
  152. void LLViewerTextureList::doPrefetchImages()
  153. {
  154. if (LLAppViewer::instance()->getPurgeCache())
  155. {
  156. // cache was purged, no point
  157. return;
  158. }
  159. // Pre-fetch textures from last logout
  160. LLSD imagelist;
  161. std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, get_texture_list_name());
  162. llifstream file;
  163. file.open(filename);
  164. if (file.is_open())
  165. {
  166. LLSDSerialize::fromXML(imagelist, file);
  167. }
  168. for (LLSD::array_iterator iter = imagelist.beginArray();
  169.  iter != imagelist.endArray(); ++iter)
  170. {
  171. LLSD imagesd = *iter;
  172. LLUUID uuid = imagesd["uuid"];
  173. S32 pixel_area = imagesd["area"];
  174. S32 texture_type = imagesd["type"];
  175. if(LLViewerTexture::FETCHED_TEXTURE == texture_type || LLViewerTexture::LOD_TEXTURE == texture_type)
  176. {
  177. LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(uuid, MIPMAP_TRUE, LLViewerTexture::BOOST_NONE, texture_type);
  178. if (image)
  179. {
  180. image->addTextureStats((F32)pixel_area);
  181. }
  182. }
  183. }
  184. }
  185. ///////////////////////////////////////////////////////////////////////////////
  186. LLViewerTextureList::~LLViewerTextureList()
  187. {
  188. }
  189. void LLViewerTextureList::shutdown()
  190. {
  191. // clear out preloads
  192. mImagePreloads.clear();
  193. // Write out list of currently loaded textures for precaching on startup
  194. typedef std::set<std::pair<S32,LLViewerFetchedTexture*> > image_area_list_t;
  195. image_area_list_t image_area_list;
  196. for (image_priority_list_t::iterator iter = mImageList.begin();
  197.  iter != mImageList.end(); ++iter)
  198. {
  199. LLViewerFetchedTexture* image = *iter;
  200. if (!image->hasGLTexture() ||
  201. !image->getUseDiscard() ||
  202. image->needsAux() ||
  203. image->getTargetHost() != LLHost::invalid)
  204. {
  205. continue; // avoid UI, baked, and other special images
  206. }
  207. if(!image->getBoundRecently())
  208. {
  209. continue ;
  210. }
  211. S32 desired = image->getDesiredDiscardLevel();
  212. if (desired >= 0 && desired < MAX_DISCARD_LEVEL)
  213. {
  214. S32 pixel_area = image->getWidth(desired) * image->getHeight(desired);
  215. image_area_list.insert(std::make_pair(pixel_area, image));
  216. }
  217. }
  218. LLSD imagelist;
  219. const S32 max_count = 1000;
  220. S32 count = 0;
  221. S32 image_type ;
  222. for (image_area_list_t::reverse_iterator riter = image_area_list.rbegin();
  223.  riter != image_area_list.rend(); ++riter)
  224. {
  225. LLViewerFetchedTexture* image = riter->second;
  226. image_type = (S32)image->getType() ;
  227. imagelist[count]["area"] = riter->first;
  228. imagelist[count]["uuid"] = image->getID();
  229. imagelist[count]["type"] = image_type;
  230. if (++count >= max_count)
  231. break;
  232. }
  233. if (count > 0 && !gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "").empty())
  234. {
  235. std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, get_texture_list_name());
  236. llofstream file;
  237. file.open(filename);
  238. LLSDSerialize::toPrettyXML(imagelist, file);
  239. }
  240. //
  241. // Clean up "loaded" callbacks.
  242. //
  243. mCallbackList.clear();
  244. // Flush all of the references
  245. mLoadingStreamList.clear();
  246. mCreateTextureList.clear();
  247. mUUIDMap.clear();
  248. mImageList.clear();
  249. }
  250. void LLViewerTextureList::dump()
  251. {
  252. llinfos << "LLViewerTextureList::dump()" << llendl;
  253. for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it)
  254. {
  255. LLViewerFetchedTexture* image = *it;
  256. llinfos << "priority " << image->getDecodePriority()
  257. << " boost " << image->getBoostLevel()
  258. << " size " << image->getWidth() << "x" << image->getHeight()
  259. << " discard " << image->getDiscardLevel()
  260. << " desired " << image->getDesiredDiscardLevel()
  261. << " http://asset.siva.lindenlab.com/" << image->getID() << ".texture"
  262. << llendl;
  263. }
  264. }
  265. void LLViewerTextureList::destroyGL(BOOL save_state)
  266. {
  267. LLImageGL::destroyGL(save_state);
  268. }
  269. void LLViewerTextureList::restoreGL()
  270. {
  271. LLImageGL::restoreGL();
  272. }
  273. /* Vertical tab container button image IDs
  274.  Seem to not decode when running app in debug.
  275.  
  276.  const LLUUID BAD_IMG_ONE("1097dcb3-aef9-8152-f471-431d840ea89e");
  277.  const LLUUID BAD_IMG_TWO("bea77041-5835-1661-f298-47e2d32b7a70");
  278.  */
  279. ///////////////////////////////////////////////////////////////////////////////
  280. LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string& filename,    
  281.    BOOL usemipmaps,
  282.    LLViewerTexture::EBoostLevel boost_priority,
  283.    S8 texture_type,
  284.    LLGLint internal_format,
  285.    LLGLenum primary_format, 
  286.    const LLUUID& force_id)
  287. {
  288. std::string full_path = gDirUtilp->findSkinnedFilename("textures", filename);
  289. if (full_path.empty())
  290. {
  291. llwarns << "Failed to find local image file: " << filename << llendl;
  292. return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, LLViewerTexture::BOOST_UI);
  293. }
  294. std::string url = "file://" + full_path;
  295. return getImageFromUrl(url, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id);
  296. }
  297. LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& url,
  298.    BOOL usemipmaps,
  299.    LLViewerTexture::EBoostLevel boost_priority,
  300.    S8 texture_type,
  301.    LLGLint internal_format,
  302.    LLGLenum primary_format, 
  303.    const LLUUID& force_id)
  304. {
  305. if (gNoRender)
  306. {
  307. // Never mind that this ignores image_set_id;
  308. // getImage() will handle that later.
  309. return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, LLViewerTexture::BOOST_UI);
  310. }
  311. // generate UUID based on hash of filename
  312. LLUUID new_id;
  313. if (force_id.notNull())
  314. {
  315. new_id = force_id;
  316. }
  317. else
  318. {
  319. new_id.generate(url);
  320. }
  321. LLPointer<LLViewerFetchedTexture> imagep = findImage(new_id);
  322. if (imagep.isNull())
  323. {
  324. switch(texture_type)
  325. {
  326. case LLViewerTexture::FETCHED_TEXTURE:
  327. imagep = new LLViewerFetchedTexture(url, new_id, usemipmaps);
  328. break ;
  329. case LLViewerTexture::LOD_TEXTURE:
  330. imagep = new LLViewerLODTexture(url, new_id, usemipmaps);
  331. break ;
  332. default:
  333. llerrs << "Invalid texture type " << texture_type << llendl ;
  334. }
  335. if (internal_format && primary_format)
  336. {
  337. imagep->setExplicitFormat(internal_format, primary_format);
  338. }
  339. addImage(imagep);
  340. if (boost_priority != 0)
  341. {
  342. if (boost_priority == LLViewerFetchedTexture::BOOST_UI ||
  343. boost_priority == LLViewerFetchedTexture::BOOST_ICON)
  344. {
  345. imagep->dontDiscard();
  346. }
  347. imagep->setBoostLevel(boost_priority);
  348. }
  349. }
  350. imagep->setGLTextureCreated(true);
  351. return imagep;
  352. }
  353. LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,        
  354.    BOOL usemipmaps,
  355.    LLViewerTexture::EBoostLevel boost_priority,
  356.    S8 texture_type,
  357.    LLGLint internal_format,
  358.    LLGLenum primary_format,
  359.    LLHost request_from_host)
  360. {
  361. // Return the image with ID image_id
  362. // If the image is not found, creates new image and
  363. // enqueues a request for transmission
  364. if ((&image_id == NULL) || image_id.isNull())
  365. {
  366. return (LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, LLViewerTexture::BOOST_UI));
  367. }
  368. LLPointer<LLViewerFetchedTexture> imagep = findImage(image_id);
  369. if (imagep.isNull())
  370. {
  371. imagep = createImage(image_id, usemipmaps, boost_priority, texture_type, internal_format, primary_format, request_from_host) ;
  372. }
  373. imagep->setGLTextureCreated(true);
  374. return imagep;
  375. }
  376. //when this function is called, there is no such texture in the gTextureList with image_id.
  377. LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,        
  378.    BOOL usemipmaps,
  379.    LLViewerTexture::EBoostLevel boost_priority,
  380.    S8 texture_type,
  381.    LLGLint internal_format,
  382.    LLGLenum primary_format,
  383.    LLHost request_from_host)
  384. {
  385. LLPointer<LLViewerFetchedTexture> imagep ;
  386. switch(texture_type)
  387. {
  388. case LLViewerTexture::FETCHED_TEXTURE:
  389. imagep = new LLViewerFetchedTexture(image_id, request_from_host, usemipmaps);
  390. break ;
  391. case LLViewerTexture::LOD_TEXTURE:
  392. imagep = new LLViewerLODTexture(image_id, request_from_host, usemipmaps);
  393. break ;
  394. default:
  395. llerrs << "Invalid texture type " << texture_type << llendl ;
  396. }
  397. if (internal_format && primary_format)
  398. {
  399. imagep->setExplicitFormat(internal_format, primary_format);
  400. }
  401. addImage(imagep);
  402. if (boost_priority != 0)
  403. {
  404. if (boost_priority == LLViewerFetchedTexture::BOOST_UI ||
  405. boost_priority == LLViewerFetchedTexture::BOOST_ICON)
  406. {
  407. imagep->dontDiscard();
  408. }
  409. imagep->setBoostLevel(boost_priority);
  410. }
  411. else
  412. {
  413. //by default, the texure can not be removed from memory even if it is not used.
  414. //here turn this off
  415. //if this texture should be set to NO_DELETE, call setNoDelete() afterwards.
  416. imagep->forceActive() ;
  417. }
  418. return imagep ;
  419. }
  420. LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLUUID &image_id)
  421. {
  422. uuid_map_t::iterator iter = mUUIDMap.find(image_id);
  423. if(iter == mUUIDMap.end())
  424. return NULL;
  425. return iter->second;
  426. }
  427. void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
  428. {
  429. llassert(image);
  430. if (image->isInImageList())
  431. {
  432. llerrs << "LLViewerTextureList::addImageToList - Image already in list" << llendl;
  433. }
  434. if ((mImageList.insert(image)).second != true)
  435. {
  436. llwarns << "BAD STUFF!  (mImageList.insert(image)).second != true" << llendl;
  437. }
  438. image->setInImageList(TRUE) ;
  439. }
  440. void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
  441. {
  442. llassert(image);
  443. if (!image->isInImageList())
  444. {
  445. llinfos << "RefCount: " << image->getNumRefs() << llendl ;
  446. uuid_map_t::iterator iter = mUUIDMap.find(image->getID());
  447. if(iter == mUUIDMap.end() || iter->second != image)
  448. {
  449. llinfos << "Image is not in mUUIDMap!" << llendl ;
  450. }
  451. llerrs << "LLViewerTextureList::removeImageFromList - Image not in list" << llendl;
  452. }
  453. if (mImageList.erase(image) != 1)
  454.         {
  455.                 llwarns << "BAD STUFF!  mImageList.erase(image) != 1" << llendl;
  456.         }
  457. image->setInImageList(FALSE) ;
  458. }
  459. void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image)
  460. {
  461. if (!new_image)
  462. {
  463. llwarning("No image to add to image list", 0);
  464. return;
  465. }
  466. LLUUID image_id = new_image->getID();
  467. LLViewerFetchedTexture *image = findImage(image_id);
  468. if (image)
  469. {
  470. llwarns << "Image with ID " << image_id << " already in list" << llendl;
  471. }
  472. sNumImages++;
  473. addImageToList(new_image);
  474. mUUIDMap[image_id] = new_image;
  475. }
  476. void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image)
  477. {
  478. if( image)
  479. {
  480. if (image->hasCallbacks())
  481. {
  482. mCallbackList.erase(image);
  483. }
  484. llverify(mUUIDMap.erase(image->getID()) == 1);
  485. sNumImages--;
  486. removeImageFromList(image);
  487. }
  488. }
  489. ///////////////////////////////////////////////////////////////////////////////
  490. ////////////////////////////////////////////////////////////////////////////
  491. void LLViewerTextureList::dirtyImage(LLViewerFetchedTexture *image)
  492. {
  493. mDirtyTextureList.insert(image);
  494. }
  495. ////////////////////////////////////////////////////////////////////////////
  496. static LLFastTimer::DeclareTimer FTM_IMAGE_MARK_DIRTY("Dirty Images");
  497. void LLViewerTextureList::updateImages(F32 max_time)
  498. {
  499. LLAppViewer::getTextureFetch()->setTextureBandwidth(LLViewerStats::getInstance()->mTextureKBitStat.getMeanPerSec());
  500. LLViewerStats::getInstance()->mNumImagesStat.addValue(sNumImages);
  501. LLViewerStats::getInstance()->mNumRawImagesStat.addValue(LLImageRaw::sRawImageCount);
  502. LLViewerStats::getInstance()->mGLTexMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sGlobalTextureMemoryInBytes));
  503. LLViewerStats::getInstance()->mGLBoundMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sBoundTextureMemoryInBytes));
  504. LLViewerStats::getInstance()->mRawMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageRaw::sGlobalRawMemory));
  505. LLViewerStats::getInstance()->mFormattedMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageFormatted::sGlobalFormattedMemory));
  506. updateImagesDecodePriorities();
  507. F32 total_max_time = max_time;
  508. max_time -= updateImagesFetchTextures(max_time);
  509. max_time = llmax(max_time, total_max_time*.50f); // at least 50% of max_time
  510. max_time -= updateImagesCreateTextures(max_time);
  511. if (!mDirtyTextureList.empty())
  512. {
  513. LLFastTimer t(FTM_IMAGE_MARK_DIRTY);
  514. gPipeline.dirtyPoolObjectTextures(mDirtyTextureList);
  515. mDirtyTextureList.clear();
  516. }
  517. bool didone = false;
  518. for (image_list_t::iterator iter = mCallbackList.begin();
  519. iter != mCallbackList.end(); )
  520. {
  521. //trigger loaded callbacks on local textures immediately
  522. LLViewerFetchedTexture* image = *iter++;
  523. if (!image->getUrl().empty())
  524. {
  525. // Do stuff to handle callbacks, update priorities, etc.
  526. didone = image->doLoadedCallbacks();
  527. }
  528. else if (!didone)
  529. {
  530. // Do stuff to handle callbacks, update priorities, etc.
  531. didone = image->doLoadedCallbacks();
  532. }
  533. }
  534. updateImagesUpdateStats();
  535. }
  536. void LLViewerTextureList::updateImagesDecodePriorities()
  537. {
  538. // Update the decode priority for N images each frame
  539. {
  540. const size_t max_update_count = llmin((S32) (1024*gFrameIntervalSeconds) + 1, 32); //target 1024 textures per second
  541. S32 update_counter = llmin(max_update_count, mUUIDMap.size()/10);
  542. uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateUUID);
  543. while(update_counter > 0 && !mUUIDMap.empty())
  544. {
  545. if (iter == mUUIDMap.end())
  546. {
  547. iter = mUUIDMap.begin();
  548. }
  549. mLastUpdateUUID = iter->first;
  550. LLPointer<LLViewerFetchedTexture> imagep = iter->second;
  551. ++iter; // safe to incrament now
  552. //
  553. // Flush formatted images using a lazy flush
  554. //
  555. const F32 LAZY_FLUSH_TIMEOUT = 30.f; // stop decoding
  556. const F32 MAX_INACTIVE_TIME  = 50.f; // actually delete
  557. S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference
  558. if (imagep->hasCallbacks())
  559. {
  560. min_refs++; // Add an extra reference if we're on the loaded callback list
  561. }
  562. S32 num_refs = imagep->getNumRefs();
  563. if (num_refs == min_refs)
  564. {
  565. if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > LAZY_FLUSH_TIMEOUT)
  566. {
  567. // Remove the unused image from the image list
  568. deleteImage(imagep);
  569. imagep = NULL; // should destroy the image
  570. }
  571. continue;
  572. }
  573. else
  574. {
  575. if(imagep->hasSavedRawImage())
  576. {
  577. if(imagep->getElapsedLastReferencedSavedRawImageTime() > MAX_INACTIVE_TIME)
  578. {
  579. imagep->destroySavedRawImage() ;
  580. }
  581. }
  582. if(imagep->isDeleted())
  583. {
  584. continue ;
  585. }
  586. else if(imagep->isDeletionCandidate())
  587. {
  588. imagep->destroyTexture() ;
  589. continue ;
  590. }
  591. else if(imagep->isInactive())
  592. {
  593. if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > MAX_INACTIVE_TIME)
  594. {
  595. imagep->setDeletionCandidate() ;
  596. }
  597. continue ;
  598. }
  599. else
  600. {
  601. imagep->getLastReferencedTimer()->reset();
  602. //reset texture state.
  603. imagep->setInactive() ;
  604. }
  605. }
  606. imagep->processTextureStats();
  607. F32 old_priority = imagep->getDecodePriority();
  608. F32 old_priority_test = llmax(old_priority, 0.0f);
  609. F32 decode_priority = imagep->calcDecodePriority();
  610. F32 decode_priority_test = llmax(decode_priority, 0.0f);
  611. // Ignore < 20% difference
  612. if ((decode_priority_test < old_priority_test * .8f) ||
  613. (decode_priority_test > old_priority_test * 1.25f))
  614. {
  615. removeImageFromList(imagep);
  616. imagep->setDecodePriority(decode_priority);
  617. addImageToList(imagep);
  618. }
  619. update_counter--;
  620. }
  621. }
  622. }
  623. /*
  624.  static U8 get_image_type(LLViewerFetchedTexture* imagep, LLHost target_host)
  625.  {
  626.  // Having a target host implies this is a baked image.  I don't
  627.  // believe that boost level has been set at this point. JC
  628.  U8 type_from_host = (target_host.isOk() 
  629.  ? LLImageBase::TYPE_AVATAR_BAKE 
  630.  : LLImageBase::TYPE_NORMAL);
  631.  S32 boost_level = imagep->getBoostLevel();
  632.  U8 type_from_boost = ( (boost_level == LLViewerFetchedTexture::BOOST_AVATAR_BAKED 
  633.  || boost_level == LLViewerFetchedTexture::BOOST_AVATAR_BAKED_SELF)
  634.  ? LLImageBase::TYPE_AVATAR_BAKE 
  635.  : LLImageBase::TYPE_NORMAL);
  636.  if (type_from_host == LLImageBase::TYPE_NORMAL
  637.  && type_from_boost == LLImageBase::TYPE_AVATAR_BAKE)
  638.  {
  639.  llwarns << "TAT: get_image_type() type_from_host doesn't match type_from_boost"
  640.  << " host " << target_host
  641.  << " boost " << imagep->getBoostLevel()
  642.  << " imageid " << imagep->getID()
  643.  << llendl;
  644.  imagep->dump();
  645.  }
  646.  return type_from_host;
  647.  }
  648.  */
  649. static LLFastTimer::DeclareTimer FTM_IMAGE_CREATE("Create Images");
  650. F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
  651. {
  652. if (gNoRender || gGLManager.mIsDisabled) return 0.0f;
  653. //
  654. // Create GL textures for all textures that need them (images which have been
  655. // decoded, but haven't been pushed into GL).
  656. //
  657. LLFastTimer t(FTM_IMAGE_CREATE);
  658. LLTimer create_timer;
  659. image_list_t::iterator enditer = mCreateTextureList.begin();
  660. for (image_list_t::iterator iter = mCreateTextureList.begin();
  661.  iter != mCreateTextureList.end();)
  662. {
  663. image_list_t::iterator curiter = iter++;
  664. enditer = iter;
  665. LLViewerFetchedTexture *imagep = *curiter;
  666. imagep->createTexture();
  667. if (create_timer.getElapsedTimeF32() > max_time)
  668. {
  669. break;
  670. }
  671. }
  672. mCreateTextureList.erase(mCreateTextureList.begin(), enditer);
  673. return create_timer.getElapsedTimeF32();
  674. }
  675. void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
  676. {
  677. if(!imagep)
  678. {
  679. return ;
  680. }
  681. if(imagep->isInImageList())
  682. {
  683. removeImageFromList(imagep);
  684. }
  685. imagep->processTextureStats();
  686. F32 decode_priority = LLViewerFetchedTexture::maxDecodePriority() ;
  687. imagep->setDecodePriority(decode_priority);
  688. mImageList.insert(imagep);
  689. imagep->setInImageList(TRUE) ;
  690. return ;
  691. }
  692. F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
  693. {
  694. LLTimer image_op_timer;
  695. // Update the decode priority for N images each frame
  696. // Make a list with 32 high priority entries + 256 cycled entries
  697. const size_t max_priority_count = llmin((S32) (256*10.f*gFrameIntervalSeconds)+1, 32);
  698. const size_t max_update_count = llmin((S32) (1024*10.f*gFrameIntervalSeconds)+1, 256);
  699. // 32 high priority entries
  700. typedef std::vector<LLViewerFetchedTexture*> entries_list_t;
  701. entries_list_t entries;
  702. size_t update_counter = llmin(max_priority_count, mImageList.size());
  703. image_priority_list_t::iterator iter1 = mImageList.begin();
  704. while(update_counter > 0)
  705. {
  706. entries.push_back(*iter1);
  707. ++iter1;
  708. update_counter--;
  709. }
  710. // 256 cycled entries
  711. update_counter = llmin(max_update_count, mUUIDMap.size());
  712. if(update_counter > 0)
  713. {
  714. uuid_map_t::iterator iter2 = mUUIDMap.upper_bound(mLastFetchUUID);
  715. uuid_map_t::iterator iter2p = iter2;
  716. while(update_counter > 0)
  717. {
  718. if (iter2 == mUUIDMap.end())
  719. {
  720. iter2 = mUUIDMap.begin();
  721. }
  722. entries.push_back(iter2->second);
  723. iter2p = iter2++;
  724. update_counter--;
  725. }
  726. mLastFetchUUID = iter2p->first;
  727. }
  728. S32 fetch_count = 0;
  729. S32 min_count = max_priority_count + max_update_count/4;
  730. for (entries_list_t::iterator iter3 = entries.begin();
  731.  iter3 != entries.end(); )
  732. {
  733. LLPointer<LLViewerFetchedTexture> imagep = *iter3++;
  734. bool fetching = imagep->updateFetch();
  735. if (fetching)
  736. {
  737. fetch_count++;
  738. }
  739. if (min_count <= 0 && image_op_timer.getElapsedTimeF32() > max_time)
  740. {
  741. break;
  742. }
  743. min_count--;
  744. }
  745. if (fetch_count == 0)
  746. {
  747. gDebugTimers[0].pause();
  748. }
  749. else
  750. {
  751. gDebugTimers[0].unpause();
  752. }
  753. return image_op_timer.getElapsedTimeF32();
  754. }
  755. void LLViewerTextureList::updateImagesUpdateStats()
  756. {
  757. if (mUpdateStats && mForceResetTextureStats)
  758. {
  759. for (image_priority_list_t::iterator iter = mImageList.begin();
  760.  iter != mImageList.end(); )
  761. {
  762. LLViewerFetchedTexture* imagep = *iter++;
  763. imagep->resetTextureStats();
  764. }
  765. mUpdateStats = FALSE;
  766. mForceResetTextureStats = FALSE;
  767. }
  768. }
  769. void LLViewerTextureList::decodeAllImages(F32 max_time)
  770. {
  771. LLTimer timer;
  772. if(gNoRender) return;
  773. // Update texture stats and priorities
  774. std::vector<LLPointer<LLViewerFetchedTexture> > image_list;
  775. for (image_priority_list_t::iterator iter = mImageList.begin();
  776.  iter != mImageList.end(); )
  777. {
  778. LLViewerFetchedTexture* imagep = *iter++;
  779. image_list.push_back(imagep);
  780. imagep->setInImageList(FALSE) ;
  781. }
  782. mImageList.clear();
  783. for (std::vector<LLPointer<LLViewerFetchedTexture> >::iterator iter = image_list.begin();
  784.  iter != image_list.end(); ++iter)
  785. {
  786. LLViewerFetchedTexture* imagep = *iter;
  787. imagep->processTextureStats();
  788. F32 decode_priority = imagep->calcDecodePriority();
  789. imagep->setDecodePriority(decode_priority);
  790. mImageList.insert(imagep);
  791. imagep->setInImageList(TRUE) ;
  792. }
  793. image_list.clear();
  794. // Update fetch (decode)
  795. for (image_priority_list_t::iterator iter = mImageList.begin();
  796.  iter != mImageList.end(); )
  797. {
  798. LLViewerFetchedTexture* imagep = *iter++;
  799. imagep->updateFetch();
  800. }
  801. // Run threads
  802. S32 fetch_pending = 0;
  803. while (1)
  804. {
  805. LLAppViewer::instance()->getTextureCache()->update(1); // unpauses the texture cache thread
  806. LLAppViewer::instance()->getImageDecodeThread()->update(1); // unpauses the image thread
  807. fetch_pending = LLAppViewer::instance()->getTextureFetch()->update(1); // unpauses the texture fetch thread
  808. if (fetch_pending == 0 || timer.getElapsedTimeF32() > max_time)
  809. {
  810. break;
  811. }
  812. }
  813. // Update fetch again
  814. for (image_priority_list_t::iterator iter = mImageList.begin();
  815.  iter != mImageList.end(); )
  816. {
  817. LLViewerFetchedTexture* imagep = *iter++;
  818. imagep->updateFetch();
  819. }
  820. max_time -= timer.getElapsedTimeF32();
  821. max_time = llmax(max_time, .001f);
  822. F32 create_time = updateImagesCreateTextures(max_time);
  823. LL_DEBUGS("ViewerImages") << "decodeAllImages() took " << timer.getElapsedTimeF32() << " seconds. " 
  824. << " fetch_pending " << fetch_pending
  825. << " create_time " << create_time
  826. << LL_ENDL;
  827. }
  828. BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
  829.  const std::string& out_filename,
  830.  const U8 codec)
  831. {
  832. // First, load the image.
  833. LLPointer<LLImageRaw> raw_image = new LLImageRaw;
  834. switch (codec)
  835. {
  836. case IMG_CODEC_BMP:
  837. {
  838. LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
  839. if (!bmp_image->load(filename))
  840. {
  841. return FALSE;
  842. }
  843. if (!bmp_image->decode(raw_image, 0.0f))
  844. {
  845. return FALSE;
  846. }
  847. }
  848. break;
  849. case IMG_CODEC_TGA:
  850. {
  851. LLPointer<LLImageTGA> tga_image = new LLImageTGA;
  852. if (!tga_image->load(filename))
  853. {
  854. return FALSE;
  855. }
  856. if (!tga_image->decode(raw_image))
  857. {
  858. return FALSE;
  859. }
  860. if( (tga_image->getComponents() != 3) &&
  861.    (tga_image->getComponents() != 4) )
  862. {
  863. tga_image->setLastError( "Image files with less than 3 or more than 4 components are not supported." );
  864. return FALSE;
  865. }
  866. }
  867. break;
  868. case IMG_CODEC_JPEG:
  869. {
  870. LLPointer<LLImageJPEG> jpeg_image = new LLImageJPEG;
  871. if (!jpeg_image->load(filename))
  872. {
  873. return FALSE;
  874. }
  875. if (!jpeg_image->decode(raw_image, 0.0f))
  876. {
  877. return FALSE;
  878. }
  879. }
  880. break;
  881. case IMG_CODEC_PNG:
  882. {
  883. LLPointer<LLImagePNG> png_image = new LLImagePNG;
  884. if (!png_image->load(filename))
  885. {
  886. return FALSE;
  887. }
  888. if (!png_image->decode(raw_image, 0.0f))
  889. {
  890. return FALSE;
  891. }
  892. }
  893. break;
  894. default:
  895. return FALSE;
  896. }
  897. LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image);
  898. if( !compressedImage->save(out_filename) )
  899. {
  900. llinfos << "Couldn't create output file " << out_filename << llendl;
  901. return FALSE;
  902. }
  903. // test to see if the encode and save worked.
  904. LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
  905. if( !integrity_test->loadAndValidate( out_filename ) )
  906. {
  907. llinfos << "Image: " << out_filename << " is corrupt." << llendl;
  908. return FALSE;
  909. }
  910. return TRUE;
  911. }
  912. // note: modifies the argument raw_image!!!!
  913. LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImageRaw> raw_image)
  914. {
  915. raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
  916. LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C();
  917. compressedImage->setRate(0.f);
  918. if (gSavedSettings.getBOOL("LosslessJ2CUpload") &&
  919. (raw_image->getWidth() * raw_image->getHeight() <= LL_IMAGE_REZ_LOSSLESS_CUTOFF * LL_IMAGE_REZ_LOSSLESS_CUTOFF))
  920. compressedImage->setReversible(TRUE);
  921. compressedImage->encode(raw_image, 0.0f);
  922. return compressedImage;
  923. }
  924. const S32 MIN_VIDEO_RAM = 32;
  925. const S32 MAX_VIDEO_RAM = 512; // 512MB max for performance reasons.
  926. // Returns min setting for TextureMemory (in MB)
  927. S32 LLViewerTextureList::getMinVideoRamSetting()
  928. {
  929. S32 system_ram = (S32)BYTES_TO_MEGA_BYTES(gSysMemory.getPhysicalMemoryClamped());
  930. //min texture mem sets to 64M if total physical mem is more than 1.5GB
  931. return (system_ram > 1500) ? 64 : MIN_VIDEO_RAM_IN_MEGA_BYTES ;
  932. }
  933. //static
  934. // Returns max setting for TextureMemory (in MB)
  935. S32 LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended)
  936. {
  937. S32 max_texmem;
  938. if (gGLManager.mVRAM != 0)
  939. {
  940. // Treat any card with < 32 MB (shudder) as having 32 MB
  941. //  - it's going to be swapping constantly regardless
  942. S32 max_vram = gGLManager.mVRAM;
  943. max_vram = llmax(max_vram, getMinVideoRamSetting());
  944. max_texmem = max_vram;
  945. if (!get_recommended)
  946. max_texmem *= 2;
  947. }
  948. else
  949. {
  950. if (get_recommended)
  951. max_texmem = 128;
  952. else
  953. max_texmem = 512;
  954. llwarns << "VRAM amount not detected, defaulting to " << max_texmem << " MB" << llendl;
  955. }
  956. S32 system_ram = (S32)BYTES_TO_MEGA_BYTES(gSysMemory.getPhysicalMemoryClamped()); // In MB
  957. //llinfos << "*** DETECTED " << system_ram << " MB of system memory." << llendl;
  958. if (get_recommended)
  959. max_texmem = llmin(max_texmem, (S32)(system_ram/2));
  960. else
  961. max_texmem = llmin(max_texmem, (S32)(system_ram));
  962. max_texmem = llclamp(max_texmem, getMinVideoRamSetting(), MAX_VIDEO_RAM_IN_MEGA_BYTES); 
  963. return max_texmem;
  964. }
  965. const S32 VIDEO_CARD_FRAMEBUFFER_MEM = 12; // MB
  966. const S32 MIN_MEM_FOR_NON_TEXTURE = 512 ; //MB
  967. void LLViewerTextureList::updateMaxResidentTexMem(S32 mem)
  968. {
  969. // Initialize the image pipeline VRAM settings
  970. S32 cur_mem = gSavedSettings.getS32("TextureMemory");
  971. F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple");
  972. S32 default_mem = getMaxVideoRamSetting(true); // recommended default
  973. if (mem == 0)
  974. {
  975. mem = cur_mem > 0 ? cur_mem : default_mem;
  976. }
  977. else if (mem < 0)
  978. {
  979. mem = default_mem;
  980. }
  981. // limit the texture memory to a multiple of the default if we've found some cards to behave poorly otherwise
  982. mem = llmin(mem, (S32) (mem_multiplier * (F32) default_mem));
  983. mem = llclamp(mem, getMinVideoRamSetting(), getMaxVideoRamSetting());
  984. if (mem != cur_mem)
  985. {
  986. gSavedSettings.setS32("TextureMemory", mem);
  987. return; //listener will re-enter this function
  988. }
  989. // TODO: set available resident texture mem based on use by other subsystems
  990. // currently max(12MB, VRAM/4) assumed...
  991. S32 vb_mem = mem;
  992. S32 fb_mem = llmax(VIDEO_CARD_FRAMEBUFFER_MEM, vb_mem/4);
  993. mMaxResidentTexMemInMegaBytes = (vb_mem - fb_mem) ; //in MB
  994. mMaxTotalTextureMemInMegaBytes = mMaxResidentTexMemInMegaBytes * 2;
  995. if (mMaxResidentTexMemInMegaBytes > 640)
  996. {
  997. mMaxTotalTextureMemInMegaBytes -= (mMaxResidentTexMemInMegaBytes >> 2);
  998. }
  999. //system mem
  1000. S32 system_ram = (S32)BYTES_TO_MEGA_BYTES(gSysMemory.getPhysicalMemoryClamped()); // In MB
  1001. //minimum memory reserved for non-texture use.
  1002. //if system_raw >= 1GB, reserve at least 512MB for non-texture use;
  1003. //otherwise reserve half of the system_ram for non-texture use.
  1004. S32 min_non_texture_mem = llmin(system_ram / 2, MIN_MEM_FOR_NON_TEXTURE) ; 
  1005. if (mMaxTotalTextureMemInMegaBytes > system_ram - min_non_texture_mem)
  1006. {
  1007. mMaxTotalTextureMemInMegaBytes = system_ram - min_non_texture_mem ;
  1008. }
  1009. llinfos << "Total Video Memory set to: " << vb_mem << " MB" << llendl;
  1010. llinfos << "Available Texture Memory set to: " << (vb_mem - fb_mem) << " MB" << llendl;
  1011. }
  1012. ///////////////////////////////////////////////////////////////////////////////
  1013. // static
  1014. void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_data)
  1015. {
  1016. LLFastTimer t(FTM_PROCESS_IMAGES);
  1017. // Receive image header, copy into image object and decompresses 
  1018. // if this is a one-packet image. 
  1019. LLUUID id;
  1020. char ip_string[256];
  1021. u32_to_ip_string(msg->getSenderIP(),ip_string);
  1022. if (msg->getReceiveCompressedSize())
  1023. {
  1024. gTextureList.sTextureBits += msg->getReceiveCompressedSize() * 8;
  1025. }
  1026. else
  1027. {
  1028. gTextureList.sTextureBits += msg->getReceiveSize() * 8;
  1029. }
  1030. gTextureList.sTexturePackets++;
  1031. U8 codec;
  1032. U16 packets;
  1033. U32 totalbytes;
  1034. msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id);
  1035. msg->getU8Fast(_PREHASH_ImageID, _PREHASH_Codec, codec);
  1036. msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packets, packets);
  1037. msg->getU32Fast(_PREHASH_ImageID, _PREHASH_Size, totalbytes);
  1038. S32 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data); 
  1039. if (!data_size)
  1040. {
  1041. return;
  1042. }
  1043. if (data_size < 0)
  1044. {
  1045. // msg->getSizeFast() is probably trying to tell us there
  1046. // was an error.
  1047. llerrs << "image header chunk size was negative: "
  1048. << data_size << llendl;
  1049. return;
  1050. }
  1051. // this buffer gets saved off in the packet list
  1052. U8 *data = new U8[data_size];
  1053. msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size);
  1054. LLViewerFetchedTexture *image = LLViewerTextureManager::getFetchedTexture(id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
  1055. if (!image)
  1056. {
  1057. delete [] data;
  1058. return;
  1059. }
  1060. image->getLastPacketTimer()->reset();
  1061. bool res = LLAppViewer::getTextureFetch()->receiveImageHeader(msg->getSender(), id, codec, packets, totalbytes, data_size, data);
  1062. if (!res)
  1063. {
  1064. delete[] data;
  1065. }
  1066. }
  1067. // static
  1068. void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_data)
  1069. {
  1070. LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE);
  1071. LLFastTimer t(FTM_PROCESS_IMAGES);
  1072. // Receives image packet, copy into image object,
  1073. // checks if all packets received, decompresses if so. 
  1074. LLUUID id;
  1075. U16 packet_num;
  1076. char ip_string[256];
  1077. u32_to_ip_string(msg->getSenderIP(),ip_string);
  1078. if (msg->getReceiveCompressedSize())
  1079. {
  1080. gTextureList.sTextureBits += msg->getReceiveCompressedSize() * 8;
  1081. }
  1082. else
  1083. {
  1084. gTextureList.sTextureBits += msg->getReceiveSize() * 8;
  1085. }
  1086. gTextureList.sTexturePackets++;
  1087. //llprintline("Start decode, image header...");
  1088. msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id);
  1089. msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packet, packet_num);
  1090. S32 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data); 
  1091. if (!data_size)
  1092. {
  1093. return;
  1094. }
  1095. if (data_size < 0)
  1096. {
  1097. // msg->getSizeFast() is probably trying to tell us there
  1098. // was an error.
  1099. llerrs << "image data chunk size was negative: "
  1100. << data_size << llendl;
  1101. return;
  1102. }
  1103. if (data_size > MTUBYTES)
  1104. {
  1105. llerrs << "image data chunk too large: " << data_size << " bytes" << llendl;
  1106. return;
  1107. }
  1108. U8 *data = new U8[data_size];
  1109. msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size);
  1110. LLViewerFetchedTexture *image = LLViewerTextureManager::getFetchedTexture(id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
  1111. if (!image)
  1112. {
  1113. delete [] data;
  1114. return;
  1115. }
  1116. image->getLastPacketTimer()->reset();
  1117. bool res = LLAppViewer::getTextureFetch()->receiveImagePacket(msg->getSender(), id, packet_num, data_size, data);
  1118. if (!res)
  1119. {
  1120. delete[] data;
  1121. }
  1122. }
  1123. // We've been that the asset server does not contain the requested image id.
  1124. // static
  1125. void LLViewerTextureList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data)
  1126. {
  1127. LLFastTimer t(FTM_PROCESS_IMAGES);
  1128. LLUUID image_id;
  1129. msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, image_id);
  1130. LLViewerFetchedTexture* image = gTextureList.findImage( image_id );
  1131. if( image )
  1132. {
  1133. image->setIsMissingAsset();
  1134. }
  1135. }
  1136. ///////////////////////////////////////////////////////////////////////////////
  1137. //static
  1138. const U32 SIXTEEN_MEG = 0x1000000;
  1139. S32 LLViewerTextureList::calcMaxTextureRAM()
  1140. {
  1141. // Decide the maximum amount of RAM we should allow the user to allocate to texture cache
  1142. LLMemoryInfo memory_info;
  1143. U32 available_memory = memory_info.getPhysicalMemoryClamped();
  1144. clamp_rescale((F32)available_memory,
  1145.   (F32)(SIXTEEN_MEG * 16),
  1146.   (F32)U32_MAX,
  1147.   (F32)(SIXTEEN_MEG * 4),
  1148.   (F32)(U32_MAX >> 1));
  1149. return available_memory;
  1150. }
  1151. ///////////////////////////////////////////////////////////////////////////////
  1152. // explicitly cleanup resources, as this is a singleton class with process
  1153. // lifetime so ability to perform std::map operations in destructor is not
  1154. // guaranteed.
  1155. void LLUIImageList::cleanUp()
  1156. {
  1157. mUIImages.clear();
  1158. mUITextureList.clear() ;
  1159. }
  1160. LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id, S32 priority)
  1161. {
  1162. // use id as image name
  1163. std::string image_name = image_id.asString();
  1164. // look for existing image
  1165. uuid_ui_image_map_t::iterator found_it = mUIImages.find(image_name);
  1166. if (found_it != mUIImages.end())
  1167. {
  1168. return found_it->second;
  1169. }
  1170. const BOOL use_mips = FALSE;
  1171. const LLRect scale_rect = LLRect::null;
  1172. return loadUIImageByID(image_id, use_mips, scale_rect, (LLViewerTexture::EBoostLevel)priority);
  1173. }
  1174. LLUIImagePtr LLUIImageList::getUIImage(const std::string& image_name, S32 priority)
  1175. {
  1176. // look for existing image
  1177. uuid_ui_image_map_t::iterator found_it = mUIImages.find(image_name);
  1178. if (found_it != mUIImages.end())
  1179. {
  1180. return found_it->second;
  1181. }
  1182. const BOOL use_mips = FALSE;
  1183. const LLRect scale_rect = LLRect::null;
  1184. return loadUIImageByName(image_name, image_name, use_mips, scale_rect, (LLViewerTexture::EBoostLevel)priority);
  1185. }
  1186. LLUIImagePtr LLUIImageList::loadUIImageByName(const std::string& name, const std::string& filename,
  1187.   BOOL use_mips, const LLRect& scale_rect, LLViewerTexture::EBoostLevel boost_priority )
  1188. {
  1189. if (boost_priority == LLViewerTexture::BOOST_NONE)
  1190. {
  1191. boost_priority = LLViewerTexture::BOOST_UI;
  1192. }
  1193. LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTextureFromFile(filename, MIPMAP_NO, boost_priority);
  1194. return loadUIImage(imagep, name, use_mips, scale_rect);
  1195. }
  1196. LLUIImagePtr LLUIImageList::loadUIImageByID(const LLUUID& id,
  1197. BOOL use_mips, const LLRect& scale_rect, LLViewerTexture::EBoostLevel boost_priority)
  1198. {
  1199. if (boost_priority == LLViewerTexture::BOOST_NONE)
  1200. {
  1201. boost_priority = LLViewerTexture::BOOST_UI;
  1202. }
  1203. LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(id, MIPMAP_NO, boost_priority);
  1204. return loadUIImage(imagep, id.asString(), use_mips, scale_rect);
  1205. }
  1206. LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips, const LLRect& scale_rect)
  1207. {
  1208. if (!imagep) return NULL;
  1209. imagep->setAddressMode(LLTexUnit::TAM_CLAMP);
  1210. //all UI images are non-deletable
  1211. imagep->setNoDelete();
  1212. LLUIImagePtr new_imagep = new LLUIImage(name, imagep);
  1213. mUIImages.insert(std::make_pair(name, new_imagep));
  1214. mUITextureList.push_back(imagep);
  1215. LLUIImageLoadData* datap = new LLUIImageLoadData;
  1216. datap->mImageName = name;
  1217. datap->mImageScaleRegion = scale_rect;
  1218. imagep->setLoadedCallback(onUIImageLoaded, 0, FALSE, FALSE, datap);
  1219. return new_imagep;
  1220. }
  1221. LLUIImagePtr LLUIImageList::preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect)
  1222. {
  1223. // look for existing image
  1224. uuid_ui_image_map_t::iterator found_it = mUIImages.find(name);
  1225. if (found_it != mUIImages.end())
  1226. {
  1227. // image already loaded!
  1228. llerrs << "UI Image " << name << " already loaded." << llendl;
  1229. }
  1230. return loadUIImageByName(name, filename, use_mips, scale_rect);
  1231. }
  1232. //static 
  1233. void LLUIImageList::onUIImageLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* user_data )
  1234. {
  1235. if(!success || !user_data) 
  1236. {
  1237. return;
  1238. }
  1239. LLUIImageLoadData* image_datap = (LLUIImageLoadData*)user_data;
  1240. std::string ui_image_name = image_datap->mImageName;
  1241. LLRect scale_rect = image_datap->mImageScaleRegion;
  1242. if (final)
  1243. {
  1244. delete image_datap;
  1245. }
  1246. LLUIImageList* instance = getInstance();
  1247. uuid_ui_image_map_t::iterator found_it = instance->mUIImages.find(ui_image_name);
  1248. if (found_it != instance->mUIImages.end())
  1249. {
  1250. LLUIImagePtr imagep = found_it->second;
  1251. // for images grabbed from local files, apply clipping rectangle to restore original dimensions
  1252. // from power-of-2 gl image
  1253. if (success && imagep.notNull() && src_vi && (src_vi->getUrl().compare(0, 7, "file://")==0))
  1254. {
  1255. F32 clip_x = (F32)src_vi->getOriginalWidth() / (F32)src_vi->getFullWidth();
  1256. F32 clip_y = (F32)src_vi->getOriginalHeight() / (F32)src_vi->getFullHeight();
  1257. imagep->setClipRegion(LLRectf(0.f, clip_y, clip_x, 0.f));
  1258. if (scale_rect != LLRect::null)
  1259. {
  1260. imagep->setScaleRegion(
  1261. LLRectf(llclamp((F32)scale_rect.mLeft / (F32)imagep->getWidth(), 0.f, 1.f),
  1262. llclamp((F32)scale_rect.mTop / (F32)imagep->getHeight(), 0.f, 1.f),
  1263. llclamp((F32)scale_rect.mRight / (F32)imagep->getWidth(), 0.f, 1.f),
  1264. llclamp((F32)scale_rect.mBottom / (F32)imagep->getHeight(), 0.f, 1.f)));
  1265. }
  1266. imagep->onImageLoaded();
  1267. }
  1268. }
  1269. }
  1270. struct UIImageDeclaration : public LLInitParam::Block<UIImageDeclaration>
  1271. {
  1272. Mandatory<std::string> name;
  1273. Optional<std::string> file_name;
  1274. Optional<bool> preload;
  1275. Optional<LLRect> scale;
  1276. Optional<bool> use_mips;
  1277. UIImageDeclaration()
  1278. : name("name"),
  1279. file_name("file_name"),
  1280. preload("preload", false),
  1281. scale("scale"),
  1282. use_mips("use_mips", false)
  1283. {}
  1284. };
  1285. struct UIImageDeclarations : public LLInitParam::Block<UIImageDeclarations>
  1286. {
  1287. Mandatory<S32> version;
  1288. Multiple<UIImageDeclaration> textures;
  1289. UIImageDeclarations()
  1290. : version("version"),
  1291. textures("texture")
  1292. {}
  1293. };
  1294. bool LLUIImageList::initFromFile()
  1295. {
  1296. // construct path to canonical textures.xml in default skin dir
  1297. std::string base_file_path = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "default", "textures", "textures.xml");
  1298. LLXMLNodePtr root;
  1299. if (!LLXMLNode::parseFile(base_file_path, root, NULL))
  1300. {
  1301. llwarns << "Unable to parse UI image list file " << base_file_path << llendl;
  1302. return false;
  1303. }
  1304. if (!root->hasAttribute("version"))
  1305. {
  1306. llwarns << "No valid version number in UI image list file " << base_file_path << llendl;
  1307. return false;
  1308. }
  1309. std::vector<std::string> paths;
  1310. // path to current selected skin
  1311. paths.push_back(gDirUtilp->getSkinDir() 
  1312. + gDirUtilp->getDirDelimiter() 
  1313. + "textures"
  1314. + gDirUtilp->getDirDelimiter()
  1315. + "textures.xml");
  1316. // path to user overrides on current skin
  1317. paths.push_back(gDirUtilp->getUserSkinDir() 
  1318. + gDirUtilp->getDirDelimiter() 
  1319. + "textures"
  1320. + gDirUtilp->getDirDelimiter()
  1321. + "textures.xml");
  1322. // apply skinned xml files incrementally
  1323. for(std::vector<std::string>::iterator path_it = paths.begin();
  1324. path_it != paths.end();
  1325. ++path_it)
  1326. {
  1327. // don't reapply base file to itself
  1328. if (!path_it->empty() && (*path_it) != base_file_path)
  1329. {
  1330. LLXMLNodePtr update_root;
  1331. if (LLXMLNode::parseFile(*path_it, update_root, NULL))
  1332. {
  1333. LLXMLNode::updateNode(root, update_root);
  1334. }
  1335. }
  1336. }
  1337. UIImageDeclarations images;
  1338. LLXUIParser::instance().readXUI(root, images, base_file_path);
  1339. if (!images.validateBlock()) return false;
  1340. enum e_decode_pass
  1341. {
  1342. PASS_DECODE_NOW,
  1343. PASS_DECODE_LATER,
  1344. NUM_PASSES
  1345. };
  1346. for (S32 cur_pass = PASS_DECODE_NOW; cur_pass < NUM_PASSES; cur_pass++)
  1347. {
  1348. for (LLInitParam::ParamIterator<UIImageDeclaration>::const_iterator image_it = images.textures().begin();
  1349. image_it != images.textures().end();
  1350. ++image_it)
  1351. {
  1352. std::string file_name = image_it->file_name.isProvided() ? image_it->file_name() : image_it->name();
  1353. // load high priority textures on first pass (to kick off decode)
  1354. enum e_decode_pass decode_pass = image_it->preload ? PASS_DECODE_NOW : PASS_DECODE_LATER;
  1355. if (decode_pass != cur_pass)
  1356. {
  1357. continue;
  1358. }
  1359. preloadUIImage(image_it->name, file_name, image_it->use_mips, image_it->scale);
  1360. }
  1361. if (cur_pass == PASS_DECODE_NOW && !gSavedSettings.getBOOL("NoPreload"))
  1362. {
  1363. gTextureList.decodeAllImages(10.f); // decode preloaded images
  1364. }
  1365. }
  1366. return true;
  1367. }