lltexturecache.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "lltexturecache.h"
00035 
00036 #include "llapr.h"
00037 #include "lldir.h"
00038 #include "llimage.h"
00039 #include "lllfsthread.h"
00040 #include "llviewercontrol.h"
00041 
00042 #define USE_LFS_READ 0
00043 #define USE_LFS_WRITE 0
00044 
00045 // Note: first 4 bytes store file size, rest is j2c data
00046 const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE; //1024;
00047 
00048 class LLTextureCacheWorker : public LLWorkerClass
00049 {
00050         friend class LLTextureCache;
00051 
00052 private:
00053         enum e_state
00054         {
00055                 INIT = 0,
00056                 LOCAL = 1,
00057                 CACHE = 2,
00058                 HEADER = 3,
00059                 BODY = 4
00060         };
00061 
00062         class ReadResponder : public LLLFSThread::Responder
00063         {
00064         public:
00065                 ReadResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {}
00066                 ~ReadResponder() {}
00067                 void completed(S32 bytes)
00068                 {
00069                         mCache->lockWorkers();
00070                         LLTextureCacheWorker* reader = mCache->getReader(mHandle);
00071                         if (reader) reader->ioComplete(bytes);
00072                         mCache->unlockWorkers();
00073                 }
00074                 LLTextureCache* mCache;
00075                 LLTextureCacheWorker::handle_t mHandle;
00076         };
00077 
00078         class WriteResponder : public LLLFSThread::Responder
00079         {
00080         public:
00081                 WriteResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {}
00082                 ~WriteResponder() {}
00083                 void completed(S32 bytes)
00084                 {
00085                         mCache->lockWorkers();
00086                         LLTextureCacheWorker* writer = mCache->getWriter(mHandle);
00087                         if (writer) writer->ioComplete(bytes);
00088                         mCache->unlockWorkers();
00089                 }
00090                 LLTextureCache* mCache;
00091                 LLTextureCacheWorker::handle_t mHandle;
00092         };
00093         
00094 public:
00095         LLTextureCacheWorker(LLTextureCache* cache, U32 priority, const LLUUID& id,
00096                                                  U8* data, S32 datasize, S32 offset,
00097                                                  S32 imagesize, // for writes
00098                                                  LLTextureCache::Responder* responder)
00099                 : LLWorkerClass(cache, "LLTextureCacheWorker"),
00100                   mCache(cache),
00101                   mPriority(priority),
00102                   mID(id),
00103                   mState(INIT),
00104                   mReadData(NULL),
00105                   mWriteData(data),
00106                   mDataSize(datasize),
00107                   mOffset(offset),
00108                   mImageSize(imagesize),
00109                   mImageFormat(IMG_CODEC_J2C),
00110                   mImageLocal(FALSE),
00111                   mResponder(responder),
00112                   mFileHandle(LLLFSThread::nullHandle()),
00113                   mBytesToRead(0),
00114                   mBytesRead(0)
00115         {
00116                 mPriority &= LLWorkerThread::PRIORITY_LOWBITS;
00117         }
00118         ~LLTextureCacheWorker()
00119         {
00120                 llassert_always(!haveWork());
00121                 delete[] mReadData;
00122         }
00123 
00124         bool doRead();
00125         bool doWrite();
00126         virtual bool doWork(S32 param); // Called from LLWorkerThread::processRequest()
00127 
00128         handle_t read() { addWork(0, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; }
00129         handle_t write() { addWork(1, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; }
00130         bool complete() { return checkWork(); }
00131         void ioComplete(S32 bytes)
00132         {
00133                 mBytesRead = bytes;
00134                 setPriority(LLWorkerThread::PRIORITY_HIGH | mPriority);
00135         }
00136         
00137 private:
00138         virtual void startWork(S32 param); // called from addWork() (MAIN THREAD)
00139         virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD)
00140         virtual void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD)
00141 
00142 private:
00143         LLTextureCache* mCache;
00144         U32 mPriority;
00145         LLUUID mID;
00146         e_state mState;
00147         
00148         U8* mReadData;
00149         U8* mWriteData;
00150         S32 mDataSize;
00151         S32 mOffset;
00152         S32 mImageSize;
00153         S32 mImageFormat;
00154         BOOL mImageLocal;
00155         LLPointer<LLTextureCache::Responder> mResponder;
00156         LLLFSThread::handle_t mFileHandle;
00157         S32 mBytesToRead;
00158         LLAtomicS32 mBytesRead;
00159 };
00160 
00161 //virtual
00162 void LLTextureCacheWorker::startWork(S32 param)
00163 {
00164 }
00165 
00166 bool LLTextureCacheWorker::doRead()
00167 {
00168         S32 local_size = 0;
00169         std::string local_filename;
00170         
00171         if (mState == INIT)
00172         {
00173                 std::string filename = mCache->getLocalFileName(mID);
00174                 local_filename = filename + ".j2c";
00175                 local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool());
00176                 if (local_size == 0)
00177                 {
00178                         local_filename = filename + ".tga";
00179                         local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool());
00180                         if (local_size > 0)
00181                         {
00182                                 mImageFormat = IMG_CODEC_TGA;
00183                                 mDataSize = local_size; // Only a complete .tga file is valid
00184                         }
00185                 }
00186                 if (local_size > 0)
00187                 {
00188                         mState = LOCAL;
00189                 }
00190                 else
00191                 {
00192                         mState = CACHE;
00193                 }
00194         }
00195 
00196         if (mState == LOCAL)
00197         {
00198 #if USE_LFS_READ
00199                 if (mFileHandle == LLLFSThread::nullHandle())
00200                 {
00201                         mImageLocal = TRUE;
00202                         mImageSize = local_size;
00203                         if (!mDataSize || mDataSize + mOffset > local_size)
00204                         {
00205                                 mDataSize = local_size - mOffset;
00206                         }
00207                         if (mDataSize <= 0)
00208                         {
00209                                 // no more data to read
00210                                 mDataSize = 0;
00211                                 return true;
00212                         }
00213                         mReadData = new U8[mDataSize];
00214                         mBytesRead = -1;
00215                         mBytesToRead = mDataSize;
00216                         setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
00217                         mFileHandle = LLLFSThread::sLocal->read(local_filename, mReadData, mOffset, mDataSize,
00218                                                                                                         new ReadResponder(mCache, mRequestHandle));
00219                         return false;
00220                 }
00221                 else
00222                 {
00223                         if (mBytesRead >= 0)
00224                         {
00225                                 if (mBytesRead != mBytesToRead)
00226                                 {
00227                                         llwarns << "Error reading file from local cache: " << local_filename
00228                                                         << " Bytes: " << mDataSize << " Offset: " << mOffset
00229                                                         << " / " << mDataSize << llendl;
00230                                         mDataSize = 0; // failed
00231                                         delete[] mReadData;
00232                                         mReadData = NULL;
00233                                 }
00234                                 return true;
00235                         }
00236                         else
00237                         {
00238                                 return false;
00239                         }
00240                 }
00241 #else
00242                 if (!mDataSize || mDataSize > local_size)
00243                 {
00244                         mDataSize = local_size;
00245                 }
00246                 mReadData = new U8[mDataSize];
00247                 S32 bytes_read = ll_apr_file_read_ex(local_filename, mCache->getFileAPRPool(),
00248                                                                                          mReadData, mOffset, mDataSize);
00249                 if (bytes_read != mDataSize)
00250                 {
00251                         llwarns << "Error reading file from local cache: " << local_filename
00252                                         << " Bytes: " << mDataSize << " Offset: " << mOffset
00253                                         << " / " << mDataSize << llendl;
00254                         mDataSize = 0;
00255                         delete[] mReadData;
00256                         mReadData = NULL;
00257                 }
00258                 else
00259                 {
00260                         mImageSize = local_size;
00261                         mImageLocal = TRUE;
00262                 }
00263                 return true;
00264 #endif
00265         }
00266 
00267         S32 idx = -1;
00268         
00269         if (mState == CACHE)
00270         {
00271                 llassert_always(mImageSize == 0);
00272                 idx = mCache->getHeaderCacheEntry(mID, false, &mImageSize);
00273                 if (idx >= 0 && mImageSize > mOffset)
00274                 {
00275                         llassert_always(mImageSize > 0);
00276                         if (!mDataSize || mDataSize > mImageSize)
00277                         {
00278                                 mDataSize = mImageSize;
00279                         }
00280                         mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
00281                 }
00282                 else
00283                 {
00284                         mDataSize = 0; // no data
00285                         return true;
00286                 }
00287         }
00288 
00289         if (mState == HEADER)
00290         {
00291 #if USE_LFS_READ
00292                 if (mFileHandle == LLLFSThread::nullHandle())
00293                 {
00294                         llassert_always(idx >= 0);
00295                         llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
00296                         S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
00297                         S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00298                         llassert_always(mReadData == NULL);
00299                         mReadData = new U8[size];
00300                         mBytesRead = -1;
00301                         mBytesToRead = size;
00302                         setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
00303                         mFileHandle = LLLFSThread::sLocal->read(mCache->mHeaderDataFileName,
00304                                                                                                         mReadData, offset, mBytesToRead,
00305                                                                                                         new ReadResponder(mCache, mRequestHandle));
00306                         return false;
00307                 }
00308                 else
00309                 {
00310                         if (mBytesRead >= 0)
00311                         {
00312                                 if (mBytesRead != mBytesToRead)
00313                                 {
00314                                         llwarns << "LLTextureCacheWorker: "  << mID
00315                                                         << " incorrect number of bytes read from header: " << mBytesRead
00316                                                         << " != " << mBytesToRead << llendl;
00317                                         mDataSize = -1; // failed
00318                                         return true;
00319                                 }
00320                                 if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
00321                                 {
00322                                         return true; // done
00323                                 }
00324                                 else
00325                                 {
00326                                         mFileHandle = LLLFSThread::nullHandle();
00327                                         mState = BODY;
00328                                 }
00329                         }
00330                         else
00331                         {
00332                                 return false;
00333                         }
00334                 }
00335 #else
00336                 llassert_always(idx >= 0);
00337                 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
00338                 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
00339                 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00340                 mReadData = new U8[size];
00341                 S32 bytes_read = ll_apr_file_read_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(),
00342                                                                                          mReadData, offset, size);
00343                 if (bytes_read != size)
00344                 {
00345                         llwarns << "LLTextureCacheWorker: "  << mID
00346                                         << " incorrect number of bytes read from header: " << bytes_read
00347                                         << " / " << size << llendl;
00348                         mDataSize = -1; // failed
00349                         return true;
00350                 }
00351                 if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
00352                 {
00353                         return true; // done
00354                 }
00355                 else
00356                 {
00357                         mState = BODY;
00358                 }
00359 #endif
00360         }
00361 
00362         if (mState == BODY)
00363         {
00364 #if USE_LFS_READ
00365                 if (mFileHandle == LLLFSThread::nullHandle())
00366                 {
00367                         std::string filename = mCache->getTextureFileName(mID);
00368                         S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool());
00369                         if (filesize > mOffset)
00370                         {
00371                                 S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
00372                                 mDataSize = llmin(datasize, mDataSize);
00373                                 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00374                                 data_offset = llmax(data_offset, 0);
00375                                 S32 file_size = mDataSize - data_offset;
00376                                 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
00377                                 file_offset = llmax(file_offset, 0);
00378 
00379                                 llassert_always(mDataSize > 0);
00380                                 U8* data = new U8[mDataSize];
00381                                 if (data_offset > 0)
00382                                 {
00383                                         llassert_always(mReadData);
00384                                         llassert_always(data_offset <= mDataSize);
00385                                         memcpy(data, mReadData, data_offset);
00386                                         delete[] mReadData;
00387                                         mReadData = NULL;
00388                                 }
00389                                 llassert_always(mReadData == NULL);
00390                                 mReadData = data;
00391 
00392                                 mBytesRead = -1;
00393                                 mBytesToRead = file_size;
00394                                 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
00395                                 llassert_always(data_offset + mBytesToRead <= mDataSize);
00396                                 mFileHandle = LLLFSThread::sLocal->read(filename,
00397                                                                                                                 mReadData + data_offset, file_offset, mBytesToRead,
00398                                                                                                                 new ReadResponder(mCache, mRequestHandle));
00399                                 return false;
00400                         }
00401                         else
00402                         {
00403                                 mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
00404                                 return true; // done
00405                         }
00406                 }
00407                 else
00408                 {
00409                         if (mBytesRead >= 0)
00410                         {
00411                                 if (mBytesRead != mBytesToRead)
00412                                 {
00413                                         llwarns << "LLTextureCacheWorker: "  << mID
00414                                                         << " incorrect number of bytes read from body: " << mBytesRead
00415                                                         << " != " << mBytesToRead << llendl;
00416                                         mDataSize = -1; // failed
00417                                 }
00418                                 return true;
00419                         }
00420                         else
00421                         {
00422                                 return false;
00423                         }
00424                 }
00425 #else
00426                 std::string filename = mCache->getTextureFileName(mID);
00427                 S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool());
00428                 S32 bytes_read = 0;
00429                 if (filesize > mOffset)
00430                 {
00431                         S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
00432                         mDataSize = llmin(datasize, mDataSize);
00433                         S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00434                         data_offset = llmax(data_offset, 0);
00435                         S32 file_size = mDataSize - data_offset;
00436                         S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
00437                         file_offset = llmax(file_offset, 0);
00438                         
00439                         U8* data = new U8[mDataSize];
00440                         if (data_offset > 0)
00441                         {
00442                                 llassert_always(mReadData);
00443                                 memcpy(data, mReadData, data_offset);
00444                                 delete[] mReadData;
00445                         }
00446                         mReadData = data;
00447                         bytes_read = ll_apr_file_read_ex(filename, mCache->getFileAPRPool(),
00448                                                                                          mReadData + data_offset,
00449                                                                                          file_offset, file_size);
00450                         if (bytes_read != file_size)
00451                         {
00452                                 llwarns << "LLTextureCacheWorker: "  << mID
00453                                                 << " incorrect number of bytes read from body: " << bytes_read
00454                                                 << " / " << file_size << llendl;
00455                                 mDataSize = -1; // failed
00456                                 return true;
00457                         }
00458                 }
00459                 else
00460                 {
00461                         mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
00462                 }
00463                 
00464                 return true;
00465 #endif
00466         }
00467         
00468         return false;
00469 }
00470 
00471 bool LLTextureCacheWorker::doWrite()
00472 {
00473         S32 idx = -1;
00474 
00475         if (mState == INIT)
00476         {
00477                 llassert_always(mOffset == 0); // Currently don't support offsets
00478                 mState = CACHE;
00479         }
00480 
00481         // No LOCAL state for write()
00482         
00483         if (mState == CACHE)
00484         {
00485                 S32 cur_imagesize = 0;
00486                 S32 offset = mOffset;
00487                 idx = mCache->getHeaderCacheEntry(mID, false, &cur_imagesize);
00488                 if (idx >= 0 && cur_imagesize > 0)
00489                 {
00490                         offset = TEXTURE_CACHE_ENTRY_SIZE; // don't re-write header
00491                 }
00492                 idx = mCache->getHeaderCacheEntry(mID, true, &mImageSize); // touch entry
00493                 if (idx >= 0)
00494                 {
00495                         llassert_always(cur_imagesize <= 0 || mImageSize == cur_imagesize);
00496                         mState = offset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
00497                 }
00498                 else
00499                 {
00500                         mDataSize = -1; // failed
00501                         return true;
00502                 }
00503         }
00504         
00505         if (mState == HEADER)
00506         {
00507 #if USE_LFS_WRITE
00508                 if (mFileHandle == LLLFSThread::nullHandle())
00509                 {
00510                         llassert_always(idx >= 0);
00511                         llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
00512                         S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
00513                         S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00514                         mBytesRead = -1;
00515                         mBytesToRead = size;
00516                         setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
00517                         mFileHandle = LLLFSThread::sLocal->write(mCache->mHeaderDataFileName,
00518                                                                                                          mWriteData, offset, mBytesToRead,
00519                                                                                                          new WriteResponder(mCache, mRequestHandle));
00520                         return false;
00521                 }
00522                 else
00523                 {
00524                         if (mBytesRead >= 0)
00525                         {
00526                                 if (mBytesRead != mBytesToRead)
00527                                 {
00528                                         llwarns << "LLTextureCacheWorker: "  << mID
00529                                                         << " incorrect number of bytes written to header: " << mBytesRead
00530                                                         << " != " << mBytesToRead << llendl;
00531                                         mDataSize = -1; // failed
00532                                         return true;
00533                                 }
00534                                 if (mDataSize <=  mBytesToRead)
00535                                 {
00536                                         return true; // done
00537                                 }
00538                                 else
00539                                 {
00540                                         mFileHandle = LLLFSThread::nullHandle();
00541                                         mState = BODY;
00542                                 }
00543                         }
00544                         else
00545                         {
00546                                 return false;
00547                         }
00548                 }
00549 #else
00550                 llassert_always(idx >= 0);
00551                 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
00552                 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
00553                 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00554                 S32 bytes_written = ll_apr_file_write_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(),
00555                                                                                                  mWriteData, offset, size);
00556 
00557                 if (bytes_written <= 0)
00558                 {
00559                         llwarns << "LLTextureCacheWorker: missing entry: " << mID << llendl;
00560                         mDataSize = -1; // failed
00561                         return true;
00562                 }
00563 
00564                 if (mDataSize <= size)
00565                 {
00566                         return true; // done
00567                 }
00568                 else
00569                 {
00570                         mState = BODY;
00571                 }
00572 #endif
00573         }
00574         
00575         if (mState == BODY)
00576         {
00577 #if USE_LFS_WRITE
00578                 if (mFileHandle == LLLFSThread::nullHandle())
00579                 {
00580                         S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00581                         data_offset = llmax(data_offset, 0);
00582                         S32 file_size = mDataSize - data_offset;
00583                         S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
00584                         file_offset = llmax(file_offset, 0);
00585                         if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
00586                         {
00587                                 std::string filename = mCache->getTextureFileName(mID);
00588                                 mBytesRead = -1;
00589                                 mBytesToRead = file_size;
00590                                 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
00591                                 mFileHandle = LLLFSThread::sLocal->write(filename,
00592                                                                                                                  mWriteData + data_offset, file_offset, mBytesToRead,
00593                                                                                                                  new WriteResponder(mCache, mRequestHandle));
00594                                 return false;
00595                         }
00596                         else
00597                         {
00598                                 mDataSize = 0; // no data written
00599                                 return true; // done
00600                         }
00601                 }
00602                 else
00603                 {
00604                         if (mBytesRead >= 0)
00605                         {
00606                                 if (mBytesRead != mBytesToRead)
00607                                 {
00608                                         llwarns << "LLTextureCacheWorker: "  << mID
00609                                                         << " incorrect number of bytes written to body: " << mBytesRead
00610                                                         << " != " << mBytesToRead << llendl;
00611                                         mDataSize = -1; // failed
00612                                 }
00613                                 return true;
00614                         }
00615                         else
00616                         {
00617                                 return false;
00618                         }
00619                 }
00620 #else
00621                 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00622                 data_offset = llmax(data_offset, 0);
00623                 S32 file_size = mDataSize - data_offset;
00624                 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
00625                 file_offset = llmax(file_offset, 0);
00626                 S32 bytes_written = 0;
00627                 if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
00628                 {
00629                         std::string filename = mCache->getTextureFileName(mID);
00630                         bytes_written = ll_apr_file_write_ex(filename, mCache->getFileAPRPool(),
00631                                                                                                  mWriteData + data_offset,
00632                                                                                                  file_offset, file_size);
00633                         if (bytes_written <= 0)
00634                         {
00635                                 mDataSize = -1; // failed
00636                         }
00637                 }
00638                 else
00639                 {
00640                         mDataSize = 0; // no data written
00641                 }
00642 
00643                 return true;
00644 #endif
00645         }
00646         
00647         return false;
00648 }
00649 
00650 //virtual
00651 bool LLTextureCacheWorker::doWork(S32 param)
00652 {
00653         bool res = false;
00654         if (param == 0) // read
00655         {
00656                 res = doRead();
00657         }
00658         else if (param == 1) // write
00659         {
00660                 res = doWrite();
00661         }
00662         else
00663         {
00664                 llassert_always(0);
00665         }
00666         return res;
00667 }
00668 
00669 //virtual (WORKER THREAD)
00670 void LLTextureCacheWorker::finishWork(S32 param, bool completed)
00671 {
00672         if (mResponder.notNull())
00673         {
00674                 bool success = (completed && mDataSize > 0);
00675                 if (param == 0)
00676                 {
00677                         // read
00678                         if (success)
00679                         {
00680                                 mResponder->setData(mReadData, mDataSize, mImageSize, mImageFormat, mImageLocal);
00681                                 mReadData = NULL; // responder owns data
00682                                 mDataSize = 0;
00683                         }
00684                         else
00685                         {
00686                                 delete[] mReadData;
00687                                 mReadData = NULL;
00688                                 
00689                         }
00690                 }
00691                 else
00692                 {
00693                         // write
00694                         mWriteData = NULL; // we never owned data
00695                         mDataSize = 0;
00696                 }
00697                 mCache->addCompleted(mResponder, success);
00698         }
00699 }
00700 
00701 //virtual (MAIN THREAD)
00702 void LLTextureCacheWorker::endWork(S32 param, bool aborted)
00703 {
00704         if (aborted)
00705         {
00706                 // Let the destructor handle any cleanup
00707                 return;
00708         }
00709         switch(param)
00710         {
00711           default:
00712           case 0: // read
00713           case 1: // write
00714           {
00715                   if (mDataSize < 0)
00716                   {
00717                           // failed
00718                           mCache->removeFromCache(mID);
00719                   }
00720                   break;
00721           }
00722         }
00723 }
00724 
00726 
00727 LLTextureCache::LLTextureCache(bool threaded)
00728         : LLWorkerThread("TextureCache", threaded),
00729           mWorkersMutex(getAPRPool()),
00730           mHeaderMutex(getAPRPool()),
00731           mListMutex(getAPRPool()),
00732           mFileAPRPool(NULL),
00733           mReadOnly(FALSE),
00734           mTexturesSizeTotal(0),
00735           mDoPurge(FALSE)
00736 {
00737         apr_pool_create(&mFileAPRPool, NULL);
00738 }
00739 
00740 LLTextureCache::~LLTextureCache()
00741 {
00742         apr_pool_destroy(mFileAPRPool);
00743 }
00744 
00746 
00747 //virtual
00748 S32 LLTextureCache::update(U32 max_time_ms)
00749 {
00750         S32 res;
00751         res = LLWorkerThread::update(max_time_ms);
00752 
00753         mListMutex.lock();
00754         handle_list_t priorty_list = mPrioritizeWriteList; // copy list
00755         mPrioritizeWriteList.clear();
00756         responder_list_t completed_list = mCompletedList; // copy list
00757         mCompletedList.clear();
00758         mListMutex.unlock();
00759         
00760         lockWorkers();
00761         
00762         for (handle_list_t::iterator iter1 = priorty_list.begin();
00763                  iter1 != priorty_list.end(); ++iter1)
00764         {
00765                 handle_t handle = *iter1;
00766                 handle_map_t::iterator iter2 = mWriters.find(handle);
00767                 if(iter2 != mWriters.end())
00768                 {
00769                         LLTextureCacheWorker* worker = iter2->second;
00770                         worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mPriority);
00771                 }
00772         }
00773 
00774         for (responder_list_t::iterator iter1 = completed_list.begin();
00775                  iter1 != completed_list.end(); ++iter1)
00776         {
00777                 Responder *responder = iter1->first;
00778                 bool success = iter1->second;
00779                 responder->completed(success);
00780         }
00781         
00782         unlockWorkers();
00783         
00784         return res;
00785 }
00786 
00788 
00789 std::string LLTextureCache::getLocalFileName(const LLUUID& id)
00790 {
00791         // Does not include extension
00792         std::string idstr = id.asString();
00793         std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "textures", idstr);
00794         return filename;
00795 }
00796 
00797 std::string LLTextureCache::getTextureFileName(const LLUUID& id)
00798 {
00799         std::string idstr = id.asString();
00800         std::string delem = gDirUtilp->getDirDelimiter();
00801         std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr;
00802         return filename;
00803 }
00804 
00805 bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize)
00806 {
00807         bool res = false;
00808         bool purge = false;
00809         // Append UUID to end of texture entries
00810         {
00811                 LLMutexLock lock(&mHeaderMutex);
00812                 size_map_t::iterator iter = mTexturesSizeMap.find(id);
00813                 if (iter == mTexturesSizeMap.end() || iter->second < bodysize)
00814                 {
00815                         llassert_always(bodysize > 0);
00816                         Entry* entry = new Entry(id, bodysize, time(NULL));
00817                         ll_apr_file_write_ex(mTexturesDirEntriesFileName, getFileAPRPool(),
00818                                                                  (U8*)entry, -1, 1*sizeof(Entry));
00819                         delete entry;
00820                         if (iter != mTexturesSizeMap.end())
00821                         {
00822                                 mTexturesSizeTotal -= iter->second;
00823                         }
00824                         mTexturesSizeTotal += bodysize;
00825                         mTexturesSizeMap[id] = bodysize;
00826                         if (mTexturesSizeTotal > sCacheMaxTexturesSize)
00827                         {
00828                                 purge = true;
00829                         }
00830                         res = true;
00831                 }
00832         }
00833         if (purge)
00834         {
00835                 mDoPurge = TRUE;
00836         }
00837         return res;
00838 }
00839 
00841 
00842 //static
00843 const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024; // 512 MB
00844 F32 LLTextureCache::sHeaderCacheVersion = 1.0f;
00845 U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE;
00846 S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit
00847 const char* entries_filename = "texture.entries";
00848 const char* cache_filename = "texture.cache";
00849 const char* textures_dirname = "textures";
00850 
00851 void LLTextureCache::setDirNames(ELLPath location)
00852 {
00853         std::string delem = gDirUtilp->getDirDelimiter();
00854         mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename);
00855         mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename);
00856         mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname);
00857         mTexturesDirEntriesFileName = mTexturesDirName + delem + entries_filename;
00858 }
00859 
00860 void LLTextureCache::purgeCache(ELLPath location)
00861 {
00862         if (!mReadOnly)
00863         {
00864                 setDirNames(location);
00865         
00866                 ll_apr_file_remove(mHeaderEntriesFileName, NULL);
00867                 ll_apr_file_remove(mHeaderDataFileName, NULL);
00868         }
00869         purgeAllTextures(true);
00870 }
00871 
00872 S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
00873 {
00874         mReadOnly = read_only;
00875         
00876         S64 header_size = (max_size * 2) / 10;
00877         S64 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE;
00878         sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries));
00879         header_size = sCacheMaxEntries * TEXTURE_CACHE_ENTRY_SIZE;
00880         max_size -= header_size;
00881         if (sCacheMaxTexturesSize > 0)
00882                 sCacheMaxTexturesSize = llmin(sCacheMaxTexturesSize, max_size);
00883         else
00884                 sCacheMaxTexturesSize = max_size;
00885         max_size -= sCacheMaxTexturesSize;
00886         
00887         llinfos << "TEXTURE CACHE: Headers: " << sCacheMaxEntries
00888                         << " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << llendl;
00889 
00890         setDirNames(location);
00891         
00892         if (!mReadOnly)
00893         {
00894                 LLFile::mkdir(mTexturesDirName.c_str());
00895                 const char* subdirs = "0123456789abcdef";
00896                 for (S32 i=0; i<16; i++)
00897                 {
00898                         std::string dirname = mTexturesDirName + gDirUtilp->getDirDelimiter() + subdirs[i];
00899                         LLFile::mkdir(dirname.c_str());
00900                 }
00901         }
00902         readHeaderCache();
00903         purgeTextures(true); // calc mTexturesSize and make some room in the texture cache if we need it
00904 
00905         return max_size; // unused cache space
00906 }
00907 
00908 struct lru_data
00909 {
00910         lru_data(U32 t, S32 i, const LLUUID& id) { time=t; index=i; uuid=id; }
00911         U32 time;
00912         S32 index;
00913         LLUUID uuid;
00914         struct Compare
00915         {
00916                 // lhs < rhs
00917                 typedef const lru_data* lru_data_ptr;
00918                 bool operator()(const lru_data_ptr& a, const lru_data_ptr& b) const
00919                 {
00920                         if (!(a->time < b->time))
00921                                 return true;
00922                         else if (!(b->time < a->time))
00923                                 return false;
00924                         else
00925                                 return a->index < b->index;
00926                 }
00927         };                              
00928 };
00929 
00930 // Called from either the main thread or the worker thread
00931 void LLTextureCache::readHeaderCache(apr_pool_t* poolp)
00932 {
00933         LLMutexLock lock(&mHeaderMutex);
00934         mHeaderEntriesInfo.mVersion = 0.f;
00935         mHeaderEntriesInfo.mEntries = 0;
00936         if (ll_apr_file_exists(mHeaderEntriesFileName, poolp))
00937         {
00938                 ll_apr_file_read_ex(mHeaderEntriesFileName, poolp,
00939                                                         (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
00940         }
00941         if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion)
00942         {
00943                 if (!mReadOnly)
00944                 {
00945                         // Info with 0 entries
00946                         mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
00947                         ll_apr_file_write_ex(mHeaderEntriesFileName, poolp,
00948                                                                  (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
00949                 }
00950         }
00951         else
00952         {
00953                 S32 num_entries = mHeaderEntriesInfo.mEntries;
00954                 if (num_entries)
00955                 {
00956                         Entry* entries = new Entry[num_entries];
00957                         ll_apr_file_read_ex(mHeaderEntriesFileName, poolp,
00958                                                                 (U8*)entries, sizeof(EntriesInfo), num_entries*sizeof(Entry));
00959                         typedef std::set<lru_data*, lru_data::Compare> lru_set_t;
00960                         lru_set_t lru;
00961                         for (S32 i=0; i<num_entries; i++)
00962                         {
00963                                 if (entries[i].mSize >= 0) // -1 indicates erased entry, skip
00964                                 {
00965                                         const LLUUID& id = entries[i].mID;
00966                                         lru.insert(new lru_data(entries[i].mTime, i, id));
00967                                         mHeaderIDMap[id] = i;
00968                                 }
00969                         }
00970                         mLRU.clear();
00971                         S32 lru_entries = sCacheMaxEntries / 10;
00972                         for (lru_set_t::iterator iter = lru.begin(); iter != lru.end(); ++iter)
00973                         {
00974                                 lru_data* data = *iter;
00975                                 mLRU[data->index] = data->uuid;
00976                                 if (--lru_entries <= 0)
00977                                         break;
00978                         }
00979                         for_each(lru.begin(), lru.end(), DeletePointer());
00980                         delete[] entries;
00981                 }
00982         }
00983 }
00984 
00986 
00987 void LLTextureCache::purgeAllTextures(bool purge_directories)
00988 {
00989         if (!mReadOnly)
00990         {
00991                 const char* subdirs = "0123456789abcdef";
00992                 std::string delem = gDirUtilp->getDirDelimiter();
00993                 std::string mask = delem + "*";
00994                 for (S32 i=0; i<16; i++)
00995                 {
00996                         std::string dirname = mTexturesDirName + delem + subdirs[i];
00997                         gDirUtilp->deleteFilesInDir(dirname.c_str(),mask);
00998                         if (purge_directories)
00999                         {
01000                                 LLFile::rmdir(dirname.c_str());
01001                         }
01002                 }
01003                 ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
01004                 if (purge_directories)
01005                 {
01006                         LLFile::rmdir(mTexturesDirName.c_str());
01007                 }
01008         }
01009         mTexturesSizeMap.clear();
01010 }
01011 
01012 void LLTextureCache::purgeTextures(bool validate)
01013 {
01014         if (mReadOnly)
01015         {
01016                 return;
01017         }
01018 
01019         LLMutexLock lock(&mHeaderMutex);
01020         
01021         S32 filesize = ll_apr_file_size(mTexturesDirEntriesFileName, NULL);
01022         S32 num_entries = filesize / sizeof(Entry);
01023         if (num_entries * (S32)sizeof(Entry) != filesize)
01024         {
01025                 llwarns << "Bad cache file: " << mTexturesDirEntriesFileName << " Purging." << llendl;
01026                 purgeAllTextures(false);
01027                 return;
01028         }
01029         if (num_entries == 0)
01030         {
01031                 return; // nothing to do
01032         }
01033         
01034         Entry* entries = new Entry[num_entries];
01035         S32 bytes_read = ll_apr_file_read_ex(mTexturesDirEntriesFileName, NULL,
01036                                                                                  (U8*)entries, 0, num_entries*sizeof(Entry));
01037         if (bytes_read != filesize)
01038         {
01039                 llwarns << "Bad cache file (2): " << mTexturesDirEntriesFileName << " Purging." << llendl;
01040                 purgeAllTextures(false);
01041                 return;
01042         }
01043         
01044         llinfos << "TEXTURE CACHE: Reading Entries..." << llendl;
01045         
01046         std::map<LLUUID, S32> entry_idx_map;
01047         S64 total_size = 0;
01048         for (S32 idx=0; idx<num_entries; idx++)
01049         {
01050                 const LLUUID& id = entries[idx].mID;
01051 //              llinfos << "Entry: " << id << " Size: " << entries[i].mSize << " Time: " << entries[i].mTime << llendl;
01052                 std::map<LLUUID, S32>::iterator iter = entry_idx_map.find(id);
01053                 if (iter != entry_idx_map.end())
01054                 {
01055                         // Newer entry replacing older entry
01056                         S32 pidx = iter->second;
01057                         total_size -= entries[pidx].mSize;
01058                         entries[pidx].mSize = 0; // flag: skip older entry
01059                 }
01060                 entry_idx_map[id] = idx;
01061                 total_size += entries[idx].mSize;
01062         }
01063 
01064         U32 validate_idx = 0;
01065         if (validate)
01066         {
01067                 validate_idx = gSavedSettings.getU32("CacheValidateCounter");
01068                 U32 next_idx = (++validate_idx) % 256;
01069                 gSavedSettings.setU32("CacheValidateCounter", next_idx);
01070                 llinfos << "TEXTURE CACHE: Validating: " << validate_idx << llendl;
01071         }
01072         
01073         S64 min_cache_size = (sCacheMaxTexturesSize * 9) / 10;
01074         S32 purge_count = 0;
01075         S32 next_idx = 0;
01076         for (S32 idx=0; idx<num_entries; idx++)
01077         {
01078                 if (entries[idx].mSize == 0)
01079                 {
01080                         continue;
01081                 }
01082                 bool purge_entry = false;
01083                 std::string filename = getTextureFileName(entries[idx].mID);
01084                 if (total_size >= min_cache_size)
01085                 {
01086                         purge_entry = true;
01087                 }
01088                 else if (validate)
01089                 {
01090                         // make sure file exists and is the correct size
01091                         S32 uuididx = entries[idx].mID.mData[0];
01092                         if (uuididx == validate_idx)
01093                         {
01094 //                              llinfos << "Validating: " << filename << "Size: " << entries[idx].mSize << llendl;
01095                                 S32 bodysize = ll_apr_file_size(filename, NULL);
01096                                 if (bodysize != entries[idx].mSize)
01097                                 {
01098                                         llwarns << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mSize
01099                                                         << filename << llendl;
01100                                         purge_entry = true;
01101                                 }
01102                         }
01103                 }
01104                 if (purge_entry)
01105                 {
01106                         purge_count++;
01107 //                      llinfos << "PURGING: " << filename << llendl;
01108                         ll_apr_file_remove(filename, NULL);
01109                         total_size -= entries[idx].mSize;
01110                         entries[idx].mSize = 0;
01111                 }
01112                 else
01113                 {
01114                         if (next_idx != idx)
01115                         {
01116                                 entries[next_idx] = entries[idx];
01117                         }
01118                         ++next_idx;
01119                 }
01120         }
01121         num_entries = next_idx;
01122 
01123         llinfos << "TEXTURE CACHE: Writing Entries: " << num_entries << llendl;
01124         
01125         ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
01126         ll_apr_file_write_ex(mTexturesDirEntriesFileName, NULL,
01127                                                  (U8*)&entries[0], 0, num_entries*sizeof(Entry));
01128         
01129         mTexturesSizeTotal = 0;
01130         mTexturesSizeMap.clear();
01131         for (S32 idx=0; idx<num_entries; idx++)
01132         {
01133                 mTexturesSizeMap[entries[idx].mID] = entries[idx].mSize;
01134                 mTexturesSizeTotal += entries[idx].mSize;
01135         }
01136         llassert(mTexturesSizeTotal == total_size);
01137         
01138         delete[] entries;
01139         
01140         llinfos << "TEXTURE CACHE:"
01141                         << " PURGED: " << purge_count
01142                         << " ENTRIES: " << num_entries
01143                         << " CACHE SIZE: " << total_size / 1024*1024 << " MB"
01144                         << llendl;
01145 }
01146 
01148 
01149 // call lockWorkers() first!
01150 LLTextureCacheWorker* LLTextureCache::getReader(handle_t handle)
01151 {
01152         LLTextureCacheWorker* res = NULL;
01153         handle_map_t::iterator iter = mReaders.find(handle);
01154         if (iter != mReaders.end())
01155         {
01156                 res = iter->second;
01157         }
01158         return res;
01159 }
01160 
01161 LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle)
01162 {
01163         LLTextureCacheWorker* res = NULL;
01164         handle_map_t::iterator iter = mWriters.find(handle);
01165         if (iter != mWriters.end())
01166         {
01167                 res = iter->second;
01168         }
01169         return res;
01170 }
01171 
01173 
01174 // Called from work thread
01175 S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize)
01176 {
01177         bool retry = false;
01178         S32 idx = -1;
01179 
01180         {
01181                 LLMutexLock lock(&mHeaderMutex);
01182                 id_map_t::iterator iter = mHeaderIDMap.find(id);
01183                 if (iter != mHeaderIDMap.end())
01184                 {
01185                         idx = iter->second;
01186                 }
01187                 else if (touch && !mReadOnly)
01188                 {
01189                         if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
01190                         {
01191                                 // Add an entry
01192                                 idx = mHeaderEntriesInfo.mEntries++;
01193                                 mHeaderIDMap[id] = idx;
01194                                 // Update Info
01195                                 ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(),
01196                                                                         (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
01197                         }
01198                         else if (!mLRU.empty())
01199                         {
01200                                 idx = mLRU.begin()->first; // will be erased below
01201                                 const LLUUID& oldid = mLRU.begin()->second;
01202                                 mHeaderIDMap.erase(oldid);
01203                                 mTexturesSizeMap.erase(oldid);
01204                                 mHeaderIDMap[id] = idx;
01205                         }
01206                         else
01207                         {
01208                                 idx = -1;
01209                                 retry = true;
01210                         }
01211                 }
01212                 if (idx >= 0)
01213                 {
01214                         if (touch && !mReadOnly)
01215                         {
01216                                 // Update the lru entry
01217                                 mLRU.erase(idx);
01218                                 llassert_always(imagesize && *imagesize > 0);
01219                                 Entry* entry = new Entry(id, *imagesize, time(NULL));
01220                                 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
01221                                 ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(),
01222                                                                          (U8*)entry, offset, sizeof(Entry));
01223                                 delete entry;
01224                         }
01225                         else if (imagesize)
01226                         {
01227                                 // Get the image size
01228                                 Entry entry;
01229                                 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
01230                                 ll_apr_file_read_ex(mHeaderEntriesFileName, getFileAPRPool(),
01231                                                                         (U8*)&entry, offset, sizeof(Entry));
01232                                 *imagesize = entry.mSize;
01233                         }
01234                 }
01235         }
01236         if (retry)
01237         {
01238                 readHeaderCache(getFileAPRPool()); // updates the lru
01239                 llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
01240                 idx = getHeaderCacheEntry(id, touch, imagesize); // assert above ensures no inf. recursion
01241         }
01242         return idx;
01243 }
01244 
01246 
01247 // Calls from texture pipeline thread (i.e. LLTextureFetch)
01248 
01249 LLTextureCache::handle_t LLTextureCache::readFromCache(const LLUUID& id, U32 priority,
01250                                                                                                            S32 offset, S32 size, ReadResponder* responder)
01251 {
01252         // Note: checking to see if an entry exists can cause a stall,
01253         //  so let the thread handle it
01254         LLMutexLock lock(&mWorkersMutex);
01255         LLTextureCacheWorker* worker = new LLTextureCacheWorker(this, priority, id,
01256                                                                                                                         NULL, size, offset, 0,
01257                                                                                                                         responder);
01258         handle_t handle = worker->read();
01259         mReaders[handle] = worker;
01260         return handle;
01261 }
01262 
01263 bool LLTextureCache::readComplete(handle_t handle, bool abort)
01264 {
01265         lockWorkers();
01266         handle_map_t::iterator iter = mReaders.find(handle);
01267         llassert_always(iter != mReaders.end());
01268         LLTextureCacheWorker* worker = iter->second;
01269         bool res = worker->complete();
01270         if (res || abort)
01271         {
01272                 mReaders.erase(handle);
01273                 unlockWorkers();
01274                 worker->scheduleDelete();
01275                 return true;
01276         }
01277         else
01278         {
01279                 unlockWorkers();
01280                 return false;
01281         }
01282 }
01283 
01284 LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 priority,
01285                                                                                                           U8* data, S32 datasize, S32 imagesize,
01286                                                                                                           WriteResponder* responder)
01287 {
01288         if (mReadOnly)
01289         {
01290                 delete responder;
01291                 return LLWorkerThread::nullHandle();
01292         }
01293         if (mDoPurge)
01294         {
01295                 // NOTE: This may cause an occasional hiccup,
01296                 //  but it really needs to be done on the control thread
01297                 //  (i.e. here)
01298                 purgeTextures(false);
01299                 mDoPurge = FALSE;
01300         }
01301         if (datasize >= TEXTURE_CACHE_ENTRY_SIZE)
01302         {
01303                 LLMutexLock lock(&mWorkersMutex);
01304                 llassert_always(imagesize > 0);
01305                 LLTextureCacheWorker* worker = new LLTextureCacheWorker(this, priority, id,
01306                                                                                                                                 data, datasize, 0,
01307                                                                                                                                 imagesize, responder);
01308                 handle_t handle = worker->write();
01309                 mWriters[handle] = worker;
01310                 return handle;
01311         }
01312         delete responder;
01313         return LLWorkerThread::nullHandle();
01314 }
01315 
01316 bool LLTextureCache::writeComplete(handle_t handle, bool abort)
01317 {
01318         lockWorkers();
01319         handle_map_t::iterator iter = mWriters.find(handle);
01320         llassert_always(iter != mWriters.end());
01321         LLTextureCacheWorker* worker = iter->second;
01322         if (worker->complete() || abort)
01323         {
01324                 mWriters.erase(handle);
01325                 unlockWorkers();
01326                 worker->scheduleDelete();
01327                 return true;
01328         }
01329         else
01330         {
01331                 unlockWorkers();
01332                 return false;
01333         }
01334 }
01335 
01336 void LLTextureCache::prioritizeWrite(handle_t handle)
01337 {
01338         // Don't prioritize yet, we might be working on this now
01339         //   which could create a deadlock
01340         LLMutexLock lock(&mListMutex);  
01341         mPrioritizeWriteList.push_back(handle);
01342 }
01343 
01344 void LLTextureCache::addCompleted(Responder* responder, bool success)
01345 {
01346         LLMutexLock lock(&mListMutex);
01347         mCompletedList.push_back(std::make_pair(responder,success));
01348 }
01349 
01351 
01352 // Called from MAIN thread (endWork())
01353 
01354 bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id)
01355 {
01356         if (mReadOnly)
01357         {
01358                 return false;
01359         }
01360         LLMutexLock lock(&mHeaderMutex);
01361         id_map_t::iterator iter = mHeaderIDMap.find(id);
01362         if (iter != mHeaderIDMap.end())
01363         {
01364                 S32 idx = iter->second;
01365                 if (idx >= 0)
01366                 {
01367                         Entry* entry = new Entry(id, -1, time(NULL));
01368                         S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
01369                         ll_apr_file_write_ex(mHeaderEntriesFileName, NULL,
01370                                                                  (U8*)entry, offset, sizeof(Entry));
01371                         delete entry;
01372                         mLRU[idx] = id;
01373                         mHeaderIDMap.erase(id);
01374                         mTexturesSizeMap.erase(id);
01375                         return true;
01376                 }
01377         }
01378         return false;
01379 }
01380 
01381 void LLTextureCache::removeFromCache(const LLUUID& id)
01382 {
01383         llwarns << "Removing texture from cache: " << id << llendl;
01384         if (!mReadOnly)
01385         {
01386                 removeHeaderCacheEntry(id);
01387                 ll_apr_file_remove(getTextureFileName(id), NULL);
01388         }
01389 }
01390 
01392 
01393 LLTextureCache::ReadResponder::ReadResponder()
01394         : mImageSize(0),
01395           mImageLocal(FALSE)
01396 {
01397 }
01398 
01399 void LLTextureCache::ReadResponder::setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal)
01400 {
01401         if (mFormattedImage.notNull())
01402         {
01403                 llassert_always(mFormattedImage->getCodec() == imageformat);
01404                 mFormattedImage->appendData(data, datasize);
01405         }
01406         else
01407         {
01408                 mFormattedImage = LLImageFormatted::createFromType(imageformat);
01409                 mFormattedImage->setData(data,datasize);
01410         }
01411         mImageSize = imagesize;
01412         mImageLocal = imagelocal;
01413 }
01414 

Generated on Thu Jul 1 06:09:18 2010 for Second Life Viewer by  doxygen 1.4.7