• 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 #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, &currentIndex, 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