• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SkColor.h"
12 #include "include/core/SkSpan.h"
13 #include "include/core/SkTypes.h"
14 #include "include/private/base/SkMacros.h"
15 #include "include/private/base/SkTDArray.h"
16 #include "src/gpu/Blend.h"
17 #include "src/gpu/graphite/BuiltInCodeSnippetID.h"
18 
19 #include <array>
20 #include <limits>
21 
22 
23 namespace skgpu::graphite {
24 
25 class PaintParamsKeyBuilder;
26 class ShaderCodeDictionary;
27 class ShaderInfo;
28 struct ShaderSnippet;
29 
30 // This class is a compact representation of the shader needed to implement a given
31 // PaintParams. Its structure is a series of blocks where each block has a
32 // Header, consisting of 2 bytes:
33 //   4 bytes: code-snippet ID
34 //   1 byte: size of the block, in bytes (header, plus all data payload bytes)
35 // The rest of the data in the block is dependent on the individual code snippet.
36 // If a given block has child blocks, they appear in the key right after their parent
37 // block's header.
38 class PaintParamsKey {
39 public:
40     #pragma pack(push, 1)
41     struct Header {
42         int32_t codeSnippetID;
43         uint8_t blockSize;
44     };
45     #pragma pack(pop)
46 
47     static const int kBlockSizeOffsetInBytes = offsetof(Header, blockSize);
48     static const int kMaxBlockSize = std::numeric_limits<uint8_t>::max();
49 
50     enum class DataPayloadType {
51         kByte,
52         kInt,
53         kFloat4,
54     };
55 
56     // A given snippet's data payload is stored as an SkSpan of DataPayloadFields in the
57     // ShaderCodeDictionary. That span just defines the structure of the data payload. The actual
58     // data is stored in the paint params key.
59     struct DataPayloadField {
60         const char* fName;
61         DataPayloadType fType;
62         uint32_t fCount;
63     };
64 
65     ~PaintParamsKey();
66 
67     class BlockReader {
68     public:
69         // Returns the combined size of the header, all children, and every data payload.
blockSize()70         uint8_t blockSize() const {
71             SkASSERT(fBlock[kBlockSizeOffsetInBytes] == fBlock.size());
72             return SkTo<uint8_t>(fBlock.size());
73         }
74 
75         int numChildren() const;
76 
77         // Returns the code-snippet ID of this block.
78         int32_t codeSnippetId() const;
79 
80         // Return the childIndex-th child's BlockReader
81         BlockReader child(const ShaderCodeDictionary*, int childIndex) const;
82 
83         // Retrieve the fieldIndex-th field in the data payload as a span. The type being read
84         // is checked against the data payload's structure.
85         SkSpan<const uint8_t> bytes(int fieldIndex) const;
86         SkSpan<const int32_t> ints(int fieldIndex) const;
87         SkSpan<const SkColor4f> colors(int fieldIndex) const;
88 
entry()89         const ShaderSnippet* entry() const { return fEntry; }
90 
91 #ifdef SK_DEBUG
92         int numDataPayloadFields() const;
93         void dump(const ShaderCodeDictionary*, int indent) const;
94 #endif
95 
96     private:
97         friend class PaintParamsKey; // for ctor
98 
99         BlockReader(const ShaderCodeDictionary*,
100                     SkSpan<const uint8_t> parentSpan,
101                     int offsetInParent);
102 
103         // The data payload appears after any children and occupies the remainder of the
104         // block's space.
105         SkSpan<const uint8_t> dataPayload() const;
106 
107         SkSpan<const uint8_t> fBlock;
108         const ShaderSnippet* fEntry;
109     };
110 
111     BlockReader reader(const ShaderCodeDictionary*, int headerOffset) const;
112 
113 #ifdef SK_DEBUG
byte(int offset)114     uint8_t byte(int offset) const {
115         SkASSERT(offset < this->sizeInBytes());
116         return fData[offset];
117     }
118     void dump(const ShaderCodeDictionary*) const;
119 #endif
120     void toShaderInfo(const ShaderCodeDictionary*, ShaderInfo*) const;
121 
asSpan()122     SkSpan<const uint8_t> asSpan() const { return fData; }
data()123     const uint8_t* data() const { return fData.data(); }
sizeInBytes()124     int sizeInBytes() const { return SkTo<int>(fData.size()); }
125 
126     bool operator==(const PaintParamsKey& that) const;
127     bool operator!=(const PaintParamsKey& that) const { return !(*this == that); }
128 
129 #if GRAPHITE_TEST_UTILS
130     bool isErrorKey() const;
131 #endif
132 
133 private:
134     friend class PaintParamsKeyBuilder;   // for the parented-data ctor
135     friend class ShaderCodeDictionary;    // for the raw-data ctor
136 
137     // This ctor is to be used when paintparams keys are being consecutively generated
138     // by a key builder. The memory backing this key's span is shared between the
139     // builder and its keys.
140     PaintParamsKey(SkSpan<const uint8_t> span, PaintParamsKeyBuilder* originatingBuilder);
141 
142     // This ctor is used when this key isn't being created by a builder (i.e., when the key
143     // is in the dictionary). In this case the dictionary will own the memory backing the span.
144     PaintParamsKey(SkSpan<const uint8_t> rawData);
145 
146     static void AddBlockToShaderInfo(const ShaderCodeDictionary*,
147                                      const BlockReader&,
148                                      ShaderInfo*);
149 
150     // The memory referenced in 'fData' is always owned by someone else.
151     // If 'fOriginatingBuilder' is null, the dictionary's SkArena owns the 'fData' memory and no
152     // explicit freeing is required.
153     // If 'fOriginatingBuilder' is non-null then the 'fData' memory must be explicitly locked (in
154     // the ctor) and unlocked (in the dtor) on the 'fOriginatingBuilder' object.
155     SkSpan<const uint8_t> fData;
156 
157     // This class should only ever access the 'lock' and 'unlock' calls on 'fOriginatingBuilder'
158     PaintParamsKeyBuilder* fOriginatingBuilder;
159 };
160 
161 // The PaintParamsKeyBuilder and the PaintParamsKeys snapped from it share the same
162 // underlying block of memory. When an PaintParamsKey is snapped from the builder it 'locks'
163 // the memory and 'unlocks' it in its destructor. Because of this relationship, the builder
164 // can only have one extant key and that key must be destroyed before the builder can be reused
165 // to create another one.
166 //
167 // This arrangement is intended to improve performance in the expected case, where a builder is
168 // being used in a tight loop to generate keys which can be recycled once they've been used to
169 // find the dictionary's matching uniqueID. We don't expect the cost of copying the key's memory
170 // into the dictionary to be prohibitive since that should be infrequent.
171 class PaintParamsKeyBuilder {
172 public:
173     PaintParamsKeyBuilder(const ShaderCodeDictionary*);
~PaintParamsKeyBuilder()174     ~PaintParamsKeyBuilder() {
175         SkASSERT(!this->isLocked());
176     }
177 
setBlendInfo(const skgpu::BlendInfo & blendInfo)178     void setBlendInfo(const skgpu::BlendInfo& blendInfo) {
179         fBlendInfo = blendInfo;
180     }
blendInfo()181     const skgpu::BlendInfo& blendInfo() const { return fBlendInfo; }
182 
183     void beginBlock(int32_t codeSnippetID);
beginBlock(BuiltInCodeSnippetID id)184     void beginBlock(BuiltInCodeSnippetID id) { this->beginBlock(static_cast<int32_t>(id)); }
185     void endBlock();
186 
187     void addBytes(uint32_t numBytes, const uint8_t* data);
addByte(uint8_t data)188     void addByte(uint8_t data) {
189         this->addBytes(1, &data);
190     }
191     void addInts(uint32_t numInts, const int32_t* data);
addInt(int32_t data)192     void addInt(int32_t data) {
193         this->addInts(1, &data);
194     }
195     void add(int numColors, const SkColor4f* colors);
add(const SkColor4f & color)196     void add(const SkColor4f& color) {
197         this->add(/*numColors=*/1, &color);
198     }
199 
200 #ifdef SK_DEBUG
201     // Check that the builder has been reset to its initial state prior to creating a new key.
202     void checkReset();
byte(int offset)203     uint8_t byte(int offset) const { return fData[offset]; }
204 #endif
205 
206     PaintParamsKey lockAsKey();
207 
sizeInBytes()208     int sizeInBytes() const { return fData.size(); }
209 
isValid()210     bool isValid() const { return fIsValid; }
211 
lock()212     void lock() {
213         SkASSERT(!fLocked);
214         SkDEBUGCODE(fLocked = true;)
215     }
216 
unlock()217     void unlock() {
218         SkASSERT(fLocked);
219         fData.clear();
220         fBlendInfo = {};
221 
222         SkDEBUGCODE(fLocked = false;)
223         SkDEBUGCODE(this->checkReset();)
224     }
225 
226     SkDEBUGCODE(bool isLocked() const { return fLocked; })
227 
228 private:
229     void addToKey(uint32_t count, const void* data, PaintParamsKey::DataPayloadType payloadType);
230     void makeInvalid();
231 
232 #ifdef SK_DEBUG
233     void checkExpectations(PaintParamsKey::DataPayloadType actualType, uint32_t actualCount);
234 #endif
235 
236     // Information about the current block being written
237     struct StackFrame {
238         int fCodeSnippetID;
239         int fHeaderOffset;
240 #ifdef SK_DEBUG
241         SkSpan<const PaintParamsKey::DataPayloadField> fDataPayloadExpectations;
242         int fCurDataPayloadEntry = 0;
243         int fNumExpectedChildren = 0;
244         int fNumActualChildren = 0;
245 #endif
246     };
247 
248     const ShaderCodeDictionary* fDict;
249 
250     bool fIsValid = true;
251     SkDEBUGCODE(bool fLocked = false;)
252 
253     // Use SkTDArray so that we can guarantee that rewind() preserves the underlying storage and
254     // repeated use of the builder will hit a high-water mark and avoid lots of allocations.
255     SkTDArray<StackFrame> fStack;
256     SkTDArray<uint8_t> fData;
257     skgpu::BlendInfo fBlendInfo;
258 };
259 
260 } // skgpu::graphite
261 
262 #endif // skgpu_graphite_PaintParamsKey_DEFINED
263