summaryrefslogtreecommitdiff
path: root/indra/newview/lltexturecache.cpp
diff options
context:
space:
mode:
authorJonathan Yap <jhwelch@gmail.com>2018-01-12 09:08:49 -0500
committerJonathan Yap <jhwelch@gmail.com>2018-01-12 09:08:49 -0500
commit1e586749efeeb8c40503330572680a8709ae5487 (patch)
tree5c1ebee5dbdb5004f354b9fb0837d60f6dd3cfcc /indra/newview/lltexturecache.cpp
parent32f16633c77564d567ed0752e56eb38abb916ccd (diff)
parent1693ccba58eef676df1f91e50627545ac35bb819 (diff)
STORM-2145 Merge up to viewer-release
Diffstat (limited to 'indra/newview/lltexturecache.cpp')
-rw-r--r--indra/newview/lltexturecache.cpp355
1 files changed, 221 insertions, 134 deletions
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 36c4f0d516..435d833345 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -31,6 +31,7 @@
#include "llapr.h"
#include "lldir.h"
#include "llimage.h"
+#include "llimagej2c.h" // for version control
#include "lllfsthread.h"
#include "llviewercontrol.h"
@@ -386,22 +387,35 @@ bool LLTextureCacheRemoteWorker::doRead()
}
// Allocate read buffer
mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize);
- S32 bytes_read = LLAPRFile::readEx(local_filename,
- mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool());
- if (bytes_read != mDataSize)
+
+ if (mReadData)
{
- LL_WARNS() << "Error reading file from local cache: " << local_filename
- << " Bytes: " << mDataSize << " Offset: " << mOffset
+ S32 bytes_read = LLAPRFile::readEx( local_filename,
+ mReadData,
+ mOffset,
+ mDataSize,
+ mCache->getLocalAPRFilePool());
+
+ if (bytes_read != mDataSize)
+ {
+ LL_WARNS() << "Error reading file from local cache: " << local_filename
+ << " Bytes: " << mDataSize << " Offset: " << mOffset
<< " / " << mDataSize << LL_ENDL;
- mDataSize = 0;
- FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
- mReadData = NULL;
+ mDataSize = 0;
+ FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
+ mReadData = NULL;
+ }
+ else
+ {
+ mImageSize = local_size;
+ mImageLocal = TRUE;
+ }
}
else
{
- //LL_INFOS() << "texture " << mID.asString() << " found in local_assets" << LL_ENDL;
- mImageSize = local_size;
- mImageLocal = TRUE;
+ LL_WARNS() << "Error allocating memory for cache: " << local_filename
+ << " of size: " << mDataSize << LL_ENDL;
+ mDataSize = 0;
}
// We're done...
done = true;
@@ -476,44 +490,55 @@ bool LLTextureCacheRemoteWorker::doRead()
// Reserve the whole data buffer first
U8* data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize);
-
- // Set the data file pointers taking the read offset into account. 2 cases:
- if (mOffset < TEXTURE_CACHE_ENTRY_SIZE)
+ if (data)
{
- // Offset within the header record. That means we read something from the header cache.
- // Note: most common case is (mOffset = 0), so this is the "normal" code path.
- data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; // i.e. TEXTURE_CACHE_ENTRY_SIZE if mOffset nul (common case)
- file_offset = 0;
- file_size = mDataSize - data_offset;
- // Copy the raw data we've been holding from the header cache into the new sized buffer
- llassert_always(mReadData);
- memcpy(data, mReadData, data_offset);
- FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
- mReadData = NULL;
- }
- else
- {
- // Offset bigger than the header record. That means we haven't read anything yet.
- data_offset = 0;
- file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
- file_size = mDataSize;
- // No data from header cache to copy in that case, we skipped it all
- }
+ // Set the data file pointers taking the read offset into account. 2 cases:
+ if (mOffset < TEXTURE_CACHE_ENTRY_SIZE)
+ {
+ // Offset within the header record. That means we read something from the header cache.
+ // Note: most common case is (mOffset = 0), so this is the "normal" code path.
+ data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; // i.e. TEXTURE_CACHE_ENTRY_SIZE if mOffset nul (common case)
+ file_offset = 0;
+ file_size = mDataSize - data_offset;
+ // Copy the raw data we've been holding from the header cache into the new sized buffer
+ llassert_always(mReadData);
+ memcpy(data, mReadData, data_offset);
+ FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
+ mReadData = NULL;
+ }
+ else
+ {
+ // Offset bigger than the header record. That means we haven't read anything yet.
+ data_offset = 0;
+ file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
+ file_size = mDataSize;
+ // No data from header cache to copy in that case, we skipped it all
+ }
- // Now use that buffer as the object read buffer
- llassert_always(mReadData == NULL);
- mReadData = data;
+ // Now use that buffer as the object read buffer
+ llassert_always(mReadData == NULL);
+ mReadData = data;
- // Read the data at last
- S32 bytes_read = LLAPRFile::readEx(filename,
- mReadData + data_offset,
- file_offset, file_size,
- mCache->getLocalAPRFilePool());
- if (bytes_read != file_size)
+ // Read the data at last
+ S32 bytes_read = LLAPRFile::readEx(filename,
+ mReadData + data_offset,
+ file_offset, file_size,
+ mCache->getLocalAPRFilePool());
+ if (bytes_read != file_size)
+ {
+ LL_WARNS() << "LLTextureCacheWorker: " << mID
+ << " incorrect number of bytes read from body: " << bytes_read
+ << " / " << file_size << LL_ENDL;
+ FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
+ mReadData = NULL;
+ mDataSize = -1; // failed
+ done = true;
+ }
+ }
+ else
{
LL_WARNS() << "LLTextureCacheWorker: " << mID
- << " incorrect number of bytes read from body: " << bytes_read
- << " / " << file_size << LL_ENDL;
+ << " failed to allocate memory for reading: " << mDataSize << LL_ENDL;
FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
mReadData = NULL;
mDataSize = -1; // failed
@@ -547,10 +572,20 @@ bool LLTextureCacheRemoteWorker::doWrite()
// 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;
+ if ((mOffset != 0) // We currently do not support write offsets
+ || (mDataSize <= 0) // Things will go badly wrong if mDataSize is nul or negative...
+ || (mImageSize < mDataSize)
+ || (mRawDiscardLevel < 0)
+ || (mRawImage->isBufferInvalid())) // decode failed or malfunctioned, don't write
+ {
+ LL_WARNS() << "INIT state check failed for image: " << mID << " Size: " << mImageSize << " DataSize: " << mDataSize << " Discard:" << mRawDiscardLevel << LL_ENDL;
+ mDataSize = -1; // failed
+ done = true;
+ }
+ else
+ {
+ mState = CACHE;
+ }
}
// No LOCAL state for write(): because it doesn't make much sense to cache a local file...
@@ -559,7 +594,7 @@ bool LLTextureCacheRemoteWorker::doWrite()
if (!done && (mState == CACHE))
{
bool alreadyCached = false;
- LLTextureCache::Entry entry ;
+ LLTextureCache::Entry entry;
// Checks if this image is already in the entry list
idx = mCache->getHeaderCacheEntry(mID, entry);
@@ -568,110 +603,132 @@ bool LLTextureCacheRemoteWorker::doWrite()
idx = mCache->setHeaderCacheEntry(mID, entry, mImageSize, mDataSize); // create the new entry.
if(idx >= 0)
{
- // (almost always) write to the fast cache.
- if (mRawImage->getDataSize())
+ // write to the fast cache.
+ if(!mCache->writeToFastCache(idx, mRawImage, mRawDiscardLevel))
{
- llassert_always(mCache->writeToFastCache(idx, mRawImage, mRawDiscardLevel));
+ LL_WARNS() << "writeToFastCache failed" << LL_ENDL;
+ mDataSize = -1; // failed
+ done = true;
+ }
}
}
- }
else
{
alreadyCached = mCache->updateEntry(idx, entry, mImageSize, mDataSize); // update the existing entry.
}
- if (idx < 0)
+ if (!done)
{
- LL_WARNS() << "LLTextureCacheWorker: " << mID
- << " Unable to create header entry for writing!" << LL_ENDL;
- mDataSize = -1; // failed
- done = true;
- }
- else
- {
- if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE))
+ if (idx < 0)
{
- // Small texture already cached case: we're done with writing
+ LL_WARNS() << "LLTextureCacheWorker: " << mID
+ << " Unable to create header entry for writing!" << LL_ENDL;
+ mDataSize = -1; // failed
done = true;
}
else
{
- // If the texture has already been cached, we don't resave the header and go directly to the body part
- mState = alreadyCached ? BODY : HEADER;
+ if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE))
+ {
+ // Small texture already cached case: we're done with writing
+ done = true;
+ }
+ else
+ {
+ // If the texture has already been cached, we don't resave the header and go directly to the body part
+ mState = alreadyCached ? BODY : HEADER;
+ }
}
}
}
+
// Third stage / state : write the header record in the header file (texture.cache)
if (!done && (mState == HEADER))
{
- llassert_always(idx >= 0); // we need an entry here or storing the header makes no sense
- S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE; // skip to the correct spot in the header file
- S32 size = TEXTURE_CACHE_ENTRY_SIZE; // record size is fixed for the header
- S32 bytes_written;
-
- if (mDataSize < TEXTURE_CACHE_ENTRY_SIZE)
+ if (idx < 0) // we need an entry here or storing the header makes no sense
{
- // We need to write a full record in the header cache so, if the amount of data is smaller
- // than a record, we need to transfer the data to a buffer padded with 0 and write that
- U8* padBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), TEXTURE_CACHE_ENTRY_SIZE);
- memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros
- memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer
- bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size, mCache->getLocalAPRFilePool());
- FREE_MEM(LLImageBase::getPrivatePool(), padBuffer);
+ LL_WARNS() << "index check failed" << LL_ENDL;
+ mDataSize = -1; // failed
+ done = true;
}
else
{
- // Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file
- bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool());
- }
+ S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE; // skip to the correct spot in the header file
+ S32 size = TEXTURE_CACHE_ENTRY_SIZE; // record size is fixed for the header
+ S32 bytes_written;
- if (bytes_written <= 0)
- {
- LL_WARNS() << "LLTextureCacheWorker: " << mID
+ if (mDataSize < TEXTURE_CACHE_ENTRY_SIZE)
+ {
+ // We need to write a full record in the header cache so, if the amount of data is smaller
+ // than a record, we need to transfer the data to a buffer padded with 0 and write that
+ U8* padBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), TEXTURE_CACHE_ENTRY_SIZE);
+ memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros
+ memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer
+ bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size, mCache->getLocalAPRFilePool());
+ FREE_MEM(LLImageBase::getPrivatePool(), padBuffer);
+ }
+ else
+ {
+ // Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file
+ bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool());
+ }
+
+ if (bytes_written <= 0)
+ {
+ LL_WARNS() << "LLTextureCacheWorker: " << mID
<< " Unable to write header entry!" << LL_ENDL;
- mDataSize = -1; // failed
- done = true;
- }
+ mDataSize = -1; // failed
+ done = true;
+ }
- // If we wrote everything (may be more with padding) in the header cache,
- // we're done so we don't have a body to store
- if (mDataSize <= bytes_written)
- {
- done = true;
- }
- else
- {
- mState = BODY;
+ // If we wrote everything (may be more with padding) in the header cache,
+ // we're done so we don't have a body to store
+ if (mDataSize <= bytes_written)
+ {
+ done = true;
+ }
+ else
+ {
+ mState = BODY;
+ }
}
}
// Fourth stage / state : write the body file, i.e. the rest of the texture in a "UUID" file name
if (!done && (mState == BODY))
{
- llassert(mDataSize > TEXTURE_CACHE_ENTRY_SIZE); // wouldn't make sense to be here otherwise...
- S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE;
-
+ if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE) // wouldn't make sense to be here otherwise...
{
- // build the cache file name from the UUID
- std::string filename = mCache->getTextureFileName(mID);
-// LL_INFOS() << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << LL_ENDL;
- S32 bytes_written = LLAPRFile::writeEx( filename,
- mWriteData + TEXTURE_CACHE_ENTRY_SIZE,
- 0, file_size,
- mCache->getLocalAPRFilePool());
- if (bytes_written <= 0)
+ LL_WARNS() << "mDataSize check failed" << LL_ENDL;
+ mDataSize = -1; // failed
+ done = true;
+ }
+ else
+ {
+ S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE;
+
{
- LL_WARNS() << "LLTextureCacheWorker: " << mID
+ // build the cache file name from the UUID
+ std::string filename = mCache->getTextureFileName(mID);
+ // LL_INFOS() << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << LL_ENDL;
+ S32 bytes_written = LLAPRFile::writeEx(filename,
+ mWriteData + TEXTURE_CACHE_ENTRY_SIZE,
+ 0, file_size,
+ mCache->getLocalAPRFilePool());
+ if (bytes_written <= 0)
+ {
+ LL_WARNS() << "LLTextureCacheWorker: " << mID
<< " incorrect number of bytes written to body: " << bytes_written
<< " / " << file_size << LL_ENDL;
- mDataSize = -1; // failed
- done = true;
+ mDataSize = -1; // failed
+ done = true;
+ }
}
+
+ // Nothing else to do at that point...
+ done = true;
}
-
- // Nothing else to do at that point...
- done = true;
}
mRawImage = NULL;
@@ -902,9 +959,17 @@ BOOL LLTextureCache::isInLocal(const LLUUID& id)
//////////////////////////////////////////////////////////////////////////////
//static
-F32 LLTextureCache::sHeaderCacheVersion = 1.7f;
+F32 LLTextureCache::sHeaderCacheVersion = 1.71f;
U32 LLTextureCache::sCacheMaxEntries = 1024 * 1024; //~1 million textures.
S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit
+std::string LLTextureCache::sHeaderCacheEncoderVersion = LLImageJ2C::getEngineInfo();
+
+#if defined(ADDRESS_SIZE)
+U32 LLTextureCache::sHeaderCacheAddressSize = ADDRESS_SIZE;
+#else
+U32 LLTextureCache::sHeaderCacheAddressSize = 32;
+#endif
+
const char* entries_filename = "texture.entries";
const char* cache_filename = "texture.cache";
const char* old_textures_dirname = "textures";
@@ -1047,12 +1112,28 @@ void LLTextureCache::readEntriesHeader()
}
else //create an empty entries header.
{
- mHeaderEntriesInfo.mVersion = sHeaderCacheVersion ;
- mHeaderEntriesInfo.mEntries = 0 ;
+ setEntriesHeader();
writeEntriesHeader() ;
}
}
+void LLTextureCache::setEntriesHeader()
+{
+ if (sHeaderEncoderStringSize < sHeaderCacheEncoderVersion.size() + 1)
+ {
+ // For simplicity we use predefined size of header, so if version string
+ // doesn't fit, either getEngineInfo() returned malformed string or
+ // sHeaderEncoderStringSize need to be increased.
+ // Also take into accout that c_str() returns additional null character
+ LL_ERRS() << "Version string doesn't fit in header" << LL_ENDL;
+ }
+
+ mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
+ mHeaderEntriesInfo.mAdressSize = sHeaderCacheAddressSize;
+ strcpy(mHeaderEntriesInfo.mEncoderVersion, sHeaderCacheEncoderVersion.c_str());
+ mHeaderEntriesInfo.mEntries = 0;
+}
+
void LLTextureCache::writeEntriesHeader()
{
llassert_always(mHeaderAPRFile == NULL);
@@ -1406,10 +1487,13 @@ void LLTextureCache::readHeaderCache()
readEntriesHeader();
- if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion)
+ if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion
+ || mHeaderEntriesInfo.mAdressSize != sHeaderCacheAddressSize
+ || strcmp(mHeaderEntriesInfo.mEncoderVersion, sHeaderCacheEncoderVersion.c_str()) != 0)
{
if (!mReadOnly)
{
+ LL_INFOS() << "Texture Cache version mismatch, Purging." << LL_ENDL;
purgeAllTextures(false);
}
}
@@ -1554,9 +1638,9 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
gDirUtilp->deleteFilesInDir(dirname, mask);
}
}
+ gDirUtilp->deleteFilesInDir(mTexturesDirName, mask); // headers, fast cache
if (purge_directories)
{
- gDirUtilp->deleteFilesInDir(mTexturesDirName, mask);
LLFile::rmdir(mTexturesDirName);
}
}
@@ -1568,8 +1652,7 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
mUpdatedEntryMap.clear();
// Info with 0 entries
- mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
- mHeaderEntriesInfo.mEntries = 0;
+ setEntriesHeader();
writeEntriesHeader();
LL_INFOS() << "The entire texture cache is cleared." << LL_ENDL ;
@@ -1733,24 +1816,30 @@ S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, Entry& entry)
S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, Entry& entry, S32 imagesize, S32 datasize)
{
mHeaderMutex.lock();
- S32 idx = openAndReadEntry(id, entry, true);
+ S32 idx = openAndReadEntry(id, entry, true); // read or create
mHeaderMutex.unlock();
- if (idx >= 0)
- {
- updateEntry(idx, entry, imagesize, datasize);
- }
-
- if(idx < 0) // retry
+ if(idx < 0) // retry once
{
readHeaderCache(); // We couldn't write an entry, so refresh the LRU
-
+
mHeaderMutex.lock();
- llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
+ idx = openAndReadEntry(id, entry, true);
mHeaderMutex.unlock();
+ }
- idx = setHeaderCacheEntry(id, entry, imagesize, datasize); // assert above ensures no inf. recursion
+ if (idx >= 0)
+ {
+ updateEntry(idx, entry, imagesize, datasize);
+ }
+ else
+ {
+ LL_WARNS() << "Failed to set cache entry for image: " << id << LL_ENDL;
+ // We couldn't write to file, switch to read only mode and clear data
+ setReadOnly(true);
+ clearCorruptedCache(); // won't remove files due to "read only"
}
+
return idx;
}
@@ -1902,7 +1991,7 @@ LLPointer<LLImageRaw> LLTextureCache::readFromFastCache(const LLUUID& id, S32& d
bool LLTextureCache::writeToFastCache(S32 id, LLPointer<LLImageRaw> raw, S32 discardlevel)
{
//rescale image if needed
- if (raw.isNull() || !raw->getData())
+ if (raw.isNull() || raw->isBufferInvalid() || !raw->getData())
{
LL_ERRS() << "Attempted to write NULL raw image to fastcache" << LL_ENDL;
return false;
@@ -1927,15 +2016,13 @@ bool LLTextureCache::writeToFastCache(S32 id, LLPointer<LLImageRaw> raw, S32 dis
if(w * h *c > 0) //valid
{
//make a duplicate to keep the original raw image untouched.
- raw = raw->duplicate();
+ raw = raw->scaled(w, h);
if (raw->isBufferInvalid())
{
LL_WARNS() << "Invalid image duplicate buffer" << LL_ENDL;
return false;
}
- raw->scale(w, h) ;
-
discardlevel += i ;
}
}