diff options
author | Tofu Linden <tofu.linden@lindenlab.com> | 2010-04-07 13:37:37 +0100 |
---|---|---|
committer | Tofu Linden <tofu.linden@lindenlab.com> | 2010-04-07 13:37:37 +0100 |
commit | 4533d1b59b2e8fc534ad3de7a896aaa8514fe653 (patch) | |
tree | 38b4d2398d66a0e18cd8e4dcd47efba0ad5326a1 /indra/newview/lltexturecache.cpp | |
parent | 92f630871386bafc4548eb9beb45063e40b6139c (diff) | |
parent | adce2ecdf8f3a0efcd4907699d286012124ac496 (diff) |
merge from viewer-trunk
Diffstat (limited to 'indra/newview/lltexturecache.cpp')
-rw-r--r-- | indra/newview/lltexturecache.cpp | 358 |
1 files changed, 150 insertions, 208 deletions
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 2fd0a22f80..651070a2ea 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -2,25 +2,31 @@ * @file lltexturecache.cpp * @brief Object which handles local texture caching * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ @@ -385,7 +391,6 @@ bool LLTextureCacheRemoteWorker::doRead() } else { - //llinfos << "texture " << mID.asString() << " found in local_assets" << llendl; mImageSize = local_size; mImageLocal = TRUE; } @@ -396,8 +401,7 @@ bool LLTextureCacheRemoteWorker::doRead() // Second state / stage : identify the cache or not... if (!done && (mState == CACHE)) { - LLTextureCache::Entry entry ; - idx = mCache->getHeaderCacheEntry(mID, entry); + idx = mCache->getHeaderCacheEntry(mID, mImageSize); if (idx < 0) { // The texture is *not* cached. We're done here... @@ -406,7 +410,6 @@ bool LLTextureCacheRemoteWorker::doRead() } else { - mImageSize = entry.mImageSize ; // If the read offset is bigger than the header cache, we read directly from the body // Note that currently, we *never* read with offset from the cache, so the result is *always* HEADER mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY; @@ -528,14 +531,13 @@ bool LLTextureCacheRemoteWorker::doRead() bool LLTextureCacheRemoteWorker::doWrite() { bool done = false; - S32 idx = -1; + S32 idx = -1; // First state / stage : check that what we're trying to cache is in an OK shape if (mState == INIT) { llassert_always(mOffset == 0); // We currently do not support write offsets llassert_always(mDataSize > 0); // Things will go badly wrong if mDataSize is nul or negative... - llassert_always(mImageSize >= mDataSize); mState = CACHE; } @@ -545,19 +547,14 @@ bool LLTextureCacheRemoteWorker::doWrite() if (!done && (mState == CACHE)) { bool alreadyCached = false; - LLTextureCache::Entry entry ; - + S32 cur_imagesize = 0; // Checks if this image is already in the entry list - idx = mCache->getHeaderCacheEntry(mID, entry); - if(idx < 0) - { - idx = mCache->setHeaderCacheEntry(mID, entry, mImageSize, mDataSize); // create the new entry. - } - else + idx = mCache->getHeaderCacheEntry(mID, cur_imagesize); + if (idx >= 0 && (cur_imagesize > 0)) { - alreadyCached = mCache->updateEntry(idx, entry, mImageSize, mDataSize); // update the existing entry. + alreadyCached = true; // already there and non empty } - + idx = mCache->setHeaderCacheEntry(mID, mImageSize); // create or touch the entry if (idx < 0) { llwarns << "LLTextureCacheWorker: " << mID @@ -567,6 +564,10 @@ bool LLTextureCacheRemoteWorker::doWrite() } else { + if (cur_imagesize > 0 && (mImageSize != cur_imagesize)) + { + alreadyCached = false; // re-write the header if the size changed in all cases + } if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)) { // Small texture already cached case: we're done with writing @@ -629,7 +630,7 @@ bool LLTextureCacheRemoteWorker::doWrite() { llassert(mDataSize > TEXTURE_CACHE_ENTRY_SIZE); // wouldn't make sense to be here otherwise... S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE; - + if ((file_size > 0) && mCache->updateTextureEntryList(mID, file_size)) { // build the cache file name from the UUID std::string filename = mCache->getTextureFileName(mID); @@ -647,7 +648,10 @@ bool LLTextureCacheRemoteWorker::doWrite() done = true; } } - + else + { + mDataSize = 0; // no data written + } // Nothing else to do at that point... done = true; } @@ -738,7 +742,7 @@ LLTextureCache::LLTextureCache(bool threaded) mHeaderMutex(NULL), mListMutex(NULL), mHeaderAPRFile(NULL), - mReadOnly(TRUE), //do not allow to change the texture cache until setReadOnly() is called. + mReadOnly(FALSE), mTexturesSizeTotal(0), mDoPurge(FALSE) { @@ -821,6 +825,53 @@ std::string LLTextureCache::getTextureFileName(const LLUUID& id) return filename; } +bool LLTextureCache::updateTextureEntryList(const LLUUID& id, S32 bodysize) +{ + bool res = false; + bool purge = false; + { + LLMutexLock lock(&mHeaderMutex); + size_map_t::iterator iter1 = mTexturesSizeMap.find(id); + if (iter1 == mTexturesSizeMap.end() || iter1->second < bodysize) + { + llassert_always(bodysize > 0); + + S32 oldbodysize = 0; + if (iter1 != mTexturesSizeMap.end()) + { + oldbodysize = iter1->second; + } + + Entry entry; + S32 idx = openAndReadEntry(id, entry, false); + if (idx < 0) + { + llwarns << "Failed to open entry: " << id << llendl; + removeCachedTexture(id) ; + return false; + } + else if (oldbodysize != entry.mBodySize) + { + // only happens to 64 bits systems, do not know why. + llwarns << "Entry mismatch in mTextureSizeMap / mHeaderIDMap" + << " idx=" << idx << " oldsize=" << oldbodysize << " entrysize=" << entry.mBodySize << llendl; + } + updateEntry(idx, entry, entry.mImageSize, bodysize); + + if (mTexturesSizeTotal > sCacheMaxTexturesSize) + { + purge = true; + } + res = true; + } + } + if (purge) + { + mDoPurge = TRUE; + } + return res; +} + //debug BOOL LLTextureCache::isInCache(const LLUUID& id) { @@ -878,16 +929,13 @@ U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit const char* entries_filename = "texture.entries"; const char* cache_filename = "texture.cache"; -const char* old_textures_dirname = "textures"; -//change the location of the texture cache to prevent from being deleted by old version viewers. -const char* textures_dirname = "texturecache"; +const char* textures_dirname = "textures"; void LLTextureCache::setDirNames(ELLPath location) { std::string delem = gDirUtilp->getDirDelimiter(); - - mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, textures_dirname, entries_filename); - mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, textures_dirname, cache_filename); + mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename); + mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename); mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname); } @@ -899,38 +947,16 @@ void LLTextureCache::purgeCache(ELLPath location) { setDirNames(location); llassert_always(mHeaderAPRFile == NULL); - - //remove the legacy cache if exists - std::string texture_dir = mTexturesDirName ; - mTexturesDirName = gDirUtilp->getExpandedFilename(location, old_textures_dirname); - if(LLFile::isdir(mTexturesDirName)) - { - std::string file_name = gDirUtilp->getExpandedFilename(location, entries_filename); - LLAPRFile::remove(file_name, getLocalAPRFilePool()); - - file_name = gDirUtilp->getExpandedFilename(location, cache_filename); - LLAPRFile::remove(file_name, getLocalAPRFilePool()); - - purgeAllTextures(true); - } - mTexturesDirName = texture_dir ; + LLAPRFile::remove(mHeaderEntriesFileName, getLocalAPRFilePool()); + LLAPRFile::remove(mHeaderDataFileName, getLocalAPRFilePool()); } - - //remove the current texture cache. purgeAllTextures(true); } -//is called in the main thread before initCache(...) is called. -void LLTextureCache::setReadOnly(BOOL read_only) -{ - mReadOnly = read_only ; -} - -//called in the main thread. -S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL disable_texture_cache) +S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only) { - llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized. - + mReadOnly = read_only; + S64 header_size = (max_size * 2) / 10; S64 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE; sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries)); @@ -942,15 +968,6 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL disable_textu sCacheMaxTexturesSize = max_size; max_size -= sCacheMaxTexturesSize; - if(disable_texture_cache) //the texture cache is disabled - { - llinfos << "The texture cache is disabled!" << llendl ; - setReadOnly(TRUE) ; - purgeAllTextures(true); - - return max_size ; - } - LL_INFOS("TextureCache") << "Headers: " << sCacheMaxEntries << " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << LL_ENDL; @@ -959,7 +976,6 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL disable_textu if (!mReadOnly) { LLFile::mkdir(mTexturesDirName); - const char* subdirs = "0123456789abcdef"; for (S32 i=0; i<16; i++) { @@ -970,8 +986,6 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL disable_textu readHeaderCache(); purgeTextures(true); // calc mTexturesSize and make some room in the texture cache if we need it - llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized. - return max_size; // unused cache space } @@ -992,11 +1006,7 @@ LLAPRFile* LLTextureCache::openHeaderEntriesFile(bool readonly, S32 offset) void LLTextureCache::closeHeaderEntriesFile() { - if(!mHeaderAPRFile) - { - return ; - } - + llassert_always(mHeaderAPRFile != NULL); delete mHeaderAPRFile; mHeaderAPRFile = NULL; } @@ -1113,7 +1123,7 @@ S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create } //mHeaderMutex is locked before calling this. -void LLTextureCache::writeEntryToHeaderImmediately(S32& idx, Entry& entry, bool write_header) +void LLTextureCache::writeEntryToHeaderImmediately(S32 idx, Entry& entry, bool write_header) { LLAPRFile* aprfile ; S32 bytes_written ; @@ -1122,13 +1132,7 @@ void LLTextureCache::writeEntryToHeaderImmediately(S32& idx, Entry& entry, bool { aprfile = openHeaderEntriesFile(false, 0); bytes_written = aprfile->write((U8*)&mHeaderEntriesInfo, sizeof(EntriesInfo)) ; - if(bytes_written != sizeof(EntriesInfo)) - { - clearCorruptedCache() ; //clear the cache. - idx = -1 ;//mark the idx invalid. - return ; - } - + llassert_always(bytes_written == sizeof(EntriesInfo)); mHeaderAPRFile->seek(APR_SET, offset); } else @@ -1136,31 +1140,19 @@ void LLTextureCache::writeEntryToHeaderImmediately(S32& idx, Entry& entry, bool aprfile = openHeaderEntriesFile(false, offset); } bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry)); - if(bytes_written != sizeof(Entry)) - { - clearCorruptedCache() ; //clear the cache. - idx = -1 ;//mark the idx invalid. - - return ; - } - + llassert_always(bytes_written == sizeof(Entry)); closeHeaderEntriesFile(); mUpdatedEntryMap.erase(idx) ; } //mHeaderMutex is locked before calling this. -void LLTextureCache::readEntryFromHeaderImmediately(S32& idx, Entry& entry) +void LLTextureCache::readEntryFromHeaderImmediately(S32 idx, Entry& entry) { S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry); LLAPRFile* aprfile = openHeaderEntriesFile(true, offset); S32 bytes_read = aprfile->read((void*)&entry, (S32)sizeof(Entry)); + llassert_always(bytes_read == sizeof(Entry)); closeHeaderEntriesFile(); - - if(bytes_read != sizeof(Entry)) - { - clearCorruptedCache() ; //clear the cache. - idx = -1 ;//mark the idx invalid. - } } //mHeaderMutex is locked before calling this. @@ -1178,64 +1170,55 @@ void LLTextureCache::updateEntryTimeStamp(S32 idx, Entry& entry) { if (!mReadOnly) { + llassert_always(entry.mImageSize > entry.mBodySize); + entry.mTime = time(NULL); mUpdatedEntryMap[idx] = entry ; } } } +//mHeaderMutex is locked before calling this. //update an existing entry, write to header file immediately. -bool LLTextureCache::updateEntry(S32& idx, Entry& entry, S32 new_image_size, S32 new_data_size) +void LLTextureCache::updateEntry(S32 idx, Entry& entry, S32 new_image_size, S32 new_body_size) { - S32 new_body_size = llmax(0, new_data_size - TEXTURE_CACHE_ENTRY_SIZE) ; - + llassert_always(new_image_size > -1) ; + if(new_image_size == entry.mImageSize && new_body_size == entry.mBodySize) { - return true ; //nothing changed. + updateEntryTimeStamp(idx, entry) ; //nothing changed. } - else + else if (idx >= 0) { - bool purge = false ; - - lockHeaders() ; - - bool update_header = false ; - if(entry.mImageSize < 0) //is a brand-new entry - { - mHeaderIDMap[entry.mID] = idx; - mTexturesSizeMap[entry.mID] = new_body_size ; - mTexturesSizeTotal += new_body_size ; - - // Update Header - update_header = true ; - } - else if (entry.mBodySize != new_body_size) - { - //already in mHeaderIDMap. - mTexturesSizeMap[entry.mID] = new_body_size ; - mTexturesSizeTotal -= entry.mBodySize ; - mTexturesSizeTotal += new_body_size ; - } - entry.mTime = time(NULL); - entry.mImageSize = new_image_size ; - entry.mBodySize = new_body_size ; - - writeEntryToHeaderImmediately(idx, entry, update_header) ; - - if (mTexturesSizeTotal > sCacheMaxTexturesSize) + if (!mReadOnly) { - purge = true; - } - - unlockHeaders() ; + llassert_always(new_image_size > new_body_size) ; - if (purge) - { - mDoPurge = TRUE; + bool update_header = false ; + if(entry.mImageSize < 0) //is a brand-new entry + { + mHeaderIDMap[entry.mID] = idx; + mTexturesSizeMap[entry.mID] = new_body_size ; + mTexturesSizeTotal += new_body_size ; + + // Update Header + update_header = true ; + } + else if (entry.mBodySize != new_body_size) + { + //already in mHeaderIDMap. + mTexturesSizeMap[entry.mID] = new_body_size ; + mTexturesSizeTotal -= entry.mBodySize ; + mTexturesSizeTotal += new_body_size ; + } + entry.mTime = time(NULL); + entry.mImageSize = new_image_size ; + entry.mBodySize = new_body_size ; + +// llinfos << "Updating TE: " << idx << ": " << id << " Size: " << entry.mBodySize << " Time: " << entry.mTime << llendl; + writeEntryToHeaderImmediately(idx, entry, update_header) ; } } - - return false ; } U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries) @@ -1256,10 +1239,6 @@ U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries) { aprfile = openHeaderEntriesFile(false, 0); updatedHeaderEntriesFile() ; - if(!aprfile) - { - return 0; - } aprfile->seek(APR_SET, (S32)sizeof(EntriesInfo)); } for (U32 idx=0; idx<num_entries; idx++) @@ -1301,11 +1280,7 @@ void LLTextureCache::writeEntriesAndClose(const std::vector<Entry>& entries) for (S32 idx=0; idx<num_entries; idx++) { S32 bytes_written = aprfile->write((void*)(&entries[idx]), (S32)sizeof(Entry)); - if(bytes_written != sizeof(Entry)) - { - clearCorruptedCache() ; //clear the cache. - return ; - } + llassert_always(bytes_written == sizeof(Entry)); } closeHeaderEntriesFile(); } @@ -1331,11 +1306,7 @@ void LLTextureCache::updatedHeaderEntriesFile() //entriesInfo mHeaderAPRFile->seek(APR_SET, 0); S32 bytes_written = mHeaderAPRFile->write((U8*)&mHeaderEntriesInfo, sizeof(EntriesInfo)) ; - if(bytes_written != sizeof(EntriesInfo)) - { - clearCorruptedCache() ; //clear the cache. - return ; - } + llassert_always(bytes_written == sizeof(EntriesInfo)); //write each updated entry S32 entry_size = (S32)sizeof(Entry) ; @@ -1351,11 +1322,7 @@ void LLTextureCache::updatedHeaderEntriesFile() } bytes_written = mHeaderAPRFile->write((void*)(&iter->second), entry_size); - if(bytes_written != entry_size) - { - clearCorruptedCache() ; //clear the cache. - return ; - } + llassert_always(bytes_written == entry_size); } mUpdatedEntryMap.clear() ; } @@ -1476,29 +1443,6 @@ void LLTextureCache::readHeaderCache() ////////////////////////////////////////////////////////////////////////////// -//the header mutex is locked before calling this. -void LLTextureCache::clearCorruptedCache() -{ - llwarns << "the texture cache is corrupted, need to be cleared." << llendl ; - - closeHeaderEntriesFile();//close possible file handler - purgeAllTextures(false) ; //clear the cache. - - if (!mReadOnly) //regenerate the directory tree if not exists. - { - LLFile::mkdir(mTexturesDirName); - - const char* subdirs = "0123456789abcdef"; - for (S32 i=0; i<16; i++) - { - std::string dirname = mTexturesDirName + gDirUtilp->getDirDelimiter() + subdirs[i]; - LLFile::mkdir(dirname); - } - } - - return ; -} - void LLTextureCache::purgeAllTextures(bool purge_directories) { if (!mReadOnly) @@ -1518,23 +1462,20 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) } if (purge_directories) { - gDirUtilp->deleteFilesInDir(mTexturesDirName, mask); + gDirUtilp->deleteFilesInDir(mTexturesDirName,mask); LLFile::rmdir(mTexturesDirName); - } + } } mHeaderIDMap.clear(); mTexturesSizeMap.clear(); mTexturesSizeTotal = 0; mFreeList.clear(); mTexturesSizeTotal = 0; - mUpdatedEntryMap.clear(); // Info with 0 entries mHeaderEntriesInfo.mVersion = sHeaderCacheVersion; mHeaderEntriesInfo.mEntries = 0; writeEntriesHeader(); - - llinfos << "The entire texture cache is cleared." << llendl ; } void LLTextureCache::purgeTextures(bool validate) @@ -1680,38 +1621,39 @@ LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle) // Called from work thread // Reads imagesize from the header, updates timestamp -S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, Entry& entry) +S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, S32& imagesize) { - LLMutexLock lock(&mHeaderMutex); + LLMutexLock lock(&mHeaderMutex); + Entry entry; S32 idx = openAndReadEntry(id, entry, false); if (idx >= 0) - { + { + imagesize = entry.mImageSize; updateEntryTimeStamp(idx, entry); // updates time } return idx; } // Writes imagesize to the header, updates timestamp -S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, Entry& entry, S32 imagesize, S32 datasize) +S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, S32 imagesize) { mHeaderMutex.lock(); + llassert_always(imagesize >= 0); + Entry entry; S32 idx = openAndReadEntry(id, entry, true); - mHeaderMutex.unlock(); - if (idx >= 0) { - updateEntry(idx, entry, imagesize, datasize); + updateEntry(idx, entry, imagesize, entry.mBodySize); + mHeaderMutex.unlock(); } - - if(idx < 0) // retry + else // retry { + mHeaderMutex.unlock(); readHeaderCache(); // We couldn't write an entry, so refresh the LRU - mHeaderMutex.lock(); llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries); mHeaderMutex.unlock(); - - idx = setHeaderCacheEntry(id, entry, imagesize, datasize); // assert above ensures no inf. recursion + idx = setHeaderCacheEntry(id, imagesize); // assert above ensures no inf. recursion } return idx; } |