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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file lltexturecache.cpp
  3.  * @brief Object which handles local texture caching
  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 "lltexturecache.h"
  34. #include "llapr.h"
  35. #include "lldir.h"
  36. #include "llimage.h"
  37. #include "lllfsthread.h"
  38. #include "llviewercontrol.h"
  39. // Included to allow LLTextureCache::purgeTextures() to pause watchdog timeout
  40. #include "llappviewer.h" 
  41. // Cache organization:
  42. // cache/texture.entries
  43. //  Unordered array of Entry structs
  44. // cache/texture.cache
  45. //  First TEXTURE_CACHE_ENTRY_SIZE bytes of each texture in texture.entries in same order
  46. // cache/textures/[0-F]/UUID.texture
  47. //  Actual texture body files
  48. //note: there is no good to define 1024 for TEXTURE_CACHE_ENTRY_SIZE while FIRST_PACKET_SIZE is 600 on sim side.
  49. const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE;//1024;
  50. const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by when it exceeds its limit
  51. const F32 TEXTURE_CACHE_LRU_SIZE = .10f; // % amount for LRU list (low overhead to regenerate)
  52. class LLTextureCacheWorker : public LLWorkerClass
  53. {
  54. friend class LLTextureCache;
  55. private:
  56. class ReadResponder : public LLLFSThread::Responder
  57. {
  58. public:
  59. ReadResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {}
  60. ~ReadResponder() {}
  61. void completed(S32 bytes)
  62. {
  63. mCache->lockWorkers();
  64. LLTextureCacheWorker* reader = mCache->getReader(mHandle);
  65. if (reader) reader->ioComplete(bytes);
  66. mCache->unlockWorkers();
  67. }
  68. LLTextureCache* mCache;
  69. LLTextureCacheWorker::handle_t mHandle;
  70. };
  71. class WriteResponder : public LLLFSThread::Responder
  72. {
  73. public:
  74. WriteResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {}
  75. ~WriteResponder() {}
  76. void completed(S32 bytes)
  77. {
  78. mCache->lockWorkers();
  79. LLTextureCacheWorker* writer = mCache->getWriter(mHandle);
  80. if (writer) writer->ioComplete(bytes);
  81. mCache->unlockWorkers();
  82. }
  83. LLTextureCache* mCache;
  84. LLTextureCacheWorker::handle_t mHandle;
  85. };
  86. public:
  87. LLTextureCacheWorker(LLTextureCache* cache, U32 priority, const LLUUID& id,
  88.  U8* data, S32 datasize, S32 offset,
  89.  S32 imagesize, // for writes
  90.  LLTextureCache::Responder* responder)
  91. : LLWorkerClass(cache, "LLTextureCacheWorker"),
  92.   mID(id),
  93.   mCache(cache),
  94.   mPriority(priority),
  95.   mReadData(NULL),
  96.   mWriteData(data),
  97.   mDataSize(datasize),
  98.   mOffset(offset),
  99.   mImageSize(imagesize),
  100.   mImageFormat(IMG_CODEC_J2C),
  101.   mImageLocal(FALSE),
  102.   mResponder(responder),
  103.   mFileHandle(LLLFSThread::nullHandle()),
  104.   mBytesToRead(0),
  105.   mBytesRead(0)
  106. {
  107. mPriority &= LLWorkerThread::PRIORITY_LOWBITS;
  108. }
  109. ~LLTextureCacheWorker()
  110. {
  111. llassert_always(!haveWork());
  112. delete[] mReadData;
  113. }
  114. // override this interface
  115. virtual bool doRead() = 0;
  116. virtual bool doWrite() = 0;
  117. virtual bool doWork(S32 param); // Called from LLWorkerThread::processRequest()
  118. handle_t read() { addWork(0, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; }
  119. handle_t write() { addWork(1, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; }
  120. bool complete() { return checkWork(); }
  121. void ioComplete(S32 bytes)
  122. {
  123. mBytesRead = bytes;
  124. setPriority(LLWorkerThread::PRIORITY_HIGH | mPriority);
  125. }
  126. private:
  127. virtual void startWork(S32 param); // called from addWork() (MAIN THREAD)
  128. virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD)
  129. virtual void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD)
  130. protected:
  131. LLTextureCache* mCache;
  132. U32 mPriority;
  133. LLUUID mID;
  134. U8* mReadData;
  135. U8* mWriteData;
  136. S32 mDataSize;
  137. S32 mOffset;
  138. S32 mImageSize;
  139. EImageCodec mImageFormat;
  140. BOOL mImageLocal;
  141. LLPointer<LLTextureCache::Responder> mResponder;
  142. LLLFSThread::handle_t mFileHandle;
  143. S32 mBytesToRead;
  144. LLAtomicS32 mBytesRead;
  145. };
  146. class LLTextureCacheLocalFileWorker : public LLTextureCacheWorker
  147. {
  148. public:
  149. LLTextureCacheLocalFileWorker(LLTextureCache* cache, U32 priority, const std::string& filename, const LLUUID& id,
  150.  U8* data, S32 datasize, S32 offset,
  151.  S32 imagesize, // for writes
  152.  LLTextureCache::Responder* responder) 
  153. : LLTextureCacheWorker(cache, priority, id, data, datasize, offset, imagesize, responder),
  154. mFileName(filename)
  155. {
  156. }
  157. virtual bool doRead();
  158. virtual bool doWrite();
  159. private:
  160. std::string mFileName;
  161. };
  162. bool LLTextureCacheLocalFileWorker::doRead()
  163. {
  164. S32 local_size = LLAPRFile::size(mFileName, mCache->getLocalAPRFilePool());
  165. if (local_size > 0 && mFileName.size() > 4)
  166. {
  167. mDataSize = local_size; // Only a complete file is valid
  168. std::string extension = mFileName.substr(mFileName.size() - 3, 3);
  169. mImageFormat = LLImageBase::getCodecFromExtension(extension);
  170. if (mImageFormat == IMG_CODEC_INVALID)
  171. {
  172. //  llwarns << "Unrecognized file extension " << extension << " for local texture " << mFileName << llendl;
  173. mDataSize = 0; // no data
  174. return true;
  175. }
  176. }
  177. else
  178. {
  179. // file doesn't exist
  180. mDataSize = 0; // no data
  181. return true;
  182. }
  183. #if USE_LFS_READ
  184. if (mFileHandle == LLLFSThread::nullHandle())
  185. {
  186. mImageLocal = TRUE;
  187. mImageSize = local_size;
  188. if (!mDataSize || mDataSize + mOffset > local_size)
  189. {
  190. mDataSize = local_size - mOffset;
  191. }
  192. if (mDataSize <= 0)
  193. {
  194. // no more data to read
  195. mDataSize = 0;
  196. return true;
  197. }
  198. mReadData = new U8[mDataSize];
  199. mBytesRead = -1;
  200. mBytesToRead = mDataSize;
  201. setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
  202. mFileHandle = LLLFSThread::sLocal->read(local_filename, mReadData, mOffset, mDataSize,
  203. new ReadResponder(mCache, mRequestHandle));
  204. return false;
  205. }
  206. else
  207. {
  208. if (mBytesRead >= 0)
  209. {
  210. if (mBytesRead != mBytesToRead)
  211. {
  212. //  llwarns << "Error reading file from local cache: " << local_filename
  213. //  << " Bytes: " << mDataSize << " Offset: " << mOffset
  214. //  << " / " << mDataSize << llendl;
  215. mDataSize = 0; // failed
  216. delete[] mReadData;
  217. mReadData = NULL;
  218. }
  219. return true;
  220. }
  221. else
  222. {
  223. return false;
  224. }
  225. }
  226. #else
  227. if (!mDataSize || mDataSize > local_size)
  228. {
  229. mDataSize = local_size;
  230. }
  231. mReadData = new U8[mDataSize];
  232. S32 bytes_read = LLAPRFile::readEx(mFileName, mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool());
  233. if (bytes_read != mDataSize)
  234. {
  235. //  llwarns << "Error reading file from local cache: " << mFileName
  236. //  << " Bytes: " << mDataSize << " Offset: " << mOffset
  237. //  << " / " << mDataSize << llendl;
  238. mDataSize = 0;
  239. delete[] mReadData;
  240. mReadData = NULL;
  241. }
  242. else
  243. {
  244. mImageSize = local_size;
  245. mImageLocal = TRUE;
  246. }
  247. return true;
  248. #endif
  249. }
  250. bool LLTextureCacheLocalFileWorker::doWrite()
  251. {
  252. // no writes for local files
  253. return false;
  254. }
  255. class LLTextureCacheRemoteWorker : public LLTextureCacheWorker
  256. {
  257. public:
  258. LLTextureCacheRemoteWorker(LLTextureCache* cache, U32 priority, const LLUUID& id,
  259.  U8* data, S32 datasize, S32 offset,
  260.  S32 imagesize, // for writes
  261.  LLTextureCache::Responder* responder) 
  262. : LLTextureCacheWorker(cache, priority, id, data, datasize, offset, imagesize, responder),
  263. mState(INIT)
  264. {
  265. }
  266. virtual bool doRead();
  267. virtual bool doWrite();
  268. private:
  269. enum e_state
  270. {
  271. INIT = 0,
  272. LOCAL = 1,
  273. CACHE = 2,
  274. HEADER = 3,
  275. BODY = 4
  276. };
  277. e_state mState;
  278. };
  279. //virtual
  280. void LLTextureCacheWorker::startWork(S32 param)
  281. {
  282. }
  283. // This is where a texture is read from the cache system (header and body)
  284. // Current assumption are:
  285. // - the whole data are in a raw form, will be stored at mReadData
  286. // - the size of this raw data is mDataSize and can be smaller than TEXTURE_CACHE_ENTRY_SIZE (the size of a record in the header cache)
  287. // - the code supports offset reading but this is actually never exercised in the viewer
  288. bool LLTextureCacheRemoteWorker::doRead()
  289. {
  290. bool done = false;
  291. S32 idx = -1;
  292. S32 local_size = 0;
  293. std::string local_filename;
  294. // First state / stage : find out if the file is local
  295. if (mState == INIT)
  296. {
  297. std::string filename = mCache->getLocalFileName(mID);
  298. // Is it a JPEG2000 file? 
  299. {
  300. local_filename = filename + ".j2c";
  301. local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
  302. if (local_size > 0)
  303. {
  304. mImageFormat = IMG_CODEC_J2C;
  305. }
  306. }
  307. // If not, is it a jpeg file?
  308. if (local_size == 0)
  309. {
  310. local_filename = filename + ".jpg";
  311. local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
  312. if (local_size > 0)
  313. {
  314. mImageFormat = IMG_CODEC_JPEG;
  315. mDataSize = local_size; // Only a complete .jpg file is valid
  316. }
  317. }
  318. // Hmm... What about a targa file? (used for UI texture mostly)
  319. if (local_size == 0)
  320. {
  321. local_filename = filename + ".tga";
  322. local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
  323. if (local_size > 0)
  324. {
  325. mImageFormat = IMG_CODEC_TGA;
  326. mDataSize = local_size; // Only a complete .tga file is valid
  327. }
  328. }
  329. // Determine the next stage: if we found a file, then LOCAL else CACHE
  330. mState = (local_size > 0 ? LOCAL : CACHE);
  331. }
  332. // Second state / stage : if the file is local, load it and leave
  333. if (!done && (mState == LOCAL))
  334. {
  335. llassert(local_size != 0); // we're assuming there is a non empty local file here...
  336. if (!mDataSize || mDataSize > local_size)
  337. {
  338. mDataSize = local_size;
  339. }
  340. // Allocate read buffer
  341. mReadData = new U8[mDataSize];
  342. S32 bytes_read = LLAPRFile::readEx(local_filename, 
  343.  mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool());
  344. if (bytes_read != mDataSize)
  345. {
  346.   llwarns << "Error reading file from local cache: " << local_filename
  347.   << " Bytes: " << mDataSize << " Offset: " << mOffset
  348.   << " / " << mDataSize << llendl;
  349. mDataSize = 0;
  350. delete[] mReadData;
  351. mReadData = NULL;
  352. }
  353. else
  354. {
  355. mImageSize = local_size;
  356. mImageLocal = TRUE;
  357. }
  358. // We're done...
  359. done = true;
  360. }
  361. // Second state / stage : identify the cache or not...
  362. if (!done && (mState == CACHE))
  363. {
  364. idx = mCache->getHeaderCacheEntry(mID, mImageSize);
  365. if (idx < 0)
  366. {
  367. // The texture is *not* cached. We're done here...
  368. mDataSize = 0; // no data 
  369. done = true;
  370. }
  371. else
  372. {
  373. // If the read offset is bigger than the header cache, we read directly from the body
  374. // Note that currently, we *never* read with offset from the cache, so the result is *always* HEADER
  375. mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
  376. }
  377. }
  378. // Third state / stage : read data from the header cache (texture.entries) file
  379. if (!done && (mState == HEADER))
  380. {
  381. llassert_always(idx >= 0); // we need an entry here or reading the header makes no sense
  382. llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
  383. S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
  384. // Compute the size we need to read (in bytes)
  385. S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
  386. size = llmin(size, mDataSize);
  387. // Allocate the read buffer
  388. mReadData = new U8[size];
  389. S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, 
  390.  mReadData, offset, size, mCache->getLocalAPRFilePool());
  391. if (bytes_read != size)
  392. {
  393. llwarns << "LLTextureCacheWorker: "  << mID
  394. << " incorrect number of bytes read from header: " << bytes_read
  395. << " / " << size << llendl;
  396. delete[] mReadData;
  397. mReadData = NULL;
  398. mDataSize = -1; // failed
  399. done = true;
  400. }
  401. // If we already read all we expected, we're actually done
  402. if (mDataSize <= bytes_read)
  403. {
  404. done = true;
  405. }
  406. else
  407. {
  408. mState = BODY;
  409. }
  410. }
  411. // Fourth state / stage : read the rest of the data from the UUID based cached file
  412. if (!done && (mState == BODY))
  413. {
  414. std::string filename = mCache->getTextureFileName(mID);
  415. S32 filesize = LLAPRFile::size(filename, mCache->getLocalAPRFilePool());
  416. if (filesize && (filesize + TEXTURE_CACHE_ENTRY_SIZE) > mOffset)
  417. {
  418. S32 max_datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize - mOffset;
  419. mDataSize = llmin(max_datasize, mDataSize);
  420. S32 data_offset, file_size, file_offset;
  421. // Reserve the whole data buffer first
  422. U8* data = new U8[mDataSize];
  423. // Set the data file pointers taking the read offset into account. 2 cases:
  424. if (mOffset < TEXTURE_CACHE_ENTRY_SIZE)
  425. {
  426. // Offset within the header record. That means we read something from the header cache.
  427. // Note: most common case is (mOffset = 0), so this is the "normal" code path.
  428. data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; // i.e. TEXTURE_CACHE_ENTRY_SIZE if mOffset nul (common case)
  429. file_offset = 0;
  430. file_size = mDataSize - data_offset;
  431. // Copy the raw data we've been holding from the header cache into the new sized buffer
  432. llassert_always(mReadData);
  433. memcpy(data, mReadData, data_offset);
  434. delete[] mReadData;
  435. mReadData = NULL;
  436. }
  437. else
  438. {
  439. // Offset bigger than the header record. That means we haven't read anything yet.
  440. data_offset = 0;
  441. file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
  442. file_size = mDataSize;
  443. // No data from header cache to copy in that case, we skipped it all
  444. }
  445. // Now use that buffer as the object read buffer
  446. llassert_always(mReadData == NULL);
  447. mReadData = data;
  448. // Read the data at last
  449. S32 bytes_read = LLAPRFile::readEx(filename, 
  450.  mReadData + data_offset,
  451.  file_offset, file_size,
  452.  mCache->getLocalAPRFilePool());
  453. if (bytes_read != file_size)
  454. {
  455. llwarns << "LLTextureCacheWorker: "  << mID
  456. << " incorrect number of bytes read from body: " << bytes_read
  457. << " / " << file_size << llendl;
  458. delete[] mReadData;
  459. mReadData = NULL;
  460. mDataSize = -1; // failed
  461. done = true;
  462. }
  463. }
  464. else
  465. {
  466. // No body, we're done.
  467. mDataSize = llmax(TEXTURE_CACHE_ENTRY_SIZE - mOffset, 0);
  468. lldebugs << "No body file for: " << filename << llendl;
  469. }
  470. // Nothing else to do at that point...
  471. done = true;
  472. }
  473. // Clean up and exit
  474. return done;
  475. }
  476. // This is where *everything* about a texture is written down in the cache system (entry map, header and body)
  477. // Current assumption are:
  478. // - the whole data are in a raw form, starting at mWriteData
  479. // - the size of this raw data is mDataSize and can be smaller than TEXTURE_CACHE_ENTRY_SIZE (the size of a record in the header cache)
  480. // - the code *does not* support offset writing so there are no difference between buffer addresses and start of data
  481. bool LLTextureCacheRemoteWorker::doWrite()
  482. {
  483. bool done = false;
  484. S32 idx = -1;
  485. // First state / stage : check that what we're trying to cache is in an OK shape
  486. if (mState == INIT)
  487. {
  488. llassert_always(mOffset == 0); // We currently do not support write offsets
  489. llassert_always(mDataSize > 0); // Things will go badly wrong if mDataSize is nul or negative...
  490. mState = CACHE;
  491. }
  492. // No LOCAL state for write(): because it doesn't make much sense to cache a local file...
  493. // Second state / stage : set an entry in the headers entry (texture.entries) file
  494. if (!done && (mState == CACHE))
  495. {
  496. bool alreadyCached = false;
  497. S32 cur_imagesize = 0;
  498. // Checks if this image is already in the entry list
  499. idx = mCache->getHeaderCacheEntry(mID, cur_imagesize);
  500. if (idx >= 0 && (cur_imagesize >= 0))
  501. {
  502. alreadyCached = true; // already there and non empty
  503. }
  504. idx = mCache->setHeaderCacheEntry(mID, mImageSize); // create or touch the entry
  505. if (idx < 0)
  506. {
  507. llwarns << "LLTextureCacheWorker: "  << mID
  508. << " Unable to create header entry for writing!" << llendl;
  509. mDataSize = -1; // failed
  510. done = true;
  511. }
  512. else
  513. {
  514. if (cur_imagesize > 0 && (mImageSize != cur_imagesize))
  515. {
  516. alreadyCached = false; // re-write the header if the size changed in all cases
  517. }
  518. if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE))
  519. {
  520. // Small texture already cached case: we're done with writing
  521. done = true;
  522. }
  523. else
  524. {
  525. // If the texture has already been cached, we don't resave the header and go directly to the body part
  526. mState = alreadyCached ? BODY : HEADER;
  527. }
  528. }
  529. }
  530. // Third stage / state : write the header record in the header file (texture.cache)
  531. if (!done && (mState == HEADER))
  532. {
  533. llassert_always(idx >= 0); // we need an entry here or storing the header makes no sense
  534. S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE; // skip to the correct spot in the header file
  535. S32 size = TEXTURE_CACHE_ENTRY_SIZE; // record size is fixed for the header
  536. S32 bytes_written;
  537. if (mDataSize < TEXTURE_CACHE_ENTRY_SIZE)
  538. {
  539. // We need to write a full record in the header cache so, if the amount of data is smaller
  540. // than a record, we need to transfer the data to a buffer padded with 0 and write that
  541. U8* padBuffer = new U8[TEXTURE_CACHE_ENTRY_SIZE];
  542. memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros
  543. memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer
  544. bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size, mCache->getLocalAPRFilePool());
  545. delete [] padBuffer;
  546. }
  547. else
  548. {
  549. // Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file
  550. bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool());
  551. }
  552. if (bytes_written <= 0)
  553. {
  554. llwarns << "LLTextureCacheWorker: "  << mID
  555. << " Unable to write header entry!" << llendl;
  556. mDataSize = -1; // failed
  557. done = true;
  558. }
  559. // If we wrote everything (may be more with padding) in the header cache, 
  560. // we're done so we don't have a body to store
  561. if (mDataSize <= bytes_written)
  562. {
  563. done = true;
  564. }
  565. else
  566. {
  567. mState = BODY;
  568. }
  569. }
  570. // Fourth stage / state : write the body file, i.e. the rest of the texture in a "UUID" file name
  571. if (!done && (mState == BODY))
  572. {
  573. llassert(mDataSize > TEXTURE_CACHE_ENTRY_SIZE); // wouldn't make sense to be here otherwise...
  574. S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE;
  575. if ((file_size > 0) && mCache->updateTextureEntryList(mID, file_size))
  576. {
  577. // build the cache file name from the UUID
  578. std::string filename = mCache->getTextureFileName(mID);
  579. //  llinfos << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << llendl;
  580. S32 bytes_written = LLAPRFile::writeEx( filename, 
  581. mWriteData + TEXTURE_CACHE_ENTRY_SIZE,
  582. 0, file_size,
  583. mCache->getLocalAPRFilePool());
  584. if (bytes_written <= 0)
  585. {
  586. llwarns << "LLTextureCacheWorker: "  << mID
  587. << " incorrect number of bytes written to body: " << bytes_written
  588. << " / " << file_size << llendl;
  589. mDataSize = -1; // failed
  590. done = true;
  591. }
  592. }
  593. else
  594. {
  595. mDataSize = 0; // no data written
  596. }
  597. // Nothing else to do at that point...
  598. done = true;
  599. }
  600. // Clean up and exit
  601. return done;
  602. }
  603. //virtual
  604. bool LLTextureCacheWorker::doWork(S32 param)
  605. {
  606. bool res = false;
  607. if (param == 0) // read
  608. {
  609. res = doRead();
  610. }
  611. else if (param == 1) // write
  612. {
  613. res = doWrite();
  614. }
  615. else
  616. {
  617. llassert_always(0);
  618. }
  619. return res;
  620. }
  621. //virtual (WORKER THREAD)
  622. void LLTextureCacheWorker::finishWork(S32 param, bool completed)
  623. {
  624. if (mResponder.notNull())
  625. {
  626. bool success = (completed && mDataSize > 0);
  627. if (param == 0)
  628. {
  629. // read
  630. if (success)
  631. {
  632. mResponder->setData(mReadData, mDataSize, mImageSize, mImageFormat, mImageLocal);
  633. mReadData = NULL; // responder owns data
  634. mDataSize = 0;
  635. }
  636. else
  637. {
  638. delete[] mReadData;
  639. mReadData = NULL;
  640. }
  641. }
  642. else
  643. {
  644. // write
  645. mWriteData = NULL; // we never owned data
  646. mDataSize = 0;
  647. }
  648. mCache->addCompleted(mResponder, success);
  649. }
  650. }
  651. //virtual (MAIN THREAD)
  652. void LLTextureCacheWorker::endWork(S32 param, bool aborted)
  653. {
  654. if (aborted)
  655. {
  656. // Let the destructor handle any cleanup
  657. return;
  658. }
  659. switch(param)
  660. {
  661.   default:
  662.   case 0: // read
  663.   case 1: // write
  664.   {
  665.   if (mDataSize < 0)
  666.   {
  667.   // failed
  668.   mCache->removeFromCache(mID);
  669.   }
  670.   break;
  671.   }
  672. }
  673. }
  674. //////////////////////////////////////////////////////////////////////////////
  675. LLTextureCache::LLTextureCache(bool threaded)
  676. : LLWorkerThread("TextureCache", threaded),
  677.   mWorkersMutex(NULL),
  678.   mHeaderMutex(NULL),
  679.   mListMutex(NULL),
  680.   mHeaderAPRFile(NULL),
  681.   mReadOnly(FALSE),
  682.   mTexturesSizeTotal(0),
  683.   mDoPurge(FALSE)
  684. {
  685. }
  686. LLTextureCache::~LLTextureCache()
  687. {
  688. }
  689. //////////////////////////////////////////////////////////////////////////////
  690. //virtual
  691. S32 LLTextureCache::update(U32 max_time_ms)
  692. {
  693. S32 res;
  694. res = LLWorkerThread::update(max_time_ms);
  695. mListMutex.lock();
  696. handle_list_t priorty_list = mPrioritizeWriteList; // copy list
  697. mPrioritizeWriteList.clear();
  698. responder_list_t completed_list = mCompletedList; // copy list
  699. mCompletedList.clear();
  700. mListMutex.unlock();
  701. lockWorkers();
  702. for (handle_list_t::iterator iter1 = priorty_list.begin();
  703.  iter1 != priorty_list.end(); ++iter1)
  704. {
  705. handle_t handle = *iter1;
  706. handle_map_t::iterator iter2 = mWriters.find(handle);
  707. if(iter2 != mWriters.end())
  708. {
  709. LLTextureCacheWorker* worker = iter2->second;
  710. worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mPriority);
  711. }
  712. }
  713. unlockWorkers(); 
  714. // call 'completed' with workers list unlocked (may call readComplete() or writeComplete()
  715. for (responder_list_t::iterator iter1 = completed_list.begin();
  716.  iter1 != completed_list.end(); ++iter1)
  717. {
  718. Responder *responder = iter1->first;
  719. bool success = iter1->second;
  720. responder->completed(success);
  721. }
  722. return res;
  723. }
  724. //////////////////////////////////////////////////////////////////////////////
  725. // search for local copy of UUID-based image file
  726. std::string LLTextureCache::getLocalFileName(const LLUUID& id)
  727. {
  728. // Does not include extension
  729. std::string idstr = id.asString();
  730. // TODO: should we be storing cached textures in skin directory?
  731. std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_LOCAL_ASSETS, idstr);
  732. return filename;
  733. }
  734. std::string LLTextureCache::getTextureFileName(const LLUUID& id)
  735. {
  736. std::string idstr = id.asString();
  737. std::string delem = gDirUtilp->getDirDelimiter();
  738. std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr + ".texture";
  739. return filename;
  740. }
  741. bool LLTextureCache::updateTextureEntryList(const LLUUID& id, S32 bodysize)
  742. {
  743. bool res = false;
  744. bool purge = false;
  745. {
  746. LLMutexLock lock(&mHeaderMutex);
  747. size_map_t::iterator iter1 = mTexturesSizeMap.find(id);
  748. if (iter1 == mTexturesSizeMap.end() || iter1->second < bodysize)
  749. {
  750. llassert_always(bodysize > 0);
  751. S32 oldbodysize = 0;
  752. if (iter1 != mTexturesSizeMap.end())
  753. {
  754. oldbodysize = iter1->second;
  755. }
  756. Entry entry;
  757. S32 idx = openAndReadEntry(id, entry, false);
  758. if (idx < 0)
  759. {
  760. llwarns << "Failed to open entry: " << id << llendl;
  761. removeHeaderCacheEntry(id);
  762. LLAPRFile::remove(getTextureFileName(id), getLocalAPRFilePool());
  763. return false;
  764. }
  765. else if (oldbodysize != entry.mBodySize)
  766. {
  767. // TODO: change to llwarns
  768. llerrs << "Entry mismatch in mTextureSizeMap / mHeaderIDMap"
  769.    << " idx=" << idx << " oldsize=" << oldbodysize << " entrysize=" << entry.mBodySize << llendl;
  770. }
  771. entry.mBodySize = bodysize;
  772. writeEntryAndClose(idx, entry);
  773. mTexturesSizeTotal -= oldbodysize;
  774. mTexturesSizeTotal += bodysize;
  775. if (mTexturesSizeTotal > sCacheMaxTexturesSize)
  776. {
  777. purge = true;
  778. }
  779. res = true;
  780. }
  781. }
  782. if (purge)
  783. {
  784. mDoPurge = TRUE;
  785. }
  786. return res;
  787. }
  788. //debug
  789. BOOL LLTextureCache::isInCache(const LLUUID& id) 
  790. {
  791. LLMutexLock lock(&mHeaderMutex);
  792. id_map_t::const_iterator iter = mHeaderIDMap.find(id);
  793. return (iter != mHeaderIDMap.end()) ;
  794. }
  795. //debug
  796. BOOL LLTextureCache::isInLocal(const LLUUID& id) 
  797. {
  798. S32 local_size = 0;
  799. std::string local_filename;
  800. std::string filename = getLocalFileName(id);
  801. // Is it a JPEG2000 file? 
  802. {
  803. local_filename = filename + ".j2c";
  804. local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool());
  805. if (local_size > 0)
  806. {
  807. return TRUE ;
  808. }
  809. }
  810. // If not, is it a jpeg file?
  811. {
  812. local_filename = filename + ".jpg";
  813. local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool());
  814. if (local_size > 0)
  815. {
  816. return TRUE ;
  817. }
  818. }
  819. // Hmm... What about a targa file? (used for UI texture mostly)
  820. {
  821. local_filename = filename + ".tga";
  822. local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool());
  823. if (local_size > 0)
  824. {
  825. return TRUE ;
  826. }
  827. }
  828. return FALSE ;
  829. }
  830. //////////////////////////////////////////////////////////////////////////////
  831. //static
  832. const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024; // 512 MB
  833. F32 LLTextureCache::sHeaderCacheVersion = 1.4f;
  834. U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE;
  835. S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit
  836. const char* entries_filename = "texture.entries";
  837. const char* cache_filename = "texture.cache";
  838. const char* textures_dirname = "textures";
  839. void LLTextureCache::setDirNames(ELLPath location)
  840. {
  841. std::string delem = gDirUtilp->getDirDelimiter();
  842. mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename);
  843. mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename);
  844. mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname);
  845. }
  846. void LLTextureCache::purgeCache(ELLPath location)
  847. {
  848. LLMutexLock lock(&mHeaderMutex);
  849. if (!mReadOnly)
  850. {
  851. setDirNames(location);
  852. llassert_always(mHeaderAPRFile == NULL);
  853. LLAPRFile::remove(mHeaderEntriesFileName, getLocalAPRFilePool());
  854. LLAPRFile::remove(mHeaderDataFileName, getLocalAPRFilePool());
  855. }
  856. purgeAllTextures(true);
  857. }
  858. S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
  859. {
  860. mReadOnly = read_only;
  861. S64 header_size = (max_size * 2) / 10;
  862. S64 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE;
  863. sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries));
  864. header_size = sCacheMaxEntries * TEXTURE_CACHE_ENTRY_SIZE;
  865. max_size -= header_size;
  866. if (sCacheMaxTexturesSize > 0)
  867. sCacheMaxTexturesSize = llmin(sCacheMaxTexturesSize, max_size);
  868. else
  869. sCacheMaxTexturesSize = max_size;
  870. max_size -= sCacheMaxTexturesSize;
  871. LL_INFOS("TextureCache") << "Headers: " << sCacheMaxEntries
  872. << " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << LL_ENDL;
  873. setDirNames(location);
  874. if (!mReadOnly)
  875. {
  876. LLFile::mkdir(mTexturesDirName);
  877. const char* subdirs = "0123456789abcdef";
  878. for (S32 i=0; i<16; i++)
  879. {
  880. std::string dirname = mTexturesDirName + gDirUtilp->getDirDelimiter() + subdirs[i];
  881. LLFile::mkdir(dirname);
  882. }
  883. }
  884. readHeaderCache();
  885. purgeTextures(true); // calc mTexturesSize and make some room in the texture cache if we need it
  886. return max_size; // unused cache space
  887. }
  888. //----------------------------------------------------------------------------
  889. // mHeaderMutex must be locked for the following functions!
  890. LLAPRFile* LLTextureCache::openHeaderEntriesFile(bool readonly, S32 offset)
  891. {
  892. llassert_always(mHeaderAPRFile == NULL);
  893. apr_int32_t flags = readonly ? APR_READ|APR_BINARY : APR_READ|APR_WRITE|APR_BINARY;
  894. mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags, getLocalAPRFilePool());
  895. mHeaderAPRFile->seek(APR_SET, offset);
  896. return mHeaderAPRFile;
  897. }
  898. void LLTextureCache::closeHeaderEntriesFile()
  899. {
  900. llassert_always(mHeaderAPRFile != NULL);
  901. delete mHeaderAPRFile;
  902. mHeaderAPRFile = NULL;
  903. }
  904. void LLTextureCache::readEntriesHeader()
  905. {
  906. // mHeaderEntriesInfo initializes to default values so safe not to read it
  907. llassert_always(mHeaderAPRFile == NULL);
  908. if (LLAPRFile::isExist(mHeaderEntriesFileName, getLocalAPRFilePool()))
  909. {
  910. LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
  911.   getLocalAPRFilePool());
  912. }
  913. }
  914. void LLTextureCache::writeEntriesHeader()
  915. {
  916. llassert_always(mHeaderAPRFile == NULL);
  917. if (!mReadOnly)
  918. {
  919. LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
  920.    getLocalAPRFilePool());
  921. }
  922. }
  923. static S32 mHeaderEntriesMaxWriteIdx = 0;
  924. S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create)
  925. {
  926. S32 idx = -1;
  927. id_map_t::iterator iter1 = mHeaderIDMap.find(id);
  928. if (iter1 != mHeaderIDMap.end())
  929. {
  930. idx = iter1->second;
  931. }
  932. if (idx < 0)
  933. {
  934. if (create && !mReadOnly)
  935. {
  936. if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
  937. {
  938. // Add an entry to the end of the list
  939. idx = mHeaderEntriesInfo.mEntries++;
  940. }
  941. else if (!mFreeList.empty())
  942. {
  943. idx = *(mFreeList.begin());
  944. mFreeList.erase(mFreeList.begin());
  945. }
  946. else
  947. {
  948. // Look for a still valid entry in the LRU
  949. for (std::set<LLUUID>::iterator iter2 = mLRU.begin(); iter2 != mLRU.end();)
  950. {
  951. std::set<LLUUID>::iterator curiter2 = iter2++;
  952. LLUUID oldid = *curiter2;
  953. // Erase entry from LRU regardless
  954. mLRU.erase(curiter2);
  955. // Look up entry and use it if it is valid
  956. id_map_t::iterator iter3 = mHeaderIDMap.find(oldid);
  957. if (iter3 != mHeaderIDMap.end() && iter3->second >= 0)
  958. {
  959. idx = iter3->second;
  960. mHeaderIDMap.erase(oldid);
  961. mTexturesSizeMap.erase(oldid);
  962. break;
  963. }
  964. }
  965. // if (idx < 0) at this point, we will rebuild the LRU 
  966. //  and retry if called from setHeaderCacheEntry(),
  967. //  otherwise this shouldn't happen and will trigger an error
  968. }
  969. if (idx >= 0)
  970. {
  971. // Set the header index
  972. mHeaderIDMap[id] = idx;
  973. llassert_always(mTexturesSizeMap.erase(id) == 0);
  974. // Initialize the entry (will get written later)
  975. entry.init(id, time(NULL));
  976. // Update Header
  977. writeEntriesHeader();
  978. // Write Entry
  979. S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
  980. LLAPRFile* aprfile = openHeaderEntriesFile(false, offset);
  981. S32 bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry));
  982. llassert_always(bytes_written == sizeof(Entry));
  983. mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, idx);
  984. closeHeaderEntriesFile();
  985. }
  986. }
  987. }
  988. else
  989. {
  990. // Remove this entry from the LRU if it exists
  991. mLRU.erase(id);
  992. // Read the entry
  993. S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
  994. LLAPRFile* aprfile = openHeaderEntriesFile(true, offset);
  995. S32 bytes_read = aprfile->read((void*)&entry, (S32)sizeof(Entry));
  996. llassert_always(bytes_read == sizeof(Entry));
  997. llassert_always(entry.mImageSize == 0 || entry.mImageSize == -1 || entry.mImageSize > entry.mBodySize);
  998. closeHeaderEntriesFile();
  999. }
  1000. return idx;
  1001. }
  1002. void LLTextureCache::writeEntryAndClose(S32 idx, Entry& entry)
  1003. {
  1004. if (idx >= 0)
  1005. {
  1006. if (!mReadOnly)
  1007. {
  1008. entry.mTime = time(NULL);
  1009. llassert_always(entry.mImageSize == 0 || entry.mImageSize == -1 || entry.mImageSize > entry.mBodySize);
  1010. if (entry.mBodySize > 0)
  1011. {
  1012. mTexturesSizeMap[entry.mID] = entry.mBodySize;
  1013. }
  1014. //  llinfos << "Updating TE: " << idx << ": " << id << " Size: " << entry.mBodySize << " Time: " << entry.mTime << llendl;
  1015. S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
  1016. LLAPRFile* aprfile = openHeaderEntriesFile(false, offset);
  1017. S32 bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry));
  1018. llassert_always(bytes_written == sizeof(Entry));
  1019. mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, idx);
  1020. closeHeaderEntriesFile();
  1021. }
  1022. }
  1023. }
  1024. U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries)
  1025. {
  1026. U32 num_entries = mHeaderEntriesInfo.mEntries;
  1027. mHeaderIDMap.clear();
  1028. mTexturesSizeMap.clear();
  1029. mFreeList.clear();
  1030. mTexturesSizeTotal = 0;
  1031. LLAPRFile* aprfile = openHeaderEntriesFile(false, (S32)sizeof(EntriesInfo));
  1032. for (U32 idx=0; idx<num_entries; idx++)
  1033. {
  1034. Entry entry;
  1035. S32 bytes_read = aprfile->read((void*)(&entry), (S32)sizeof(Entry));
  1036. if (bytes_read < sizeof(Entry))
  1037. {
  1038. llwarns << "Corrupted header entries, failed at " << idx << " / " << num_entries << llendl;
  1039. closeHeaderEntriesFile();
  1040. purgeAllTextures(false);
  1041. return 0;
  1042. }
  1043. entries.push_back(entry);
  1044. //  llinfos << "ENTRY: " << entry.mTime << " TEX: " << entry.mID << " IDX: " << idx << " Size: " << entry.mImageSize << llendl;
  1045. if (entry.mImageSize < 0)
  1046. {
  1047. mFreeList.insert(idx);
  1048. }
  1049. else
  1050. {
  1051. mHeaderIDMap[entry.mID] = idx;
  1052. if (entry.mBodySize > 0)
  1053. {
  1054. mTexturesSizeMap[entry.mID] = entry.mBodySize;
  1055. mTexturesSizeTotal += entry.mBodySize;
  1056. }
  1057. llassert_always(entry.mImageSize == 0 || entry.mImageSize > entry.mBodySize);
  1058. }
  1059. }
  1060. closeHeaderEntriesFile();
  1061. return num_entries;
  1062. }
  1063. void LLTextureCache::writeEntriesAndClose(const std::vector<Entry>& entries)
  1064. {
  1065. S32 num_entries = entries.size();
  1066. llassert_always(num_entries == mHeaderEntriesInfo.mEntries);
  1067. if (!mReadOnly)
  1068. {
  1069. LLAPRFile* aprfile = openHeaderEntriesFile(false, (S32)sizeof(EntriesInfo));
  1070. for (S32 idx=0; idx<num_entries; idx++)
  1071. {
  1072. S32 bytes_written = aprfile->write((void*)(&entries[idx]), (S32)sizeof(Entry));
  1073. llassert_always(bytes_written == sizeof(Entry));
  1074. }
  1075. mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, num_entries-1);
  1076. closeHeaderEntriesFile();
  1077. }
  1078. }
  1079. //----------------------------------------------------------------------------
  1080. // Called from either the main thread or the worker thread
  1081. void LLTextureCache::readHeaderCache()
  1082. {
  1083. mHeaderMutex.lock();
  1084. mLRU.clear(); // always clear the LRU
  1085. readEntriesHeader();
  1086. if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion)
  1087. {
  1088. if (!mReadOnly)
  1089. {
  1090. purgeAllTextures(false);
  1091. }
  1092. }
  1093. else
  1094. {
  1095. std::vector<Entry> entries;
  1096. U32 num_entries = openAndReadEntries(entries);
  1097. if (num_entries)
  1098. {
  1099. U32 empty_entries = 0;
  1100. typedef std::pair<U32, S32> lru_data_t;
  1101. std::set<lru_data_t> lru;
  1102. std::set<LLUUID> purge_list;
  1103. for (U32 i=0; i<num_entries; i++)
  1104. {
  1105. Entry& entry = entries[i];
  1106. const LLUUID& id = entry.mID;
  1107. if (entry.mImageSize < 0)
  1108. {
  1109. // This will be in the Free List, don't put it in the LRU
  1110. ++empty_entries;
  1111. }
  1112. else
  1113. {
  1114. lru.insert(std::make_pair(entry.mTime, i));
  1115. if (entry.mBodySize > 0)
  1116. {
  1117. if (entry.mBodySize > entry.mImageSize)
  1118. {
  1119. // Shouldn't happen, failsafe only
  1120. llwarns << "Bad entry: " << i << ": " << id << ": BodySize: " << entry.mBodySize << llendl;
  1121. purge_list.insert(entry.mID);
  1122. entry.mImageSize = -1; // empty/available
  1123. }
  1124. }
  1125. }
  1126. }
  1127. if (num_entries > sCacheMaxEntries)
  1128. {
  1129. // Special case: cache size was reduced, need to remove entries
  1130. // Note: After we prune entries, we will call this again and create the LRU
  1131. U32 entries_to_purge = (num_entries-empty_entries) - sCacheMaxEntries;
  1132. llinfos << "Texture Cache Entries: " << num_entries << " Max: " << sCacheMaxEntries << " Empty: " << empty_entries << " Purging: " << entries_to_purge << llendl;
  1133. if (entries_to_purge > 0)
  1134. {
  1135. for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
  1136. {
  1137. S32 idx = iter->second;
  1138. if (entries[idx].mImageSize >= 0)
  1139. {
  1140. purge_list.insert(entries[idx].mID);
  1141. entries[idx].mImageSize = -1;
  1142. if (purge_list.size() >= entries_to_purge)
  1143. break;
  1144. }
  1145. }
  1146. }
  1147. llassert_always(purge_list.size() >= entries_to_purge);
  1148. }
  1149. else
  1150. {
  1151. S32 lru_entries = (S32)((F32)sCacheMaxEntries * TEXTURE_CACHE_LRU_SIZE);
  1152. for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
  1153. {
  1154. S32 idx = iter->second;
  1155. const LLUUID& id = entries[idx].mID;
  1156. mLRU.insert(id);
  1157. //  llinfos << "LRU: " << iter->first << " : " << iter->second << llendl;
  1158. if (--lru_entries <= 0)
  1159. break;
  1160. }
  1161. }
  1162. if (purge_list.size() > 0)
  1163. {
  1164. for (std::set<LLUUID>::iterator iter = purge_list.begin(); iter != purge_list.end(); ++iter)
  1165. {
  1166. const LLUUID& id = *iter;
  1167. bool res = removeHeaderCacheEntry(id); // sets entry size on disk to -1
  1168. llassert_always(res);
  1169. LLAPRFile::remove(getTextureFileName(id), getLocalAPRFilePool());
  1170. }
  1171. // If we removed any entries, we need to rebuild the entries list,
  1172. // write the header, and call this again
  1173. std::vector<Entry> new_entries;
  1174. for (U32 i=0; i<num_entries; i++)
  1175. {
  1176. const Entry& entry = entries[i];
  1177. if (entry.mImageSize >=0)
  1178. {
  1179. new_entries.push_back(entry);
  1180. }
  1181. }
  1182. llassert_always(new_entries.size() <= sCacheMaxEntries);
  1183. mHeaderEntriesInfo.mEntries = new_entries.size();
  1184. writeEntriesAndClose(new_entries);
  1185. mHeaderMutex.unlock(); // unlock the mutex before calling again
  1186. readHeaderCache(); // repeat with new entries file
  1187. mHeaderMutex.lock();
  1188. }
  1189. else
  1190. {
  1191. writeEntriesAndClose(entries);
  1192. }
  1193. }
  1194. }
  1195. mHeaderMutex.unlock();
  1196. }
  1197. //////////////////////////////////////////////////////////////////////////////
  1198. void LLTextureCache::purgeAllTextures(bool purge_directories)
  1199. {
  1200. if (!mReadOnly)
  1201. {
  1202. const char* subdirs = "0123456789abcdef";
  1203. std::string delem = gDirUtilp->getDirDelimiter();
  1204. std::string mask = delem + "*";
  1205. for (S32 i=0; i<16; i++)
  1206. {
  1207. std::string dirname = mTexturesDirName + delem + subdirs[i];
  1208. llinfos << "Deleting files in directory: " << dirname << llendl;
  1209. gDirUtilp->deleteFilesInDir(dirname,mask);
  1210. if (purge_directories)
  1211. {
  1212. LLFile::rmdir(dirname);
  1213. }
  1214. }
  1215. if (purge_directories)
  1216. {
  1217. LLFile::rmdir(mTexturesDirName);
  1218. }
  1219. }
  1220. mHeaderIDMap.clear();
  1221. mTexturesSizeMap.clear();
  1222. mTexturesSizeTotal = 0;
  1223. mFreeList.clear();
  1224. mTexturesSizeTotal = 0;
  1225. // Info with 0 entries
  1226. mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
  1227. mHeaderEntriesInfo.mEntries = 0;
  1228. writeEntriesHeader();
  1229. }
  1230. void LLTextureCache::purgeTextures(bool validate)
  1231. {
  1232. if (mReadOnly)
  1233. {
  1234. return;
  1235. }
  1236. if (!mThreaded)
  1237. {
  1238. // *FIX:Mani - watchdog off.
  1239. LLAppViewer::instance()->pauseMainloopTimeout();
  1240. }
  1241. LLMutexLock lock(&mHeaderMutex);
  1242. llinfos << "TEXTURE CACHE: Purging." << llendl;
  1243. // Read the entries list
  1244. std::vector<Entry> entries;
  1245. U32 num_entries = openAndReadEntries(entries);
  1246. if (!num_entries)
  1247. {
  1248. writeEntriesAndClose(entries);
  1249. return; // nothing to purge
  1250. }
  1251. // Use mTexturesSizeMap to collect UUIDs of textures with bodies
  1252. typedef std::set<std::pair<U32,S32> > time_idx_set_t;
  1253. std::set<std::pair<U32,S32> > time_idx_set;
  1254. for (size_map_t::iterator iter1 = mTexturesSizeMap.begin();
  1255.  iter1 != mTexturesSizeMap.end(); ++iter1)
  1256. {
  1257. if (iter1->second > 0)
  1258. {
  1259. id_map_t::iterator iter2 = mHeaderIDMap.find(iter1->first);
  1260. if (iter2 != mHeaderIDMap.end())
  1261. {
  1262. S32 idx = iter2->second;
  1263. time_idx_set.insert(std::make_pair(entries[idx].mTime, idx));
  1264. //  llinfos << "TIME: " << entries[idx].mTime << " TEX: " << entries[idx].mID << " IDX: " << idx << " Size: " << entries[idx].mImageSize << llendl;
  1265. }
  1266. }
  1267. }
  1268. // Validate 1/256th of the files on startup
  1269. U32 validate_idx = 0;
  1270. if (validate)
  1271. {
  1272. validate_idx = gSavedSettings.getU32("CacheValidateCounter");
  1273. U32 next_idx = (++validate_idx) % 256;
  1274. gSavedSettings.setU32("CacheValidateCounter", next_idx);
  1275. LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL;
  1276. }
  1277. S64 cache_size = mTexturesSizeTotal;
  1278. S64 purged_cache_size = (sCacheMaxTexturesSize * (S64)((1.f-TEXTURE_CACHE_PURGE_AMOUNT)*100)) / 100;
  1279. S32 purge_count = 0;
  1280. for (time_idx_set_t::iterator iter = time_idx_set.begin();
  1281.  iter != time_idx_set.end(); ++iter)
  1282. {
  1283. S32 idx = iter->second;
  1284. bool purge_entry = false;
  1285. std::string filename = getTextureFileName(entries[idx].mID);
  1286. if (cache_size >= purged_cache_size)
  1287. {
  1288. purge_entry = true;
  1289. }
  1290. else if (validate)
  1291. {
  1292. // make sure file exists and is the correct size
  1293. U32 uuididx = entries[idx].mID.mData[0];
  1294. if (uuididx == validate_idx)
  1295. {
  1296.   LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mBodySize << LL_ENDL;
  1297. S32 bodysize = LLAPRFile::size(filename, getLocalAPRFilePool());
  1298. if (bodysize != entries[idx].mBodySize)
  1299. {
  1300. LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mBodySize
  1301. << filename << LL_ENDL;
  1302. purge_entry = true;
  1303. }
  1304. }
  1305. }
  1306. else
  1307. {
  1308. break;
  1309. }
  1310. if (purge_entry)
  1311. {
  1312. purge_count++;
  1313.   LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL;
  1314. LLAPRFile::remove(filename, getLocalAPRFilePool());
  1315. cache_size -= entries[idx].mBodySize;
  1316. mTexturesSizeTotal -= entries[idx].mBodySize;
  1317. entries[idx].mBodySize = 0;
  1318. mTexturesSizeMap.erase(entries[idx].mID);
  1319. }
  1320. }
  1321. LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Writing Entries: " << num_entries << LL_ENDL;
  1322. writeEntriesAndClose(entries);
  1323. // *FIX:Mani - watchdog back on.
  1324. LLAppViewer::instance()->resumeMainloopTimeout();
  1325. LL_INFOS("TextureCache") << "TEXTURE CACHE:"
  1326. << " PURGED: " << purge_count
  1327. << " ENTRIES: " << num_entries
  1328. << " CACHE SIZE: " << mTexturesSizeTotal / 1024*1024 << " MB"
  1329. << llendl;
  1330. }
  1331. //////////////////////////////////////////////////////////////////////////////
  1332. // call lockWorkers() first!
  1333. LLTextureCacheWorker* LLTextureCache::getReader(handle_t handle)
  1334. {
  1335. LLTextureCacheWorker* res = NULL;
  1336. handle_map_t::iterator iter = mReaders.find(handle);
  1337. if (iter != mReaders.end())
  1338. {
  1339. res = iter->second;
  1340. }
  1341. return res;
  1342. }
  1343. LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle)
  1344. {
  1345. LLTextureCacheWorker* res = NULL;
  1346. handle_map_t::iterator iter = mWriters.find(handle);
  1347. if (iter != mWriters.end())
  1348. {
  1349. res = iter->second;
  1350. }
  1351. return res;
  1352. }
  1353. //////////////////////////////////////////////////////////////////////////////
  1354. // Called from work thread
  1355. // Reads imagesize from the header, updates timestamp
  1356. S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, S32& imagesize)
  1357. {
  1358. LLMutexLock lock(&mHeaderMutex);
  1359. Entry entry;
  1360. S32 idx = openAndReadEntry(id, entry, false);
  1361. if (idx >= 0)
  1362. {
  1363. imagesize = entry.mImageSize;
  1364. writeEntryAndClose(idx, entry); // updates time
  1365. }
  1366. return idx;
  1367. }
  1368. // Writes imagesize to the header, updates timestamp
  1369. S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, S32 imagesize)
  1370. {
  1371. mHeaderMutex.lock();
  1372. llassert_always(imagesize >= 0);
  1373. Entry entry;
  1374. S32 idx = openAndReadEntry(id, entry, true);
  1375. if (idx >= 0)
  1376. {
  1377. entry.mImageSize = imagesize;
  1378. writeEntryAndClose(idx, entry);
  1379. mHeaderMutex.unlock();
  1380. }
  1381. else // retry
  1382. {
  1383. mHeaderMutex.unlock();
  1384. readHeaderCache(); // We couldn't write an entry, so refresh the LRU
  1385. mHeaderMutex.lock();
  1386. llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
  1387. mHeaderMutex.unlock();
  1388. idx = setHeaderCacheEntry(id, imagesize); // assert above ensures no inf. recursion
  1389. }
  1390. return idx;
  1391. }
  1392. //////////////////////////////////////////////////////////////////////////////
  1393. // Calls from texture pipeline thread (i.e. LLTextureFetch)
  1394. LLTextureCache::handle_t LLTextureCache::readFromCache(const std::string& filename, const LLUUID& id, U32 priority,
  1395.    S32 offset, S32 size, ReadResponder* responder)
  1396. {
  1397. // Note: checking to see if an entry exists can cause a stall,
  1398. //  so let the thread handle it
  1399. LLMutexLock lock(&mWorkersMutex);
  1400. LLTextureCacheWorker* worker = new LLTextureCacheLocalFileWorker(this, priority, filename, id,
  1401.  NULL, size, offset, 0,
  1402.  responder);
  1403. handle_t handle = worker->read();
  1404. mReaders[handle] = worker;
  1405. return handle;
  1406. }
  1407. LLTextureCache::handle_t LLTextureCache::readFromCache(const LLUUID& id, U32 priority,
  1408.    S32 offset, S32 size, ReadResponder* responder)
  1409. {
  1410. // Note: checking to see if an entry exists can cause a stall,
  1411. //  so let the thread handle it
  1412. LLMutexLock lock(&mWorkersMutex);
  1413. LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
  1414.   NULL, size, offset,
  1415.   0, responder);
  1416. handle_t handle = worker->read();
  1417. mReaders[handle] = worker;
  1418. return handle;
  1419. }
  1420. bool LLTextureCache::readComplete(handle_t handle, bool abort)
  1421. {
  1422. lockWorkers();
  1423. handle_map_t::iterator iter = mReaders.find(handle);
  1424. LLTextureCacheWorker* worker = NULL;
  1425. bool complete = false;
  1426. if (iter != mReaders.end())
  1427. {
  1428. worker = iter->second;
  1429. complete = worker->complete();
  1430. }
  1431. if (worker && (complete || abort))
  1432. {
  1433. mReaders.erase(iter);
  1434. unlockWorkers();
  1435. worker->scheduleDelete();
  1436. }
  1437. else
  1438. {
  1439. unlockWorkers();
  1440. }
  1441. return (complete || abort);
  1442. }
  1443. LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 priority,
  1444.   U8* data, S32 datasize, S32 imagesize,
  1445.   WriteResponder* responder)
  1446. {
  1447. if (mReadOnly)
  1448. {
  1449. delete responder;
  1450. return LLWorkerThread::nullHandle();
  1451. }
  1452. if (mDoPurge)
  1453. {
  1454. // NOTE: This may cause an occasional hiccup,
  1455. //  but it really needs to be done on the control thread
  1456. //  (i.e. here)
  1457. purgeTextures(false);
  1458. mDoPurge = FALSE;
  1459. }
  1460. LLMutexLock lock(&mWorkersMutex);
  1461. LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
  1462.   data, datasize, 0,
  1463.   imagesize, responder);
  1464. handle_t handle = worker->write();
  1465. mWriters[handle] = worker;
  1466. return handle;
  1467. }
  1468. bool LLTextureCache::writeComplete(handle_t handle, bool abort)
  1469. {
  1470. lockWorkers();
  1471. handle_map_t::iterator iter = mWriters.find(handle);
  1472. llassert(iter != mWriters.end());
  1473. if (iter != mWriters.end())
  1474. {
  1475. LLTextureCacheWorker* worker = iter->second;
  1476. if (worker->complete() || abort)
  1477. {
  1478. mWriters.erase(handle);
  1479. unlockWorkers();
  1480. worker->scheduleDelete();
  1481. return true;
  1482. }
  1483. }
  1484. unlockWorkers();
  1485. return false;
  1486. }
  1487. void LLTextureCache::prioritizeWrite(handle_t handle)
  1488. {
  1489. // Don't prioritize yet, we might be working on this now
  1490. //   which could create a deadlock
  1491. LLMutexLock lock(&mListMutex);
  1492. mPrioritizeWriteList.push_back(handle);
  1493. }
  1494. void LLTextureCache::addCompleted(Responder* responder, bool success)
  1495. {
  1496. LLMutexLock lock(&mListMutex);
  1497. mCompletedList.push_back(std::make_pair(responder,success));
  1498. }
  1499. //////////////////////////////////////////////////////////////////////////////
  1500. // Called from MAIN thread (endWork())
  1501. // Ensure that mHeaderMutex is locked first!
  1502. bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id)
  1503. {
  1504. Entry entry;
  1505. S32 idx = openAndReadEntry(id, entry, false);
  1506. if (idx >= 0)
  1507. {
  1508. entry.mImageSize = -1;
  1509. entry.mBodySize = 0;
  1510. writeEntryAndClose(idx, entry);
  1511. mFreeList.insert(idx);
  1512. mHeaderIDMap.erase(id);
  1513. mTexturesSizeMap.erase(id);
  1514. return true;
  1515. }
  1516. return false;
  1517. }
  1518. void LLTextureCache::removeFromCache(const LLUUID& id)
  1519. {
  1520. //llwarns << "Removing texture from cache: " << id << llendl;
  1521. if (!mReadOnly)
  1522. {
  1523. LLMutexLock lock(&mHeaderMutex);
  1524. removeHeaderCacheEntry(id);
  1525. LLAPRFile::remove(getTextureFileName(id), getLocalAPRFilePool());
  1526. }
  1527. }
  1528. //////////////////////////////////////////////////////////////////////////////
  1529. LLTextureCache::ReadResponder::ReadResponder()
  1530. : mImageSize(0),
  1531.   mImageLocal(FALSE)
  1532. {
  1533. }
  1534. void LLTextureCache::ReadResponder::setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal)
  1535. {
  1536. if (mFormattedImage.notNull())
  1537. {
  1538. llassert_always(mFormattedImage->getCodec() == imageformat);
  1539. mFormattedImage->appendData(data, datasize);
  1540. }
  1541. else
  1542. {
  1543. mFormattedImage = LLImageFormatted::createFromType(imageformat);
  1544. mFormattedImage->setData(data,datasize);
  1545. }
  1546. mImageSize = imagesize;
  1547. mImageLocal = imagelocal;
  1548. }
  1549. //////////////////////////////////////////////////////////////////////////////