// // Copyright 2022 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // MemoryShaderCache: Stores compiled shader in memory so they don't // always have to be re-compiled. Can be used in conjunction with the platform // layer to warm up the cache from disk. #include "libANGLE/MemoryShaderCache.h" #include #include #include "common/BinaryStream.h" #include "common/utilities.h" #include "libANGLE/Compiler.h" #include "libANGLE/Context.h" #include "libANGLE/Debug.h" #include "libANGLE/Uniform.h" #include "libANGLE/histogram_macros.h" #include "libANGLE/renderer/ShaderImpl.h" #include "platform/PlatformMethods.h" namespace gl { MemoryShaderCache::MemoryShaderCache(egl::BlobCache &blobCache) : mBlobCache(blobCache) {} MemoryShaderCache::~MemoryShaderCache() {} angle::Result MemoryShaderCache::getShader(const Context *context, Shader *shader, const ShCompileOptions &compileOptions, const ShCompilerInstance &compilerInstance, const egl::BlobCache::Key &shaderHash) { // If caching is effectively disabled, don't bother calculating the hash. if (!mBlobCache.isCachingEnabled()) { return angle::Result::Incomplete; } angle::MemoryBuffer uncompressedData; switch (mBlobCache.getAndDecompress(context->getScratchBuffer(), shaderHash, &uncompressedData)) { case egl::BlobCache::GetAndDecompressResult::DecompressFailure: ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW, "Error decompressing shader binary data from cache."); return angle::Result::Incomplete; case egl::BlobCache::GetAndDecompressResult::NotFound: return angle::Result::Incomplete; case egl::BlobCache::GetAndDecompressResult::GetSuccess: angle::Result result = shader->loadBinary(context, uncompressedData.data(), static_cast(uncompressedData.size())); { std::scoped_lock lock(mHistogramMutex); ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ShaderCache.LoadBinarySuccess", result == angle::Result::Continue); } ANGLE_TRY(result); if (result == angle::Result::Continue) return angle::Result::Continue; // Cache load failed, evict. ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW, "Failed to load shader binary from cache."); mBlobCache.remove(shaderHash); return angle::Result::Incomplete; } UNREACHABLE(); return angle::Result::Incomplete; } angle::Result MemoryShaderCache::putShader(const Context *context, const egl::BlobCache::Key &shaderHash, const Shader *shader) { // If caching is effectively disabled, don't bother serializing the shader. if (!mBlobCache.isCachingEnabled()) { return angle::Result::Incomplete; } angle::MemoryBuffer serializedShader; ANGLE_TRY(shader->serialize(nullptr, &serializedShader)); size_t compressedSize; if (!mBlobCache.compressAndPut(shaderHash, std::move(serializedShader), &compressedSize)) { ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW, "Error compressing shader binary data for insertion into cache."); return angle::Result::Incomplete; } { std::scoped_lock lock(mHistogramMutex); ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ShaderCache.ShaderBinarySizeBytes", static_cast(compressedSize)); } return angle::Result::Continue; } void MemoryShaderCache::clear() { mBlobCache.clear(); } size_t MemoryShaderCache::maxSize() const { return mBlobCache.maxSize(); } } // namespace gl