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 application cache, only if application callbacks are set. 100 void putApplication(const BlobCache::Key &key, const angle::MemoryBuffer &value); 101 102 // Store a key-blob pair in the cache without making callbacks to the application. This is used 103 // to repopulate this object's cache on startup without generating callback calls. 104 void populate(const BlobCache::Key &key, 105 angle::MemoryBuffer &&value, 106 CacheSource source = CacheSource::Disk); 107 108 // Check if the cache contains the blob corresponding to this key. If application callbacks are 109 // set, those will be used. Otherwise they key is looked up in this object's cache. 110 ANGLE_NO_DISCARD bool get(angle::ScratchBuffer *scratchBuffer, 111 const BlobCache::Key &key, 112 BlobCache::Value *valueOut, 113 size_t *bufferSizeOut); 114 115 // For querying the contents of the cache. 116 ANGLE_NO_DISCARD bool getAt(size_t index, 117 const BlobCache::Key **keyOut, 118 BlobCache::Value *valueOut); 119 120 // Evict a blob from the binary cache. 121 void remove(const BlobCache::Key &key); 122 123 // Empty the cache. 124 void clear() { mBlobCache.clear(); } 125 126 // Resize the cache. Discards current contents. 127 void resize(size_t maxCacheSizeBytes) { mBlobCache.resize(maxCacheSizeBytes); } 128 129 // Returns the number of entries in the cache. 130 size_t entryCount() const { return mBlobCache.entryCount(); } 131 132 // Reduces the current cache size and returns the number of bytes freed. 133 size_t trim(size_t limit) { return mBlobCache.shrinkToSize(limit); } 134 135 // Returns the current cache size in bytes. 136 size_t size() const { return mBlobCache.size(); } 137 138 // Returns whether the cache is empty 139 bool empty() const { return mBlobCache.empty(); } 140 141 // Returns the maximum cache size in bytes. 142 size_t maxSize() const { return mBlobCache.maxSize(); } 143 144 void setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get); 145 146 bool areBlobCacheFuncsSet() const; 147 148 bool isCachingEnabled() const { return areBlobCacheFuncsSet() || maxSize() > 0; } 149 150 private: 151 // This internal cache is used only if the application is not providing caching callbacks 152 using CacheEntry = std::pair<angle::MemoryBuffer, CacheSource>; 153 154 std::mutex mBlobCacheMutex; 155 angle::SizedMRUCache<BlobCache::Key, CacheEntry> mBlobCache; 156 157 EGLSetBlobFuncANDROID mSetBlobFunc; 158 EGLGetBlobFuncANDROID mGetBlobFunc; 159 }; 160 161 } // namespace egl 162 163 #endif // LIBANGLE_MEMORY_PROGRAM_CACHE_H_ 164