xref: /aosp_15_r20/external/angle/src/libANGLE/MemoryShaderCache.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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