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