/* * Copyright 2021 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef skgpu_graphite_PipelineDataCache_DEFINED #define skgpu_graphite_PipelineDataCache_DEFINED #include "src/base/SkArenaAlloc.h" #include "src/core/SkTHash.h" #include "src/gpu/graphite/PipelineData.h" namespace skgpu::graphite { // Add a block of data to the cache and return a stable pointer to the contents (assuming that a // resettable gatherer had accumulated the input data pointer). // // If an identical block of data is already in the cache, that existing pointer is returned, making // pointer comparison suitable when comparing data blocks retrieved from the cache. // // T must define a hash() function, an operator==, and a static Make(const T&, SkArenaAlloc*) // factory that's used to copy the data into an arena allocation owned by the PipelineDataCache. template class PipelineDataCache { public: PipelineDataCache() = default; const T* insert(const T& dataBlock) { DataRef data{&dataBlock}; // will not be persisted, since pointer isn't from the arena. const DataRef* existing = fDataPointers.find(data); if (existing) { return existing->fPointer; } else { // Need to make a copy of dataBlock into the arena T* copy = T::Make(dataBlock, &fArena); fDataPointers.add(DataRef{copy}); return copy; } } // The number of unique T objects in the cache int count() const { return fDataPointers.count(); } // Call fn on every item in the set. You may not mutate anything. template // f(T), f(const T&) void foreach(Fn&& fn) const { fDataPointers.foreach([fn](const DataRef& ref){ fn(ref.fPointer); }); } private: struct DataRef { const T* fPointer; bool operator==(const DataRef& o) const { if (!fPointer || !o.fPointer) { return !fPointer && !o.fPointer; } else { return *fPointer == *o.fPointer; } } }; struct Hash { // This hash operator de-references and hashes the data contents size_t operator()(const DataRef& dataBlock) const { return dataBlock.fPointer ? dataBlock.fPointer->hash() : 0; } }; skia_private::THashSet fDataPointers; // Holds the data that is pointed to by fDataPointers SkArenaAlloc fArena{0}; }; // A UniformDataCache only lives for a single Recording. It's used to deduplicate uniform data // blocks uploaded to uniform/storage buffers for a DrawPass pipeline. using UniformDataCache = PipelineDataCache; // A TextureDataCache only lives for a single Recording. When a Recording is snapped it is pulled // off of the Recorder and goes with the Recording as a record of the required Textures and // Samplers. using TextureDataCache = PipelineDataCache; } // namespace skgpu::graphite #endif // skgpu_graphite_PipelineDataCache_DEFINED