1 //
2 // Copyright 2022 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // MemoryShaderCache: Stores compiled shader in memory so they don't
7 // always have to be re-compiled. Can be used in conjunction with the platform
8 // layer to warm up the cache from disk.
9
10 #include "libANGLE/MemoryShaderCache.h"
11
12 #include <GLSLANG/ShaderVars.h>
13 #include <anglebase/sha1.h>
14
15 #include "common/BinaryStream.h"
16 #include "common/utilities.h"
17 #include "libANGLE/Compiler.h"
18 #include "libANGLE/Context.h"
19 #include "libANGLE/Debug.h"
20 #include "libANGLE/Uniform.h"
21 #include "libANGLE/histogram_macros.h"
22 #include "libANGLE/renderer/ShaderImpl.h"
23 #include "platform/PlatformMethods.h"
24
25 namespace gl
26 {
27
MemoryShaderCache(egl::BlobCache & blobCache)28 MemoryShaderCache::MemoryShaderCache(egl::BlobCache &blobCache) : mBlobCache(blobCache) {}
29
~MemoryShaderCache()30 MemoryShaderCache::~MemoryShaderCache() {}
31
getShader(const Context * context,Shader * shader,const ShCompileOptions & compileOptions,const ShCompilerInstance & compilerInstance,const egl::BlobCache::Key & shaderHash)32 angle::Result MemoryShaderCache::getShader(const Context *context,
33 Shader *shader,
34 const ShCompileOptions &compileOptions,
35 const ShCompilerInstance &compilerInstance,
36 const egl::BlobCache::Key &shaderHash)
37 {
38 // If caching is effectively disabled, don't bother calculating the hash.
39 if (!mBlobCache.isCachingEnabled())
40 {
41 return angle::Result::Incomplete;
42 }
43
44 angle::MemoryBuffer uncompressedData;
45 switch (mBlobCache.getAndDecompress(context->getScratchBuffer(), shaderHash, &uncompressedData))
46 {
47 case egl::BlobCache::GetAndDecompressResult::DecompressFailure:
48 ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
49 "Error decompressing shader binary data from cache.");
50 return angle::Result::Incomplete;
51
52 case egl::BlobCache::GetAndDecompressResult::NotFound:
53 return angle::Result::Incomplete;
54
55 case egl::BlobCache::GetAndDecompressResult::GetSuccess:
56 angle::Result result = shader->loadBinary(context, uncompressedData.data(),
57 static_cast<int>(uncompressedData.size()));
58
59 {
60 std::scoped_lock<std::mutex> lock(mHistogramMutex);
61 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ShaderCache.LoadBinarySuccess",
62 result == angle::Result::Continue);
63 }
64 ANGLE_TRY(result);
65
66 if (result == angle::Result::Continue)
67 return angle::Result::Continue;
68
69 // Cache load failed, evict.
70 ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
71 "Failed to load shader binary from cache.");
72 mBlobCache.remove(shaderHash);
73 return angle::Result::Incomplete;
74 }
75
76 UNREACHABLE();
77 return angle::Result::Incomplete;
78 }
79
putShader(const Context * context,const egl::BlobCache::Key & shaderHash,const Shader * shader)80 angle::Result MemoryShaderCache::putShader(const Context *context,
81 const egl::BlobCache::Key &shaderHash,
82 const Shader *shader)
83 {
84 // If caching is effectively disabled, don't bother serializing the shader.
85 if (!mBlobCache.isCachingEnabled())
86 {
87 return angle::Result::Incomplete;
88 }
89
90 angle::MemoryBuffer serializedShader;
91 ANGLE_TRY(shader->serialize(nullptr, &serializedShader));
92
93 size_t compressedSize;
94 if (!mBlobCache.compressAndPut(shaderHash, std::move(serializedShader), &compressedSize))
95 {
96 ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
97 "Error compressing shader binary data for insertion into cache.");
98 return angle::Result::Incomplete;
99 }
100
101 {
102 std::scoped_lock<std::mutex> lock(mHistogramMutex);
103 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ShaderCache.ShaderBinarySizeBytes",
104 static_cast<int>(compressedSize));
105 }
106
107 return angle::Result::Continue;
108 }
109
clear()110 void MemoryShaderCache::clear()
111 {
112 mBlobCache.clear();
113 }
114
maxSize() const115 size_t MemoryShaderCache::maxSize() const
116 {
117 return mBlobCache.maxSize();
118 }
119
120 } // namespace gl
121