Flutter Engine
The Flutter Engine
PaintParamsKey.h
Go to the documentation of this file.
1/*
2 * Copyright 2022 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_PaintParamsKey_DEFINED
9#define skgpu_graphite_PaintParamsKey_DEFINED
10
11#include "include/core/SkSpan.h"
15#include "src/core/SkChecksum.h"
17
18#include <limits>
19#include <cstring> // for memcmp
20
21class SkArenaAlloc;
23enum class SkTileMode;
24
25namespace skgpu::graphite {
26
27class Caps;
28class ShaderCodeDictionary;
29class ShaderNode;
30class TextureProxy;
31class UniquePaintParamsID;
32
33// This class is a compact representation of the shader needed to implement a given
34// PaintParams. Its structure is a series of nodes where each node consists of:
35// 4 bytes: code-snippet ID
36// N child nodes, where N is the constant number of children defined by the ShaderCodeDictionary
37// for the node's snippet ID.
38//
39// All children of a child node are stored in the key before the next child is encoded in the key,
40// e.g. iterating the data in a key is a depth-first traversal of the node tree.
42public:
43 // PaintParamsKey can only be created by using a PaintParamsKeyBuilder or by cloning the key
44 // data from a Builder-owned key, but they can be passed around by value after that.
45 constexpr PaintParamsKey(const PaintParamsKey&) = default;
46
47 ~PaintParamsKey() = default;
49
51 bool isValid() const { return !fData.empty(); }
52
53 // Return a PaintParamsKey whose data is owned by the provided arena and is not attached to
54 // a PaintParamsKeyBuilder. The caller must ensure that the SkArenaAlloc remains alive longer
55 // than the returned key.
57
58 // Converts the key into a forest of ShaderNode trees. If the key is valid this will return at
59 // least one root node. If the key contains unknown shader snippet IDs, returns an empty span.
60 // All shader nodes, and the returned span's backing data, are owned by the provided arena.
61 // TODO: Strengthen PaintParams key generation so we can assume there's only ever one root node
62 // representing the final blend (either a shader blend (with 2 children: main effect & dst) or
63 // a fixed function blend (with 1 child being the main effect)).
65
66 // Converts the key to a structured list of snippet information for debugging or labeling
67 // purposes.
68 SkString toString(const ShaderCodeDictionary* dict, bool includeData) const;
69
70#ifdef SK_DEBUG
72#endif
73
74 bool operator==(const PaintParamsKey& that) const {
75 return fData.size() == that.fData.size() &&
76 !memcmp(fData.data(), that.fData.data(), fData.size());
77 }
78 bool operator!=(const PaintParamsKey& that) const { return !(*this == that); }
79
80 struct Hash {
81 uint32_t operator()(const PaintParamsKey& k) const {
82 return SkChecksum::Hash32(k.fData.data(), k.fData.size_bytes());
83 }
84 };
85
86private:
87 friend class PaintParamsKeyBuilder; // for the parented-data ctor
88
89 constexpr PaintParamsKey(SkSpan<const uint32_t> span) : fData(span) {}
90
91 // Returns null if the node or any of its children have an invalid snippet ID. Recursively
92 // creates a node and all of its children, incrementing 'currentIndex' by the total number of
93 // nodes created.
94 const ShaderNode* createNode(const ShaderCodeDictionary*,
95 int* currentIndex,
96 SkArenaAlloc* arena) const;
97
98 // The memory referenced in 'fData' is always owned by someone else. It either shares the span
99 // from the Builder, or clone() puts the span in an arena.
101};
102
103// The PaintParamsKeyBuilder and the PaintParamsKeys snapped from it share the same
104// underlying block of memory. When an PaintParamsKey is snapped from the builder it 'locks'
105// the memory and 'unlocks' it in its destructor. Because of this relationship, the builder
106// can only have one extant key and that key must be destroyed before the builder can be reused
107// to create another one.
108//
109// This arrangement is intended to improve performance in the expected case, where a builder is
110// being used in a tight loop to generate keys which can be recycled once they've been used to
111// find the dictionary's matching uniqueID. We don't expect the cost of copying the key's memory
112// into the dictionary to be prohibitive since that should be infrequent.
114public:
116 SkDEBUGCODE(fDict = dict;)
117 }
118
120
121 void beginBlock(BuiltInCodeSnippetID id) { this->beginBlock(static_cast<int32_t>(id)); }
122 void beginBlock(int32_t codeSnippetID) {
123 SkASSERT(!fLocked);
124 SkDEBUGCODE(this->pushStack(codeSnippetID);)
125 fData.push_back(codeSnippetID);
126 }
127
128 // TODO: Have endBlock() be handled automatically with RAII, in which case we could have it
129 // validate the snippet ID being popped off the stack frame.
130 void endBlock() {
131 SkDEBUGCODE(this->popStack();)
132 }
133
134#ifdef SK_DEBUG
135 // Check that the builder has been reset to its initial state prior to creating a new key.
136 void checkReset();
137#endif
138
139 // Helper to add blocks that don't have children
141 this->beginBlock(id);
142 this->endBlock();
143 }
144
146 // First push the data size followed by the actual data.
147 fData.push_back(data.size());
148 fData.push_back_n(data.size(), data.begin());
149 }
150
151private:
152 friend class AutoLockBuilderAsKey; // for lockAsKey() and unlock()
153
154 // Returns a view of this builder as a PaintParamsKey. The Builder cannot be used until the
155 // returned Key goes out of scope.
156 PaintParamsKey lockAsKey() {
157 SkASSERT(!fLocked); // lockAsKey() is not re-entrant
158 SkASSERT(fStack.empty()); // All beginBlocks() had a matching endBlock()
159
160 SkDEBUGCODE(fLocked = true;)
161 return PaintParamsKey({fData.data(), fData.size()});
162 }
163
164 // Invalidates any PaintParamsKey returned by lockAsKey() unless it has been cloned.
165 void unlock() {
166 SkASSERT(fLocked);
167 fData.clear();
168
169 SkDEBUGCODE(fLocked = false;)
170 SkDEBUGCODE(fStack.clear();)
171 SkDEBUGCODE(this->checkReset();)
172 }
173
174 // The data array uses clear() on unlock so that it's underlying storage and repeated use of the
175 // builder will hit a high-water mark and avoid lots of allocations when recording draws.
176 skia_private::TArray<uint32_t> fData;
177
178#ifdef SK_DEBUG
179 void pushStack(int32_t codeSnippetID);
180 void popStack();
181
182 // Information about the current block being written
183 struct StackFrame {
184 int fCodeSnippetID;
185 int fNumExpectedChildren;
186 int fNumActualChildren = 0;
187 };
188
189 const ShaderCodeDictionary* fDict;
191 bool fLocked = false;
192#endif
193};
194
196public:
198 : fBuilder(builder)
199 , fKey(builder->lockAsKey()) {}
200
202 fBuilder->unlock();
203 }
204
205 // Use as a PaintParamsKey
206 const PaintParamsKey& operator*() const { return fKey; }
207 const PaintParamsKey* operator->() const { return &fKey; }
208
209private:
210 PaintParamsKeyBuilder* fBuilder;
211 PaintParamsKey fKey;
212};
213
214} // namespace skgpu::graphite
215
216#endif // skgpu_graphite_PaintParamsKey_DEFINED
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
SkTileMode
Definition: SkTileMode.h:13
static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv)
Definition: SkYUVMath.cpp:629
constexpr T * data() const
Definition: SkSpan_impl.h:94
constexpr bool empty() const
Definition: SkSpan_impl.h:96
constexpr size_t size_bytes() const
Definition: SkSpan_impl.h:97
constexpr size_t size() const
Definition: SkSpan_impl.h:95
const PaintParamsKey & operator*() const
AutoLockBuilderAsKey(PaintParamsKeyBuilder *builder)
const PaintParamsKey * operator->() const
void addBlock(BuiltInCodeSnippetID id)
void beginBlock(int32_t codeSnippetID)
void addData(SkSpan< const uint32_t > data)
PaintParamsKeyBuilder(const ShaderCodeDictionary *dict)
void beginBlock(BuiltInCodeSnippetID id)
constexpr PaintParamsKey(const PaintParamsKey &)=default
bool operator==(const PaintParamsKey &that) const
PaintParamsKey clone(SkArenaAlloc *) const
PaintParamsKey & operator=(const PaintParamsKey &)=default
SkString toString(const ShaderCodeDictionary *dict, bool includeData) const
static constexpr PaintParamsKey Invalid()
SkSpan< const ShaderNode * > getRootNodes(const ShaderCodeDictionary *, SkArenaAlloc *) const
bool operator!=(const PaintParamsKey &that) const
T * push_back_n(int n)
Definition: SkTArray.h:267
int size() const
Definition: SkTArray.h:421
uint32_t Hash32(const void *data, size_t bytes, uint32_t seed)
Definition: SkChecksum.cpp:113
uint32_t operator()(const PaintParamsKey &k) const
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63