summaryrefslogtreecommitdiff
path: root/indra/llrender/llshadermgr.cpp
diff options
context:
space:
mode:
authorErik Kundiman <erik@megapahit.org>2026-09-01 18:35:23 +0800
committerErik Kundiman <erik@megapahit.org>2026-09-04 21:58:53 +0800
commit00bb3bb6f07660bd914d29a1389342bb3060d254 (patch)
tree431f574922494d2201718f13085f17bc6bd7fb42 /indra/llrender/llshadermgr.cpp
parenta8636720129952c10cf49ab80da21bf8b340b96c (diff)
parent4ef9f8f14b35ed388c294d53767a0dca0e890924 (diff)
Merge remote-tracking branch 'secondlife/release/26.4' into 26.4
Diffstat (limited to 'indra/llrender/llshadermgr.cpp')
-rw-r--r--indra/llrender/llshadermgr.cpp107
1 files changed, 78 insertions, 29 deletions
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index fae2bd5034..5030e004f6 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -503,7 +503,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
open_file_name = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "shaders/errorF.glsl");
}
- file = LLFile::fopen(open_file_name, "r");
+ file = LLFile::fopen(open_file_name, LLFILE_MODE("r"));
}
else
#endif
@@ -531,7 +531,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
*/
LL_DEBUGS("ShaderLoading") << "Looking in " << open_file_name << LL_ENDL;
- file = LLFile::fopen(open_file_name, "r"); /* Flawfinder: ignore */
+ file = LLFile::fopen(open_file_name, LLFILE_MODE("r")); /* Flawfinder: ignore */
if (file)
{
LL_DEBUGS("ShaderLoading") << "Loading file: " << open_file_name << " (Want class " << gpu_class << ")" << LL_ENDL;
@@ -1016,7 +1016,6 @@ void LLShaderMgr::initShaderCache(bool enabled, const LLUUID& old_cache_version,
mShaderCacheDir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "shader_cache");
LLFile::mkdir(mShaderCacheDir);
-
{
std::string meta_out_path = gDirUtilp->add(mShaderCacheDir, "shaderdata.llsd");
if (gDirUtilp->fileExists(meta_out_path))
@@ -1076,7 +1075,6 @@ void LLShaderMgr::clearShaderCache()
LL_INFOS("ShaderMgr") << "Removing shader cache at " << shader_cache << LL_ENDL;
const std::string mask = "*";
gDirUtilp->deleteFilesInDir(shader_cache, mask);
- LLFile::rmdir(shader_cache);
mShaderBinaryCache.clear();
}
@@ -1089,17 +1087,26 @@ void LLShaderMgr::persistShaderCacheMetadata()
return;
}
- LL_INFOS("ShaderMgr") << "Persisting shader cache metadata to disk" << LL_ENDL;
+ if (mShaderCacheDir.empty() || !LLFile::isdir(mShaderCacheDir))
+ {
+ LL_WARNS("ShaderMgr") << "Invalid shader cache directory: " << mShaderCacheDir << LL_ENDL;
+ return;
+ }
+
+ size_t total_entries = mShaderBinaryCache.size();
+ LL_INFOS("ShaderMgr") << "Persisting shader " << (S32)total_entries << " cache metadata entries to disk" << LL_ENDL;
LLSD out;
// Settings and shader cache get saved at different time, thus making
// RenderShaderCacheVersion unreliable when running multiple viewer
// instances, or for cases where viewer crashes before saving settings.
- // Dupplicate version to the cache itself.
+ // Duplicate version to the cache itself.
out["version"] = mShaderCacheVersion;
out["shaders"] = LLSD::emptyMap();
LLSD &shaders = out["shaders"];
+ size_t removed = 0;
+
static const F32 LRU_TIME = (60.f * 60.f) * 24.f * 7.f; // 14 days
const F32 current_time = (F32)LLTimer::getTotalSeconds();
for (auto it = mShaderBinaryCache.begin(); it != mShaderBinaryCache.end();)
@@ -1108,8 +1115,9 @@ void LLShaderMgr::persistShaderCacheMetadata()
if ((shader_metadata.mLastUsedTime + LRU_TIME) < current_time)
{
std::string shader_path = gDirUtilp->add(mShaderCacheDir, it->first.asString() + ".shaderbin");
- LLFile::remove(shader_path);
+ LLFile::remove(shader_path, ENOENT);
it = mShaderBinaryCache.erase(it);
+ removed++;
}
else
{
@@ -1123,14 +1131,32 @@ void LLShaderMgr::persistShaderCacheMetadata()
}
std::string meta_out_path = gDirUtilp->add(mShaderCacheDir, "shaderdata.llsd");
+ if (shaders.size() == 0)
+ {
+ LL_WARNS("ShaderMgr") << "No shader cache entries to persist, removing cache metadata file" << LL_ENDL;
+ LLFile::remove(meta_out_path);
+ return;
+ }
+
llofstream outstream(meta_out_path, std::ios_base::out | std::ios_base::binary);
if (!outstream.is_open())
{
LL_WARNS("ShaderMgr") << "Failed to open file. Unable to save shader cache to: " << mShaderCacheDir << LL_ENDL;
return;
}
+
LLSDSerialize::toBinary(out, outstream);
+ if (outstream.fail())
+ {
+ LL_WARNS("ShaderMgr") << "Failed to serialize shader cache metadata" << LL_ENDL;
+ outstream.close();
+ LLFile::remove(meta_out_path); // Clean up partial write
+ return;
+ }
outstream.close();
+
+ LL_INFOS("ShaderMgr") << "Persisted " << (S32)shaders.size()
+ << " entries. Removed " << (S32)removed << " entries." << LL_ENDL;
}
bool LLShaderMgr::loadCachedProgramBinary(LLGLSLShader* shader)
@@ -1144,34 +1170,56 @@ bool LLShaderMgr::loadCachedProgramBinary(LLGLSLShader* shader)
{
std::string in_path = gDirUtilp->add(mShaderCacheDir, shader->mShaderHash.asString() + ".shaderbin");
auto& shader_info = binary_iter->second;
- if (shader_info.mBinaryLength > 0)
- {
- std::vector<U8> in_data;
- in_data.resize(shader_info.mBinaryLength);
- LLUniqueFile filep = LLFile::fopen(in_path, "rb");
- if (filep)
+ try
+ {
+ constexpr GLsizei MAX_SHADER_BINARY_SIZE = 1024 * 1024; // 1 MB, normally around 10KB
+ if (shader_info.mBinaryLength > 0 && shader_info.mBinaryLength <= MAX_SHADER_BINARY_SIZE)
{
- size_t result = fread(in_data.data(), sizeof(U8), in_data.size(), filep);
- filep.close();
+ std::vector<U8> in_data;
+ in_data.resize(shader_info.mBinaryLength);
- if (result == in_data.size())
+ std::error_code ec;
+ LLFile filep = LLFile(in_path, LLFile::in | LLFile::binary, ec);
+ if (!ec && (bool)filep)
{
- GLenum error = glGetError(); // Clear current error
- glProgramBinary(shader->mProgramObject, shader_info.mBinaryFormat, in_data.data(), shader_info.mBinaryLength);
+ size_t result = filep.read(in_data.data(), in_data.size(), ec);
+ filep.close();
- error = glGetError();
- GLint success = GL_TRUE;
- glGetProgramiv(shader->mProgramObject, GL_LINK_STATUS, &success);
- if (error == GL_NO_ERROR && success == GL_TRUE)
+ if (result == in_data.size())
+ {
+ GLenum error = glGetError(); // Clear current error
+ glProgramBinary(shader->mProgramObject, shader_info.mBinaryFormat, in_data.data(), shader_info.mBinaryLength);
+
+ error = glGetError();
+ GLint success = GL_TRUE;
+ glGetProgramiv(shader->mProgramObject, GL_LINK_STATUS, &success);
+ if (error == GL_NO_ERROR && success == GL_TRUE)
+ {
+ binary_iter->second.mLastUsedTime = (F32)LLTimer::getTotalSeconds();
+ LL_INFOS() << "Loaded cached binary for shader: " << shader->mName << LL_ENDL;
+ return true;
+ }
+ }
+ else
{
- binary_iter->second.mLastUsedTime = (F32)LLTimer::getTotalSeconds();
- LL_INFOS() << "Loaded cached binary for shader: " << shader->mName << LL_ENDL;
- return true;
+ LL_WARNS("ShaderMgr") << "Incomplete read of shader binary. Expected: "
+ << in_data.size() << ", read: " << result << LL_ENDL;
}
}
}
}
+ catch (const std::bad_alloc&)
+ {
+ LL_WARNS("ShaderMgr") << "Failed to allocate memory for shader binary ("
+ << shader_info.mBinaryLength << " bytes) for: "
+ << shader->mName << LL_ENDL;
+ }
+ catch (const std::exception& err)
+ {
+ LL_WARNS("ShaderMgr") << "Caught exception " << err.what() << " while loading shader binary for: " << shader->mName << LL_ENDL;
+ }
+
//an error occured, normally we would print log but in this case it means the shader needs recompiling.
LL_INFOS() << "Failed to load cached binary for shader: " << shader->mName << " falling back to compilation" << LL_ENDL;
LLFile::remove(in_path);
@@ -1197,11 +1245,12 @@ bool LLShaderMgr::saveCachedProgramBinary(LLGLSLShader* shader)
if (error == GL_NO_ERROR)
{
std::string out_path = gDirUtilp->add(mShaderCacheDir, shader->mShaderHash.asString() + ".shaderbin");
- LLUniqueFile outfile = LLFile::fopen(out_path, "wb");
- if (outfile)
+ std::error_code ec;
+ LLFile filep = LLFile(out_path, LLFile::out | LLFile::binary, ec);
+ if (filep)
{
- fwrite(program_binary.data(), sizeof(U8), program_binary.size(), outfile);
- outfile.close();
+ filep.write(program_binary.data(), program_binary.size(), ec);
+ filep.close();
binary_info.mLastUsedTime = (F32)LLTimer::getTotalSeconds();