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 class BlobCache final : angle::NonCopyable 52 { 53 public: 54 // 160-bit SHA-1 hash key used for hasing a program. BlobCache opts in using fixed keys for 55 // simplicity and efficiency. 56 static constexpr size_t kKeyLength = kBlobCacheKeyLength; 57 using Key = BlobCacheKey; 58 class Value 59 { 60 public: 61 Value() : mPtr(nullptr), mSize(0) {} 62 Value(const uint8_t *ptr, size_t sz) : mPtr(ptr), mSize(sz) {} 63 64 // A very basic struct to hold the pointer and size together. The objects of this class 65 // don't own the memory. 66 const uint8_t *data() { return mPtr; } 67 size_t size() { return mSize; } 68 69 const uint8_t &operator[](size_t pos) const 70 { 71 ASSERT(pos < mSize); 72 return mPtr[pos]; 73 } 74 75 private: 76 const uint8_t *mPtr; 77 size_t mSize; 78 }; 79 enum class CacheSource 80 { 81 Memory, 82 Disk, 83 }; 84 85 explicit BlobCache(size_t maxCacheSizeBytes); 86 ~BlobCache(); 87 88 // Store a key-blob pair in the cache. If application callbacks are set, the application cache 89 // will be used. Otherwise the value is cached in this object. 90 void put(const BlobCache::Key &key, angle::MemoryBuffer &&value); 91 92 // Store a key-blob pair in the application cache, only if application callbacks are set. 93 void putApplication(const BlobCache::Key &key, const angle::MemoryBuffer &value); 94 95 // Store a key-blob pair in the cache without making callbacks to the application. This is used 96 // to repopulate this object's cache on startup without generating callback calls. 97 void populate(const BlobCache::Key &key, 98 angle::MemoryBuffer &&value, 99 CacheSource source = CacheSource::Disk); 100 101 // Check if the cache contains the blob corresponding to this key. If application callbacks are 102 // set, those will be used. Otherwise they key is looked up in this object's cache. 103 ANGLE_NO_DISCARD bool get(angle::ScratchBuffer *scratchBuffer, 104 const BlobCache::Key &key, 105 BlobCache::Value *valueOut); 106 107 // For querying the contents of the cache. 108 ANGLE_NO_DISCARD bool getAt(size_t index, 109 const BlobCache::Key **keyOut, 110 BlobCache::Value *valueOut); 111 112 // Evict a blob from the binary cache. 113 void remove(const BlobCache::Key &key); 114 115 // Empty the cache. 116 void clear() { mBlobCache.clear(); } 117 118 // Resize the cache. Discards current contents. 119 void resize(size_t maxCacheSizeBytes) { mBlobCache.resize(maxCacheSizeBytes); } 120 121 // Returns the number of entries in the cache. 122 size_t entryCount() const { return mBlobCache.entryCount(); } 123 124 // Reduces the current cache size and returns the number of bytes freed. 125 size_t trim(size_t limit) { return mBlobCache.shrinkToSize(limit); } 126 127 // Returns the current cache size in bytes. 128 size_t size() const { return mBlobCache.size(); } 129 130 // Returns whether the cache is empty 131 bool empty() const { return mBlobCache.empty(); } 132 133 // Returns the maximum cache size in bytes. 134 size_t maxSize() const { return mBlobCache.maxSize(); } 135 136 void setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get); 137 138 bool areBlobCacheFuncsSet() const; 139 140 bool isCachingEnabled() const { return areBlobCacheFuncsSet() || maxSize() > 0; } 141 142 private: 143 // This internal cache is used only if the application is not providing caching callbacks 144 using CacheEntry = std::pair<angle::MemoryBuffer, CacheSource>; 145 angle::SizedMRUCache<BlobCache::Key, CacheEntry> mBlobCache; 146 147 EGLSetBlobFuncANDROID mSetBlobFunc; 148 EGLGetBlobFuncANDROID mGetBlobFunc; 149 }; 150 151 } // namespace egl 152 153 #endif // LIBANGLE_MEMORY_PROGRAM_CACHE_H_ 154