• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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