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 "common/SimpleMutex.h" 17 #include "libANGLE/Error.h" 18 #include "libANGLE/SizedMRUCache.h" 19 #include "libANGLE/angletypes.h" 20 21 namespace gl 22 { 23 class Context; 24 } // namespace gl 25 26 namespace egl 27 { 28 29 // Used by MemoryProgramCache and MemoryShaderCache, this result indicates whether program/shader 30 // cache load from blob was successful. 31 enum class CacheGetResult 32 { 33 // Binary blob was found and is valid 34 Success, 35 // Binary blob was not found 36 NotFound, 37 // Binary blob was found, but was rejected due to errors (corruption, version mismatch, etc) 38 Rejected, 39 }; 40 41 class BlobCache final : angle::NonCopyable 42 { 43 public: 44 // 160-bit SHA-1 hash key used for hasing a program. BlobCache opts in using fixed keys for 45 // simplicity and efficiency. 46 static constexpr size_t kKeyLength = angle::kBlobCacheKeyLength; 47 using Key = angle::BlobCacheKey; 48 using Value = angle::BlobCacheValue; 49 enum class CacheSource 50 { 51 Memory, 52 Disk, 53 }; 54 55 explicit BlobCache(size_t maxCacheSizeBytes); 56 ~BlobCache(); 57 58 // Store a key-blob pair in the cache. If application callbacks are set, the application cache 59 // will be used. Otherwise the value is cached in this object. 60 void put(const gl::Context *context, const BlobCache::Key &key, angle::MemoryBuffer &&value); 61 62 // Store a key-blob pair in the cache, but compress the blob before insertion. Returns false if 63 // compression fails, returns true otherwise. 64 bool compressAndPut(const gl::Context *context, 65 const BlobCache::Key &key, 66 angle::MemoryBuffer &&uncompressedValue, 67 size_t *compressedSize); 68 69 // Store a key-blob pair in the application cache, only if application callbacks are set. 70 void putApplication(const gl::Context *context, 71 const BlobCache::Key &key, 72 const angle::MemoryBuffer &value); 73 74 // Store a key-blob pair in the cache without making callbacks to the application. This is used 75 // to repopulate this object's cache on startup without generating callback calls. 76 void populate(const BlobCache::Key &key, 77 angle::MemoryBuffer &&value, 78 CacheSource source = CacheSource::Disk); 79 80 // Check if the cache contains the blob corresponding to this key. If application callbacks are 81 // set, those will be used. Otherwise they key is looked up in this object's cache. 82 [[nodiscard]] bool get(const gl::Context *context, 83 angle::ScratchBuffer *scratchBuffer, 84 const BlobCache::Key &key, 85 BlobCache::Value *valueOut); 86 87 // For querying the contents of the cache. 88 [[nodiscard]] bool getAt(size_t index, 89 const BlobCache::Key **keyOut, 90 BlobCache::Value *valueOut); 91 92 enum class GetAndDecompressResult 93 { 94 Success, 95 NotFound, 96 DecompressFailure, 97 }; 98 [[nodiscard]] GetAndDecompressResult getAndDecompress( 99 const gl::Context *context, 100 angle::ScratchBuffer *scratchBuffer, 101 const BlobCache::Key &key, 102 size_t maxUncompressedDataSize, 103 angle::MemoryBuffer *uncompressedValueOut); 104 105 // Evict a blob from the binary cache. 106 void remove(const BlobCache::Key &key); 107 108 // Empty the cache. clear()109 void clear() { mBlobCache.clear(); } 110 111 // Resize the cache. Discards current contents. resize(size_t maxCacheSizeBytes)112 void resize(size_t maxCacheSizeBytes) { mBlobCache.resize(maxCacheSizeBytes); } 113 114 // Returns the number of entries in the cache. entryCount()115 size_t entryCount() const { return mBlobCache.entryCount(); } 116 117 // Reduces the current cache size and returns the number of bytes freed. trim(size_t limit)118 size_t trim(size_t limit) { return mBlobCache.shrinkToSize(limit); } 119 120 // Returns the current cache size in bytes. size()121 size_t size() const { return mBlobCache.size(); } 122 123 // Returns whether the cache is empty empty()124 bool empty() const { return mBlobCache.empty(); } 125 126 // Returns the maximum cache size in bytes. maxSize()127 size_t maxSize() const { return mBlobCache.maxSize(); } 128 129 void setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get); 130 131 bool areBlobCacheFuncsSet() const; 132 133 bool isCachingEnabled(const gl::Context *context) const; 134 getMutex()135 angle::SimpleMutex &getMutex() { return mBlobCacheMutex; } 136 137 private: 138 size_t callBlobGetCallback(const gl::Context *context, 139 const void *key, 140 size_t keySize, 141 void *value, 142 size_t valueSize); 143 144 // This internal cache is used only if the application is not providing caching callbacks 145 using CacheEntry = std::pair<angle::MemoryBuffer, CacheSource>; 146 147 mutable angle::SimpleMutex mBlobCacheMutex; 148 angle::SizedMRUCache<BlobCache::Key, CacheEntry> mBlobCache; 149 150 EGLSetBlobFuncANDROID mSetBlobFunc; 151 EGLGetBlobFuncANDROID mGetBlobFunc; 152 }; 153 154 } // namespace egl 155 156 #endif // LIBANGLE_MEMORY_PROGRAM_CACHE_H_ 157