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
28 namespace
29 {
30 // Limit decompressed programs to 5MB. If they're larger then this there is a good chance the data
31 // is not what we expect. This limits the amount of memory we will allocate based on a binary blob
32 // we believe is compressed data.
33 static constexpr size_t kMaxUncompressedShaderSize = 5 * 1024 * 1024;
34 } // namespace
35
MemoryShaderCache(egl::BlobCache & blobCache)36 MemoryShaderCache::MemoryShaderCache(egl::BlobCache &blobCache) : mBlobCache(blobCache) {}
37
~MemoryShaderCache()38 MemoryShaderCache::~MemoryShaderCache() {}
39
getShader(const Context * context,Shader * shader,const egl::BlobCache::Key & shaderHash,angle::JobResultExpectancy resultExpectancy)40 egl::CacheGetResult MemoryShaderCache::getShader(const Context *context,
41 Shader *shader,
42 const egl::BlobCache::Key &shaderHash,
43 angle::JobResultExpectancy resultExpectancy)
44 {
45 // If caching is effectively disabled, don't bother calculating the hash.
46 if (!mBlobCache.isCachingEnabled(context))
47 {
48 return egl::CacheGetResult::NotFound;
49 }
50
51 angle::MemoryBuffer uncompressedData;
52 const egl::BlobCache::GetAndDecompressResult result =
53 mBlobCache.getAndDecompress(context, context->getScratchBuffer(), shaderHash,
54 kMaxUncompressedShaderSize, &uncompressedData);
55 switch (result)
56 {
57 case egl::BlobCache::GetAndDecompressResult::DecompressFailure:
58 ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
59 "Error decompressing shader binary data from cache.");
60 mBlobCache.remove(shaderHash);
61 return egl::CacheGetResult::NotFound;
62
63 case egl::BlobCache::GetAndDecompressResult::NotFound:
64 return egl::CacheGetResult::NotFound;
65
66 case egl::BlobCache::GetAndDecompressResult::Success:
67 if (shader->loadBinary(context, uncompressedData.data(),
68 static_cast<int>(uncompressedData.size()), resultExpectancy))
69 {
70 return egl::CacheGetResult::Success;
71 }
72
73 // Cache load failed, evict.
74 ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
75 "Failed to load shader binary from cache.");
76 mBlobCache.remove(shaderHash);
77 return egl::CacheGetResult::Rejected;
78 }
79
80 UNREACHABLE();
81 return egl::CacheGetResult::NotFound;
82 }
83
putShader(const Context * context,const egl::BlobCache::Key & shaderHash,const Shader * shader)84 angle::Result MemoryShaderCache::putShader(const Context *context,
85 const egl::BlobCache::Key &shaderHash,
86 const Shader *shader)
87 {
88 // If caching is effectively disabled, don't bother serializing the shader.
89 if (!mBlobCache.isCachingEnabled(context))
90 {
91 return angle::Result::Continue;
92 }
93
94 angle::MemoryBuffer serializedShader;
95 ANGLE_TRY(shader->serialize(nullptr, &serializedShader));
96
97 size_t compressedSize;
98 if (!mBlobCache.compressAndPut(context, shaderHash, std::move(serializedShader),
99 &compressedSize))
100 {
101 ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
102 "Error compressing shader binary data for insertion into cache.");
103 return angle::Result::Continue;
104 }
105
106 return angle::Result::Continue;
107 }
108
clear()109 void MemoryShaderCache::clear()
110 {
111 mBlobCache.clear();
112 }
113
maxSize() const114 size_t MemoryShaderCache::maxSize() const
115 {
116 return mBlobCache.maxSize();
117 }
118
119 } // namespace gl
120