Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
ShaderCodeDictionary.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_ShaderCodeDictionary_DEFINED
9#define skgpu_graphite_ShaderCodeDictionary_DEFINED
10
12#include "include/core/SkSpan.h"
20#include "src/base/SkSpinlock.h"
22#include "src/core/SkTHash.h"
23#include "src/gpu/Blend.h"
28
29#include <array>
30#include <cstddef>
31#include <cstdint>
32#include <memory>
33#include <string>
34#include <string_view>
35
36class SkRuntimeEffect;
37
38namespace skgpu {
39class Swizzle;
40}
41
42namespace skgpu::graphite {
43
44class Caps;
45class RenderStep;
46class RuntimeEffectDictionary;
47
48// TODO: How to represent the type (e.g., 2D) of texture being sampled?
50public:
51 constexpr TextureAndSampler(const char* name) : fName(name) {}
52
53 const char* name() const { return fName; }
54
55private:
56 const char* fName;
57};
58
59enum class SnippetRequirementFlags : uint32_t {
60 kNone = 0x0,
61 kLocalCoords = 0x1,
62 kPriorStageOutput = 0x2, // AKA the "input" color, or the "src" argument for a blender
63 kBlenderDstColor = 0x4, // The "dst" argument for a blender
64 kSurfaceColor = 0x8,
65};
67
68class ShaderInfo;
69class ShaderNode;
70
71// ShaderSnippets define the "ABI" of a SkSL module function and its required uniform data, as
72// well as functions for generating the invoking SkSL. Snippets are composed into an effect tree
73// using ShaderNodes.
75 using GeneratePreambleForSnippetFn = std::string (*)(const ShaderInfo& shaderInfo,
76 const ShaderNode*);
77 struct Args {
78 std::string fPriorStageOutput;
79 std::string fBlenderDstColor;
80 std::string fFragCoord;
81 };
82 using GenerateExpressionForSnippetFn = std::string (*)(const ShaderInfo& shaderInfo,
83 const ShaderNode*,
84 const Args& args);
85
86 ShaderSnippet() = default;
87
88 ShaderSnippet(const char* name,
89 SkSpan<const Uniform> uniforms,
90 SkEnumBitMask<SnippetRequirementFlags> snippetRequirementFlags,
91 SkSpan<const TextureAndSampler> texturesAndSamplers,
92 const char* functionName,
93 GenerateExpressionForSnippetFn expressionGenerator,
94 GeneratePreambleForSnippetFn preambleGenerator,
95 int numChildren)
96 : fName(name)
97 , fUniforms(uniforms)
98 , fSnippetRequirementFlags(snippetRequirementFlags)
99 , fTexturesAndSamplers(texturesAndSamplers)
100 , fStaticFunctionName(functionName)
101 , fExpressionGenerator(expressionGenerator)
102 , fPreambleGenerator(preambleGenerator)
103 , fNumChildren(numChildren) {}
104
114
115 const char* fName = nullptr;
119 const char* fStaticFunctionName = nullptr;
123};
124
125// ShaderNodes organize snippets into an effect tree, and provide random access to the dynamically
126// bound child snippets. Each node has a fixed number of children defined by its code ID
127// (either a BuiltInCodeSnippetID or a runtime effect's assigned ID). All children are non-null.
128// A ShaderNode tree represents a decompressed PaintParamsKey.
130public:
131 // ShaderNodes should be created in conjunction with an SkArenaAlloc that owns all nodes.
132 ShaderNode(const ShaderSnippet* snippet,
134 int codeID,
135 int keyIndex)
136 : fEntry(snippet)
137 , fChildren(children)
138 , fCodeID(codeID)
139 , fKeyIndex(keyIndex)
140 , fRequiredFlags(snippet->fSnippetRequirementFlags) {
141 SkASSERT(children.size() == (size_t) fEntry->fNumChildren);
142 // TODO: RuntimeEffects can actually mask off requirements if they invoke a child with
143 // explicit arguments.
144 for (const ShaderNode* child : children) {
145 fRequiredFlags |= child->requiredFlags();
146 }
147 }
148
149 int32_t codeSnippetId() const { return fCodeID; }
150 int32_t keyIndex() const { return fKeyIndex; }
151 const ShaderSnippet* entry() const { return fEntry; }
152
153 SkEnumBitMask<SnippetRequirementFlags> requiredFlags() const { return fRequiredFlags; }
154
155 int numChildren() const { return fEntry->fNumChildren; }
156 SkSpan<const ShaderNode*> children() const { return fChildren; }
157 const ShaderNode* child(int childIndex) const { return fChildren[childIndex]; }
158
159private:
160 const ShaderSnippet* fEntry; // Owned by the ShaderCodeDictionary
161 SkSpan<const ShaderNode*> fChildren; // Owned by the ShaderInfo's arena
162
163 int32_t fCodeID;
164 int32_t fKeyIndex; // index back to PaintParamsKey, unique across nodes within a ShaderInfo
165
167};
168
169// ShaderInfo holds all root ShaderNodes defined for a PaintParams as well as the extracted fixed
170// function blending parameters and other aggregate requirements for the effect trees that have
171// been linked into a single fragment program (sans any RenderStep fragment work and fixed SkSL
172// logic required for all rendering in Graphite).
173class ShaderInfo {
174public:
176 const ShaderCodeDictionary* dict,
177 const RuntimeEffectDictionary* rteDict,
178 const char* ssboIndex);
179
180 bool needsLocalCoords() const {
181 return SkToBool(fSnippetRequirementFlags & SnippetRequirementFlags::kLocalCoords);
182 }
183 bool needsSurfaceColor() const {
184 return SkToBool(fSnippetRequirementFlags & SnippetRequirementFlags::kSurfaceColor);
185 }
187 return fRuntimeEffectDictionary;
188 }
189 const char* ssboIndex() const { return fSsboIndex; }
190
191 const skgpu::BlendInfo& blendInfo() const { return fBlendInfo; }
192
193 std::string toSkSL(const Caps* caps,
194 const RenderStep* step,
195 bool useStorageBuffers,
196 int* numTexturesAndSamplersUsed,
197 int* numPaintUniforms,
198 int* renderStepUniformTotalBytes,
199 int* paintUniformsTotalBytes,
200 Swizzle writeSwizzle);
201
202private:
203 // All shader nodes and arrays of children pointers are held in this arena
204 SkArenaAlloc fShaderNodeAlloc{256};
205
206 const RuntimeEffectDictionary* fRuntimeEffectDictionary;
207 const char* fSsboIndex;
208
209 // De-compressed shader tree from a PaintParamsKey with accumulated blend info and requirements.
210 // The blendInfo doesn't contribute to the program's SkSL but contains the fixed-function state
211 // required to function correctly, which the program's caller is responsible for configuring.
212 // TODO: There should really only be one root node representing the final blend, which has a
213 // child defining how the src color is calculated.
214 SkSpan<const ShaderNode*> fRootNodes;
216 skgpu::BlendInfo fBlendInfo;
217 SkEnumBitMask<SnippetRequirementFlags> fSnippetRequirementFlags;
218};
219
220// ShaderCodeDictionary is a thread-safe dictionary of ShaderSnippets to code IDs for use with
221// creating PaintParamKeys, as well as assigning unique IDs to each encountered PaintParamKey.
222// It defines ShaderSnippets for every BuiltInCodeSnippetID and maintains records for IDs per
223// SkRuntimeEffect, including de-duplicating equivalent SkRuntimeEffect objects.
225public:
227
229
231
233 return this->lookup(id).toString(this);
234 }
235
238 BuiltInCodeSnippetID id) const {
239 return fBuiltInCodeSnippets[(int) id].fSnippetRequirementFlags;
240 }
241
242#if defined(SK_DEBUG)
243 bool isValidID(int snippetID) const SK_EXCLUDES(fSpinLock);
244#endif
245
246 // This method can return nullptr
247 const ShaderSnippet* getEntry(int codeSnippetID) const SK_EXCLUDES(fSpinLock);
248 const ShaderSnippet* getEntry(BuiltInCodeSnippetID codeSnippetID) const SK_EXCLUDES(fSpinLock) {
249 return this->getEntry(SkTo<int>(codeSnippetID));
250 }
251
253
254#if defined(GRAPHITE_TEST_UTILS)
255 int addRuntimeEffectSnippet(const char* name) SK_EXCLUDES(fSpinLock);
256#endif
257
258private:
259 const char* addTextToArena(std::string_view text);
260
261 SkSpan<const Uniform> convertUniforms(const SkRuntimeEffect* effect);
262
263 std::array<ShaderSnippet, kBuiltInCodeSnippetIDCount> fBuiltInCodeSnippets;
264
265 using KnownRuntimeEffectArray = std::array<ShaderSnippet, SkKnownRuntimeEffects::kStableKeyCnt>;
266 KnownRuntimeEffectArray fKnownRuntimeEffectCodeSnippets SK_GUARDED_BY(fSpinLock);
267
268 // The value returned from 'getEntry' must be stable so, hold the user-defined code snippet
269 // entries as pointers.
270 using RuntimeEffectArray = skia_private::TArray<std::unique_ptr<ShaderSnippet>>;
271 RuntimeEffectArray fUserDefinedCodeSnippets SK_GUARDED_BY(fSpinLock);
272
273 // TODO: can we do something better given this should have write-seldom/read-often behavior?
274 mutable SkSpinlock fSpinLock;
275
276 using PaintIDMap = skia_private::THashMap<PaintParamsKey,
279
280 PaintIDMap fPaintKeyToID SK_GUARDED_BY(fSpinLock);
282
284 struct RuntimeEffectKey {
285 uint32_t fHash;
286 uint32_t fUniformSize;
287
288 bool operator==(RuntimeEffectKey rhs) const {
289 return fHash == rhs.fHash && fUniformSize == rhs.fUniformSize;
290 }
291 };
293
294 // A map from RuntimeEffectKeys (hash plus uniforms) to code-snippet IDs. RuntimeEffectKeys
295 // don't track the lifetime of a runtime effect at all; they live forever, and a newly-
296 // instantiated runtime effect with the same program as a previously-discarded effect will reuse
297 // an existing ID. Entries in the runtime-effect map are never removed; they only disappear when
298 // the context is discarded, which takes the ShaderCodeDictionary along with it. However, they
299 // are extremely small (< 20 bytes) so the memory footprint should be unnoticeable.
301 RuntimeEffectMap fRuntimeEffectMap SK_GUARDED_BY(fSpinLock);
302
303 // This arena holds:
304 // - the backing data for PaintParamsKeys in `fPaintKeyToID` and `fIDToPaintKey`
305 // - Uniform data created by `findOrCreateRuntimeEffectSnippet`
306 // and in all cases is guarded by `fSpinLock`
307 SkArenaAlloc fArena{256};
308};
309
310} // namespace skgpu::graphite
311
312#endif // skgpu_graphite_ShaderCodeDictionary_DEFINED
static int step(int x, SkScalar min, SkScalar max)
Definition BlurTest.cpp:215
SkBlendMode fBlendMode
Definition Layer.cpp:55
#define SkASSERT(cond)
Definition SkAssert.h:116
SkBlendMode
Definition SkBlendMode.h:38
@ kClear
r = 0
#define SK_MAKE_BITMASK_OPS(E)
#define SK_BEGIN_REQUIRE_DENSE
Definition SkMacros.h:37
#define SK_END_REQUIRE_DENSE
Definition SkMacros.h:38
#define SK_EXCLUDES(...)
#define SK_GUARDED_BY(x)
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
Type::kYUV Type::kRGBA() int(0.7 *637)
SkString toString(const ShaderCodeDictionary *dict) const
PaintParamsKey lookup(UniquePaintParamsID) const SK_EXCLUDES(fSpinLock)
SkEnumBitMask< SnippetRequirementFlags > getSnippetRequirementFlags(BuiltInCodeSnippetID id) const
UniquePaintParamsID findOrCreate(PaintParamsKeyBuilder *) SK_EXCLUDES(fSpinLock)
const ShaderSnippet * getEntry(BuiltInCodeSnippetID codeSnippetID) const SK_EXCLUDES(fSpinLock)
int findOrCreateRuntimeEffectSnippet(const SkRuntimeEffect *effect)
SkSpan< const Uniform > getUniforms(BuiltInCodeSnippetID) const
const ShaderSnippet * getEntry(int codeSnippetID) const SK_EXCLUDES(fSpinLock)
SkString idToString(UniquePaintParamsID id) const
ShaderInfo(UniquePaintParamsID id, const ShaderCodeDictionary *dict, const RuntimeEffectDictionary *rteDict, const char *ssboIndex)
const skgpu::BlendInfo & blendInfo() const
const RuntimeEffectDictionary * runtimeEffectDictionary() const
const ShaderNode * child(int childIndex) const
const ShaderSnippet * entry() const
ShaderNode(const ShaderSnippet *snippet, SkSpan< const ShaderNode * > children, int codeID, int keyIndex)
SkSpan< const ShaderNode * > children() const
SkEnumBitMask< SnippetRequirementFlags > requiredFlags() const
constexpr TextureAndSampler(const char *name)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const char * name
Definition fuchsia.cc:50
std::u16string text
std::string(*)(const ShaderInfo &shaderInfo, const ShaderNode *) GeneratePreambleForSnippetFn
SkEnumBitMask< SnippetRequirementFlags > fSnippetRequirementFlags
GeneratePreambleForSnippetFn fPreambleGenerator
std::string(*)(const ShaderInfo &shaderInfo, const ShaderNode *, const Args &args) GenerateExpressionForSnippetFn
GenerateExpressionForSnippetFn fExpressionGenerator
SkSpan< const TextureAndSampler > fTexturesAndSamplers
ShaderSnippet(const char *name, SkSpan< const Uniform > uniforms, SkEnumBitMask< SnippetRequirementFlags > snippetRequirementFlags, SkSpan< const TextureAndSampler > texturesAndSamplers, const char *functionName, GenerateExpressionForSnippetFn expressionGenerator, GeneratePreambleForSnippetFn preambleGenerator, int numChildren)