• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkSLCompiler.h"
9 
10 #include "Test.h"
11 
test(skiatest::Reporter * r,const char * src,const GrShaderCaps & caps,std::vector<const char * > expectedH,std::vector<const char * > expectedCPP)12 static void test(skiatest::Reporter* r, const char* src, const GrShaderCaps& caps,
13                  std::vector<const char*> expectedH, std::vector<const char*> expectedCPP) {
14     SkSL::Program::Settings settings;
15     settings.fCaps = &caps;
16     SkSL::Compiler compiler;
17     SkSL::StringStream output;
18     std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
19                                                              SkSL::Program::kFragmentProcessor_Kind,
20                                                              SkSL::String(src),
21                                                              settings);
22     if (!program) {
23         SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
24         return;
25     }
26     REPORTER_ASSERT(r, program);
27     bool success = compiler.toH(*program, "Test", output);
28     if (!success) {
29         SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
30     }
31     REPORTER_ASSERT(r, success);
32     if (success) {
33         for (const char* expected : expectedH) {
34             bool found = strstr(output.str().c_str(), expected);
35             if (!found) {
36                 SkDebugf("HEADER MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src,
37                          expected, output.str().c_str());
38             }
39             REPORTER_ASSERT(r, found);
40         }
41     }
42     output.reset();
43     success = compiler.toCPP(*program, "Test", output);
44     if (!success) {
45         SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
46     }
47     REPORTER_ASSERT(r, success);
48     if (success) {
49         for (const char* expected : expectedCPP) {
50             bool found = strstr(output.str().c_str(), expected);
51             if (!found) {
52                 SkDebugf("CPP MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src,
53                          expected, output.str().c_str());
54             }
55             REPORTER_ASSERT(r, found);
56         }
57     }
58 }
59 
DEF_TEST(SkSLFPHelloWorld,r)60 DEF_TEST(SkSLFPHelloWorld, r) {
61     test(r,
62          "/* HEADER */"
63          "void main() {"
64          "sk_OutColor = half4(1);"
65          "}",
66          *SkSL::ShaderCapsFactory::Default(),
67          {
68              "/* HEADER */\n"
69              "\n"
70              "/**************************************************************************************************\n"
71              " *** This file was autogenerated from GrTest.fp; do not modify.\n"
72              " **************************************************************************************************/\n"
73              "#ifndef GrTest_DEFINED\n"
74              "#define GrTest_DEFINED\n"
75              "#include \"SkTypes.h\"\n"
76              "#include \"GrFragmentProcessor.h\"\n"
77              "#include \"GrCoordTransform.h\"\n"
78              "class GrTest : public GrFragmentProcessor {\n"
79              "public:\n"
80              "    static std::unique_ptr<GrFragmentProcessor> Make() {\n"
81              "        return std::unique_ptr<GrFragmentProcessor>(new GrTest());\n"
82              "    }\n"
83              "    GrTest(const GrTest& src);\n"
84              "    std::unique_ptr<GrFragmentProcessor> clone() const override;\n"
85              "    const char* name() const override { return \"Test\"; }\n"
86              "private:\n"
87              "    GrTest()\n"
88              "    : INHERITED(kGrTest_ClassID, kNone_OptimizationFlags) {\n"
89              "    }\n"
90              "    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
91              "    void onGetGLSLProcessorKey(const GrShaderCaps&,GrProcessorKeyBuilder*) "
92                     "const override;\n"
93              "    bool onIsEqual(const GrFragmentProcessor&) const override;\n"
94              "    GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n"
95              "    typedef GrFragmentProcessor INHERITED;\n"
96              "};\n"
97              "#endif\n"
98          },
99          {
100              "/* HEADER */\n"
101              "\n"
102              "/**************************************************************************************************\n"
103              " *** This file was autogenerated from GrTest.fp; do not modify.\n"
104              " **************************************************************************************************/\n"
105              "#include \"GrTest.h\"\n"
106              "#include \"glsl/GrGLSLFragmentProcessor.h\"\n"
107              "#include \"glsl/GrGLSLFragmentShaderBuilder.h\"\n"
108              "#include \"glsl/GrGLSLProgramBuilder.h\"\n"
109              "#include \"GrTexture.h\"\n"
110              "#include \"SkSLCPP.h\"\n"
111              "#include \"SkSLUtil.h\"\n"
112              "class GrGLSLTest : public GrGLSLFragmentProcessor {\n"
113              "public:\n"
114              "    GrGLSLTest() {}\n"
115              "    void emitCode(EmitArgs& args) override {\n"
116              "        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;\n"
117              "        const GrTest& _outer = args.fFp.cast<GrTest>();\n"
118              "        (void) _outer;\n"
119              "        fragBuilder->codeAppendf(\"%s = half4(1.0);\\n\", args.fOutputColor);\n"
120              "    }\n"
121              "private:\n"
122              "    void onSetData(const GrGLSLProgramDataManager& pdman, "
123                                 "const GrFragmentProcessor& _proc) override {\n"
124              "    }\n"
125              "};\n"
126              "GrGLSLFragmentProcessor* GrTest::onCreateGLSLInstance() const {\n"
127              "    return new GrGLSLTest();\n"
128              "}\n"
129              "void GrTest::onGetGLSLProcessorKey(const GrShaderCaps& caps, "
130                                                 "GrProcessorKeyBuilder* b) const {\n"
131              "}\n"
132              "bool GrTest::onIsEqual(const GrFragmentProcessor& other) const {\n"
133              "    const GrTest& that = other.cast<GrTest>();\n"
134              "    (void) that;\n"
135              "    return true;\n"
136              "}\n"
137              "GrTest::GrTest(const GrTest& src)\n"
138              ": INHERITED(kGrTest_ClassID, src.optimizationFlags()) {\n"
139              "}\n"
140              "std::unique_ptr<GrFragmentProcessor> GrTest::clone() const {\n"
141              "    return std::unique_ptr<GrFragmentProcessor>(new GrTest(*this));\n"
142              "}\n"
143          });
144 }
145 
DEF_TEST(SkSLFPInput,r)146 DEF_TEST(SkSLFPInput, r) {
147     test(r,
148          "in half2 point;"
149          "void main() {"
150          "sk_OutColor = half4(point, point);"
151          "}",
152          *SkSL::ShaderCapsFactory::Default(),
153          {
154              "const SkPoint& point() const { return fPoint; }",
155              "static std::unique_ptr<GrFragmentProcessor> Make(SkPoint point) {",
156              "return std::unique_ptr<GrFragmentProcessor>(new GrTest(point));",
157              "GrTest(SkPoint point)",
158              ", fPoint(point)"
159          },
160          {
161              "fragBuilder->codeAppendf(\"%s = half4(half2(%f, %f), half2(%f, %f));\\n\", "
162                                       "args.fOutputColor, _outer.point().fX, _outer.point().fY, "
163                                       "_outer.point().fX, _outer.point().fY);",
164              "if (fPoint != that.fPoint) return false;"
165          });
166 }
167 
DEF_TEST(SkSLFPUniform,r)168 DEF_TEST(SkSLFPUniform, r) {
169     test(r,
170          "uniform half4 color;"
171          "void main() {"
172          "sk_OutColor = color;"
173          "}",
174          *SkSL::ShaderCapsFactory::Default(),
175          {
176              "static std::unique_ptr<GrFragmentProcessor> Make()"
177          },
178          {
179             "fColorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, "
180                                                          "kDefault_GrSLPrecision, \"color\");",
181          });
182 }
183 
184 // SkSLFPInUniform tests the simplest plumbing case, default type, no tracking
185 // with a setUniform template that supports inlining the value call with no
186 // local variable.
DEF_TEST(SkSLFPInUniform,r)187 DEF_TEST(SkSLFPInUniform, r) {
188     test(r,
189          "in uniform half4 color;"
190          "void main() {"
191          "sk_OutColor = color;"
192          "}",
193          *SkSL::ShaderCapsFactory::Default(),
194          {
195              "static std::unique_ptr<GrFragmentProcessor> Make(SkRect color) {",
196          },
197          {
198             "fColorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, "
199                                                          "kDefault_GrSLPrecision, \"color\");",
200             "pdman.set4fv(fColorVar, 1, reinterpret_cast<const float*>(&(_outer.color())));"
201          });
202 }
203 
204 // As above, but tests in uniform's ability to override the default ctype.
DEF_TEST(SkSLFPInUniformCType,r)205 DEF_TEST(SkSLFPInUniformCType, r) {
206     test(r,
207          "layout(ctype=SkPMColor4f) in uniform half4 color;"
208          "void main() {"
209          "sk_OutColor = color;"
210          "}",
211          *SkSL::ShaderCapsFactory::Default(),
212          {
213              "static std::unique_ptr<GrFragmentProcessor> Make(SkPMColor4f color) {",
214          },
215          {
216             "fColorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, "
217                                                          "kDefault_GrSLPrecision, \"color\");",
218             "pdman.set4fv(fColorVar, 1, (_outer.color()).vec());"
219          });
220 }
221 
222 // Add state tracking to the default typed SkRect <-> half4 uniform. But since
223 // it now has to track state, the value inlining previously done for the
224 // setUniform call is removed in favor of a local variable.
DEF_TEST(SkSLFPTrackedInUniform,r)225 DEF_TEST(SkSLFPTrackedInUniform, r) {
226     test(r,
227          "layout(tracked) in uniform half4 color;"
228          "void main() {"
229          "sk_OutColor = color;"
230          "}",
231          *SkSL::ShaderCapsFactory::Default(),
232          {
233              "static std::unique_ptr<GrFragmentProcessor> Make(SkRect color) {",
234          },
235          {
236             "SkRect fColorPrev = SkRect::MakeEmpty();",
237             "fColorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, "
238                                                          "kDefault_GrSLPrecision, \"color\");",
239             "const SkRect& colorValue = _outer.color();",
240             "if (fColorPrev.isEmpty() || fColorPrev != colorValue) {",
241             "fColorPrev = colorValue;",
242             "pdman.set4fv(fColorVar, 1, reinterpret_cast<const float*>(&colorValue));"
243          });
244 }
245 
246 // Test the case where the template does not support variable inlining in
247 // setUniform (i.e. it references the value multiple times).
DEF_TEST(SkSLFPNonInlinedInUniform,r)248 DEF_TEST(SkSLFPNonInlinedInUniform, r) {
249     test(r,
250          "in uniform half2 point;"
251          "void main() {"
252          "sk_OutColor = half4(point, point);"
253          "}",
254          *SkSL::ShaderCapsFactory::Default(),
255          {
256              "static std::unique_ptr<GrFragmentProcessor> Make(SkPoint point) {",
257          },
258          {
259             "fPointVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType, "
260                                                          "kDefault_GrSLPrecision, \"point\");",
261             "const SkPoint& pointValue = _outer.point();",
262             "pdman.set2f(fPointVar, pointValue.fX, pointValue.fY);"
263          });
264 }
265 
266 // Test handling conditional uniforms (that use when= in layout), combined with
267 // state tracking and custom ctypes to really put the code generation through its paces.
DEF_TEST(SkSLFPConditionalInUniform,r)268 DEF_TEST(SkSLFPConditionalInUniform, r) {
269     test(r,
270          "in bool test;"
271          "layout(ctype=SkPMColor4f, tracked, when=test) in uniform half4 color;"
272          "void main() {"
273          "  if (test) {"
274          "    sk_OutColor = color;"
275          "  } else {"
276          "    sk_OutColor = half4(1);"
277          "  }"
278          "}",
279          *SkSL::ShaderCapsFactory::Default(),
280          {
281              "static std::unique_ptr<GrFragmentProcessor> Make(bool test, SkPMColor4f color) {",
282          },
283          {
284             "SkPMColor4f fColorPrev = {SK_FloatNaN, SK_FloatNaN, SK_FloatNaN, SK_FloatNaN}",
285             "auto test = _outer.test();",
286             "if (test) {",
287             "fColorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, "
288                                                          "kDefault_GrSLPrecision, \"color\");",
289             "if (fColorVar.isValid()) {",
290             "const SkPMColor4f& colorValue = _outer.color();",
291             "if (fColorPrev != colorValue) {",
292             "fColorPrev = colorValue;",
293             "pdman.set4fv(fColorVar, 1, colorValue.vec());"
294          });
295 }
296 
DEF_TEST(SkSLFPSections,r)297 DEF_TEST(SkSLFPSections, r) {
298     test(r,
299          "@header { header section }"
300          "void main() {"
301          "sk_OutColor = half4(1);"
302          "}",
303          *SkSL::ShaderCapsFactory::Default(),
304          {
305              "header section"
306          },
307          {});
308     test(r,
309          "@class { class section }"
310          "void main() {"
311          "sk_OutColor = half4(1);"
312          "}",
313          *SkSL::ShaderCapsFactory::Default(),
314          {
315              "class GrTest : public GrFragmentProcessor {\n"
316              "public:\n"
317              " class section"
318          },
319          {});
320     test(r,
321          "@cpp { cpp section }"
322          "void main() {"
323          "sk_OutColor = half4(1);"
324          "}",
325          *SkSL::ShaderCapsFactory::Default(),
326          {},
327          {"cpp section"});
328     test(r,
329          "@constructorParams { int x, float y, std::vector<float> z }"
330          "in float w;"
331          "void main() {"
332          "sk_OutColor = float4(1);"
333          "}",
334          *SkSL::ShaderCapsFactory::Default(),
335          {
336              "Make(float w,  int x, float y, std::vector<float> z )",
337              "return std::unique_ptr<GrFragmentProcessor>(new GrTest(w, x, y, z));",
338              "GrTest(float w,  int x, float y, std::vector<float> z )",
339              ", fW(w) {"
340          },
341          {});
342     test(r,
343          "@constructor { constructor section }"
344          "void main() {"
345          "sk_OutColor = half4(1);"
346          "}",
347          *SkSL::ShaderCapsFactory::Default(),
348          {
349              "private:\n constructor section"
350          },
351          {});
352     test(r,
353          "@initializers { initializers section }"
354          "void main() {"
355          "sk_OutColor = half4(1);"
356          "}",
357          *SkSL::ShaderCapsFactory::Default(),
358          {
359              ": INHERITED(kGrTest_ClassID, kNone_OptimizationFlags)\n    ,  initializers section"
360          },
361          {});
362     test(r,
363          "half x = 10;"
364          "@emitCode { fragBuilder->codeAppendf(\"half y = %d\\n\", x * 2); }"
365          "void main() {"
366          "sk_OutColor = half4(1);"
367          "}",
368          *SkSL::ShaderCapsFactory::Default(),
369          {},
370          {
371             "x = 10.0;\n"
372             " fragBuilder->codeAppendf(\"half y = %d\\n\", x * 2);"
373          });
374     test(r,
375          "@fields { fields section }"
376          "@clone { }"
377          "void main() {"
378          "sk_OutColor = half4(1);"
379          "}",
380          *SkSL::ShaderCapsFactory::Default(),
381          {
382             "GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n"
383             " fields section     typedef GrFragmentProcessor INHERITED;"
384          },
385          {});
386     test(r,
387          "@make { make section }"
388          "void main() {"
389          "sk_OutColor = half4(1);"
390          "}",
391          *SkSL::ShaderCapsFactory::Default(),
392          {
393             "public:\n"
394             " make section"
395          },
396          {});
397     test(r,
398          "uniform half calculated;"
399          "in half provided;"
400          "@setData(varName) { varName.set1f(calculated, provided * 2); }"
401          "void main() {"
402          "sk_OutColor = half4(1);"
403          "}",
404          *SkSL::ShaderCapsFactory::Default(),
405          {},
406          {
407              "void onSetData(const GrGLSLProgramDataManager& varName, "
408                             "const GrFragmentProcessor& _proc) override {\n",
409              "UniformHandle& calculated = fCalculatedVar;",
410              "auto provided = _outer.provided();",
411              "varName.set1f(calculated, provided * 2);"
412          });
413     test(r,
414          "@test(testDataName) { testDataName section }"
415          "void main() {"
416          "sk_OutColor = half4(1);"
417          "}",
418          *SkSL::ShaderCapsFactory::Default(),
419          {},
420          {
421              "#if GR_TEST_UTILS\n"
422              "std::unique_ptr<GrFragmentProcessor> GrTest::TestCreate(GrProcessorTestData* testDataName) {\n"
423              " testDataName section }\n"
424              "#endif"
425          });
426 }
427 
DEF_TEST(SkSLFPTransformedCoords,r)428 DEF_TEST(SkSLFPTransformedCoords, r) {
429     test(r,
430          "void main() {"
431          "sk_OutColor = half4(sk_TransformedCoords2D[0], sk_TransformedCoords2D[0]);"
432          "}",
433          *SkSL::ShaderCapsFactory::Default(),
434          {},
435          {
436             "SkString sk_TransformedCoords2D_0 = "
437                                          "fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);",
438             "fragBuilder->codeAppendf(\"%s = half4(%s, %s);\\n\", args.fOutputColor, "
439                               "sk_TransformedCoords2D_0.c_str(), sk_TransformedCoords2D_0.c_str());"
440          });
441 
442 }
443 
DEF_TEST(SkSLFPLayoutWhen,r)444 DEF_TEST(SkSLFPLayoutWhen, r) {
445     test(r,
446          "layout(when=someExpression(someOtherExpression())) uniform half sometimes;"
447          "void main() {"
448          "}",
449          *SkSL::ShaderCapsFactory::Default(),
450          {},
451          {
452             "if (someExpression(someOtherExpression())) {\n"
453             "            fSometimesVar = args.fUniformHandler->addUniform"
454          });
455 
456 }
457 
DEF_TEST(SkSLFPChildProcessors,r)458 DEF_TEST(SkSLFPChildProcessors, r) {
459     test(r,
460          "in fragmentProcessor child1;"
461          "in fragmentProcessor child2;"
462          "void main() {"
463          "    sk_OutColor = process(child1) * process(child2);"
464          "}",
465          *SkSL::ShaderCapsFactory::Default(),
466          {
467             "this->registerChildProcessor(std::move(child1));",
468             "this->registerChildProcessor(std::move(child2));"
469          },
470          {
471             "SkString _child0(\"_child0\");",
472             "this->emitChild(0, &_child0, args);",
473             "SkString _child1(\"_child1\");",
474             "this->emitChild(1, &_child1, args);",
475             "this->registerChildProcessor(src.childProcessor(0).clone());",
476             "this->registerChildProcessor(src.childProcessor(1).clone());"
477          });
478 }
479 
DEF_TEST(SkSLFPChildProcessorsWithInput,r)480 DEF_TEST(SkSLFPChildProcessorsWithInput, r) {
481     test(r,
482          "in fragmentProcessor child1;"
483          "in fragmentProcessor child2;"
484          "void main() {"
485          "    half4 childIn = sk_InColor;"
486          "    half4 childOut1 = process(child1, childIn);"
487          "    half4 childOut2 = process(child2, childOut1);"
488          "    sk_OutColor = childOut2;"
489          "}",
490          *SkSL::ShaderCapsFactory::Default(),
491          {
492             "this->registerChildProcessor(std::move(child1));",
493             "this->registerChildProcessor(std::move(child2));"
494          },
495          {
496             "SkString _input0(\"childIn\");",
497             "SkString _child0(\"_child0\");",
498             "this->emitChild(0, _input0.c_str(), &_child0, args);",
499             "SkString _input1(\"childOut1\");",
500             "SkString _child1(\"_child1\");",
501             "this->emitChild(1, _input1.c_str(), &_child1, args);",
502             "this->registerChildProcessor(src.childProcessor(0).clone());",
503             "this->registerChildProcessor(src.childProcessor(1).clone());"
504          });
505 }
506 
DEF_TEST(SkSLFPChildProcessorWithInputExpression,r)507 DEF_TEST(SkSLFPChildProcessorWithInputExpression, r) {
508     test(r,
509          "in fragmentProcessor child;"
510          "void main() {"
511          "    sk_OutColor = process(child, sk_InColor * half4(0.5));"
512          "}",
513          *SkSL::ShaderCapsFactory::Default(),
514          {
515             "this->registerChildProcessor(std::move(child));",
516          },
517          {
518             "SkString _input0 = SkStringPrintf(\"%s * half4(0.5)\", args.fInputColor);",
519             "SkString _child0(\"_child0\");",
520             "this->emitChild(0, _input0.c_str(), &_child0, args);",
521             "this->registerChildProcessor(src.childProcessor(0).clone());",
522          });
523 }
524 
DEF_TEST(SkSLFPNestedChildProcessors,r)525 DEF_TEST(SkSLFPNestedChildProcessors, r) {
526     test(r,
527          "in fragmentProcessor child1;"
528          "in fragmentProcessor child2;"
529          "void main() {"
530          "    sk_OutColor = process(child2, sk_InColor * process(child1, sk_InColor * half4(0.5)));"
531          "}",
532          *SkSL::ShaderCapsFactory::Default(),
533          {
534             "this->registerChildProcessor(std::move(child1));",
535             "this->registerChildProcessor(std::move(child2));"
536          },
537          {
538             "SkString _input0 = SkStringPrintf(\"%s * half4(0.5)\", args.fInputColor);",
539             "SkString _child0(\"_child0\");",
540             "this->emitChild(0, _input0.c_str(), &_child0, args);",
541             "SkString _input1 = SkStringPrintf(\"%s * %s\", args.fInputColor, _child0.c_str());",
542             "SkString _child1(\"_child1\");",
543             "this->emitChild(1, _input1.c_str(), &_child1, args);",
544             "this->registerChildProcessor(src.childProcessor(0).clone());",
545             "this->registerChildProcessor(src.childProcessor(1).clone());"
546          });
547 }
548 
DEF_TEST(SkSLFPChildFPAndGlobal,r)549 DEF_TEST(SkSLFPChildFPAndGlobal, r) {
550     test(r,
551          "in fragmentProcessor child;"
552          "bool hasCap = sk_Caps.externalTextureSupport;"
553          "void main() {"
554          "    if (hasCap) {"
555          "        sk_OutColor = process(child, sk_InColor);"
556          "    } else {"
557          "        sk_OutColor = half4(1);"
558          "    }"
559          "}",
560          *SkSL::ShaderCapsFactory::Default(),
561          {
562             "this->registerChildProcessor(std::move(child));"
563          },
564          {
565             "hasCap = sk_Caps.externalTextureSupport;",
566             "fragBuilder->codeAppendf(\"bool hasCap = %s;\\nif (hasCap) {\", "
567                     "(hasCap ? \"true\" : \"false\"));",
568             "SkString _input0 = SkStringPrintf(\"%s\", args.fInputColor);",
569             "SkString _child0(\"_child0\");",
570             "this->emitChild(0, _input0.c_str(), &_child0, args);",
571             "fragBuilder->codeAppendf(\"\\n    %s = %s;\\n} else {\\n    %s = half4(1.0);\\n}"
572                     "\\n\", args.fOutputColor, _child0.c_str(), args.fOutputColor);",
573             "this->registerChildProcessor(src.childProcessor(0).clone());"
574          });
575 }
576 
DEF_TEST(SkSLFPChildProcessorInlineFieldAccess,r)577 DEF_TEST(SkSLFPChildProcessorInlineFieldAccess, r) {
578     test(r,
579          "in fragmentProcessor child;"
580          "void main() {"
581          "    if (child.preservesOpaqueInput) {"
582          "        sk_OutColor = process(child, sk_InColor);"
583          "    } else {"
584          "        sk_OutColor = half4(1);"
585          "    }"
586          "}",
587          *SkSL::ShaderCapsFactory::Default(),
588          {
589             "this->registerChildProcessor(std::move(child));"
590          },
591          {
592             "fragBuilder->codeAppendf(\"if (%s) {\", "
593                     "(_outer.childProcessor(0).preservesOpaqueInput() ? \"true\" : \"false\"));",
594             "SkString _input0 = SkStringPrintf(\"%s\", args.fInputColor);",
595             "SkString _child0(\"_child0\");",
596             "this->emitChild(0, _input0.c_str(), &_child0, args);",
597             "fragBuilder->codeAppendf(\"\\n    %s = %s;\\n} else {\\n    %s = half4(1.0);\\n}\\n\""
598                     ", args.fOutputColor, _child0.c_str(), args.fOutputColor);",
599             "this->registerChildProcessor(src.childProcessor(0).clone());"
600          });
601 }
602 
DEF_TEST(SkSLFPChildProcessorFieldAccess,r)603 DEF_TEST(SkSLFPChildProcessorFieldAccess, r) {
604     test(r,
605          "in fragmentProcessor child;"
606          "bool opaque = child.preservesOpaqueInput;"
607          "void main() {"
608          "    if (opaque) {"
609          "        sk_OutColor = process(child);"
610          "    } else {"
611          "        sk_OutColor = half4(0.5);"
612          "    }"
613          "}",
614          *SkSL::ShaderCapsFactory::Default(),
615          {
616             "this->registerChildProcessor(std::move(child));"
617          },
618          {
619             "opaque = _outer.childProcessor(0).preservesOpaqueInput();",
620             "fragBuilder->codeAppendf(\"bool opaque = %s;\\nif (opaque) {\", "
621                     "(opaque ? \"true\" : \"false\"));",
622             "SkString _child0(\"_child0\");",
623             "this->emitChild(0, &_child0, args);",
624             "fragBuilder->codeAppendf(\"\\n    %s = %s;\\n} else {\\n    %s = half4(0.5);\\n}\\n\""
625                     ", args.fOutputColor, _child0.c_str(), args.fOutputColor);",
626             "this->registerChildProcessor(src.childProcessor(0).clone());"
627          });
628 }
629