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 #include "src/gpu/graphite/PaintParamsKey.h"
9
10 #include "src/base/SkArenaAlloc.h"
11 #include "src/base/SkStringView.h"
12 #include "src/gpu/graphite/KeyHelpers.h"
13 #include "src/gpu/graphite/Log.h"
14 #include "src/gpu/graphite/ShaderCodeDictionary.h"
15
16 using namespace skia_private;
17
18 namespace skgpu::graphite {
19
20 //--------------------------------------------------------------------------------------------------
21 // PaintParamsKeyBuilder
22
23 #ifdef SK_DEBUG
24
checkReset()25 void PaintParamsKeyBuilder::checkReset() {
26 SkASSERT(!fLocked);
27 SkASSERT(fData.empty());
28 SkASSERT(fStack.empty());
29 }
30
pushStack(int32_t codeSnippetID)31 void PaintParamsKeyBuilder::pushStack(int32_t codeSnippetID) {
32 SkASSERT(fDict->isValidID(codeSnippetID));
33
34 if (!fStack.empty()) {
35 fStack.back().fNumActualChildren++;
36 SkASSERT(fStack.back().fNumActualChildren <= fStack.back().fNumExpectedChildren);
37 }
38
39 const ShaderSnippet* snippet = fDict->getEntry(codeSnippetID);
40 fStack.push_back({codeSnippetID, snippet->fNumChildren});
41 }
42
popStack()43 void PaintParamsKeyBuilder::popStack() {
44 SkASSERT(!fStack.empty());
45 SkASSERT(fStack.back().fNumActualChildren == fStack.back().fNumExpectedChildren);
46 fStack.pop_back();
47 }
48
49 #endif // SK_DEBUG
50
51 //--------------------------------------------------------------------------------------------------
52 // PaintParamsKey
53
clone(SkArenaAlloc * arena) const54 PaintParamsKey PaintParamsKey::clone(SkArenaAlloc* arena) const {
55 int32_t* newData = arena->makeArrayDefault<int32_t>(fData.size());
56 memcpy(newData, fData.data(), fData.size_bytes());
57 return PaintParamsKey({newData, fData.size()});
58 }
59
60
createNode(const ShaderCodeDictionary * dict,int * currentIndex,SkArenaAlloc * arena) const61 const ShaderNode* PaintParamsKey::createNode(const ShaderCodeDictionary* dict,
62 int* currentIndex,
63 SkArenaAlloc* arena) const {
64 SkASSERT(*currentIndex < SkTo<int>(fData.size()));
65 const int32_t index = (*currentIndex)++;
66 const int32_t id = fData[index];
67
68 const ShaderSnippet* entry = dict->getEntry(id);
69 if (!entry) {
70 SKGPU_LOG_E("Unknown snippet ID in key: %d", id);
71 return nullptr;
72 }
73
74 const ShaderNode** childArray = arena->makeArray<const ShaderNode*>(entry->fNumChildren);
75 for (int i = 0; i < entry->fNumChildren; ++i) {
76 const ShaderNode* child = this->createNode(dict, currentIndex, arena);
77 if (!child) {
78 return nullptr;
79 }
80 childArray[i] = child;
81 }
82
83 return arena->make<ShaderNode>(entry, SkSpan(childArray, entry->fNumChildren), id, index);
84 }
85
getRootNodes(const ShaderCodeDictionary * dict,SkArenaAlloc * arena) const86 SkSpan<const ShaderNode*> PaintParamsKey::getRootNodes(const ShaderCodeDictionary* dict,
87 SkArenaAlloc* arena) const {
88 // TODO: Once the PaintParamsKey creation is organized to represent a single tree starting at
89 // the final blend, there will only be a single root node and this can be simplified.
90 // For now, we don't know how many roots there are, so collect them into a local array before
91 // copying into the arena.
92 const int keySize = SkTo<int>(fData.size());
93
94 // Normal PaintParams creation will have up to 7 roots for the different stages.
95 STArray<7, const ShaderNode*> roots;
96 int currentIndex = 0;
97 while (currentIndex < keySize) {
98 const ShaderNode* root = this->createNode(dict, ¤tIndex, arena);
99 if (!root) {
100 return {}; // a bad key
101 }
102 roots.push_back(root);
103 }
104
105 // Copy the accumulated roots into a span stored in the arena
106 const ShaderNode** rootSpan = arena->makeArray<const ShaderNode*>(roots.size());
107 memcpy(rootSpan, roots.data(), roots.size_bytes());
108 return SkSpan(rootSpan, roots.size());
109 }
110
key_to_string(SkString * str,const ShaderCodeDictionary * dict,SkSpan<const int32_t> keyData,int currentIndex)111 static int key_to_string(SkString* str,
112 const ShaderCodeDictionary* dict,
113 SkSpan<const int32_t> keyData,
114 int currentIndex) {
115 SkASSERT(currentIndex < SkTo<int>(keyData.size()));
116
117 int32_t id = keyData[currentIndex++];
118 auto entry = dict->getEntry(id);
119 if (!entry) {
120 str->append("UnknownCodeSnippetID:");
121 str->appendS32(id);
122 str->append(" ");
123 return currentIndex;
124 }
125
126 std::string_view name = entry->fName;
127 if (skstd::ends_with(name, "Shader")) {
128 name.remove_suffix(6);
129 }
130 str->append(name);
131
132 if (entry->fNumChildren > 0) {
133 str->append(" [ ");
134 for (int i = 0; i < entry->fNumChildren; ++i) {
135 currentIndex = key_to_string(str, dict, keyData, currentIndex);
136 }
137 str->append("]");
138 }
139
140 str->append(" ");
141 return currentIndex;
142 }
143
toString(const ShaderCodeDictionary * dict) const144 SkString PaintParamsKey::toString(const ShaderCodeDictionary* dict) const {
145 SkString str;
146 const int keySize = SkTo<int>(fData.size());
147 for (int currentIndex = 0; currentIndex < keySize; ) {
148 currentIndex = key_to_string(&str, dict, fData, currentIndex);
149 }
150 return str.isEmpty() ? SkString("(empty)") : str;
151 }
152
153 #ifdef SK_DEBUG
154
dump_node(const ShaderCodeDictionary * dict,SkSpan<const int32_t> keyData,int currentIndex,int indent)155 static int dump_node(const ShaderCodeDictionary* dict,
156 SkSpan<const int32_t> keyData,
157 int currentIndex,
158 int indent) {
159 SkASSERT(currentIndex < SkTo<int>(keyData.size()));
160
161 SkDebugf("%*c", 2 * indent, ' ');
162
163 int32_t id = keyData[currentIndex++];
164 auto entry = dict->getEntry(id);
165 if (!entry) {
166 SkDebugf("[%d] unknown block!\n", id);
167 return currentIndex;
168 }
169
170 SkDebugf("[%d] %s\n", id, entry->fStaticFunctionName);
171 for (int i = 0; i < entry->fNumChildren; ++i) {
172 currentIndex = dump_node(dict, keyData, currentIndex, indent + 1);
173 }
174 return currentIndex;
175 }
176
dump(const ShaderCodeDictionary * dict,UniquePaintParamsID id) const177 void PaintParamsKey::dump(const ShaderCodeDictionary* dict, UniquePaintParamsID id) const {
178 const int keySize = SkTo<int>(fData.size());
179
180 SkDebugf("--------------------------------------\n");
181 SkDebugf("%u PaintParamsKey (keySize: %d):\n", id.asUInt(), keySize);
182
183 int currentIndex = 0;
184 while (currentIndex < keySize) {
185 currentIndex = dump_node(dict, fData, currentIndex, 1);
186 }
187 }
188
189 #endif // SK_DEBUG
190
191 } // namespace skgpu::graphite
192