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