• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2018 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 // BlobCache: Stores compiled and linked programs 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 #ifndef LIBANGLE_BLOB_CACHE_H_
11 #define LIBANGLE_BLOB_CACHE_H_
12 
13 #include <array>
14 #include <cstring>
15 
16 #include <anglebase/sha1.h>
17 #include "common/MemoryBuffer.h"
18 #include "common/hash_utils.h"
19 #include "libANGLE/Error.h"
20 #include "libANGLE/SizedMRUCache.h"
21 
22 namespace gl
23 {
24 class Context;
25 }  // namespace gl
26 
27 namespace egl
28 {
29 // 160-bit SHA-1 hash key used for hasing a program.  BlobCache opts in using fixed keys for
30 // simplicity and efficiency.
31 static constexpr size_t kBlobCacheKeyLength = angle::base::kSHA1Length;
32 using BlobCacheKey                          = std::array<uint8_t, kBlobCacheKeyLength>;
33 }  // namespace egl
34 
35 namespace std
36 {
37 template <>
38 struct hash<egl::BlobCacheKey>
39 {
40     // Simple routine to hash four ints.
41     size_t operator()(const egl::BlobCacheKey &key) const
42     {
43         return angle::ComputeGenericHash(key.data(), key.size());
44     }
45 };
46 }  // namespace std
47 
48 namespace egl
49 {
50 
51 bool CompressBlobCacheData(const size_t cacheSize,
52                            const uint8_t *cacheData,
53                            angle::MemoryBuffer *compressedData);
54 bool DecompressBlobCacheData(const uint8_t *compressedData,
55                              const size_t compressedSize,
56                              angle::MemoryBuffer *uncompressedData);
57 
58 class BlobCache final : angle::NonCopyable
59 {
60   public:
61     // 160-bit SHA-1 hash key used for hasing a program.  BlobCache opts in using fixed keys for
62     // simplicity and efficiency.
63     static constexpr size_t kKeyLength = kBlobCacheKeyLength;
64     using Key                          = BlobCacheKey;
65     class Value
66     {
67       public:
68         Value() : mPtr(nullptr), mSize(0) {}
69         Value(const uint8_t *ptr, size_t sz) : mPtr(ptr), mSize(sz) {}
70 
71         // A very basic struct to hold the pointer and size together.  The objects of this class
72         // don't own the memory.
73         const uint8_t *data() { return mPtr; }
74         size_t size() { return mSize; }
75 
76         const uint8_t &operator[](size_t pos) const
77         {
78             ASSERT(pos < mSize);
79             return mPtr[pos];
80         }
81 
82       private:
83         const uint8_t *mPtr;
84         size_t mSize;
85     };
86     enum class CacheSource
87     {
88         Memory,
89         Disk,
90     };
91 
92     explicit BlobCache(size_t maxCacheSizeBytes);
93     ~BlobCache();
94 
95     // Store a key-blob pair in the cache.  If application callbacks are set, the application cache
96     // will be used.  Otherwise the value is cached in this object.
97     void put(const BlobCache::Key &key, angle::MemoryBuffer &&value);
98 
99     // Store a key-blob pair in the cache, but compress the blob before insertion. Returns false if
100     // compression fails, returns true otherwise.
101     bool compressAndPut(const BlobCache::Key &key,
102                         angle::MemoryBuffer &&uncompressedValue,
103                         size_t *compressedSize);
104 
105     // Store a key-blob pair in the application cache, only if application callbacks are set.
106     void putApplication(const BlobCache::Key &key, const angle::MemoryBuffer &value);
107 
108     // Store a key-blob pair in the cache without making callbacks to the application.  This is used
109     // to repopulate this object's cache on startup without generating callback calls.
110     void populate(const BlobCache::Key &key,
111                   angle::MemoryBuffer &&value,
112                   CacheSource source = CacheSource::Disk);
113 
114     // Check if the cache contains the blob corresponding to this key.  If application callbacks are
115     // set, those will be used.  Otherwise they key is looked up in this object's cache.
116     [[nodiscard]] bool get(angle::ScratchBuffer *scratchBuffer,
117                            const BlobCache::Key &key,
118                            BlobCache::Value *valueOut,
119                            size_t *bufferSizeOut);
120 
121     // For querying the contents of the cache.
122     [[nodiscard]] bool getAt(size_t index,
123                              const BlobCache::Key **keyOut,
124                              BlobCache::Value *valueOut);
125 
126     enum class GetAndDecompressResult
127     {
128         GetSuccess,
129         NotFound,
130         DecompressFailure,
131     };
132     [[nodiscard]] GetAndDecompressResult getAndDecompress(
133         angle::ScratchBuffer *scratchBuffer,
134         const BlobCache::Key &key,
135         angle::MemoryBuffer *uncompressedValueOut);
136 
137     // Evict a blob from the binary cache.
138     void remove(const BlobCache::Key &key);
139 
140     // Empty the cache.
141     void clear() { mBlobCache.clear(); }
142 
143     // Resize the cache. Discards current contents.
144     void resize(size_t maxCacheSizeBytes) { mBlobCache.resize(maxCacheSizeBytes); }
145 
146     // Returns the number of entries in the cache.
147     size_t entryCount() const { return mBlobCache.entryCount(); }
148 
149     // Reduces the current cache size and returns the number of bytes freed.
150     size_t trim(size_t limit) { return mBlobCache.shrinkToSize(limit); }
151 
152     // Returns the current cache size in bytes.
153     size_t size() const { return mBlobCache.size(); }
154 
155     // Returns whether the cache is empty
156     bool empty() const { return mBlobCache.empty(); }
157 
158     // Returns the maximum cache size in bytes.
159     size_t maxSize() const { return mBlobCache.maxSize(); }
160 
161     void setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
162 
163     bool areBlobCacheFuncsSet() const;
164 
165     bool isCachingEnabled() const { return areBlobCacheFuncsSet() || maxSize() > 0; }
166 
167     std::mutex &getMutex() { return mBlobCacheMutex; }
168 
169   private:
170     // This internal cache is used only if the application is not providing caching callbacks
171     using CacheEntry = std::pair<angle::MemoryBuffer, CacheSource>;
172 
173     mutable std::mutex mBlobCacheMutex;
174     angle::SizedMRUCache<BlobCache::Key, CacheEntry> mBlobCache;
175 
176     EGLSetBlobFuncANDROID mSetBlobFunc;
177     EGLGetBlobFuncANDROID mGetBlobFunc;
178 };
179 
180 }  // namespace egl
181 
182 #endif  // LIBANGLE_MEMORY_PROGRAM_CACHE_H_
183