/indra/newview/llviewertexturelist.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 1647 lines · 1238 code · 221 blank · 188 comment · 214 complexity · 69061b83d189e269569fc28f9d2eb5f8 MD5 · raw file

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