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