PageRenderTime 57ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/indra/newview/lltexturecache.cpp

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