xref: /aosp_15_r20/external/skia/src/gpu/graphite/ShaderInfo.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2024 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 #include "src/gpu/graphite/ShaderInfo.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/BlendFormula.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ContextUtils.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PaintParamsKey.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Renderer.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ShaderCodeDictionary.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/UniformManager.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLString.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLUtil.h"
18*c8dee2aaSAndroid Build Coastguard Worker 
19*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
20*c8dee2aaSAndroid Build Coastguard Worker 
21*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
22*c8dee2aaSAndroid Build Coastguard Worker 
23*c8dee2aaSAndroid Build Coastguard Worker namespace {
24*c8dee2aaSAndroid Build Coastguard Worker 
get_uniform_header(int bufferID,const char * name)25*c8dee2aaSAndroid Build Coastguard Worker std::string get_uniform_header(int bufferID, const char* name) {
26*c8dee2aaSAndroid Build Coastguard Worker     std::string result;
27*c8dee2aaSAndroid Build Coastguard Worker 
28*c8dee2aaSAndroid Build Coastguard Worker     SkSL::String::appendf(&result, "layout (binding=%d) uniform %sUniforms {\n", bufferID, name);
29*c8dee2aaSAndroid Build Coastguard Worker 
30*c8dee2aaSAndroid Build Coastguard Worker     return result;
31*c8dee2aaSAndroid Build Coastguard Worker }
32*c8dee2aaSAndroid Build Coastguard Worker 
get_uniforms(UniformOffsetCalculator * offsetter,SkSpan<const Uniform> uniforms,int manglingSuffix,bool * wrotePaintColor)33*c8dee2aaSAndroid Build Coastguard Worker std::string get_uniforms(UniformOffsetCalculator* offsetter,
34*c8dee2aaSAndroid Build Coastguard Worker                          SkSpan<const Uniform> uniforms,
35*c8dee2aaSAndroid Build Coastguard Worker                          int manglingSuffix,
36*c8dee2aaSAndroid Build Coastguard Worker                          bool* wrotePaintColor) {
37*c8dee2aaSAndroid Build Coastguard Worker     std::string result;
38*c8dee2aaSAndroid Build Coastguard Worker     std::string uniformName;
39*c8dee2aaSAndroid Build Coastguard Worker     for (const Uniform& u : uniforms) {
40*c8dee2aaSAndroid Build Coastguard Worker         uniformName = u.name();
41*c8dee2aaSAndroid Build Coastguard Worker 
42*c8dee2aaSAndroid Build Coastguard Worker         if (u.isPaintColor() && wrotePaintColor) {
43*c8dee2aaSAndroid Build Coastguard Worker             if (*wrotePaintColor) {
44*c8dee2aaSAndroid Build Coastguard Worker                 SkSL::String::appendf(&result, "    // deduplicated %s\n", u.name());
45*c8dee2aaSAndroid Build Coastguard Worker                 continue;
46*c8dee2aaSAndroid Build Coastguard Worker             }
47*c8dee2aaSAndroid Build Coastguard Worker 
48*c8dee2aaSAndroid Build Coastguard Worker             *wrotePaintColor = true;
49*c8dee2aaSAndroid Build Coastguard Worker         } else {
50*c8dee2aaSAndroid Build Coastguard Worker             if (manglingSuffix >= 0) {
51*c8dee2aaSAndroid Build Coastguard Worker                 uniformName.append("_");
52*c8dee2aaSAndroid Build Coastguard Worker                 uniformName.append(std::to_string(manglingSuffix));
53*c8dee2aaSAndroid Build Coastguard Worker             }
54*c8dee2aaSAndroid Build Coastguard Worker         }
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker         SkSL::String::appendf(&result,
57*c8dee2aaSAndroid Build Coastguard Worker                               "    layout(offset=%d) %s %s",
58*c8dee2aaSAndroid Build Coastguard Worker                               offsetter->advanceOffset(u.type(), u.count()),
59*c8dee2aaSAndroid Build Coastguard Worker                               SkSLTypeString(u.type()),
60*c8dee2aaSAndroid Build Coastguard Worker                               uniformName.c_str());
61*c8dee2aaSAndroid Build Coastguard Worker         if (u.count()) {
62*c8dee2aaSAndroid Build Coastguard Worker             result.append("[");
63*c8dee2aaSAndroid Build Coastguard Worker             result.append(std::to_string(u.count()));
64*c8dee2aaSAndroid Build Coastguard Worker             result.append("]");
65*c8dee2aaSAndroid Build Coastguard Worker         }
66*c8dee2aaSAndroid Build Coastguard Worker         result.append(";\n");
67*c8dee2aaSAndroid Build Coastguard Worker     }
68*c8dee2aaSAndroid Build Coastguard Worker 
69*c8dee2aaSAndroid Build Coastguard Worker     return result;
70*c8dee2aaSAndroid Build Coastguard Worker }
71*c8dee2aaSAndroid Build Coastguard Worker 
get_node_uniforms(UniformOffsetCalculator * offsetter,const ShaderNode * node,bool * wrotePaintColor)72*c8dee2aaSAndroid Build Coastguard Worker std::string get_node_uniforms(UniformOffsetCalculator* offsetter,
73*c8dee2aaSAndroid Build Coastguard Worker                               const ShaderNode* node,
74*c8dee2aaSAndroid Build Coastguard Worker                               bool* wrotePaintColor) {
75*c8dee2aaSAndroid Build Coastguard Worker     std::string result;
76*c8dee2aaSAndroid Build Coastguard Worker     SkSpan<const Uniform> uniforms = node->entry()->fUniforms;
77*c8dee2aaSAndroid Build Coastguard Worker 
78*c8dee2aaSAndroid Build Coastguard Worker     if (!uniforms.empty()) {
79*c8dee2aaSAndroid Build Coastguard Worker         if (node->entry()->fUniformStructName) {
80*c8dee2aaSAndroid Build Coastguard Worker             auto substruct = UniformOffsetCalculator::ForStruct(offsetter->layout());
81*c8dee2aaSAndroid Build Coastguard Worker             for (const Uniform& u : uniforms) {
82*c8dee2aaSAndroid Build Coastguard Worker                 substruct.advanceOffset(u.type(), u.count());
83*c8dee2aaSAndroid Build Coastguard Worker             }
84*c8dee2aaSAndroid Build Coastguard Worker 
85*c8dee2aaSAndroid Build Coastguard Worker             const int structOffset = offsetter->advanceStruct(substruct);
86*c8dee2aaSAndroid Build Coastguard Worker             SkSL::String::appendf(&result,
87*c8dee2aaSAndroid Build Coastguard Worker                                   "layout(offset=%d) %s node_%d;",
88*c8dee2aaSAndroid Build Coastguard Worker                                   structOffset,
89*c8dee2aaSAndroid Build Coastguard Worker                                   node->entry()->fUniformStructName,
90*c8dee2aaSAndroid Build Coastguard Worker                                   node->keyIndex());
91*c8dee2aaSAndroid Build Coastguard Worker         } else {
92*c8dee2aaSAndroid Build Coastguard Worker             SkSL::String::appendf(&result, "// %d - %s uniforms\n",
93*c8dee2aaSAndroid Build Coastguard Worker                                   node->keyIndex(), node->entry()->fName);
94*c8dee2aaSAndroid Build Coastguard Worker             result += get_uniforms(offsetter, uniforms, node->keyIndex(), wrotePaintColor);
95*c8dee2aaSAndroid Build Coastguard Worker         }
96*c8dee2aaSAndroid Build Coastguard Worker     }
97*c8dee2aaSAndroid Build Coastguard Worker 
98*c8dee2aaSAndroid Build Coastguard Worker     for (const ShaderNode* child : node->children()) {
99*c8dee2aaSAndroid Build Coastguard Worker         result += get_node_uniforms(offsetter, child, wrotePaintColor);
100*c8dee2aaSAndroid Build Coastguard Worker     }
101*c8dee2aaSAndroid Build Coastguard Worker     return result;
102*c8dee2aaSAndroid Build Coastguard Worker }
103*c8dee2aaSAndroid Build Coastguard Worker 
get_ssbo_fields(SkSpan<const Uniform> uniforms,int manglingSuffix,bool * wrotePaintColor)104*c8dee2aaSAndroid Build Coastguard Worker std::string get_ssbo_fields(SkSpan<const Uniform> uniforms,
105*c8dee2aaSAndroid Build Coastguard Worker                             int manglingSuffix,
106*c8dee2aaSAndroid Build Coastguard Worker                             bool* wrotePaintColor) {
107*c8dee2aaSAndroid Build Coastguard Worker     std::string result;
108*c8dee2aaSAndroid Build Coastguard Worker 
109*c8dee2aaSAndroid Build Coastguard Worker     std::string uniformName;
110*c8dee2aaSAndroid Build Coastguard Worker     for (const Uniform& u : uniforms) {
111*c8dee2aaSAndroid Build Coastguard Worker         uniformName = u.name();
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker         if (u.isPaintColor() && wrotePaintColor) {
114*c8dee2aaSAndroid Build Coastguard Worker             if (*wrotePaintColor) {
115*c8dee2aaSAndroid Build Coastguard Worker                 SkSL::String::appendf(&result, "    // deduplicated %s\n", u.name());
116*c8dee2aaSAndroid Build Coastguard Worker                 continue;
117*c8dee2aaSAndroid Build Coastguard Worker             }
118*c8dee2aaSAndroid Build Coastguard Worker 
119*c8dee2aaSAndroid Build Coastguard Worker             *wrotePaintColor = true;
120*c8dee2aaSAndroid Build Coastguard Worker         } else {
121*c8dee2aaSAndroid Build Coastguard Worker             if (manglingSuffix >= 0) {
122*c8dee2aaSAndroid Build Coastguard Worker                 uniformName.append("_");
123*c8dee2aaSAndroid Build Coastguard Worker                 uniformName.append(std::to_string(manglingSuffix));
124*c8dee2aaSAndroid Build Coastguard Worker             }
125*c8dee2aaSAndroid Build Coastguard Worker         }
126*c8dee2aaSAndroid Build Coastguard Worker 
127*c8dee2aaSAndroid Build Coastguard Worker         SkSL::String::appendf(&result, "    %s %s", SkSLTypeString(u.type()), uniformName.c_str());
128*c8dee2aaSAndroid Build Coastguard Worker         if (u.count()) {
129*c8dee2aaSAndroid Build Coastguard Worker             SkSL::String::appendf(&result, "[%d]", u.count());
130*c8dee2aaSAndroid Build Coastguard Worker         }
131*c8dee2aaSAndroid Build Coastguard Worker         result.append(";\n");
132*c8dee2aaSAndroid Build Coastguard Worker     }
133*c8dee2aaSAndroid Build Coastguard Worker 
134*c8dee2aaSAndroid Build Coastguard Worker     return result;
135*c8dee2aaSAndroid Build Coastguard Worker }
136*c8dee2aaSAndroid Build Coastguard Worker 
get_node_ssbo_fields(const ShaderNode * node,bool * wrotePaintColor)137*c8dee2aaSAndroid Build Coastguard Worker std::string get_node_ssbo_fields(const ShaderNode* node, bool* wrotePaintColor) {
138*c8dee2aaSAndroid Build Coastguard Worker     std::string result;
139*c8dee2aaSAndroid Build Coastguard Worker     SkSpan<const Uniform> uniforms = node->entry()->fUniforms;
140*c8dee2aaSAndroid Build Coastguard Worker 
141*c8dee2aaSAndroid Build Coastguard Worker     if (!uniforms.empty()) {
142*c8dee2aaSAndroid Build Coastguard Worker         if (node->entry()->fUniformStructName) {
143*c8dee2aaSAndroid Build Coastguard Worker             SkSL::String::appendf(&result, "%s node_%d;",
144*c8dee2aaSAndroid Build Coastguard Worker                                   node->entry()->fUniformStructName, node->keyIndex());
145*c8dee2aaSAndroid Build Coastguard Worker         } else {
146*c8dee2aaSAndroid Build Coastguard Worker             SkSL::String::appendf(&result, "// %d - %s uniforms\n",
147*c8dee2aaSAndroid Build Coastguard Worker                                   node->keyIndex(), node->entry()->fName);
148*c8dee2aaSAndroid Build Coastguard Worker 
149*c8dee2aaSAndroid Build Coastguard Worker             result += get_ssbo_fields(uniforms, node->keyIndex(), wrotePaintColor);
150*c8dee2aaSAndroid Build Coastguard Worker         }
151*c8dee2aaSAndroid Build Coastguard Worker     }
152*c8dee2aaSAndroid Build Coastguard Worker 
153*c8dee2aaSAndroid Build Coastguard Worker     for (const ShaderNode* child : node->children()) {
154*c8dee2aaSAndroid Build Coastguard Worker         result += get_node_ssbo_fields(child, wrotePaintColor);
155*c8dee2aaSAndroid Build Coastguard Worker     }
156*c8dee2aaSAndroid Build Coastguard Worker     return result;
157*c8dee2aaSAndroid Build Coastguard Worker }
158*c8dee2aaSAndroid Build Coastguard Worker 
emit_intrinsic_uniforms(int bufferID,Layout layout)159*c8dee2aaSAndroid Build Coastguard Worker std::string emit_intrinsic_uniforms(int bufferID, Layout layout) {
160*c8dee2aaSAndroid Build Coastguard Worker     auto offsetter = UniformOffsetCalculator::ForTopLevel(layout);
161*c8dee2aaSAndroid Build Coastguard Worker 
162*c8dee2aaSAndroid Build Coastguard Worker     std::string result = get_uniform_header(bufferID, "Intrinsic");
163*c8dee2aaSAndroid Build Coastguard Worker     result += get_uniforms(&offsetter, kIntrinsicUniforms, -1, /* wrotePaintColor= */ nullptr);
164*c8dee2aaSAndroid Build Coastguard Worker     result.append("};\n\n");
165*c8dee2aaSAndroid Build Coastguard Worker 
166*c8dee2aaSAndroid Build Coastguard Worker     SkASSERTF(result.find('[') == std::string::npos,
167*c8dee2aaSAndroid Build Coastguard Worker               "Arrays are not supported in intrinsic uniforms");
168*c8dee2aaSAndroid Build Coastguard Worker 
169*c8dee2aaSAndroid Build Coastguard Worker     return result;
170*c8dee2aaSAndroid Build Coastguard Worker }
171*c8dee2aaSAndroid Build Coastguard Worker 
emit_paint_params_uniforms(int bufferID,const Layout layout,SkSpan<const ShaderNode * > nodes,bool * hasUniforms,bool * wrotePaintColor)172*c8dee2aaSAndroid Build Coastguard Worker std::string emit_paint_params_uniforms(int bufferID,
173*c8dee2aaSAndroid Build Coastguard Worker                                        const Layout layout,
174*c8dee2aaSAndroid Build Coastguard Worker                                        SkSpan<const ShaderNode*> nodes,
175*c8dee2aaSAndroid Build Coastguard Worker                                        bool* hasUniforms,
176*c8dee2aaSAndroid Build Coastguard Worker                                        bool* wrotePaintColor) {
177*c8dee2aaSAndroid Build Coastguard Worker     auto offsetter = UniformOffsetCalculator::ForTopLevel(layout);
178*c8dee2aaSAndroid Build Coastguard Worker 
179*c8dee2aaSAndroid Build Coastguard Worker     std::string result = get_uniform_header(bufferID, "FS");
180*c8dee2aaSAndroid Build Coastguard Worker     for (const ShaderNode* n : nodes) {
181*c8dee2aaSAndroid Build Coastguard Worker         result += get_node_uniforms(&offsetter, n, wrotePaintColor);
182*c8dee2aaSAndroid Build Coastguard Worker     }
183*c8dee2aaSAndroid Build Coastguard Worker     result.append("};\n\n");
184*c8dee2aaSAndroid Build Coastguard Worker 
185*c8dee2aaSAndroid Build Coastguard Worker     *hasUniforms = offsetter.size() > 0;
186*c8dee2aaSAndroid Build Coastguard Worker     if (!*hasUniforms) {
187*c8dee2aaSAndroid Build Coastguard Worker         // No uniforms were added
188*c8dee2aaSAndroid Build Coastguard Worker         return {};
189*c8dee2aaSAndroid Build Coastguard Worker     }
190*c8dee2aaSAndroid Build Coastguard Worker 
191*c8dee2aaSAndroid Build Coastguard Worker     return result;
192*c8dee2aaSAndroid Build Coastguard Worker }
193*c8dee2aaSAndroid Build Coastguard Worker 
emit_render_step_uniforms(int bufferID,const Layout layout,SkSpan<const Uniform> uniforms)194*c8dee2aaSAndroid Build Coastguard Worker std::string emit_render_step_uniforms(int bufferID,
195*c8dee2aaSAndroid Build Coastguard Worker                                       const Layout layout,
196*c8dee2aaSAndroid Build Coastguard Worker                                       SkSpan<const Uniform> uniforms) {
197*c8dee2aaSAndroid Build Coastguard Worker     auto offsetter = UniformOffsetCalculator::ForTopLevel(layout);
198*c8dee2aaSAndroid Build Coastguard Worker 
199*c8dee2aaSAndroid Build Coastguard Worker     std::string result = get_uniform_header(bufferID, "Step");
200*c8dee2aaSAndroid Build Coastguard Worker     result += get_uniforms(&offsetter, uniforms, -1, /* wrotePaintColor= */ nullptr);
201*c8dee2aaSAndroid Build Coastguard Worker     result.append("};\n\n");
202*c8dee2aaSAndroid Build Coastguard Worker 
203*c8dee2aaSAndroid Build Coastguard Worker     return result;
204*c8dee2aaSAndroid Build Coastguard Worker }
205*c8dee2aaSAndroid Build Coastguard Worker 
emit_paint_params_storage_buffer(int bufferID,SkSpan<const ShaderNode * > nodes,bool * hasUniforms,bool * wrotePaintColor)206*c8dee2aaSAndroid Build Coastguard Worker std::string emit_paint_params_storage_buffer(int bufferID,
207*c8dee2aaSAndroid Build Coastguard Worker                                              SkSpan<const ShaderNode*> nodes,
208*c8dee2aaSAndroid Build Coastguard Worker                                              bool* hasUniforms,
209*c8dee2aaSAndroid Build Coastguard Worker                                              bool* wrotePaintColor) {
210*c8dee2aaSAndroid Build Coastguard Worker     *hasUniforms = false;
211*c8dee2aaSAndroid Build Coastguard Worker 
212*c8dee2aaSAndroid Build Coastguard Worker     std::string fields;
213*c8dee2aaSAndroid Build Coastguard Worker     for (const ShaderNode* n : nodes) {
214*c8dee2aaSAndroid Build Coastguard Worker         fields += get_node_ssbo_fields(n, wrotePaintColor);
215*c8dee2aaSAndroid Build Coastguard Worker     }
216*c8dee2aaSAndroid Build Coastguard Worker 
217*c8dee2aaSAndroid Build Coastguard Worker     if (fields.empty()) {
218*c8dee2aaSAndroid Build Coastguard Worker         // No uniforms were added
219*c8dee2aaSAndroid Build Coastguard Worker         *hasUniforms = false;
220*c8dee2aaSAndroid Build Coastguard Worker         return {};
221*c8dee2aaSAndroid Build Coastguard Worker     }
222*c8dee2aaSAndroid Build Coastguard Worker 
223*c8dee2aaSAndroid Build Coastguard Worker     *hasUniforms = true;
224*c8dee2aaSAndroid Build Coastguard Worker     return SkSL::String::printf(
225*c8dee2aaSAndroid Build Coastguard Worker             "struct FSUniformData {\n"
226*c8dee2aaSAndroid Build Coastguard Worker                 "%s\n"
227*c8dee2aaSAndroid Build Coastguard Worker             "};\n\n"
228*c8dee2aaSAndroid Build Coastguard Worker             "layout (binding=%d) readonly buffer FSUniforms {\n"
229*c8dee2aaSAndroid Build Coastguard Worker                 "FSUniformData fsUniformData[];\n"
230*c8dee2aaSAndroid Build Coastguard Worker             "};\n",
231*c8dee2aaSAndroid Build Coastguard Worker             fields.c_str(),
232*c8dee2aaSAndroid Build Coastguard Worker             bufferID);
233*c8dee2aaSAndroid Build Coastguard Worker }
234*c8dee2aaSAndroid Build Coastguard Worker 
emit_render_step_storage_buffer(int bufferID,SkSpan<const Uniform> uniforms)235*c8dee2aaSAndroid Build Coastguard Worker std::string emit_render_step_storage_buffer(int bufferID, SkSpan<const Uniform> uniforms) {
236*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!uniforms.empty());
237*c8dee2aaSAndroid Build Coastguard Worker     std::string fields = get_ssbo_fields(uniforms, -1, /*wrotePaintColor=*/nullptr);
238*c8dee2aaSAndroid Build Coastguard Worker     return SkSL::String::printf(
239*c8dee2aaSAndroid Build Coastguard Worker             "struct StepUniformData {\n"
240*c8dee2aaSAndroid Build Coastguard Worker             "%s\n"
241*c8dee2aaSAndroid Build Coastguard Worker             "};\n\n"
242*c8dee2aaSAndroid Build Coastguard Worker             "layout (binding=%d) readonly buffer StepUniforms {\n"
243*c8dee2aaSAndroid Build Coastguard Worker             "    StepUniformData stepUniformData[];\n"
244*c8dee2aaSAndroid Build Coastguard Worker             "};\n",
245*c8dee2aaSAndroid Build Coastguard Worker             fields.c_str(),
246*c8dee2aaSAndroid Build Coastguard Worker             bufferID);
247*c8dee2aaSAndroid Build Coastguard Worker }
248*c8dee2aaSAndroid Build Coastguard Worker 
emit_uniforms_from_storage_buffer(const char * bufferNamePrefix,const char * ssboIndex,SkSpan<const Uniform> uniforms)249*c8dee2aaSAndroid Build Coastguard Worker std::string emit_uniforms_from_storage_buffer(const char* bufferNamePrefix,
250*c8dee2aaSAndroid Build Coastguard Worker                                               const char* ssboIndex,
251*c8dee2aaSAndroid Build Coastguard Worker                                               SkSpan<const Uniform> uniforms) {
252*c8dee2aaSAndroid Build Coastguard Worker     std::string result;
253*c8dee2aaSAndroid Build Coastguard Worker 
254*c8dee2aaSAndroid Build Coastguard Worker     for (const Uniform& u : uniforms) {
255*c8dee2aaSAndroid Build Coastguard Worker         SkSL::String::appendf(&result, "%s %s", SkSLTypeString(u.type()), u.name());
256*c8dee2aaSAndroid Build Coastguard Worker         if (u.count()) {
257*c8dee2aaSAndroid Build Coastguard Worker             SkSL::String::appendf(&result, "[%d]", u.count());
258*c8dee2aaSAndroid Build Coastguard Worker         }
259*c8dee2aaSAndroid Build Coastguard Worker         SkSL::String::appendf(
260*c8dee2aaSAndroid Build Coastguard Worker                 &result, " = %sUniformData[%s].%s;\n", bufferNamePrefix, ssboIndex, u.name());
261*c8dee2aaSAndroid Build Coastguard Worker     }
262*c8dee2aaSAndroid Build Coastguard Worker 
263*c8dee2aaSAndroid Build Coastguard Worker     return result;
264*c8dee2aaSAndroid Build Coastguard Worker }
265*c8dee2aaSAndroid Build Coastguard Worker 
append_sampler_descs(const SkSpan<const uint32_t> samplerData,skia_private::TArray<SamplerDesc> & outDescs)266*c8dee2aaSAndroid Build Coastguard Worker void append_sampler_descs(const SkSpan<const uint32_t> samplerData,
267*c8dee2aaSAndroid Build Coastguard Worker                           skia_private::TArray<SamplerDesc>& outDescs) {
268*c8dee2aaSAndroid Build Coastguard Worker     // Sampler data consists of variable-length SamplerDesc representations which can differ based
269*c8dee2aaSAndroid Build Coastguard Worker     // upon a sampler's immutability and format. For this reason, handle incrementing i in the loop.
270*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < samplerData.size();) {
271*c8dee2aaSAndroid Build Coastguard Worker         // Create a default-initialized SamplerDesc (which only takes up one uint32). If we are
272*c8dee2aaSAndroid Build Coastguard Worker         // using a dynamic sampler, this will be directly inserted into outDescs. Otherwise, it will
273*c8dee2aaSAndroid Build Coastguard Worker         // be populated with actual immutable sampler data and then inserted.
274*c8dee2aaSAndroid Build Coastguard Worker         SamplerDesc desc{};
275*c8dee2aaSAndroid Build Coastguard Worker         size_t samplerDescLength = 1;
276*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(desc.asSpan().size() == samplerDescLength);
277*c8dee2aaSAndroid Build Coastguard Worker 
278*c8dee2aaSAndroid Build Coastguard Worker         // Isolate the ImmutableSamplerInfo portion of the SamplerDesc represented by samplerData.
279*c8dee2aaSAndroid Build Coastguard Worker         // If immutableSamplerInfo is non-zero, that means we are using an immutable sampler.
280*c8dee2aaSAndroid Build Coastguard Worker         uint32_t immutableSamplerInfo = samplerData[i] >> SamplerDesc::kImmutableSamplerInfoShift;
281*c8dee2aaSAndroid Build Coastguard Worker         if (immutableSamplerInfo != 0) {
282*c8dee2aaSAndroid Build Coastguard Worker             // Consult the first bit of immutableSamplerInfo which tells us whether the sampler uses
283*c8dee2aaSAndroid Build Coastguard Worker             // a known or external format. With this, update sampler description length.
284*c8dee2aaSAndroid Build Coastguard Worker             bool usesExternalFormat = immutableSamplerInfo & 0b1;
285*c8dee2aaSAndroid Build Coastguard Worker             samplerDescLength = usesExternalFormat ? SamplerDesc::kInt32sNeededExternalFormat
286*c8dee2aaSAndroid Build Coastguard Worker                                                    : SamplerDesc::kInt32sNeededKnownFormat;
287*c8dee2aaSAndroid Build Coastguard Worker             // Populate a SamplerDesc with samplerDescLength quantity of immutable sampler data
288*c8dee2aaSAndroid Build Coastguard Worker             memcpy(&desc, samplerData.begin() + i, samplerDescLength * sizeof(uint32_t));
289*c8dee2aaSAndroid Build Coastguard Worker         }
290*c8dee2aaSAndroid Build Coastguard Worker         outDescs.push_back(desc);
291*c8dee2aaSAndroid Build Coastguard Worker         i += samplerDescLength;
292*c8dee2aaSAndroid Build Coastguard Worker     }
293*c8dee2aaSAndroid Build Coastguard Worker }
294*c8dee2aaSAndroid Build Coastguard Worker 
get_node_texture_samplers(const ResourceBindingRequirements & bindingReqs,const ShaderNode * node,int * binding,skia_private::TArray<SamplerDesc> * outDescs)295*c8dee2aaSAndroid Build Coastguard Worker std::string get_node_texture_samplers(const ResourceBindingRequirements& bindingReqs,
296*c8dee2aaSAndroid Build Coastguard Worker                                       const ShaderNode* node,
297*c8dee2aaSAndroid Build Coastguard Worker                                       int* binding,
298*c8dee2aaSAndroid Build Coastguard Worker                                       skia_private::TArray<SamplerDesc>* outDescs) {
299*c8dee2aaSAndroid Build Coastguard Worker     std::string result;
300*c8dee2aaSAndroid Build Coastguard Worker     SkSpan<const TextureAndSampler> samplers = node->entry()->fTexturesAndSamplers;
301*c8dee2aaSAndroid Build Coastguard Worker 
302*c8dee2aaSAndroid Build Coastguard Worker     if (!samplers.empty()) {
303*c8dee2aaSAndroid Build Coastguard Worker         SkSL::String::appendf(&result, "// %d - %s samplers\n",
304*c8dee2aaSAndroid Build Coastguard Worker                               node->keyIndex(), node->entry()->fName);
305*c8dee2aaSAndroid Build Coastguard Worker 
306*c8dee2aaSAndroid Build Coastguard Worker         // Determine whether we need to analyze & interpret a ShaderNode's data as immutable
307*c8dee2aaSAndroid Build Coastguard Worker         // SamplerDescs based upon whether:
308*c8dee2aaSAndroid Build Coastguard Worker         // 1) A backend passes in a non-nullptr outImmutableSamplers param (may be nullptr in
309*c8dee2aaSAndroid Build Coastguard Worker         //    backends or circumstances where we know immutable sampler data is never stored)
310*c8dee2aaSAndroid Build Coastguard Worker         // 2) Any data is stored on the ShaderNode
311*c8dee2aaSAndroid Build Coastguard Worker         // 3) Whether the ShaderNode snippet's ID matches that of any snippet ID that could store
312*c8dee2aaSAndroid Build Coastguard Worker         //    immutable sampler data.
313*c8dee2aaSAndroid Build Coastguard Worker         int32_t snippetId = node->codeSnippetId();
314*c8dee2aaSAndroid Build Coastguard Worker         if (outDescs) {
315*c8dee2aaSAndroid Build Coastguard Worker             // TODO(b/369846881): Refactor checking snippet ID to instead having a named
316*c8dee2aaSAndroid Build Coastguard Worker             // snippet requirement flag that we can check here to decrease fragility.
317*c8dee2aaSAndroid Build Coastguard Worker             if (!node->data().empty() &&
318*c8dee2aaSAndroid Build Coastguard Worker                 (snippetId == static_cast<int32_t>(BuiltInCodeSnippetID::kImageShader) ||
319*c8dee2aaSAndroid Build Coastguard Worker                  snippetId == static_cast<int32_t>(BuiltInCodeSnippetID::kCubicImageShader) ||
320*c8dee2aaSAndroid Build Coastguard Worker                  snippetId == static_cast<int32_t>(BuiltInCodeSnippetID::kHWImageShader))) {
321*c8dee2aaSAndroid Build Coastguard Worker                 append_sampler_descs(node->data(), *outDescs);
322*c8dee2aaSAndroid Build Coastguard Worker             } else {
323*c8dee2aaSAndroid Build Coastguard Worker                 // Add default SamplerDescs for any dynamic samplers to outDescs.
324*c8dee2aaSAndroid Build Coastguard Worker                 outDescs->push_back_n(samplers.size());
325*c8dee2aaSAndroid Build Coastguard Worker             }
326*c8dee2aaSAndroid Build Coastguard Worker         }
327*c8dee2aaSAndroid Build Coastguard Worker 
328*c8dee2aaSAndroid Build Coastguard Worker         for (const TextureAndSampler& t : samplers) {
329*c8dee2aaSAndroid Build Coastguard Worker             result += EmitSamplerLayout(bindingReqs, binding);
330*c8dee2aaSAndroid Build Coastguard Worker             SkSL::String::appendf(&result, " sampler2D %s_%d;\n", t.name(), node->keyIndex());
331*c8dee2aaSAndroid Build Coastguard Worker         }
332*c8dee2aaSAndroid Build Coastguard Worker     }
333*c8dee2aaSAndroid Build Coastguard Worker 
334*c8dee2aaSAndroid Build Coastguard Worker     for (const ShaderNode* child : node->children()) {
335*c8dee2aaSAndroid Build Coastguard Worker         result += get_node_texture_samplers(bindingReqs, child, binding, outDescs);
336*c8dee2aaSAndroid Build Coastguard Worker     }
337*c8dee2aaSAndroid Build Coastguard Worker     return result;
338*c8dee2aaSAndroid Build Coastguard Worker }
339*c8dee2aaSAndroid Build Coastguard Worker 
emit_textures_and_samplers(const ResourceBindingRequirements & bindingReqs,SkSpan<const ShaderNode * > nodes,int * binding,skia_private::TArray<SamplerDesc> * outDescs)340*c8dee2aaSAndroid Build Coastguard Worker std::string emit_textures_and_samplers(const ResourceBindingRequirements& bindingReqs,
341*c8dee2aaSAndroid Build Coastguard Worker                                        SkSpan<const ShaderNode*> nodes,
342*c8dee2aaSAndroid Build Coastguard Worker                                        int* binding,
343*c8dee2aaSAndroid Build Coastguard Worker                                        skia_private::TArray<SamplerDesc>* outDescs) {
344*c8dee2aaSAndroid Build Coastguard Worker     std::string result;
345*c8dee2aaSAndroid Build Coastguard Worker     for (const ShaderNode* n : nodes) {
346*c8dee2aaSAndroid Build Coastguard Worker         result += get_node_texture_samplers(bindingReqs, n, binding, outDescs);
347*c8dee2aaSAndroid Build Coastguard Worker     }
348*c8dee2aaSAndroid Build Coastguard Worker     return result;
349*c8dee2aaSAndroid Build Coastguard Worker }
350*c8dee2aaSAndroid Build Coastguard Worker 
emit_varyings(const RenderStep * step,const char * direction,bool emitSsboIndicesVarying,bool emitLocalCoordsVarying)351*c8dee2aaSAndroid Build Coastguard Worker std::string emit_varyings(const RenderStep* step,
352*c8dee2aaSAndroid Build Coastguard Worker                           const char* direction,
353*c8dee2aaSAndroid Build Coastguard Worker                           bool emitSsboIndicesVarying,
354*c8dee2aaSAndroid Build Coastguard Worker                           bool emitLocalCoordsVarying) {
355*c8dee2aaSAndroid Build Coastguard Worker     std::string result;
356*c8dee2aaSAndroid Build Coastguard Worker     int location = 0;
357*c8dee2aaSAndroid Build Coastguard Worker 
358*c8dee2aaSAndroid Build Coastguard Worker     auto appendVarying = [&](const Varying& v) {
359*c8dee2aaSAndroid Build Coastguard Worker         const char* interpolation;
360*c8dee2aaSAndroid Build Coastguard Worker         switch (v.interpolation()) {
361*c8dee2aaSAndroid Build Coastguard Worker             case Interpolation::kPerspective: interpolation = ""; break;
362*c8dee2aaSAndroid Build Coastguard Worker             case Interpolation::kLinear:      interpolation = "noperspective "; break;
363*c8dee2aaSAndroid Build Coastguard Worker             case Interpolation::kFlat:        interpolation = "flat "; break;
364*c8dee2aaSAndroid Build Coastguard Worker         }
365*c8dee2aaSAndroid Build Coastguard Worker         SkSL::String::appendf(&result, "layout(location=%d) %s %s%s %s;\n",
366*c8dee2aaSAndroid Build Coastguard Worker                               location++,
367*c8dee2aaSAndroid Build Coastguard Worker                               direction,
368*c8dee2aaSAndroid Build Coastguard Worker                               interpolation,
369*c8dee2aaSAndroid Build Coastguard Worker                               SkSLTypeString(v.gpuType()),
370*c8dee2aaSAndroid Build Coastguard Worker                               v.name());
371*c8dee2aaSAndroid Build Coastguard Worker     };
372*c8dee2aaSAndroid Build Coastguard Worker 
373*c8dee2aaSAndroid Build Coastguard Worker     if (emitSsboIndicesVarying) {
374*c8dee2aaSAndroid Build Coastguard Worker         appendVarying({RenderStep::ssboIndicesVarying(), SkSLType::kUInt2});
375*c8dee2aaSAndroid Build Coastguard Worker     }
376*c8dee2aaSAndroid Build Coastguard Worker 
377*c8dee2aaSAndroid Build Coastguard Worker     if (emitLocalCoordsVarying) {
378*c8dee2aaSAndroid Build Coastguard Worker         appendVarying({"localCoordsVar", SkSLType::kFloat2});
379*c8dee2aaSAndroid Build Coastguard Worker     }
380*c8dee2aaSAndroid Build Coastguard Worker 
381*c8dee2aaSAndroid Build Coastguard Worker     for (auto v : step->varyings()) {
382*c8dee2aaSAndroid Build Coastguard Worker         appendVarying(v);
383*c8dee2aaSAndroid Build Coastguard Worker     }
384*c8dee2aaSAndroid Build Coastguard Worker 
385*c8dee2aaSAndroid Build Coastguard Worker     return result;
386*c8dee2aaSAndroid Build Coastguard Worker }
387*c8dee2aaSAndroid Build Coastguard Worker 
388*c8dee2aaSAndroid Build Coastguard Worker // Walk the node tree and generate all preambles, accumulating into 'preamble'.
emit_preambles(const ShaderInfo & shaderInfo,SkSpan<const ShaderNode * > nodes,std::string treeLabel,std::string * preamble)389*c8dee2aaSAndroid Build Coastguard Worker void emit_preambles(const ShaderInfo& shaderInfo,
390*c8dee2aaSAndroid Build Coastguard Worker                     SkSpan<const ShaderNode*> nodes,
391*c8dee2aaSAndroid Build Coastguard Worker                     std::string treeLabel,
392*c8dee2aaSAndroid Build Coastguard Worker                     std::string* preamble) {
393*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < SkTo<int>(nodes.size()); ++i) {
394*c8dee2aaSAndroid Build Coastguard Worker         const ShaderNode* node = nodes[i];
395*c8dee2aaSAndroid Build Coastguard Worker         std::string nodeLabel = std::to_string(i);
396*c8dee2aaSAndroid Build Coastguard Worker         std::string nextLabel = treeLabel.empty() ? nodeLabel : (treeLabel + "<-" + nodeLabel);
397*c8dee2aaSAndroid Build Coastguard Worker 
398*c8dee2aaSAndroid Build Coastguard Worker         if (node->numChildren() > 0) {
399*c8dee2aaSAndroid Build Coastguard Worker             emit_preambles(shaderInfo, node->children(), nextLabel, preamble);
400*c8dee2aaSAndroid Build Coastguard Worker         }
401*c8dee2aaSAndroid Build Coastguard Worker 
402*c8dee2aaSAndroid Build Coastguard Worker         std::string nodePreamble = node->entry()->fPreambleGenerator
403*c8dee2aaSAndroid Build Coastguard Worker                                            ? node->entry()->fPreambleGenerator(shaderInfo, node)
404*c8dee2aaSAndroid Build Coastguard Worker                                            : node->generateDefaultPreamble(shaderInfo);
405*c8dee2aaSAndroid Build Coastguard Worker         if (!nodePreamble.empty()) {
406*c8dee2aaSAndroid Build Coastguard Worker             SkSL::String::appendf(preamble,
407*c8dee2aaSAndroid Build Coastguard Worker                                   "// [%d]   %s: %s\n"
408*c8dee2aaSAndroid Build Coastguard Worker                                   "%s\n",
409*c8dee2aaSAndroid Build Coastguard Worker                                   node->keyIndex(),
410*c8dee2aaSAndroid Build Coastguard Worker                                   nextLabel.c_str(),
411*c8dee2aaSAndroid Build Coastguard Worker                                   node->entry()->fName,
412*c8dee2aaSAndroid Build Coastguard Worker                                   nodePreamble.c_str());
413*c8dee2aaSAndroid Build Coastguard Worker         }
414*c8dee2aaSAndroid Build Coastguard Worker     }
415*c8dee2aaSAndroid Build Coastguard Worker }
416*c8dee2aaSAndroid Build Coastguard Worker 
emit_color_output(BlendFormula::OutputType outputType,const char * outColor,const char * inColor)417*c8dee2aaSAndroid Build Coastguard Worker std::string emit_color_output(BlendFormula::OutputType outputType,
418*c8dee2aaSAndroid Build Coastguard Worker                               const char* outColor,
419*c8dee2aaSAndroid Build Coastguard Worker                               const char* inColor) {
420*c8dee2aaSAndroid Build Coastguard Worker     switch (outputType) {
421*c8dee2aaSAndroid Build Coastguard Worker         case BlendFormula::kNone_OutputType:
422*c8dee2aaSAndroid Build Coastguard Worker             return SkSL::String::printf("%s = half4(0.0);", outColor);
423*c8dee2aaSAndroid Build Coastguard Worker 
424*c8dee2aaSAndroid Build Coastguard Worker         case BlendFormula::kCoverage_OutputType:
425*c8dee2aaSAndroid Build Coastguard Worker             return SkSL::String::printf("%s = outputCoverage;", outColor);
426*c8dee2aaSAndroid Build Coastguard Worker 
427*c8dee2aaSAndroid Build Coastguard Worker         case BlendFormula::kModulate_OutputType:
428*c8dee2aaSAndroid Build Coastguard Worker             return SkSL::String::printf("%s = %s * outputCoverage;", outColor, inColor);
429*c8dee2aaSAndroid Build Coastguard Worker 
430*c8dee2aaSAndroid Build Coastguard Worker         case BlendFormula::kSAModulate_OutputType:
431*c8dee2aaSAndroid Build Coastguard Worker             return SkSL::String::printf("%s = %s.a * outputCoverage;", outColor, inColor);
432*c8dee2aaSAndroid Build Coastguard Worker 
433*c8dee2aaSAndroid Build Coastguard Worker         case BlendFormula::kISAModulate_OutputType:
434*c8dee2aaSAndroid Build Coastguard Worker             return SkSL::String::printf("%s = (1.0 - %s.a) * outputCoverage;", outColor, inColor);
435*c8dee2aaSAndroid Build Coastguard Worker 
436*c8dee2aaSAndroid Build Coastguard Worker         case BlendFormula::kISCModulate_OutputType:
437*c8dee2aaSAndroid Build Coastguard Worker             return SkSL::String::printf(
438*c8dee2aaSAndroid Build Coastguard Worker                     "%s = (half4(1.0) - %s) * outputCoverage;", outColor, inColor);
439*c8dee2aaSAndroid Build Coastguard Worker 
440*c8dee2aaSAndroid Build Coastguard Worker         default:
441*c8dee2aaSAndroid Build Coastguard Worker             SkUNREACHABLE;
442*c8dee2aaSAndroid Build Coastguard Worker     }
443*c8dee2aaSAndroid Build Coastguard Worker }
444*c8dee2aaSAndroid Build Coastguard Worker 
make_simple_blendInfo(skgpu::BlendCoeff srcCoeff,skgpu::BlendCoeff dstCoeff)445*c8dee2aaSAndroid Build Coastguard Worker constexpr skgpu::BlendInfo make_simple_blendInfo(skgpu::BlendCoeff srcCoeff,
446*c8dee2aaSAndroid Build Coastguard Worker                                                  skgpu::BlendCoeff dstCoeff) {
447*c8dee2aaSAndroid Build Coastguard Worker     return { skgpu::BlendEquation::kAdd,
448*c8dee2aaSAndroid Build Coastguard Worker              srcCoeff,
449*c8dee2aaSAndroid Build Coastguard Worker              dstCoeff,
450*c8dee2aaSAndroid Build Coastguard Worker              SK_PMColor4fTRANSPARENT,
451*c8dee2aaSAndroid Build Coastguard Worker              skgpu::BlendModifiesDst(skgpu::BlendEquation::kAdd, srcCoeff, dstCoeff) };
452*c8dee2aaSAndroid Build Coastguard Worker }
453*c8dee2aaSAndroid Build Coastguard Worker 
454*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kNumCoeffModes = (int)SkBlendMode::kLastCoeffMode + 1;
455*c8dee2aaSAndroid Build Coastguard Worker static constexpr skgpu::BlendInfo gBlendTable[kNumCoeffModes] = {
456*c8dee2aaSAndroid Build Coastguard Worker         /* clear */      make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kZero),
457*c8dee2aaSAndroid Build Coastguard Worker         /* src */        make_simple_blendInfo(skgpu::BlendCoeff::kOne,  skgpu::BlendCoeff::kZero),
458*c8dee2aaSAndroid Build Coastguard Worker         /* dst */        make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kOne),
459*c8dee2aaSAndroid Build Coastguard Worker         /* src-over */   make_simple_blendInfo(skgpu::BlendCoeff::kOne,  skgpu::BlendCoeff::kISA),
460*c8dee2aaSAndroid Build Coastguard Worker         /* dst-over */   make_simple_blendInfo(skgpu::BlendCoeff::kIDA,  skgpu::BlendCoeff::kOne),
461*c8dee2aaSAndroid Build Coastguard Worker         /* src-in */     make_simple_blendInfo(skgpu::BlendCoeff::kDA,   skgpu::BlendCoeff::kZero),
462*c8dee2aaSAndroid Build Coastguard Worker         /* dst-in */     make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kSA),
463*c8dee2aaSAndroid Build Coastguard Worker         /* src-out */    make_simple_blendInfo(skgpu::BlendCoeff::kIDA,  skgpu::BlendCoeff::kZero),
464*c8dee2aaSAndroid Build Coastguard Worker         /* dst-out */    make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kISA),
465*c8dee2aaSAndroid Build Coastguard Worker         /* src-atop */   make_simple_blendInfo(skgpu::BlendCoeff::kDA,   skgpu::BlendCoeff::kISA),
466*c8dee2aaSAndroid Build Coastguard Worker         /* dst-atop */   make_simple_blendInfo(skgpu::BlendCoeff::kIDA,  skgpu::BlendCoeff::kSA),
467*c8dee2aaSAndroid Build Coastguard Worker         /* xor */        make_simple_blendInfo(skgpu::BlendCoeff::kIDA,  skgpu::BlendCoeff::kISA),
468*c8dee2aaSAndroid Build Coastguard Worker         /* plus */       make_simple_blendInfo(skgpu::BlendCoeff::kOne,  skgpu::BlendCoeff::kOne),
469*c8dee2aaSAndroid Build Coastguard Worker         /* modulate */   make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kSC),
470*c8dee2aaSAndroid Build Coastguard Worker         /* screen */     make_simple_blendInfo(skgpu::BlendCoeff::kOne,  skgpu::BlendCoeff::kISC)
471*c8dee2aaSAndroid Build Coastguard Worker };
472*c8dee2aaSAndroid Build Coastguard Worker 
473*c8dee2aaSAndroid Build Coastguard Worker }  // anonymous namespace
474*c8dee2aaSAndroid Build Coastguard Worker 
Make(const Caps * caps,const ShaderCodeDictionary * dict,const RuntimeEffectDictionary * rteDict,const RenderStep * step,UniquePaintParamsID paintID,bool useStorageBuffers,skgpu::Swizzle writeSwizzle,skia_private::TArray<SamplerDesc> * outDescs)475*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<ShaderInfo> ShaderInfo::Make(const Caps* caps,
476*c8dee2aaSAndroid Build Coastguard Worker                                              const ShaderCodeDictionary* dict,
477*c8dee2aaSAndroid Build Coastguard Worker                                              const RuntimeEffectDictionary* rteDict,
478*c8dee2aaSAndroid Build Coastguard Worker                                              const RenderStep* step,
479*c8dee2aaSAndroid Build Coastguard Worker                                              UniquePaintParamsID paintID,
480*c8dee2aaSAndroid Build Coastguard Worker                                              bool useStorageBuffers,
481*c8dee2aaSAndroid Build Coastguard Worker                                              skgpu::Swizzle writeSwizzle,
482*c8dee2aaSAndroid Build Coastguard Worker                                              skia_private::TArray<SamplerDesc>* outDescs) {
483*c8dee2aaSAndroid Build Coastguard Worker     const char* shadingSsboIndex =
484*c8dee2aaSAndroid Build Coastguard Worker             useStorageBuffers && step->performsShading() ? "shadingSsboIndex" : nullptr;
485*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<ShaderInfo> result =
486*c8dee2aaSAndroid Build Coastguard Worker             std::unique_ptr<ShaderInfo>(new ShaderInfo(rteDict, shadingSsboIndex));
487*c8dee2aaSAndroid Build Coastguard Worker 
488*c8dee2aaSAndroid Build Coastguard Worker     // The fragment shader must be generated before the vertex shader, because we determine
489*c8dee2aaSAndroid Build Coastguard Worker     // properties of the entire program while generating the fragment shader.
490*c8dee2aaSAndroid Build Coastguard Worker 
491*c8dee2aaSAndroid Build Coastguard Worker     // If paintID is not valid this is a depth-only draw and there's no fragment shader to compile.
492*c8dee2aaSAndroid Build Coastguard Worker     if (paintID.isValid()) {
493*c8dee2aaSAndroid Build Coastguard Worker         result->generateFragmentSkSL(caps,
494*c8dee2aaSAndroid Build Coastguard Worker                                      dict,
495*c8dee2aaSAndroid Build Coastguard Worker                                      step,
496*c8dee2aaSAndroid Build Coastguard Worker                                      paintID,
497*c8dee2aaSAndroid Build Coastguard Worker                                      useStorageBuffers,
498*c8dee2aaSAndroid Build Coastguard Worker                                      writeSwizzle,
499*c8dee2aaSAndroid Build Coastguard Worker                                      outDescs);
500*c8dee2aaSAndroid Build Coastguard Worker     }
501*c8dee2aaSAndroid Build Coastguard Worker 
502*c8dee2aaSAndroid Build Coastguard Worker     result->generateVertexSkSL(caps,
503*c8dee2aaSAndroid Build Coastguard Worker                                step,
504*c8dee2aaSAndroid Build Coastguard Worker                                useStorageBuffers);
505*c8dee2aaSAndroid Build Coastguard Worker 
506*c8dee2aaSAndroid Build Coastguard Worker     return result;
507*c8dee2aaSAndroid Build Coastguard Worker }
508*c8dee2aaSAndroid Build Coastguard Worker 
ShaderInfo(const RuntimeEffectDictionary * rteDict,const char * ssboIndex)509*c8dee2aaSAndroid Build Coastguard Worker ShaderInfo::ShaderInfo(const RuntimeEffectDictionary* rteDict, const char* ssboIndex)
510*c8dee2aaSAndroid Build Coastguard Worker         : fRuntimeEffectDictionary(rteDict), fSsboIndex(ssboIndex) {}
511*c8dee2aaSAndroid Build Coastguard Worker 
512*c8dee2aaSAndroid Build Coastguard Worker // The current, incomplete, model for shader construction is:
513*c8dee2aaSAndroid Build Coastguard Worker //   - Static code snippets (which can have an arbitrary signature) live in the Graphite
514*c8dee2aaSAndroid Build Coastguard Worker //     pre-compiled modules, which are located at `src/sksl/sksl_graphite_frag.sksl` and
515*c8dee2aaSAndroid Build Coastguard Worker //     `src/sksl/sksl_graphite_frag_es2.sksl`.
516*c8dee2aaSAndroid Build Coastguard Worker //   - Glue code is generated in a `main` method which calls these static code snippets.
517*c8dee2aaSAndroid Build Coastguard Worker //     The glue code is responsible for:
518*c8dee2aaSAndroid Build Coastguard Worker //            1) gathering the correct (mangled) uniforms
519*c8dee2aaSAndroid Build Coastguard Worker //            2) passing the uniforms and any other parameters to the helper method
520*c8dee2aaSAndroid Build Coastguard Worker //   - The result of the final code snippet is then copied into "sk_FragColor".
521*c8dee2aaSAndroid Build Coastguard Worker //   Note: each entry's 'fStaticFunctionName' field is expected to match the name of a function
522*c8dee2aaSAndroid Build Coastguard Worker //   in the Graphite pre-compiled module, or be null if the preamble and expression generators are
523*c8dee2aaSAndroid Build Coastguard Worker //   overridden to not use a static function.
generateFragmentSkSL(const Caps * caps,const ShaderCodeDictionary * dict,const RenderStep * step,UniquePaintParamsID paintID,bool useStorageBuffers,Swizzle writeSwizzle,skia_private::TArray<SamplerDesc> * outDescs)524*c8dee2aaSAndroid Build Coastguard Worker void ShaderInfo::generateFragmentSkSL(const Caps* caps,
525*c8dee2aaSAndroid Build Coastguard Worker                                       const ShaderCodeDictionary* dict,
526*c8dee2aaSAndroid Build Coastguard Worker                                       const RenderStep* step,
527*c8dee2aaSAndroid Build Coastguard Worker                                       UniquePaintParamsID paintID,
528*c8dee2aaSAndroid Build Coastguard Worker                                       bool useStorageBuffers,
529*c8dee2aaSAndroid Build Coastguard Worker                                       Swizzle writeSwizzle,
530*c8dee2aaSAndroid Build Coastguard Worker                                       skia_private::TArray<SamplerDesc>* outDescs) {
531*c8dee2aaSAndroid Build Coastguard Worker     PaintParamsKey key = dict->lookup(paintID);
532*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(key.isValid());  // invalid keys should have been caught by invalid paint ID earlier
533*c8dee2aaSAndroid Build Coastguard Worker 
534*c8dee2aaSAndroid Build Coastguard Worker     std::string label = key.toString(dict, /*includeData=*/false).c_str();
535*c8dee2aaSAndroid Build Coastguard Worker     fRootNodes = key.getRootNodes(dict, &fShaderNodeAlloc);
536*c8dee2aaSAndroid Build Coastguard Worker 
537*c8dee2aaSAndroid Build Coastguard Worker     // TODO(b/366220690): aggregateSnippetData() goes away entirely once the VulkanGraphicsPipeline
538*c8dee2aaSAndroid Build Coastguard Worker     // is updated to use the extracted SamplerDescs directly.
539*c8dee2aaSAndroid Build Coastguard Worker     for (const ShaderNode* root : fRootNodes) {
540*c8dee2aaSAndroid Build Coastguard Worker         this->aggregateSnippetData(root);
541*c8dee2aaSAndroid Build Coastguard Worker     }
542*c8dee2aaSAndroid Build Coastguard Worker 
543*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG)
544*c8dee2aaSAndroid Build Coastguard Worker     // Validate the root node structure of the key.
545*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fRootNodes.size() == 2 || fRootNodes.size() == 3);
546*c8dee2aaSAndroid Build Coastguard Worker     // First node produces the source color (all snippets return a half4), so we just require that
547*c8dee2aaSAndroid Build Coastguard Worker     // its signature takes no extra args or just local coords.
548*c8dee2aaSAndroid Build Coastguard Worker     const ShaderSnippet* srcSnippet = dict->getEntry(fRootNodes[0]->codeSnippetId());
549*c8dee2aaSAndroid Build Coastguard Worker     // TODO(b/349997190): Once SkEmptyShader doesn't use the passthrough snippet, we can assert
550*c8dee2aaSAndroid Build Coastguard Worker     // that srcSnippet->needsPriorStageOutput() is false.
551*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!srcSnippet->needsBlenderDstColor());
552*c8dee2aaSAndroid Build Coastguard Worker     // Second node is the final blender, so it must take both the src color and dst color, and not
553*c8dee2aaSAndroid Build Coastguard Worker     // any local coordinate.
554*c8dee2aaSAndroid Build Coastguard Worker     const ShaderSnippet* blendSnippet = dict->getEntry(fRootNodes[1]->codeSnippetId());
555*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(blendSnippet->needsPriorStageOutput() && blendSnippet->needsBlenderDstColor());
556*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!blendSnippet->needsLocalCoords());
557*c8dee2aaSAndroid Build Coastguard Worker 
558*c8dee2aaSAndroid Build Coastguard Worker     const ShaderSnippet* clipSnippet =
559*c8dee2aaSAndroid Build Coastguard Worker             fRootNodes.size() > 2 ? dict->getEntry(fRootNodes[2]->codeSnippetId()) : nullptr;
560*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!clipSnippet ||
561*c8dee2aaSAndroid Build Coastguard Worker              (!clipSnippet->needsPriorStageOutput() && !clipSnippet->needsBlenderDstColor()));
562*c8dee2aaSAndroid Build Coastguard Worker #endif
563*c8dee2aaSAndroid Build Coastguard Worker 
564*c8dee2aaSAndroid Build Coastguard Worker     // The RenderStep should be performing shading since otherwise there's no need to generate a
565*c8dee2aaSAndroid Build Coastguard Worker     // fragment shader program at all.
566*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(step->performsShading());
567*c8dee2aaSAndroid Build Coastguard Worker     // TODO(b/372912880): Release assert debugging for illegal instruction occurring in the wild.
568*c8dee2aaSAndroid Build Coastguard Worker     SkASSERTF_RELEASE(step->performsShading(),
569*c8dee2aaSAndroid Build Coastguard Worker                       "render step: %s, label: %s",
570*c8dee2aaSAndroid Build Coastguard Worker                       step->name(),
571*c8dee2aaSAndroid Build Coastguard Worker                       label.c_str());
572*c8dee2aaSAndroid Build Coastguard Worker 
573*c8dee2aaSAndroid Build Coastguard Worker     // Extract the root nodes for clarity
574*c8dee2aaSAndroid Build Coastguard Worker     // TODO(b/372912880): Release assert debugging for illegal instruction occurring in the wild.
575*c8dee2aaSAndroid Build Coastguard Worker     SkASSERTF_RELEASE(fRootNodes.size() == 2 || fRootNodes.size() == 3,
576*c8dee2aaSAndroid Build Coastguard Worker                       "root node size = %zu, label = %s",
577*c8dee2aaSAndroid Build Coastguard Worker                       fRootNodes.size(),
578*c8dee2aaSAndroid Build Coastguard Worker                       label.c_str());
579*c8dee2aaSAndroid Build Coastguard Worker     const ShaderNode* const srcColorRoot = fRootNodes[0];
580*c8dee2aaSAndroid Build Coastguard Worker     const ShaderNode* const finalBlendRoot = fRootNodes[1];
581*c8dee2aaSAndroid Build Coastguard Worker     const ShaderNode* const clipRoot = fRootNodes.size() > 2 ? fRootNodes[2] : nullptr;
582*c8dee2aaSAndroid Build Coastguard Worker 
583*c8dee2aaSAndroid Build Coastguard Worker     // Determine the algorithm for final blending: direct HW blending, coverage-modified HW
584*c8dee2aaSAndroid Build Coastguard Worker     // blending (w/ or w/o dual-source blending) or via dst-read requirement.
585*c8dee2aaSAndroid Build Coastguard Worker     Coverage finalCoverage = step->coverage();
586*c8dee2aaSAndroid Build Coastguard Worker     if (finalCoverage == Coverage::kNone && SkToBool(clipRoot)) {
587*c8dee2aaSAndroid Build Coastguard Worker         finalCoverage = Coverage::kSingleChannel;
588*c8dee2aaSAndroid Build Coastguard Worker     }
589*c8dee2aaSAndroid Build Coastguard Worker     std::optional<SkBlendMode> finalBlendMode;
590*c8dee2aaSAndroid Build Coastguard Worker     if (finalBlendRoot->codeSnippetId() < kBuiltInCodeSnippetIDCount &&
591*c8dee2aaSAndroid Build Coastguard Worker         finalBlendRoot->codeSnippetId() >= kFixedBlendIDOffset) {
592*c8dee2aaSAndroid Build Coastguard Worker         finalBlendMode =
593*c8dee2aaSAndroid Build Coastguard Worker                 static_cast<SkBlendMode>(finalBlendRoot->codeSnippetId() - kFixedBlendIDOffset);
594*c8dee2aaSAndroid Build Coastguard Worker         if (*finalBlendMode > SkBlendMode::kLastCoeffMode) {
595*c8dee2aaSAndroid Build Coastguard Worker             // TODO(b/239726010): When we support advanced blend modes in HW, these modes could
596*c8dee2aaSAndroid Build Coastguard Worker             // still be handled by fBlendInfo instead of SkSL
597*c8dee2aaSAndroid Build Coastguard Worker             finalBlendMode.reset();
598*c8dee2aaSAndroid Build Coastguard Worker         }
599*c8dee2aaSAndroid Build Coastguard Worker     }
600*c8dee2aaSAndroid Build Coastguard Worker     fDstReadRequirement = GetDstReadRequirement(caps, finalBlendMode, finalCoverage);
601*c8dee2aaSAndroid Build Coastguard Worker     // TODO(b/372912880): Release assert debugging for illegal instruction occurring in the wild.
602*c8dee2aaSAndroid Build Coastguard Worker     SkASSERTF_RELEASE(finalBlendMode.has_value() ||
603*c8dee2aaSAndroid Build Coastguard Worker                       fDstReadRequirement != DstReadRequirement::kNone,
604*c8dee2aaSAndroid Build Coastguard Worker                       "blend mode: %d, dst read: %d, coverage: %d, label = %s",
605*c8dee2aaSAndroid Build Coastguard Worker                       finalBlendMode.has_value() ? (int)*finalBlendMode : -1,
606*c8dee2aaSAndroid Build Coastguard Worker                       (int) fDstReadRequirement,
607*c8dee2aaSAndroid Build Coastguard Worker                       (int) finalCoverage,
608*c8dee2aaSAndroid Build Coastguard Worker                       label.c_str());
609*c8dee2aaSAndroid Build Coastguard Worker 
610*c8dee2aaSAndroid Build Coastguard Worker     const bool hasStepUniforms = step->numUniforms() > 0 && step->coverage() != Coverage::kNone;
611*c8dee2aaSAndroid Build Coastguard Worker     const bool useStepStorageBuffer = useStorageBuffers && hasStepUniforms;
612*c8dee2aaSAndroid Build Coastguard Worker     const bool useShadingStorageBuffer = useStorageBuffers && step->performsShading();
613*c8dee2aaSAndroid Build Coastguard Worker 
614*c8dee2aaSAndroid Build Coastguard Worker     auto allReqFlags = srcColorRoot->requiredFlags() | finalBlendRoot->requiredFlags();
615*c8dee2aaSAndroid Build Coastguard Worker     if (clipRoot) {
616*c8dee2aaSAndroid Build Coastguard Worker         allReqFlags |= clipRoot->requiredFlags();
617*c8dee2aaSAndroid Build Coastguard Worker     }
618*c8dee2aaSAndroid Build Coastguard Worker     const bool useGradientStorageBuffer = caps->gradientBufferSupport() &&
619*c8dee2aaSAndroid Build Coastguard Worker                                           (allReqFlags & SnippetRequirementFlags::kGradientBuffer);
620*c8dee2aaSAndroid Build Coastguard Worker     const bool useDstSampler = fDstReadRequirement == DstReadRequirement::kTextureCopy ||
621*c8dee2aaSAndroid Build Coastguard Worker                                fDstReadRequirement == DstReadRequirement::kTextureSample;
622*c8dee2aaSAndroid Build Coastguard Worker 
623*c8dee2aaSAndroid Build Coastguard Worker     const bool defineLocalCoordsVarying = this->needsLocalCoords();
624*c8dee2aaSAndroid Build Coastguard Worker     std::string preamble = emit_varyings(step,
625*c8dee2aaSAndroid Build Coastguard Worker                                          /*direction=*/"in",
626*c8dee2aaSAndroid Build Coastguard Worker                                          /*emitSsboIndicesVarying=*/useShadingStorageBuffer,
627*c8dee2aaSAndroid Build Coastguard Worker                                          defineLocalCoordsVarying);
628*c8dee2aaSAndroid Build Coastguard Worker 
629*c8dee2aaSAndroid Build Coastguard Worker     // The uniforms are mangled by having their index in 'fEntries' as a suffix (i.e., "_%d")
630*c8dee2aaSAndroid Build Coastguard Worker     const ResourceBindingRequirements& bindingReqs = caps->resourceBindingRequirements();
631*c8dee2aaSAndroid Build Coastguard Worker     preamble += emit_intrinsic_uniforms(bindingReqs.fIntrinsicBufferBinding,
632*c8dee2aaSAndroid Build Coastguard Worker                                         bindingReqs.fUniformBufferLayout);
633*c8dee2aaSAndroid Build Coastguard Worker     if (hasStepUniforms) {
634*c8dee2aaSAndroid Build Coastguard Worker         if (useStepStorageBuffer) {
635*c8dee2aaSAndroid Build Coastguard Worker             preamble += emit_render_step_storage_buffer(bindingReqs.fRenderStepBufferBinding,
636*c8dee2aaSAndroid Build Coastguard Worker                                                         step->uniforms());
637*c8dee2aaSAndroid Build Coastguard Worker         } else {
638*c8dee2aaSAndroid Build Coastguard Worker             preamble += emit_render_step_uniforms(bindingReqs.fRenderStepBufferBinding,
639*c8dee2aaSAndroid Build Coastguard Worker                                                   bindingReqs.fUniformBufferLayout,
640*c8dee2aaSAndroid Build Coastguard Worker                                                   step->uniforms());
641*c8dee2aaSAndroid Build Coastguard Worker         }
642*c8dee2aaSAndroid Build Coastguard Worker     }
643*c8dee2aaSAndroid Build Coastguard Worker 
644*c8dee2aaSAndroid Build Coastguard Worker     bool wrotePaintColor = false;
645*c8dee2aaSAndroid Build Coastguard Worker     if (useShadingStorageBuffer) {
646*c8dee2aaSAndroid Build Coastguard Worker         preamble += emit_paint_params_storage_buffer(bindingReqs.fPaintParamsBufferBinding,
647*c8dee2aaSAndroid Build Coastguard Worker                                                      fRootNodes,
648*c8dee2aaSAndroid Build Coastguard Worker                                                      &fHasPaintUniforms,
649*c8dee2aaSAndroid Build Coastguard Worker                                                      &wrotePaintColor);
650*c8dee2aaSAndroid Build Coastguard Worker         SkSL::String::appendf(&preamble, "uint %s;\n", this->ssboIndex());
651*c8dee2aaSAndroid Build Coastguard Worker     } else {
652*c8dee2aaSAndroid Build Coastguard Worker         preamble += emit_paint_params_uniforms(bindingReqs.fPaintParamsBufferBinding,
653*c8dee2aaSAndroid Build Coastguard Worker                                                bindingReqs.fUniformBufferLayout,
654*c8dee2aaSAndroid Build Coastguard Worker                                                fRootNodes,
655*c8dee2aaSAndroid Build Coastguard Worker                                                &fHasPaintUniforms,
656*c8dee2aaSAndroid Build Coastguard Worker                                                &wrotePaintColor);
657*c8dee2aaSAndroid Build Coastguard Worker     }
658*c8dee2aaSAndroid Build Coastguard Worker 
659*c8dee2aaSAndroid Build Coastguard Worker     if (useGradientStorageBuffer) {
660*c8dee2aaSAndroid Build Coastguard Worker         SkSL::String::appendf(&preamble,
661*c8dee2aaSAndroid Build Coastguard Worker                               "layout (binding=%d) readonly buffer FSGradientBuffer {\n"
662*c8dee2aaSAndroid Build Coastguard Worker                               "    float %s[];\n"
663*c8dee2aaSAndroid Build Coastguard Worker                               "};\n",
664*c8dee2aaSAndroid Build Coastguard Worker                               bindingReqs.fGradientBufferBinding,
665*c8dee2aaSAndroid Build Coastguard Worker                               ShaderInfo::kGradientBufferName);
666*c8dee2aaSAndroid Build Coastguard Worker         fHasGradientBuffer = true;
667*c8dee2aaSAndroid Build Coastguard Worker     }
668*c8dee2aaSAndroid Build Coastguard Worker 
669*c8dee2aaSAndroid Build Coastguard Worker     {
670*c8dee2aaSAndroid Build Coastguard Worker         int binding = 0;
671*c8dee2aaSAndroid Build Coastguard Worker         preamble += emit_textures_and_samplers(bindingReqs, fRootNodes, &binding, outDescs);
672*c8dee2aaSAndroid Build Coastguard Worker         int paintTextureCount = binding;
673*c8dee2aaSAndroid Build Coastguard Worker         if (step->hasTextures()) {
674*c8dee2aaSAndroid Build Coastguard Worker             preamble += step->texturesAndSamplersSkSL(bindingReqs, &binding);
675*c8dee2aaSAndroid Build Coastguard Worker             if (outDescs) {
676*c8dee2aaSAndroid Build Coastguard Worker                 // Determine how many render step samplers were used by comparing the binding value
677*c8dee2aaSAndroid Build Coastguard Worker                 // against paintTextureCount, taking into account the binding requirements. We
678*c8dee2aaSAndroid Build Coastguard Worker                 // assume and do not anticipate the render steps to use immutable samplers.
679*c8dee2aaSAndroid Build Coastguard Worker                 int renderStepSamplerCount = bindingReqs.fSeparateTextureAndSamplerBinding
680*c8dee2aaSAndroid Build Coastguard Worker                                                      ? (binding - paintTextureCount) / 2
681*c8dee2aaSAndroid Build Coastguard Worker                                                      : binding - paintTextureCount;
682*c8dee2aaSAndroid Build Coastguard Worker                 // Add default SamplerDescs for all the dynamic samplers used by the render step so
683*c8dee2aaSAndroid Build Coastguard Worker                 // the size of outDescs will be equivalent to the total number of samplers.
684*c8dee2aaSAndroid Build Coastguard Worker                 outDescs->push_back_n(renderStepSamplerCount);
685*c8dee2aaSAndroid Build Coastguard Worker             }
686*c8dee2aaSAndroid Build Coastguard Worker         }
687*c8dee2aaSAndroid Build Coastguard Worker         if (useDstSampler) {
688*c8dee2aaSAndroid Build Coastguard Worker             preamble += EmitSamplerLayout(bindingReqs, &binding);
689*c8dee2aaSAndroid Build Coastguard Worker             preamble += " sampler2D dstSampler;";
690*c8dee2aaSAndroid Build Coastguard Worker             // Add default SamplerDesc for the intrinsic dstSampler to stay consistent with
691*c8dee2aaSAndroid Build Coastguard Worker             // `fNumFragmentTexturesAndSamplers`.
692*c8dee2aaSAndroid Build Coastguard Worker             if (outDescs) {
693*c8dee2aaSAndroid Build Coastguard Worker                 outDescs->push_back({});
694*c8dee2aaSAndroid Build Coastguard Worker             }
695*c8dee2aaSAndroid Build Coastguard Worker         }
696*c8dee2aaSAndroid Build Coastguard Worker 
697*c8dee2aaSAndroid Build Coastguard Worker         // Record how many textures and samplers are used.
698*c8dee2aaSAndroid Build Coastguard Worker         fNumFragmentTexturesAndSamplers = binding;
699*c8dee2aaSAndroid Build Coastguard Worker     }
700*c8dee2aaSAndroid Build Coastguard Worker 
701*c8dee2aaSAndroid Build Coastguard Worker     // Emit preamble declarations and helper functions required for snippets. In the default case
702*c8dee2aaSAndroid Build Coastguard Worker     // this adds functions that bind a node's specific mangled uniforms to the snippet's
703*c8dee2aaSAndroid Build Coastguard Worker     // implementation in the SkSL modules.
704*c8dee2aaSAndroid Build Coastguard Worker     emit_preambles(*this, fRootNodes, /*treeLabel=*/"", &preamble);
705*c8dee2aaSAndroid Build Coastguard Worker 
706*c8dee2aaSAndroid Build Coastguard Worker     std::string mainBody = "void main() {";
707*c8dee2aaSAndroid Build Coastguard Worker 
708*c8dee2aaSAndroid Build Coastguard Worker     if (useShadingStorageBuffer) {
709*c8dee2aaSAndroid Build Coastguard Worker         SkSL::String::appendf(&mainBody,
710*c8dee2aaSAndroid Build Coastguard Worker                               "%s = %s.y;\n",
711*c8dee2aaSAndroid Build Coastguard Worker                               this->ssboIndex(),
712*c8dee2aaSAndroid Build Coastguard Worker                               RenderStep::ssboIndicesVarying());
713*c8dee2aaSAndroid Build Coastguard Worker     }
714*c8dee2aaSAndroid Build Coastguard Worker 
715*c8dee2aaSAndroid Build Coastguard Worker     if (step->emitsPrimitiveColor()) {
716*c8dee2aaSAndroid Build Coastguard Worker         mainBody += "half4 primitiveColor;";
717*c8dee2aaSAndroid Build Coastguard Worker         mainBody += step->fragmentColorSkSL();
718*c8dee2aaSAndroid Build Coastguard Worker     } else {
719*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!(fRootNodes[0]->requiredFlags() & SnippetRequirementFlags::kPrimitiveColor));
720*c8dee2aaSAndroid Build Coastguard Worker     }
721*c8dee2aaSAndroid Build Coastguard Worker 
722*c8dee2aaSAndroid Build Coastguard Worker     // Using kDefaultArgs as the initial value means it will refer to undefined variables, but the
723*c8dee2aaSAndroid Build Coastguard Worker     // root nodes should--at most--be depending on the coordinate when "needsLocalCoords" is true.
724*c8dee2aaSAndroid Build Coastguard Worker     // If the PaintParamsKey violates that structure, this will produce SkSL compile errors.
725*c8dee2aaSAndroid Build Coastguard Worker     ShaderSnippet::Args args = ShaderSnippet::kDefaultArgs;
726*c8dee2aaSAndroid Build Coastguard Worker     args.fFragCoord = "localCoordsVar";  // the varying added in emit_varyings()
727*c8dee2aaSAndroid Build Coastguard Worker     // TODO(b/349997190): The paint root node should not depend on any prior stage's output, but
728*c8dee2aaSAndroid Build Coastguard Worker     // it can happen with how SkEmptyShader is currently mapped to `sk_passthrough`. In this case
729*c8dee2aaSAndroid Build Coastguard Worker     // it requires that prior stage color to be transparent black. When SkEmptyShader can instead
730*c8dee2aaSAndroid Build Coastguard Worker     // cause the draw to be skipped, this can go away.
731*c8dee2aaSAndroid Build Coastguard Worker     args.fPriorStageOutput = "half4(0)";
732*c8dee2aaSAndroid Build Coastguard Worker 
733*c8dee2aaSAndroid Build Coastguard Worker     // Calculate the src color and stash its output variable in `args`
734*c8dee2aaSAndroid Build Coastguard Worker     args.fPriorStageOutput = srcColorRoot->invokeAndAssign(*this, args, &mainBody);
735*c8dee2aaSAndroid Build Coastguard Worker 
736*c8dee2aaSAndroid Build Coastguard Worker     if (fDstReadRequirement != DstReadRequirement::kNone) {
737*c8dee2aaSAndroid Build Coastguard Worker         // Get the current dst color into a local variable, it may be used later on for coverage
738*c8dee2aaSAndroid Build Coastguard Worker         // blending as well as the final blend.
739*c8dee2aaSAndroid Build Coastguard Worker         mainBody += "half4 dstColor;";
740*c8dee2aaSAndroid Build Coastguard Worker         if (useDstSampler) {
741*c8dee2aaSAndroid Build Coastguard Worker             // dstCopyBounds is in frag coords and already includes the replay translation. The
742*c8dee2aaSAndroid Build Coastguard Worker             // reciprocol of the dstCopy dimensions are in ZW.
743*c8dee2aaSAndroid Build Coastguard Worker             mainBody += "dstColor = sample(dstSampler,"
744*c8dee2aaSAndroid Build Coastguard Worker                                           "dstCopyBounds.zw*(sk_FragCoord.xy - dstCopyBounds.xy));";
745*c8dee2aaSAndroid Build Coastguard Worker         } else {
746*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fDstReadRequirement == DstReadRequirement::kFramebufferFetch);
747*c8dee2aaSAndroid Build Coastguard Worker             mainBody += "dstColor = sk_LastFragColor;";
748*c8dee2aaSAndroid Build Coastguard Worker         }
749*c8dee2aaSAndroid Build Coastguard Worker 
750*c8dee2aaSAndroid Build Coastguard Worker         args.fBlenderDstColor = "dstColor";
751*c8dee2aaSAndroid Build Coastguard Worker         args.fPriorStageOutput = finalBlendRoot->invokeAndAssign(*this, args, &mainBody);
752*c8dee2aaSAndroid Build Coastguard Worker         finalBlendMode = SkBlendMode::kSrc;
753*c8dee2aaSAndroid Build Coastguard Worker     }
754*c8dee2aaSAndroid Build Coastguard Worker 
755*c8dee2aaSAndroid Build Coastguard Worker     if (writeSwizzle != Swizzle::RGBA()) {
756*c8dee2aaSAndroid Build Coastguard Worker         SkSL::String::appendf(&mainBody, "%s = %s.%s;", args.fPriorStageOutput.c_str(),
757*c8dee2aaSAndroid Build Coastguard Worker                                                         args.fPriorStageOutput.c_str(),
758*c8dee2aaSAndroid Build Coastguard Worker                                                         writeSwizzle.asString().c_str());
759*c8dee2aaSAndroid Build Coastguard Worker     }
760*c8dee2aaSAndroid Build Coastguard Worker 
761*c8dee2aaSAndroid Build Coastguard Worker     if (finalCoverage == Coverage::kNone) {
762*c8dee2aaSAndroid Build Coastguard Worker         // Either direct HW blending or a dst-read w/o any extra coverage. In both cases we just
763*c8dee2aaSAndroid Build Coastguard Worker         // need to assign directly to sk_FragCoord and update the HW blend info to finalBlendMode.
764*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(finalBlendMode.has_value());
765*c8dee2aaSAndroid Build Coastguard Worker         // TODO(b/372912880): Release assert debugging for illegal instruction occurring in the wild
766*c8dee2aaSAndroid Build Coastguard Worker         SkASSERTF_RELEASE(finalBlendMode.has_value(),
767*c8dee2aaSAndroid Build Coastguard Worker                           "blend mode: %d, dst read: %d, label = %s",
768*c8dee2aaSAndroid Build Coastguard Worker                           finalBlendMode.has_value() ? (int)*finalBlendMode : -1,
769*c8dee2aaSAndroid Build Coastguard Worker                           (int) fDstReadRequirement,
770*c8dee2aaSAndroid Build Coastguard Worker                           label.c_str());
771*c8dee2aaSAndroid Build Coastguard Worker 
772*c8dee2aaSAndroid Build Coastguard Worker         fBlendInfo = gBlendTable[static_cast<int>(*finalBlendMode)];
773*c8dee2aaSAndroid Build Coastguard Worker         SkSL::String::appendf(&mainBody, "sk_FragColor = %s;", args.fPriorStageOutput.c_str());
774*c8dee2aaSAndroid Build Coastguard Worker     } else {
775*c8dee2aaSAndroid Build Coastguard Worker         // Accumulate the output coverage. This will either modify the src color and secondary
776*c8dee2aaSAndroid Build Coastguard Worker         // outputs for dual-source blending, or be combined directly with the in-shader blended
777*c8dee2aaSAndroid Build Coastguard Worker         // final color if a dst-readback was required.
778*c8dee2aaSAndroid Build Coastguard Worker         if (useStepStorageBuffer) {
779*c8dee2aaSAndroid Build Coastguard Worker             SkSL::String::appendf(&mainBody,
780*c8dee2aaSAndroid Build Coastguard Worker                                   "uint stepSsboIndex = %s.x;\n",
781*c8dee2aaSAndroid Build Coastguard Worker                                   RenderStep::ssboIndicesVarying());
782*c8dee2aaSAndroid Build Coastguard Worker             mainBody +=
783*c8dee2aaSAndroid Build Coastguard Worker                     emit_uniforms_from_storage_buffer("step", "stepSsboIndex", step->uniforms());
784*c8dee2aaSAndroid Build Coastguard Worker         }
785*c8dee2aaSAndroid Build Coastguard Worker 
786*c8dee2aaSAndroid Build Coastguard Worker         mainBody += "half4 outputCoverage = half4(1);";
787*c8dee2aaSAndroid Build Coastguard Worker         mainBody += step->fragmentCoverageSkSL();
788*c8dee2aaSAndroid Build Coastguard Worker 
789*c8dee2aaSAndroid Build Coastguard Worker         if (clipRoot) {
790*c8dee2aaSAndroid Build Coastguard Worker             // The clip block node is invoked with device coords, not local coords like the main
791*c8dee2aaSAndroid Build Coastguard Worker             // shading root node. However sk_FragCoord includes any replay translation and we
792*c8dee2aaSAndroid Build Coastguard Worker             // need to recover the original device coordinate.
793*c8dee2aaSAndroid Build Coastguard Worker             mainBody += "float2 devCoord = sk_FragCoord.xy - viewport.xy;";
794*c8dee2aaSAndroid Build Coastguard Worker             args.fFragCoord = "devCoord";
795*c8dee2aaSAndroid Build Coastguard Worker             std::string clipBlockOutput = clipRoot->invokeAndAssign(*this, args, &mainBody);
796*c8dee2aaSAndroid Build Coastguard Worker             SkSL::String::appendf(&mainBody, "outputCoverage *= %s.a;", clipBlockOutput.c_str());
797*c8dee2aaSAndroid Build Coastguard Worker         }
798*c8dee2aaSAndroid Build Coastguard Worker 
799*c8dee2aaSAndroid Build Coastguard Worker         const char* outColor = args.fPriorStageOutput.c_str();
800*c8dee2aaSAndroid Build Coastguard Worker         if (fDstReadRequirement != DstReadRequirement::kNone) {
801*c8dee2aaSAndroid Build Coastguard Worker             // If this draw uses a non-coherent dst read, we want to keep the existing dst color (or
802*c8dee2aaSAndroid Build Coastguard Worker             // whatever has been previously drawn) when there's no coverage. This helps for batching
803*c8dee2aaSAndroid Build Coastguard Worker             // text draws that need to read from a dst copy for blends. However, this only helps the
804*c8dee2aaSAndroid Build Coastguard Worker             // case where the outer bounding boxes of each letter overlap and not two actual parts
805*c8dee2aaSAndroid Build Coastguard Worker             // of the text.
806*c8dee2aaSAndroid Build Coastguard Worker             if (useDstSampler) {
807*c8dee2aaSAndroid Build Coastguard Worker                 // We don't think any shaders actually output negative coverage, but just as a
808*c8dee2aaSAndroid Build Coastguard Worker                 // safety check for floating point precision errors, we compare with <= here. We
809*c8dee2aaSAndroid Build Coastguard Worker                 // just check the RGB values of the coverage, since the alpha may not have been set
810*c8dee2aaSAndroid Build Coastguard Worker                 // when using LCD. If we are using single-channel coverage, alpha will be equal to
811*c8dee2aaSAndroid Build Coastguard Worker                 // RGB anyway.
812*c8dee2aaSAndroid Build Coastguard Worker                 mainBody +=
813*c8dee2aaSAndroid Build Coastguard Worker                     "if (all(lessThanEqual(outputCoverage.rgb, half3(0)))) {"
814*c8dee2aaSAndroid Build Coastguard Worker                         "discard;"
815*c8dee2aaSAndroid Build Coastguard Worker                     "}";
816*c8dee2aaSAndroid Build Coastguard Worker             }
817*c8dee2aaSAndroid Build Coastguard Worker 
818*c8dee2aaSAndroid Build Coastguard Worker             // Use kSrc HW BlendInfo and do the coverage blend with dst in the shader.
819*c8dee2aaSAndroid Build Coastguard Worker             fBlendInfo = gBlendTable[static_cast<int>(SkBlendMode::kSrc)];
820*c8dee2aaSAndroid Build Coastguard Worker             SkSL::String::appendf(
821*c8dee2aaSAndroid Build Coastguard Worker                     &mainBody,
822*c8dee2aaSAndroid Build Coastguard Worker                     "sk_FragColor = %s * outputCoverage + dstColor * (1.0 - outputCoverage);",
823*c8dee2aaSAndroid Build Coastguard Worker                     outColor);
824*c8dee2aaSAndroid Build Coastguard Worker             if (finalCoverage == Coverage::kLCD) {
825*c8dee2aaSAndroid Build Coastguard Worker                 SkSL::String::appendf(
826*c8dee2aaSAndroid Build Coastguard Worker                         &mainBody,
827*c8dee2aaSAndroid Build Coastguard Worker                         "half3 lerpRGB = mix(dstColor.aaa, %s.aaa, outputCoverage.rgb);"
828*c8dee2aaSAndroid Build Coastguard Worker                         "sk_FragColor.a = max(max(lerpRGB.r, lerpRGB.g), lerpRGB.b);",
829*c8dee2aaSAndroid Build Coastguard Worker                         outColor);
830*c8dee2aaSAndroid Build Coastguard Worker             }
831*c8dee2aaSAndroid Build Coastguard Worker         } else {
832*c8dee2aaSAndroid Build Coastguard Worker             // Adjust the shader output(s) to incorporate the coverage so that HW blending produces
833*c8dee2aaSAndroid Build Coastguard Worker             // the correct output.
834*c8dee2aaSAndroid Build Coastguard Worker             // TODO: Determine whether draw is opaque and pass that to GetBlendFormula.
835*c8dee2aaSAndroid Build Coastguard Worker             // TODO(b/372912880): Release assert debugging for illegal instruction
836*c8dee2aaSAndroid Build Coastguard Worker             SkASSERTF_RELEASE(finalBlendMode.has_value(),
837*c8dee2aaSAndroid Build Coastguard Worker                               "blend mode: %d, dst read: %d, coverage: %d, label = %s",
838*c8dee2aaSAndroid Build Coastguard Worker                               finalBlendMode.has_value() ? (int)*finalBlendMode : -1,
839*c8dee2aaSAndroid Build Coastguard Worker                               (int) fDstReadRequirement,
840*c8dee2aaSAndroid Build Coastguard Worker                               (int) finalCoverage,
841*c8dee2aaSAndroid Build Coastguard Worker                               label.c_str());
842*c8dee2aaSAndroid Build Coastguard Worker             BlendFormula coverageBlendFormula =
843*c8dee2aaSAndroid Build Coastguard Worker                     finalCoverage == Coverage::kLCD
844*c8dee2aaSAndroid Build Coastguard Worker                             ? skgpu::GetLCDBlendFormula(*finalBlendMode)
845*c8dee2aaSAndroid Build Coastguard Worker                             : skgpu::GetBlendFormula(
846*c8dee2aaSAndroid Build Coastguard Worker                                       /*isOpaque=*/false, /*hasCoverage=*/true, *finalBlendMode);
847*c8dee2aaSAndroid Build Coastguard Worker             fBlendInfo = {coverageBlendFormula.equation(),
848*c8dee2aaSAndroid Build Coastguard Worker                           coverageBlendFormula.srcCoeff(),
849*c8dee2aaSAndroid Build Coastguard Worker                           coverageBlendFormula.dstCoeff(),
850*c8dee2aaSAndroid Build Coastguard Worker                           SK_PMColor4fTRANSPARENT,
851*c8dee2aaSAndroid Build Coastguard Worker                           coverageBlendFormula.modifiesDst()};
852*c8dee2aaSAndroid Build Coastguard Worker 
853*c8dee2aaSAndroid Build Coastguard Worker             if (finalCoverage == Coverage::kLCD) {
854*c8dee2aaSAndroid Build Coastguard Worker                 mainBody += "outputCoverage.a = max(max(outputCoverage.r, "
855*c8dee2aaSAndroid Build Coastguard Worker                                                        "outputCoverage.g), "
856*c8dee2aaSAndroid Build Coastguard Worker                                                    "outputCoverage.b);";
857*c8dee2aaSAndroid Build Coastguard Worker             }
858*c8dee2aaSAndroid Build Coastguard Worker 
859*c8dee2aaSAndroid Build Coastguard Worker             mainBody += emit_color_output(coverageBlendFormula.primaryOutput(),
860*c8dee2aaSAndroid Build Coastguard Worker                                           "sk_FragColor",
861*c8dee2aaSAndroid Build Coastguard Worker                                           outColor);
862*c8dee2aaSAndroid Build Coastguard Worker             if (coverageBlendFormula.hasSecondaryOutput()) {
863*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(caps->shaderCaps()->fDualSourceBlendingSupport);
864*c8dee2aaSAndroid Build Coastguard Worker                 mainBody += emit_color_output(coverageBlendFormula.secondaryOutput(),
865*c8dee2aaSAndroid Build Coastguard Worker                                               "sk_SecondaryFragColor",
866*c8dee2aaSAndroid Build Coastguard Worker                                               outColor);
867*c8dee2aaSAndroid Build Coastguard Worker             }
868*c8dee2aaSAndroid Build Coastguard Worker         }
869*c8dee2aaSAndroid Build Coastguard Worker     }
870*c8dee2aaSAndroid Build Coastguard Worker     mainBody += "}\n";
871*c8dee2aaSAndroid Build Coastguard Worker 
872*c8dee2aaSAndroid Build Coastguard Worker     fFragmentSkSL = preamble + "\n" + mainBody;
873*c8dee2aaSAndroid Build Coastguard Worker 
874*c8dee2aaSAndroid Build Coastguard Worker     fFSLabel = writeSwizzle.asString().c_str();
875*c8dee2aaSAndroid Build Coastguard Worker     fFSLabel += " + ";
876*c8dee2aaSAndroid Build Coastguard Worker     fFSLabel = step->name();
877*c8dee2aaSAndroid Build Coastguard Worker     fFSLabel += " + ";
878*c8dee2aaSAndroid Build Coastguard Worker     fFSLabel += label;
879*c8dee2aaSAndroid Build Coastguard Worker }
880*c8dee2aaSAndroid Build Coastguard Worker 
generateVertexSkSL(const Caps * caps,const RenderStep * step,bool useStorageBuffers)881*c8dee2aaSAndroid Build Coastguard Worker void ShaderInfo::generateVertexSkSL(const Caps* caps,
882*c8dee2aaSAndroid Build Coastguard Worker                                     const RenderStep* step,
883*c8dee2aaSAndroid Build Coastguard Worker                                     bool useStorageBuffers) {
884*c8dee2aaSAndroid Build Coastguard Worker     const bool hasStepUniforms = step->numUniforms() > 0;
885*c8dee2aaSAndroid Build Coastguard Worker     const bool useStepStorageBuffer = useStorageBuffers && hasStepUniforms;
886*c8dee2aaSAndroid Build Coastguard Worker     const bool useShadingStorageBuffer = useStorageBuffers && step->performsShading();
887*c8dee2aaSAndroid Build Coastguard Worker     const bool defineLocalCoordsVarying = this->needsLocalCoords();
888*c8dee2aaSAndroid Build Coastguard Worker 
889*c8dee2aaSAndroid Build Coastguard Worker     // Fixed program header (intrinsics are always declared as an uniform interface block)
890*c8dee2aaSAndroid Build Coastguard Worker     const ResourceBindingRequirements& bindingReqs = caps->resourceBindingRequirements();
891*c8dee2aaSAndroid Build Coastguard Worker     std::string sksl = emit_intrinsic_uniforms(bindingReqs.fIntrinsicBufferBinding,
892*c8dee2aaSAndroid Build Coastguard Worker                                                bindingReqs.fUniformBufferLayout);
893*c8dee2aaSAndroid Build Coastguard Worker 
894*c8dee2aaSAndroid Build Coastguard Worker     if (step->numVertexAttributes() > 0 || step->numInstanceAttributes() > 0) {
895*c8dee2aaSAndroid Build Coastguard Worker         int attr = 0;
896*c8dee2aaSAndroid Build Coastguard Worker         auto add_attrs = [&sksl, &attr](SkSpan<const Attribute> attrs) {
897*c8dee2aaSAndroid Build Coastguard Worker             for (auto a : attrs) {
898*c8dee2aaSAndroid Build Coastguard Worker                 SkSL::String::appendf(&sksl, "    layout(location=%d) in ", attr++);
899*c8dee2aaSAndroid Build Coastguard Worker                 sksl.append(SkSLTypeString(a.gpuType()));
900*c8dee2aaSAndroid Build Coastguard Worker                 SkSL::String::appendf(&sksl, " %s;\n", a.name());
901*c8dee2aaSAndroid Build Coastguard Worker             }
902*c8dee2aaSAndroid Build Coastguard Worker         };
903*c8dee2aaSAndroid Build Coastguard Worker         if (step->numVertexAttributes() > 0) {
904*c8dee2aaSAndroid Build Coastguard Worker             sksl.append("// vertex attrs\n");
905*c8dee2aaSAndroid Build Coastguard Worker             add_attrs(step->vertexAttributes());
906*c8dee2aaSAndroid Build Coastguard Worker         }
907*c8dee2aaSAndroid Build Coastguard Worker         if (step->numInstanceAttributes() > 0) {
908*c8dee2aaSAndroid Build Coastguard Worker             sksl.append("// instance attrs\n");
909*c8dee2aaSAndroid Build Coastguard Worker             add_attrs(step->instanceAttributes());
910*c8dee2aaSAndroid Build Coastguard Worker         }
911*c8dee2aaSAndroid Build Coastguard Worker     }
912*c8dee2aaSAndroid Build Coastguard Worker 
913*c8dee2aaSAndroid Build Coastguard Worker     // Uniforms needed by RenderStep
914*c8dee2aaSAndroid Build Coastguard Worker     // The uniforms are mangled by having their index in 'fEntries' as a suffix (i.e., "_%d")
915*c8dee2aaSAndroid Build Coastguard Worker     if (hasStepUniforms) {
916*c8dee2aaSAndroid Build Coastguard Worker         if (useStepStorageBuffer) {
917*c8dee2aaSAndroid Build Coastguard Worker             sksl += emit_render_step_storage_buffer(bindingReqs.fRenderStepBufferBinding,
918*c8dee2aaSAndroid Build Coastguard Worker                                                     step->uniforms());
919*c8dee2aaSAndroid Build Coastguard Worker         } else {
920*c8dee2aaSAndroid Build Coastguard Worker             sksl += emit_render_step_uniforms(bindingReqs.fRenderStepBufferBinding,
921*c8dee2aaSAndroid Build Coastguard Worker                                               bindingReqs.fUniformBufferLayout,
922*c8dee2aaSAndroid Build Coastguard Worker                                               step->uniforms());
923*c8dee2aaSAndroid Build Coastguard Worker         }
924*c8dee2aaSAndroid Build Coastguard Worker     }
925*c8dee2aaSAndroid Build Coastguard Worker 
926*c8dee2aaSAndroid Build Coastguard Worker     // Varyings needed by RenderStep
927*c8dee2aaSAndroid Build Coastguard Worker     sksl += emit_varyings(step, "out", useShadingStorageBuffer, defineLocalCoordsVarying);
928*c8dee2aaSAndroid Build Coastguard Worker 
929*c8dee2aaSAndroid Build Coastguard Worker     // Vertex shader function declaration
930*c8dee2aaSAndroid Build Coastguard Worker     sksl += "void main() {";
931*c8dee2aaSAndroid Build Coastguard Worker     // Create stepLocalCoords which render steps can write to.
932*c8dee2aaSAndroid Build Coastguard Worker     sksl += "float2 stepLocalCoords = float2(0);";
933*c8dee2aaSAndroid Build Coastguard Worker     // Vertex shader body
934*c8dee2aaSAndroid Build Coastguard Worker     if (useStepStorageBuffer) {
935*c8dee2aaSAndroid Build Coastguard Worker         // Extract out render step uniforms from SSBO, declaring local variables with the expected
936*c8dee2aaSAndroid Build Coastguard Worker         // uniform names so that RenderStep SkSL is independent of storage choice.
937*c8dee2aaSAndroid Build Coastguard Worker         SkSL::String::appendf(
938*c8dee2aaSAndroid Build Coastguard Worker                 &sksl, "uint stepSsboIndex = %s.x;\n", RenderStep::ssboIndicesAttribute());
939*c8dee2aaSAndroid Build Coastguard Worker         sksl += emit_uniforms_from_storage_buffer("step", "stepSsboIndex", step->uniforms());
940*c8dee2aaSAndroid Build Coastguard Worker     }
941*c8dee2aaSAndroid Build Coastguard Worker 
942*c8dee2aaSAndroid Build Coastguard Worker     sksl += step->vertexSkSL();
943*c8dee2aaSAndroid Build Coastguard Worker 
944*c8dee2aaSAndroid Build Coastguard Worker     // We want to map the rectangle of logical device pixels from (0,0) to (viewWidth, viewHeight)
945*c8dee2aaSAndroid Build Coastguard Worker     // to normalized device coordinates: (-1,-1) to (1,1) (actually -w to w since it's before
946*c8dee2aaSAndroid Build Coastguard Worker     // homogenous division).
947*c8dee2aaSAndroid Build Coastguard Worker     //
948*c8dee2aaSAndroid Build Coastguard Worker     // For efficiency, this assumes viewport.zw holds the reciprocol of twice the viewport width and
949*c8dee2aaSAndroid Build Coastguard Worker     // height. On some backends the NDC Y axis is flipped relative to the device and
950*c8dee2aaSAndroid Build Coastguard Worker     // viewport coords (i.e. it points up instead of down). In those cases, it's also assumed that
951*c8dee2aaSAndroid Build Coastguard Worker     // viewport.w holds a negative value. In that case the sign(viewport.zw) changes from
952*c8dee2aaSAndroid Build Coastguard Worker     // subtracting w to adding w.
953*c8dee2aaSAndroid Build Coastguard Worker     sksl += "sk_Position = float4(viewport.zw*devPosition.xy - sign(viewport.zw)*devPosition.ww,"
954*c8dee2aaSAndroid Build Coastguard Worker             "devPosition.zw);";
955*c8dee2aaSAndroid Build Coastguard Worker 
956*c8dee2aaSAndroid Build Coastguard Worker     if (useShadingStorageBuffer) {
957*c8dee2aaSAndroid Build Coastguard Worker         // Assign SSBO index values to the SSBO index varying.
958*c8dee2aaSAndroid Build Coastguard Worker         SkSL::String::appendf(&sksl,
959*c8dee2aaSAndroid Build Coastguard Worker                               "%s = %s;",
960*c8dee2aaSAndroid Build Coastguard Worker                               RenderStep::ssboIndicesVarying(),
961*c8dee2aaSAndroid Build Coastguard Worker                               RenderStep::ssboIndicesAttribute());
962*c8dee2aaSAndroid Build Coastguard Worker     }
963*c8dee2aaSAndroid Build Coastguard Worker 
964*c8dee2aaSAndroid Build Coastguard Worker     if (defineLocalCoordsVarying) {
965*c8dee2aaSAndroid Build Coastguard Worker         // Assign Render Step's stepLocalCoords to the localCoordsVar varying.
966*c8dee2aaSAndroid Build Coastguard Worker         sksl += "localCoordsVar = stepLocalCoords;";
967*c8dee2aaSAndroid Build Coastguard Worker     }
968*c8dee2aaSAndroid Build Coastguard Worker     sksl += "}";
969*c8dee2aaSAndroid Build Coastguard Worker 
970*c8dee2aaSAndroid Build Coastguard Worker     fVertexSkSL = std::move(sksl);
971*c8dee2aaSAndroid Build Coastguard Worker     fVSLabel = step->name();
972*c8dee2aaSAndroid Build Coastguard Worker     if (defineLocalCoordsVarying) {
973*c8dee2aaSAndroid Build Coastguard Worker         fVSLabel += " (w/ local coords)";
974*c8dee2aaSAndroid Build Coastguard Worker     }
975*c8dee2aaSAndroid Build Coastguard Worker     fHasStepUniforms = hasStepUniforms;
976*c8dee2aaSAndroid Build Coastguard Worker }
977*c8dee2aaSAndroid Build Coastguard Worker 
needsLocalCoords() const978*c8dee2aaSAndroid Build Coastguard Worker bool ShaderInfo::needsLocalCoords() const {
979*c8dee2aaSAndroid Build Coastguard Worker     return !fRootNodes.empty() &&
980*c8dee2aaSAndroid Build Coastguard Worker            SkToBool(fRootNodes[0]->requiredFlags() & SnippetRequirementFlags::kLocalCoords);
981*c8dee2aaSAndroid Build Coastguard Worker }
982*c8dee2aaSAndroid Build Coastguard Worker 
aggregateSnippetData(const ShaderNode * node)983*c8dee2aaSAndroid Build Coastguard Worker void ShaderInfo::aggregateSnippetData(const ShaderNode* node) {
984*c8dee2aaSAndroid Build Coastguard Worker     if (!node) {
985*c8dee2aaSAndroid Build Coastguard Worker         return;
986*c8dee2aaSAndroid Build Coastguard Worker     }
987*c8dee2aaSAndroid Build Coastguard Worker 
988*c8dee2aaSAndroid Build Coastguard Worker     // Accumulate data of children first.
989*c8dee2aaSAndroid Build Coastguard Worker     for (const ShaderNode* child : node->children()) {
990*c8dee2aaSAndroid Build Coastguard Worker         this->aggregateSnippetData(child);
991*c8dee2aaSAndroid Build Coastguard Worker     }
992*c8dee2aaSAndroid Build Coastguard Worker 
993*c8dee2aaSAndroid Build Coastguard Worker     if (node->requiredFlags() & SnippetRequirementFlags::kStoresData && !node->data().empty()) {
994*c8dee2aaSAndroid Build Coastguard Worker         fData.push_back_n(node->data().size(), node->data().data());
995*c8dee2aaSAndroid Build Coastguard Worker     }
996*c8dee2aaSAndroid Build Coastguard Worker }
997*c8dee2aaSAndroid Build Coastguard Worker 
998*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu::graphite
999