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 = ∩︀
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