1 /* 2 * Copyright 2021 Google LLC 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef skgpu_graphite_PipelineDataCache_DEFINED 9 #define skgpu_graphite_PipelineDataCache_DEFINED 10 11 #include "src/base/SkArenaAlloc.h" 12 #include "src/core/SkTHash.h" 13 #include "src/gpu/graphite/PipelineData.h" 14 15 16 namespace skgpu::graphite { 17 18 // Add a block of data to the cache and return a stable pointer to the contents (assuming that a 19 // resettable gatherer had accumulated the input data pointer). 20 // 21 // If an identical block of data is already in the cache, that existing pointer is returned, making 22 // pointer comparison suitable when comparing data blocks retrieved from the cache. 23 // 24 // T must define a hash() function, an operator==, and a static Make(const T&, SkArenaAlloc*) 25 // factory that's used to copy the data into an arena allocation owned by the PipelineDataCache. 26 template<typename T> 27 class PipelineDataCache { 28 public: 29 PipelineDataCache() = default; 30 insert(const T & dataBlock)31 const T* insert(const T& dataBlock) { 32 DataRef data{&dataBlock}; // will not be persisted, since pointer isn't from the arena. 33 const DataRef* existing = fDataPointers.find(data); 34 if (existing) { 35 return existing->fPointer; 36 } else { 37 // Need to make a copy of dataBlock into the arena 38 T* copy = T::Make(dataBlock, &fArena); 39 fDataPointers.add(DataRef{copy}); 40 return copy; 41 } 42 } 43 44 // The number of unique T objects in the cache count()45 int count() const { 46 return fDataPointers.count(); 47 } 48 49 // Call fn on every item in the set. You may not mutate anything. 50 template <typename Fn> // f(T), f(const T&) foreach(Fn && fn)51 void foreach(Fn&& fn) const { 52 fDataPointers.foreach([fn](const DataRef& ref){ 53 fn(ref.fPointer); 54 }); 55 } 56 57 private: 58 struct DataRef { 59 const T* fPointer; 60 61 bool operator==(const DataRef& o) const { 62 if (!fPointer || !o.fPointer) { 63 return !fPointer && !o.fPointer; 64 } else { 65 return *fPointer == *o.fPointer; 66 } 67 } 68 }; 69 struct Hash { 70 // This hash operator de-references and hashes the data contents operatorHash71 size_t operator()(const DataRef& dataBlock) const { 72 return dataBlock.fPointer ? dataBlock.fPointer->hash() : 0; 73 } 74 }; 75 76 SkTHashSet<DataRef, Hash> fDataPointers; 77 // Holds the data that is pointed to by fDataPointers 78 SkArenaAlloc fArena{0}; 79 }; 80 81 // A UniformDataCache lives for the entire duration of a Recorder. 82 using UniformDataCache = PipelineDataCache<UniformDataBlock>; 83 84 // A TextureDataCache only lives for a single Recording. When a Recording is snapped it is pulled 85 // off of the Recorder and goes with the Recording as a record of the required Textures and 86 // Samplers. 87 using TextureDataCache = PipelineDataCache<TextureDataBlock>; 88 89 } // namespace skgpu::graphite 90 91 #endif // skgpu_graphite_PipelineDataCache_DEFINED 92