1 // Copyright 2020 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef DAWNNATIVE_PERSISTENTCACHE_H_ 16 #define DAWNNATIVE_PERSISTENTCACHE_H_ 17 18 #include "dawn_native/Error.h" 19 20 #include <mutex> 21 #include <vector> 22 23 namespace dawn_platform { 24 class CachingInterface; 25 } 26 27 namespace dawn_native { 28 29 using PersistentCacheKey = std::vector<uint8_t>; 30 31 struct ScopedCachedBlob { 32 std::unique_ptr<uint8_t[]> buffer; 33 size_t bufferSize = 0; 34 }; 35 36 class DeviceBase; 37 38 enum class PersistentKeyType { Shader }; 39 40 // This class should always be thread-safe as it is used in Create*PipelineAsync() where it is 41 // called asynchronously. 42 // The thread-safety of any access to mCache (the function LoadData() and StoreData()) is 43 // protected by mMutex. 44 class PersistentCache { 45 public: 46 PersistentCache(DeviceBase* device); 47 48 // Combines load/store operations into a single call. 49 // If the load was successful, a non-empty blob is returned to the caller. 50 // Else, the creation callback |createFn| gets invoked with a callback 51 // |doCache| to store the newly created blob back in the cache. 52 // 53 // Example usage: 54 // 55 // ScopedCachedBlob cachedBlob = {}; 56 // DAWN_TRY_ASSIGN(cachedBlob, GetOrCreate(key, [&](auto doCache)) { 57 // // Create a new blob to be stored 58 // doCache(newBlobPtr, newBlobSize); // store 59 // })); 60 // 61 template <typename CreateFn> GetOrCreate(const PersistentCacheKey & key,CreateFn && createFn)62 ResultOrError<ScopedCachedBlob> GetOrCreate(const PersistentCacheKey& key, 63 CreateFn&& createFn) { 64 // Attempt to load an existing blob from the cache. 65 ScopedCachedBlob blob = LoadData(key); 66 if (blob.bufferSize > 0) { 67 return std::move(blob); 68 } 69 70 // Allow the caller to create a new blob to be stored for the given key. 71 DAWN_TRY(createFn([this, key](const void* value, size_t size) { 72 this->StoreData(key, value, size); 73 })); 74 75 return std::move(blob); 76 } 77 78 private: 79 // PersistentCache impl 80 ScopedCachedBlob LoadData(const PersistentCacheKey& key); 81 void StoreData(const PersistentCacheKey& key, const void* value, size_t size); 82 83 dawn_platform::CachingInterface* GetPlatformCache(); 84 85 DeviceBase* mDevice = nullptr; 86 87 std::mutex mMutex; 88 dawn_platform::CachingInterface* mCache = nullptr; 89 }; 90 } // namespace dawn_native 91 92 #endif // DAWNNATIVE_PERSISTENTCACHE_H_ 93