From e440c0e47958ae9adeb775de6a4f033010b82414 Mon Sep 17 00:00:00 2001 From: Rye Date: Wed, 31 Dec 2025 13:07:22 -0500 Subject: Reduce temporary allocations and repeated utf8->utf16 in LLTextureCache with new LLFile IO code Add non-allocating to_chars and to_wchars string creation functions to LLUUID Signed-off-by: Rye --- indra/llcommon/lluuid.cpp | 46 ++++++++++++++++++++++++++++++++++-- indra/llcommon/lluuid.h | 2 ++ indra/llfilesystem/lldiskcache.cpp | 4 +++- indra/llimage/llimage.cpp | 36 +++++++++++++++++++++++++++- indra/llimage/llimage.h | 3 ++- indra/newview/lltexturecache.cpp | 48 ++++++++++++++++++++++---------------- indra/newview/lltexturecache.h | 3 ++- 7 files changed, 116 insertions(+), 26 deletions(-) diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 4aae90626e..867744a29d 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -151,6 +151,48 @@ U32 janky_fast_random_seeded_bytes(U32 seed, U32 val) } #endif +void LLUUID::to_chars(char* out) const +{ + snprintf(out, UUID_STR_LENGTH, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (U8)(mData[0]), + (U8)(mData[1]), + (U8)(mData[2]), + (U8)(mData[3]), + (U8)(mData[4]), + (U8)(mData[5]), + (U8)(mData[6]), + (U8)(mData[7]), + (U8)(mData[8]), + (U8)(mData[9]), + (U8)(mData[10]), + (U8)(mData[11]), + (U8)(mData[12]), + (U8)(mData[13]), + (U8)(mData[14]), + (U8)(mData[15])); +} + +void LLUUID::to_wchars(wchar_t* out) const +{ + swprintf(out, UUID_STR_LENGTH, L"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (U8)(mData[0]), + (U8)(mData[1]), + (U8)(mData[2]), + (U8)(mData[3]), + (U8)(mData[4]), + (U8)(mData[5]), + (U8)(mData[6]), + (U8)(mData[7]), + (U8)(mData[8]), + (U8)(mData[9]), + (U8)(mData[10]), + (U8)(mData[11]), + (U8)(mData[12]), + (U8)(mData[13]), + (U8)(mData[14]), + (U8)(mData[15])); +} + // Common to all UUID implementations void LLUUID::toString(std::string& out) const { @@ -405,8 +447,8 @@ LLUUID LLUUID::combine(const LLUUID& other) const std::ostream& operator<<(std::ostream& s, const LLUUID& uuid) { - std::string uuid_str; - uuid.toString(uuid_str); + char uuid_str[UUID_STR_LENGTH]; + uuid.to_chars(uuid_str); s << uuid_str; return s; } diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index ca1cf03c4d..e6b0eea7a1 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -103,6 +103,8 @@ public: friend LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLUUID &uuid); friend LL_COMMON_API std::istream& operator>>(std::istream& s, LLUUID &uuid); + void to_chars(char* out) const; + void to_wchars(wchar_t* out) const; void toString(std::string& out) const; void toCompressedString(std::string& out) const; diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp index c75df16b7d..3430bec925 100644 --- a/indra/llfilesystem/lldiskcache.cpp +++ b/indra/llfilesystem/lldiskcache.cpp @@ -210,7 +210,9 @@ void LLDiskCache::purge() const std::string LLDiskCache::metaDataToFilepath(const LLUUID& id, LLAssetType::EType at) { - return llformat("%s%s%s_%s_0.asset", sCacheDir.c_str(), gDirUtilp->getDirDelimiter().c_str(), CACHE_FILENAME_PREFIX.c_str(), id.asString().c_str()); + char uuid_str[UUID_STR_LENGTH]{}; + id.to_chars(uuid_str); + return llformat("%s%s%s_%s_0.asset", sCacheDir.c_str(), gDirUtilp->getDirDelimiter().c_str(), CACHE_FILENAME_PREFIX.c_str(), uuid_str); } const std::string LLDiskCache::getCacheInfo() diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index ca8a4199e8..bea33c04ed 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -2036,6 +2036,25 @@ file_extensions[] = { "dxt", IMG_CODEC_DXT }, { "png", IMG_CODEC_PNG } }; + +static struct +{ + const wchar_t* exten; + EImageCodec codec; +} +wide_file_extensions[] = +{ + { L"bmp", IMG_CODEC_BMP }, + { L"tga", IMG_CODEC_TGA }, + { L"j2c", IMG_CODEC_J2C }, + { L"jp2", IMG_CODEC_J2C }, + { L"texture", IMG_CODEC_J2C }, + { L"jpg", IMG_CODEC_JPEG }, + { L"jpeg", IMG_CODEC_JPEG }, + { L"mip", IMG_CODEC_DXT }, + { L"dxt", IMG_CODEC_DXT }, + { L"png", IMG_CODEC_PNG } +}; #define NUM_FILE_EXTENSIONS LL_ARRAY_SIZE(file_extensions) #if 0 static std::string find_file(std::string &name, S8 *codec) @@ -2056,7 +2075,8 @@ static std::string find_file(std::string &name, S8 *codec) return std::string(""); } #endif -EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten) + +EImageCodec LLImageBase::getCodecFromExtension(std::string_view exten) { if (!exten.empty()) { @@ -2068,6 +2088,20 @@ EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten) } return IMG_CODEC_INVALID; } + +EImageCodec LLImageBase::getCodecFromExtension(std::wstring_view exten) +{ + if (!exten.empty()) + { + for (int i = 0; i < (int)(NUM_FILE_EXTENSIONS); i++) + { + if (exten == wide_file_extensions[i].exten) + return wide_file_extensions[i].codec; + } + } + return IMG_CODEC_INVALID; +} + #if 0 bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip_only) { diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 6b14b68c78..16042e573a 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -158,7 +158,8 @@ public: // <= 0 priority means that there's no need for more data. static F32 calc_download_priority(F32 virtual_size, F32 visible_area, S32 bytes_sent); - static EImageCodec getCodecFromExtension(const std::string& exten); + static EImageCodec getCodecFromExtension(std::string_view exten); + static EImageCodec getCodecFromExtension(std::wstring_view exten); //static LLTrace::MemStatHandle sMemStat; diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index be6c71ab86..b0b929a3ef 100755 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -157,7 +157,7 @@ protected: LLAtomicS32 mBytesRead; }; -class LLTextureCacheLocalFileWorker : public LLTextureCacheWorker +class LLTextureCacheLocalFileWorker final : public LLTextureCacheWorker { public: LLTextureCacheLocalFileWorker(LLTextureCache* cache, const std::string& filename, const LLUUID& id, @@ -165,7 +165,7 @@ public: S32 imagesize, // for writes LLTextureCache::Responder* responder) : LLTextureCacheWorker(cache, id, data, datasize, offset, imagesize, responder), - mFileName(filename) + mFileName(fsyspath(filename)) { } @@ -174,18 +174,24 @@ public: virtual bool doWrite(); private: - std::string mFileName; + std::filesystem::path mFileName; }; bool LLTextureCacheLocalFileWorker::doRead() { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; S32 local_size = (S32)LLFile::size(mFileName); - if (local_size > 0 && mFileName.size() > 4) + if (local_size > 0 && mFileName.native().size() > 4) { mDataSize = local_size; // Only a complete file is valid - std::string extension = mFileName.substr(mFileName.size() - 3, 3); +#if LL_WINDOWS + std::wstring_view native_path = mFileName.native(); + std::wstring_view extension = native_path.substr(native_path.size() - 3, 3); +#else + std::string_view native_path = mFileName.native(); + std::string_view extension = native_path.substr(native_path.size() - 3, 3); +#endif mImageFormat = LLImageBase::getCodecFromExtension(extension); @@ -233,7 +239,7 @@ bool LLTextureCacheLocalFileWorker::doWrite() return false; } -class LLTextureCacheRemoteWorker : public LLTextureCacheWorker +class LLTextureCacheRemoteWorker final : public LLTextureCacheWorker { public: LLTextureCacheRemoteWorker(LLTextureCache* cache, const LLUUID& id, @@ -406,7 +412,7 @@ bool LLTextureCacheRemoteWorker::doRead() mReadData = (U8*)ll_aligned_malloc_16(size); if (mReadData) { - S32 bytes_read = (S32)LLFile::read(mCache->mHeaderDataFileName, mReadData, offset, size); + S32 bytes_read = (S32)LLFile::read(mCache->mHeaderDataFilePath, mReadData, offset, size); if (bytes_read != size) { LL_WARNS() << "LLTextureCacheWorker: " << mID @@ -440,8 +446,8 @@ bool LLTextureCacheRemoteWorker::doRead() // Fourth state / stage : read the rest of the data from the UUID based cached file if (!done && (mState == BODY)) { - std::string filename = mCache->getTextureFileName(mID); - S32 filesize = (S32)LLFile::size(filename); + std::filesystem::path file_path = fsyspath(mCache->getTextureFileName(mID)); + S32 filesize = (S32)LLFile::size(file_path); if (filesize > 0 && (filesize + TEXTURE_CACHE_ENTRY_SIZE) > mOffset) { @@ -482,7 +488,7 @@ bool LLTextureCacheRemoteWorker::doRead() mReadData = data; // Read the data at last - S32 bytes_read = (S32)LLFile::read(filename, + S32 bytes_read = (S32)LLFile::read(file_path, mReadData + data_offset, file_offset, file_size); if (bytes_read != file_size) @@ -510,7 +516,7 @@ bool LLTextureCacheRemoteWorker::doRead() { // No body, we're done. mDataSize = llmax(TEXTURE_CACHE_ENTRY_SIZE - mOffset, 0); - LL_DEBUGS() << "No body file for: " << filename << LL_ENDL; + LL_DEBUGS() << "No body file for: " << file_path << LL_ENDL; } // Nothing else to do at that point... done = true; @@ -630,13 +636,13 @@ bool LLTextureCacheRemoteWorker::doWrite() U8* padBuffer = (U8*)ll_aligned_malloc_16(TEXTURE_CACHE_ENTRY_SIZE); memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer - bytes_written = (S32)LLFile::write(mCache->mHeaderDataFileName, padBuffer, offset, size); + bytes_written = (S32)LLFile::write(mCache->mHeaderDataFilePath, padBuffer, offset, size); ll_aligned_free_16(padBuffer); } else { // Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file - bytes_written = (S32)LLFile::write(mCache->mHeaderDataFileName, mWriteData, offset, size); + bytes_written = (S32)LLFile::write(mCache->mHeaderDataFilePath, mWriteData, offset, size); } if (bytes_written <= 0) @@ -856,9 +862,9 @@ std::string LLTextureCache::getLocalFileName(const LLUUID& id) std::string LLTextureCache::getTextureFileName(const LLUUID& id) { - std::string idstr = id.asString(); - std::string delem = gDirUtilp->getDirDelimiter(); - std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr + ".texture"; + char idstr[UUID_STR_LENGTH]{}; + id.to_chars(idstr); + std::string filename = llformat("%s%s%c%s%s.texture", mTexturesDirName.c_str(), gDirUtilp->getDirDelimiter().c_str(), idstr[0], gDirUtilp->getDirDelimiter().c_str(), idstr); return filename; } @@ -934,7 +940,9 @@ const char* fast_cache_filename = "FastCache.cache"; void LLTextureCache::setDirNames(ELLPath location) { mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, textures_dirname, entries_filename); - mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, textures_dirname, cache_filename); + mHeaderDataFilePath = fsyspath(gDirUtilp->getExpandedFilename(location, textures_dirname, cache_filename)); + mHeaderEntriesFilePath = fsyspath(mHeaderEntriesFileName); + mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname); mFastCacheFileName = gDirUtilp->getExpandedFilename(location, textures_dirname, fast_cache_filename); } @@ -1058,9 +1066,9 @@ void LLTextureCache::readEntriesHeader() { // mHeaderEntriesInfo initializes to default values so safe not to read it llassert_always(mHeaderAPRFile == NULL); - if (LLFile::isfile(mHeaderEntriesFileName)) + if (LLFile::isfile(mHeaderEntriesFilePath)) { - LLFile::read(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); + LLFile::read(mHeaderEntriesFilePath, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); } else //create an empty entries header. { @@ -1091,7 +1099,7 @@ void LLTextureCache::writeEntriesHeader() llassert_always(mHeaderAPRFile == NULL); if (!mReadOnly) { - LLFile::write(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); + LLFile::write(mHeaderEntriesFilePath, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); } } diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index faf722dc8f..fd4c4001b6 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -218,7 +218,8 @@ private: // HEADERS (Include first mip) std::string mHeaderEntriesFileName; - std::string mHeaderDataFileName; + std::filesystem::path mHeaderEntriesFilePath; + std::filesystem::path mHeaderDataFilePath; std::string mFastCacheFileName; EntriesInfo mHeaderEntriesInfo; std::set mFreeList; // deleted entries -- cgit v1.3