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