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