• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)40 egl::CacheGetResult MemoryShaderCache::getShader(const Context *context,
41                                                  Shader *shader,
42                                                  const egl::BlobCache::Key &shaderHash)
43 {
44     // If caching is effectively disabled, don't bother calculating the hash.
45     if (!mBlobCache.isCachingEnabled())
46     {
47         return egl::CacheGetResult::NotFound;
48     }
49 
50     angle::MemoryBuffer uncompressedData;
51     const egl::BlobCache::GetAndDecompressResult result = mBlobCache.getAndDecompress(
52         context->getScratchBuffer(), shaderHash, kMaxUncompressedShaderSize, &uncompressedData);
53     switch (result)
54     {
55         case egl::BlobCache::GetAndDecompressResult::DecompressFailure:
56             ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
57                                "Error decompressing shader binary data from cache.");
58             mBlobCache.remove(shaderHash);
59             return egl::CacheGetResult::NotFound;
60 
61         case egl::BlobCache::GetAndDecompressResult::NotFound:
62             return egl::CacheGetResult::NotFound;
63 
64         case egl::BlobCache::GetAndDecompressResult::Success:
65             if (shader->loadBinary(context, uncompressedData.data(),
66                                    static_cast<int>(uncompressedData.size())))
67             {
68                 return egl::CacheGetResult::Success;
69             }
70 
71             // Cache load failed, evict.
72             ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
73                                "Failed to load shader binary from cache.");
74             mBlobCache.remove(shaderHash);
75             return egl::CacheGetResult::Rejected;
76     }
77 
78     UNREACHABLE();
79     return egl::CacheGetResult::NotFound;
80 }
81 
putShader(const Context * context,const egl::BlobCache::Key & shaderHash,const Shader * shader)82 angle::Result MemoryShaderCache::putShader(const Context *context,
83                                            const egl::BlobCache::Key &shaderHash,
84                                            const Shader *shader)
85 {
86     // If caching is effectively disabled, don't bother serializing the shader.
87     if (!mBlobCache.isCachingEnabled())
88     {
89         return angle::Result::Continue;
90     }
91 
92     angle::MemoryBuffer serializedShader;
93     ANGLE_TRY(shader->serialize(nullptr, &serializedShader));
94 
95     size_t compressedSize;
96     if (!mBlobCache.compressAndPut(shaderHash, std::move(serializedShader), &compressedSize))
97     {
98         ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
99                            "Error compressing shader binary data for insertion into cache.");
100         return angle::Result::Continue;
101     }
102 
103     return angle::Result::Continue;
104 }
105 
clear()106 void MemoryShaderCache::clear()
107 {
108     mBlobCache.clear();
109 }
110 
maxSize() const111 size_t MemoryShaderCache::maxSize() const
112 {
113     return mBlobCache.maxSize();
114 }
115 
116 }  // namespace gl
117