xref: /aosp_15_r20/external/skia/src/gpu/graphite/ShaderCodeDictionary.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2022 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef skgpu_graphite_ShaderCodeDictionary_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define skgpu_graphite_ShaderCodeDictionary_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSpan.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkEnumBitMask.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkSpinlock.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkKnownRuntimeEffects.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTHash.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/BuiltInCodeSnippetID.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PaintParamsKey.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceTypes.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Uniform.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/UniquePaintParamsID.h"
23*c8dee2aaSAndroid Build Coastguard Worker 
24*c8dee2aaSAndroid Build Coastguard Worker #include <array>
25*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
26*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
27*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
28*c8dee2aaSAndroid Build Coastguard Worker #include <string>
29*c8dee2aaSAndroid Build Coastguard Worker #include <string_view>
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker class SkRuntimeEffect;
32*c8dee2aaSAndroid Build Coastguard Worker 
33*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
34*c8dee2aaSAndroid Build Coastguard Worker 
35*c8dee2aaSAndroid Build Coastguard Worker // TODO: How to represent the type (e.g., 2D) of texture being sampled?
36*c8dee2aaSAndroid Build Coastguard Worker class TextureAndSampler {
37*c8dee2aaSAndroid Build Coastguard Worker public:
TextureAndSampler(const char * name)38*c8dee2aaSAndroid Build Coastguard Worker     constexpr TextureAndSampler(const char* name) : fName(name) {}
39*c8dee2aaSAndroid Build Coastguard Worker 
name()40*c8dee2aaSAndroid Build Coastguard Worker     const char* name() const { return fName; }
41*c8dee2aaSAndroid Build Coastguard Worker 
42*c8dee2aaSAndroid Build Coastguard Worker private:
43*c8dee2aaSAndroid Build Coastguard Worker     const char* fName;
44*c8dee2aaSAndroid Build Coastguard Worker };
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker enum class SnippetRequirementFlags : uint32_t {
47*c8dee2aaSAndroid Build Coastguard Worker     kNone             = 0x0,
48*c8dee2aaSAndroid Build Coastguard Worker     // Signature of the ShaderNode
49*c8dee2aaSAndroid Build Coastguard Worker     kLocalCoords      = 0x1,
50*c8dee2aaSAndroid Build Coastguard Worker     kPriorStageOutput = 0x2,  // AKA the "input" color, or the "src" argument for a blender
51*c8dee2aaSAndroid Build Coastguard Worker     kBlenderDstColor  = 0x4,  // The "dst" argument for a blender
52*c8dee2aaSAndroid Build Coastguard Worker     // Special values and/or behaviors required for the snippet
53*c8dee2aaSAndroid Build Coastguard Worker     kPrimitiveColor   = 0x8,
54*c8dee2aaSAndroid Build Coastguard Worker     kGradientBuffer   = 0x10,
55*c8dee2aaSAndroid Build Coastguard Worker     kStoresData       = 0x20, // Indicates that the node stores numerical data
56*c8dee2aaSAndroid Build Coastguard Worker };
57*c8dee2aaSAndroid Build Coastguard Worker SK_MAKE_BITMASK_OPS(SnippetRequirementFlags)
58*c8dee2aaSAndroid Build Coastguard Worker 
59*c8dee2aaSAndroid Build Coastguard Worker class ShaderInfo;
60*c8dee2aaSAndroid Build Coastguard Worker class ShaderNode;
61*c8dee2aaSAndroid Build Coastguard Worker 
62*c8dee2aaSAndroid Build Coastguard Worker // ShaderSnippets define the "ABI" of a SkSL module function and its required uniform data, as
63*c8dee2aaSAndroid Build Coastguard Worker // well as functions for generating the invoking SkSL. Snippets are composed into an effect tree
64*c8dee2aaSAndroid Build Coastguard Worker // using ShaderNodes.
65*c8dee2aaSAndroid Build Coastguard Worker struct ShaderSnippet {
66*c8dee2aaSAndroid Build Coastguard Worker     using GeneratePreambleForSnippetFn = std::string (*)(const ShaderInfo& shaderInfo,
67*c8dee2aaSAndroid Build Coastguard Worker                                                          const ShaderNode*);
68*c8dee2aaSAndroid Build Coastguard Worker     struct Args {
69*c8dee2aaSAndroid Build Coastguard Worker         std::string fPriorStageOutput;
70*c8dee2aaSAndroid Build Coastguard Worker         std::string fBlenderDstColor;
71*c8dee2aaSAndroid Build Coastguard Worker         std::string fFragCoord;
72*c8dee2aaSAndroid Build Coastguard Worker     };
73*c8dee2aaSAndroid Build Coastguard Worker 
74*c8dee2aaSAndroid Build Coastguard Worker     static const Args kDefaultArgs;
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker     ShaderSnippet() = default;
77*c8dee2aaSAndroid Build Coastguard Worker 
78*c8dee2aaSAndroid Build Coastguard Worker     ShaderSnippet(const char* name,
79*c8dee2aaSAndroid Build Coastguard Worker                   const char* staticFn,
80*c8dee2aaSAndroid Build Coastguard Worker                   SkEnumBitMask<SnippetRequirementFlags> snippetRequirementFlags,
81*c8dee2aaSAndroid Build Coastguard Worker                   SkSpan<const Uniform> uniforms,
82*c8dee2aaSAndroid Build Coastguard Worker                   SkSpan<const TextureAndSampler> texturesAndSamplers = {},
83*c8dee2aaSAndroid Build Coastguard Worker                   GeneratePreambleForSnippetFn preambleGenerator = nullptr,
84*c8dee2aaSAndroid Build Coastguard Worker                   int numChildren = 0)
fNameShaderSnippet85*c8dee2aaSAndroid Build Coastguard Worker             : fName(name)
86*c8dee2aaSAndroid Build Coastguard Worker             , fStaticFunctionName(staticFn)
87*c8dee2aaSAndroid Build Coastguard Worker             , fSnippetRequirementFlags(snippetRequirementFlags)
88*c8dee2aaSAndroid Build Coastguard Worker             , fUniforms(uniforms)
89*c8dee2aaSAndroid Build Coastguard Worker             , fTexturesAndSamplers(texturesAndSamplers)
90*c8dee2aaSAndroid Build Coastguard Worker             , fNumChildren(numChildren)
91*c8dee2aaSAndroid Build Coastguard Worker             , fPreambleGenerator(preambleGenerator) {
92*c8dee2aaSAndroid Build Coastguard Worker         // Must always provide a name; static function is not optional if using the default (null)
93*c8dee2aaSAndroid Build Coastguard Worker         // generation logic.
94*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(name);
95*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(staticFn || preambleGenerator);
96*c8dee2aaSAndroid Build Coastguard Worker     }
97*c8dee2aaSAndroid Build Coastguard Worker 
needsLocalCoordsShaderSnippet98*c8dee2aaSAndroid Build Coastguard Worker     bool needsLocalCoords() const {
99*c8dee2aaSAndroid Build Coastguard Worker         return SkToBool(fSnippetRequirementFlags & SnippetRequirementFlags::kLocalCoords);
100*c8dee2aaSAndroid Build Coastguard Worker     }
needsPriorStageOutputShaderSnippet101*c8dee2aaSAndroid Build Coastguard Worker     bool needsPriorStageOutput() const {
102*c8dee2aaSAndroid Build Coastguard Worker         return SkToBool(fSnippetRequirementFlags & SnippetRequirementFlags::kPriorStageOutput);
103*c8dee2aaSAndroid Build Coastguard Worker     }
needsBlenderDstColorShaderSnippet104*c8dee2aaSAndroid Build Coastguard Worker     bool needsBlenderDstColor() const {
105*c8dee2aaSAndroid Build Coastguard Worker         return SkToBool(fSnippetRequirementFlags & SnippetRequirementFlags::kBlenderDstColor);
106*c8dee2aaSAndroid Build Coastguard Worker     }
storesDataShaderSnippet107*c8dee2aaSAndroid Build Coastguard Worker     bool storesData() const {
108*c8dee2aaSAndroid Build Coastguard Worker         return SkToBool(fSnippetRequirementFlags & SnippetRequirementFlags::kStoresData);
109*c8dee2aaSAndroid Build Coastguard Worker     }
110*c8dee2aaSAndroid Build Coastguard Worker 
111*c8dee2aaSAndroid Build Coastguard Worker     const char* fName = nullptr;
112*c8dee2aaSAndroid Build Coastguard Worker     const char* fStaticFunctionName = nullptr;
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker     // The features and args that this shader snippet requires in order to be invoked
115*c8dee2aaSAndroid Build Coastguard Worker     SkEnumBitMask<SnippetRequirementFlags> fSnippetRequirementFlags{SnippetRequirementFlags::kNone};
116*c8dee2aaSAndroid Build Coastguard Worker 
117*c8dee2aaSAndroid Build Coastguard Worker     // If not null, the list of uniforms in `fUniforms` describes an existing struct type declared
118*c8dee2aaSAndroid Build Coastguard Worker     // in the Graphite modules with the given name. Instead of inlining the each uniform in the
119*c8dee2aaSAndroid Build Coastguard Worker     // top-level interface block or aggregate struct, there will be a single member of this struct's
120*c8dee2aaSAndroid Build Coastguard Worker     // type.
121*c8dee2aaSAndroid Build Coastguard Worker     const char* fUniformStructName = nullptr;
122*c8dee2aaSAndroid Build Coastguard Worker     // If the uniforms are being embedded as a sub-struct, this is the required starting alignment.
123*c8dee2aaSAndroid Build Coastguard Worker     int fRequiredAlignment = -1;
124*c8dee2aaSAndroid Build Coastguard Worker 
125*c8dee2aaSAndroid Build Coastguard Worker     skia_private::TArray<Uniform> fUniforms;
126*c8dee2aaSAndroid Build Coastguard Worker     skia_private::TArray<TextureAndSampler> fTexturesAndSamplers;
127*c8dee2aaSAndroid Build Coastguard Worker 
128*c8dee2aaSAndroid Build Coastguard Worker     int fNumChildren = 0;
129*c8dee2aaSAndroid Build Coastguard Worker     GeneratePreambleForSnippetFn fPreambleGenerator = nullptr;
130*c8dee2aaSAndroid Build Coastguard Worker };
131*c8dee2aaSAndroid Build Coastguard Worker 
132*c8dee2aaSAndroid Build Coastguard Worker // ShaderNodes organize snippets into an effect tree, and provide random access to the dynamically
133*c8dee2aaSAndroid Build Coastguard Worker // bound child snippets. Each node has a fixed number of children defined by its code ID
134*c8dee2aaSAndroid Build Coastguard Worker // (either a BuiltInCodeSnippetID or a runtime effect's assigned ID). All children are non-null.
135*c8dee2aaSAndroid Build Coastguard Worker // A ShaderNode tree represents a decompressed PaintParamsKey.
136*c8dee2aaSAndroid Build Coastguard Worker class ShaderNode {
137*c8dee2aaSAndroid Build Coastguard Worker public:
138*c8dee2aaSAndroid Build Coastguard Worker     // ShaderNodes should be created in conjunction with an SkArenaAlloc that owns all nodes.
ShaderNode(const ShaderSnippet * snippet,SkSpan<const ShaderNode * > children,int codeID,int keyIndex,SkSpan<const uint32_t> data)139*c8dee2aaSAndroid Build Coastguard Worker     ShaderNode(const ShaderSnippet* snippet,
140*c8dee2aaSAndroid Build Coastguard Worker                SkSpan<const ShaderNode*> children,
141*c8dee2aaSAndroid Build Coastguard Worker                int codeID,
142*c8dee2aaSAndroid Build Coastguard Worker                int keyIndex,
143*c8dee2aaSAndroid Build Coastguard Worker                SkSpan<const uint32_t> data)
144*c8dee2aaSAndroid Build Coastguard Worker             : fEntry(snippet)
145*c8dee2aaSAndroid Build Coastguard Worker             , fChildren(children)
146*c8dee2aaSAndroid Build Coastguard Worker             , fCodeID(codeID)
147*c8dee2aaSAndroid Build Coastguard Worker             , fKeyIndex(keyIndex)
148*c8dee2aaSAndroid Build Coastguard Worker             , fRequiredFlags(snippet->fSnippetRequirementFlags)
149*c8dee2aaSAndroid Build Coastguard Worker             , fData(data) {
150*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(children.size() == (size_t) fEntry->fNumChildren);
151*c8dee2aaSAndroid Build Coastguard Worker 
152*c8dee2aaSAndroid Build Coastguard Worker         const bool isCompose = codeID == (int) BuiltInCodeSnippetID::kCompose ||
153*c8dee2aaSAndroid Build Coastguard Worker                                codeID == (int) BuiltInCodeSnippetID::kBlendCompose;
154*c8dee2aaSAndroid Build Coastguard Worker         for (const ShaderNode* child : children) {
155*c8dee2aaSAndroid Build Coastguard Worker             // Runtime effects invoke children with explicit parameters so those requirements never
156*c8dee2aaSAndroid Build Coastguard Worker             // need to propagate to the root. Similarly, compose only needs to propagate the
157*c8dee2aaSAndroid Build Coastguard Worker             // variable parameters for the inner children.
158*c8dee2aaSAndroid Build Coastguard Worker             SkEnumBitMask<SnippetRequirementFlags> mask = SnippetRequirementFlags::kNone;
159*c8dee2aaSAndroid Build Coastguard Worker             if (codeID >= kBuiltInCodeSnippetIDCount || (isCompose && child == children.back())) {
160*c8dee2aaSAndroid Build Coastguard Worker                 // Only mask off the variable arguments; any special behaviors always propagate.
161*c8dee2aaSAndroid Build Coastguard Worker                 mask = SnippetRequirementFlags::kLocalCoords |
162*c8dee2aaSAndroid Build Coastguard Worker                        SnippetRequirementFlags::kPriorStageOutput |
163*c8dee2aaSAndroid Build Coastguard Worker                        SnippetRequirementFlags::kBlenderDstColor;
164*c8dee2aaSAndroid Build Coastguard Worker             }
165*c8dee2aaSAndroid Build Coastguard Worker 
166*c8dee2aaSAndroid Build Coastguard Worker             fRequiredFlags |= (child->requiredFlags() & ~mask);
167*c8dee2aaSAndroid Build Coastguard Worker         }
168*c8dee2aaSAndroid Build Coastguard Worker         // Data should only be provided if the snippet has the kStoresData flag.
169*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fData.empty() || snippet->storesData());
170*c8dee2aaSAndroid Build Coastguard Worker     }
171*c8dee2aaSAndroid Build Coastguard Worker 
172*c8dee2aaSAndroid Build Coastguard Worker     std::string generateDefaultPreamble(const ShaderInfo& shaderInfo) const;
173*c8dee2aaSAndroid Build Coastguard Worker     std::string invokeAndAssign(const ShaderInfo& shaderInfo,
174*c8dee2aaSAndroid Build Coastguard Worker                                 const ShaderSnippet::Args& args,
175*c8dee2aaSAndroid Build Coastguard Worker                                 std::string* funcBody) const;
176*c8dee2aaSAndroid Build Coastguard Worker 
codeSnippetId()177*c8dee2aaSAndroid Build Coastguard Worker     int32_t codeSnippetId() const { return fCodeID; }
keyIndex()178*c8dee2aaSAndroid Build Coastguard Worker     int32_t keyIndex() const { return fKeyIndex; }
entry()179*c8dee2aaSAndroid Build Coastguard Worker     const ShaderSnippet* entry() const { return fEntry; }
180*c8dee2aaSAndroid Build Coastguard Worker 
requiredFlags()181*c8dee2aaSAndroid Build Coastguard Worker     SkEnumBitMask<SnippetRequirementFlags> requiredFlags() const { return fRequiredFlags; }
182*c8dee2aaSAndroid Build Coastguard Worker 
numChildren()183*c8dee2aaSAndroid Build Coastguard Worker     int numChildren() const { return fEntry->fNumChildren; }
children()184*c8dee2aaSAndroid Build Coastguard Worker     SkSpan<const ShaderNode*> children() const { return fChildren; }
child(int childIndex)185*c8dee2aaSAndroid Build Coastguard Worker     const ShaderNode* child(int childIndex) const { return fChildren[childIndex]; }
186*c8dee2aaSAndroid Build Coastguard Worker 
data()187*c8dee2aaSAndroid Build Coastguard Worker     SkSpan<const uint32_t> data() const { return fData; }
188*c8dee2aaSAndroid Build Coastguard Worker 
189*c8dee2aaSAndroid Build Coastguard Worker private:
190*c8dee2aaSAndroid Build Coastguard Worker     const ShaderSnippet* fEntry; // Owned by the ShaderCodeDictionary
191*c8dee2aaSAndroid Build Coastguard Worker     SkSpan<const ShaderNode*> fChildren; // Owned by the ShaderInfo's arena
192*c8dee2aaSAndroid Build Coastguard Worker 
193*c8dee2aaSAndroid Build Coastguard Worker     int32_t fCodeID;
194*c8dee2aaSAndroid Build Coastguard Worker     int32_t fKeyIndex; // index back to PaintParamsKey, unique across nodes within a ShaderInfo
195*c8dee2aaSAndroid Build Coastguard Worker 
196*c8dee2aaSAndroid Build Coastguard Worker     SkEnumBitMask<SnippetRequirementFlags> fRequiredFlags;
197*c8dee2aaSAndroid Build Coastguard Worker     SkSpan<const uint32_t> fData; // Subspan of PaintParamsKey's fData; shares same owner
198*c8dee2aaSAndroid Build Coastguard Worker };
199*c8dee2aaSAndroid Build Coastguard Worker 
200*c8dee2aaSAndroid Build Coastguard Worker // ShaderCodeDictionary is a thread-safe dictionary of ShaderSnippets to code IDs for use with
201*c8dee2aaSAndroid Build Coastguard Worker // creating PaintParamKeys, as well as assigning unique IDs to each encountered PaintParamKey.
202*c8dee2aaSAndroid Build Coastguard Worker // It defines ShaderSnippets for every BuiltInCodeSnippetID and maintains records for IDs per
203*c8dee2aaSAndroid Build Coastguard Worker // SkRuntimeEffect, including de-duplicating equivalent SkRuntimeEffect objects.
204*c8dee2aaSAndroid Build Coastguard Worker class ShaderCodeDictionary {
205*c8dee2aaSAndroid Build Coastguard Worker public:
206*c8dee2aaSAndroid Build Coastguard Worker     ShaderCodeDictionary(Layout layout);
207*c8dee2aaSAndroid Build Coastguard Worker 
208*c8dee2aaSAndroid Build Coastguard Worker     UniquePaintParamsID findOrCreate(PaintParamsKeyBuilder*) SK_EXCLUDES(fSpinLock);
209*c8dee2aaSAndroid Build Coastguard Worker 
210*c8dee2aaSAndroid Build Coastguard Worker     PaintParamsKey lookup(UniquePaintParamsID) const SK_EXCLUDES(fSpinLock);
211*c8dee2aaSAndroid Build Coastguard Worker 
idToString(UniquePaintParamsID id)212*c8dee2aaSAndroid Build Coastguard Worker     SkString idToString(UniquePaintParamsID id) const {
213*c8dee2aaSAndroid Build Coastguard Worker         return this->lookup(id).toString(this, /*includeData=*/false);
214*c8dee2aaSAndroid Build Coastguard Worker     }
215*c8dee2aaSAndroid Build Coastguard Worker 
216*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG)
217*c8dee2aaSAndroid Build Coastguard Worker     bool isValidID(int snippetID) const SK_EXCLUDES(fSpinLock);
218*c8dee2aaSAndroid Build Coastguard Worker 
219*c8dee2aaSAndroid Build Coastguard Worker     void dump(UniquePaintParamsID) const;
220*c8dee2aaSAndroid Build Coastguard Worker #endif
221*c8dee2aaSAndroid Build Coastguard Worker 
222*c8dee2aaSAndroid Build Coastguard Worker     // This method can return nullptr
223*c8dee2aaSAndroid Build Coastguard Worker     const ShaderSnippet* getEntry(int codeSnippetID) const SK_EXCLUDES(fSpinLock);
getEntry(BuiltInCodeSnippetID codeSnippetID)224*c8dee2aaSAndroid Build Coastguard Worker     const ShaderSnippet* getEntry(BuiltInCodeSnippetID codeSnippetID) const {
225*c8dee2aaSAndroid Build Coastguard Worker         // Built-in code snippets are initialized once so there is no need to take a lock
226*c8dee2aaSAndroid Build Coastguard Worker         return &fBuiltInCodeSnippets[SkTo<int>(codeSnippetID)];
227*c8dee2aaSAndroid Build Coastguard Worker     }
228*c8dee2aaSAndroid Build Coastguard Worker 
229*c8dee2aaSAndroid Build Coastguard Worker     int findOrCreateRuntimeEffectSnippet(const SkRuntimeEffect* effect) SK_EXCLUDES(fSpinLock);
230*c8dee2aaSAndroid Build Coastguard Worker 
231*c8dee2aaSAndroid Build Coastguard Worker private:
232*c8dee2aaSAndroid Build Coastguard Worker     const char* addTextToArena(std::string_view text);
233*c8dee2aaSAndroid Build Coastguard Worker 
234*c8dee2aaSAndroid Build Coastguard Worker     SkSpan<const Uniform> convertUniforms(const SkRuntimeEffect* effect);
235*c8dee2aaSAndroid Build Coastguard Worker     ShaderSnippet convertRuntimeEffect(const SkRuntimeEffect* effect, const char* name);
236*c8dee2aaSAndroid Build Coastguard Worker 
237*c8dee2aaSAndroid Build Coastguard Worker     const Layout fLayout;
238*c8dee2aaSAndroid Build Coastguard Worker 
239*c8dee2aaSAndroid Build Coastguard Worker     std::array<ShaderSnippet, kBuiltInCodeSnippetIDCount> fBuiltInCodeSnippets;
240*c8dee2aaSAndroid Build Coastguard Worker 
241*c8dee2aaSAndroid Build Coastguard Worker     using KnownRuntimeEffectArray = std::array<ShaderSnippet, SkKnownRuntimeEffects::kStableKeyCnt>;
242*c8dee2aaSAndroid Build Coastguard Worker     KnownRuntimeEffectArray fKnownRuntimeEffectCodeSnippets SK_GUARDED_BY(fSpinLock);
243*c8dee2aaSAndroid Build Coastguard Worker 
244*c8dee2aaSAndroid Build Coastguard Worker     // The value returned from 'getEntry' must be stable so, hold the user-defined code snippet
245*c8dee2aaSAndroid Build Coastguard Worker     // entries as pointers.
246*c8dee2aaSAndroid Build Coastguard Worker     using RuntimeEffectArray = skia_private::TArray<ShaderSnippet>;
247*c8dee2aaSAndroid Build Coastguard Worker     RuntimeEffectArray fUserDefinedCodeSnippets SK_GUARDED_BY(fSpinLock);
248*c8dee2aaSAndroid Build Coastguard Worker 
249*c8dee2aaSAndroid Build Coastguard Worker     // TODO: can we do something better given this should have write-seldom/read-often behavior?
250*c8dee2aaSAndroid Build Coastguard Worker     mutable SkSpinlock fSpinLock;
251*c8dee2aaSAndroid Build Coastguard Worker 
252*c8dee2aaSAndroid Build Coastguard Worker     using PaintIDMap = skia_private::THashMap<PaintParamsKey,
253*c8dee2aaSAndroid Build Coastguard Worker                                               UniquePaintParamsID,
254*c8dee2aaSAndroid Build Coastguard Worker                                               PaintParamsKey::Hash>;
255*c8dee2aaSAndroid Build Coastguard Worker 
256*c8dee2aaSAndroid Build Coastguard Worker     PaintIDMap fPaintKeyToID SK_GUARDED_BY(fSpinLock);
257*c8dee2aaSAndroid Build Coastguard Worker     skia_private::TArray<PaintParamsKey> fIDToPaintKey SK_GUARDED_BY(fSpinLock);
258*c8dee2aaSAndroid Build Coastguard Worker 
259*c8dee2aaSAndroid Build Coastguard Worker     SK_BEGIN_REQUIRE_DENSE
260*c8dee2aaSAndroid Build Coastguard Worker     struct RuntimeEffectKey {
261*c8dee2aaSAndroid Build Coastguard Worker         uint32_t fHash;
262*c8dee2aaSAndroid Build Coastguard Worker         uint32_t fUniformSize;
263*c8dee2aaSAndroid Build Coastguard Worker 
264*c8dee2aaSAndroid Build Coastguard Worker         bool operator==(RuntimeEffectKey rhs) const {
265*c8dee2aaSAndroid Build Coastguard Worker             return fHash == rhs.fHash && fUniformSize == rhs.fUniformSize;
266*c8dee2aaSAndroid Build Coastguard Worker         }
267*c8dee2aaSAndroid Build Coastguard Worker     };
268*c8dee2aaSAndroid Build Coastguard Worker     SK_END_REQUIRE_DENSE
269*c8dee2aaSAndroid Build Coastguard Worker 
270*c8dee2aaSAndroid Build Coastguard Worker     // A map from RuntimeEffectKeys (hash plus uniforms) to code-snippet IDs. RuntimeEffectKeys
271*c8dee2aaSAndroid Build Coastguard Worker     // don't track the lifetime of a runtime effect at all; they live forever, and a newly-
272*c8dee2aaSAndroid Build Coastguard Worker     // instantiated runtime effect with the same program as a previously-discarded effect will reuse
273*c8dee2aaSAndroid Build Coastguard Worker     // an existing ID. Entries in the runtime-effect map are never removed; they only disappear when
274*c8dee2aaSAndroid Build Coastguard Worker     // the context is discarded, which takes the ShaderCodeDictionary along with it. However, they
275*c8dee2aaSAndroid Build Coastguard Worker     // are extremely small (< 20 bytes) so the memory footprint should be unnoticeable.
276*c8dee2aaSAndroid Build Coastguard Worker     using RuntimeEffectMap = skia_private::THashMap<RuntimeEffectKey, int32_t>;
277*c8dee2aaSAndroid Build Coastguard Worker     RuntimeEffectMap fRuntimeEffectMap SK_GUARDED_BY(fSpinLock);
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker     // This arena holds:
280*c8dee2aaSAndroid Build Coastguard Worker     //   - the backing data for PaintParamsKeys in `fPaintKeyToID` and `fIDToPaintKey`
281*c8dee2aaSAndroid Build Coastguard Worker     //   - Uniform data created by `findOrCreateRuntimeEffectSnippet`
282*c8dee2aaSAndroid Build Coastguard Worker     // and in all cases is guarded by `fSpinLock`
283*c8dee2aaSAndroid Build Coastguard Worker     SkArenaAlloc fArena{256};
284*c8dee2aaSAndroid Build Coastguard Worker };
285*c8dee2aaSAndroid Build Coastguard Worker 
286*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
287*c8dee2aaSAndroid Build Coastguard Worker 
288*c8dee2aaSAndroid Build Coastguard Worker #endif // skgpu_graphite_ShaderCodeDictionary_DEFINED
289