c0bd9f9fe5
Current strategy: everything from the top Things to look at first are the manual changes: - added tools/rewrite_includes.py - removed -Idirectives from BUILD.gn - various compile.sh simplifications - tweak tools/embed_resources.py - update gn/find_headers.py to write paths from the top - update gn/gn_to_bp.py SkUserConfig.h layout so that #include "include/config/SkUserConfig.h" always gets the header we want. No-Presubmit: true Change-Id: I73a4b181654e0e38d229bc456c0d0854bae3363e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/209706 Commit-Queue: Mike Klein <mtklein@google.com> Reviewed-by: Hal Canary <halcanary@google.com> Reviewed-by: Brian Osman <brianosman@google.com> Reviewed-by: Florin Malita <fmalita@chromium.org>
651 lines
25 KiB
C++
651 lines
25 KiB
C++
/*
|
|
* Copyright 2017 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "src/sksl/SkSLCompiler.h"
|
|
|
|
#include "tests/Test.h"
|
|
|
|
static void test(skiatest::Reporter* r, const char* src, const GrShaderCaps& caps,
|
|
std::vector<const char*> expectedH, std::vector<const char*> expectedCPP) {
|
|
SkSL::Program::Settings settings;
|
|
settings.fCaps = ∩︀
|
|
SkSL::Compiler compiler;
|
|
SkSL::StringStream output;
|
|
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
|
|
SkSL::Program::kFragmentProcessor_Kind,
|
|
SkSL::String(src),
|
|
settings);
|
|
if (!program) {
|
|
SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
|
|
return;
|
|
}
|
|
REPORTER_ASSERT(r, program);
|
|
bool success = compiler.toH(*program, "Test", output);
|
|
if (!success) {
|
|
SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
|
|
}
|
|
REPORTER_ASSERT(r, success);
|
|
if (success) {
|
|
for (const char* expected : expectedH) {
|
|
bool found = strstr(output.str().c_str(), expected);
|
|
if (!found) {
|
|
SkDebugf("HEADER MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src,
|
|
expected, output.str().c_str());
|
|
}
|
|
REPORTER_ASSERT(r, found);
|
|
}
|
|
}
|
|
output.reset();
|
|
success = compiler.toCPP(*program, "Test", output);
|
|
if (!success) {
|
|
SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
|
|
}
|
|
REPORTER_ASSERT(r, success);
|
|
if (success) {
|
|
for (const char* expected : expectedCPP) {
|
|
bool found = strstr(output.str().c_str(), expected);
|
|
if (!found) {
|
|
SkDebugf("CPP MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src,
|
|
expected, output.str().c_str());
|
|
}
|
|
REPORTER_ASSERT(r, found);
|
|
}
|
|
}
|
|
}
|
|
|
|
DEF_TEST(SkSLFPHelloWorld, r) {
|
|
test(r,
|
|
"/* HEADER */"
|
|
"void main() {"
|
|
"sk_OutColor = half4(1);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"/* HEADER */\n"
|
|
"\n"
|
|
"/**************************************************************************************************\n"
|
|
" *** This file was autogenerated from GrTest.fp; do not modify.\n"
|
|
" **************************************************************************************************/\n"
|
|
"#ifndef GrTest_DEFINED\n"
|
|
"#define GrTest_DEFINED\n"
|
|
"#include \"include/core/SkTypes.h\"\n\n"
|
|
"#include \"src/gpu/GrCoordTransform.h\"\n"
|
|
"#include \"src/gpu/GrFragmentProcessor.h\"\n"
|
|
"class GrTest : public GrFragmentProcessor {\n"
|
|
"public:\n"
|
|
" static std::unique_ptr<GrFragmentProcessor> Make() {\n"
|
|
" return std::unique_ptr<GrFragmentProcessor>(new GrTest());\n"
|
|
" }\n"
|
|
" GrTest(const GrTest& src);\n"
|
|
" std::unique_ptr<GrFragmentProcessor> clone() const override;\n"
|
|
" const char* name() const override { return \"Test\"; }\n"
|
|
"private:\n"
|
|
" GrTest()\n"
|
|
" : INHERITED(kGrTest_ClassID, kNone_OptimizationFlags) {\n"
|
|
" }\n"
|
|
" GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
|
|
" void onGetGLSLProcessorKey(const GrShaderCaps&,GrProcessorKeyBuilder*) const "
|
|
"override;\n"
|
|
" bool onIsEqual(const GrFragmentProcessor&) const override;\n"
|
|
" GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n"
|
|
" typedef GrFragmentProcessor INHERITED;\n"
|
|
"};\n"
|
|
"#endif\n"
|
|
},
|
|
{
|
|
"/**************************************************************************************************\n"
|
|
" *** This file was autogenerated from GrTest.fp; do not modify.\n"
|
|
" **************************************************************************************************/\n"
|
|
"#include \"GrTest.h\"\n\n"
|
|
"#include \"include/gpu/GrTexture.h\"\n"
|
|
"#include \"src/gpu/glsl/GrGLSLFragmentProcessor.h\"\n"
|
|
"#include \"src/gpu/glsl/GrGLSLFragmentShaderBuilder.h\"\n"
|
|
"#include \"src/gpu/glsl/GrGLSLProgramBuilder.h\"\n"
|
|
"#include \"src/sksl/SkSLCPP.h\"\n"
|
|
"#include \"src/sksl/SkSLUtil.h\"\n"
|
|
"class GrGLSLTest : public GrGLSLFragmentProcessor {\n"
|
|
"public:\n"
|
|
" GrGLSLTest() {}\n"
|
|
" void emitCode(EmitArgs& args) override {\n"
|
|
" GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;\n"
|
|
" const GrTest& _outer = args.fFp.cast<GrTest>();\n"
|
|
" (void) _outer;\n"
|
|
" fragBuilder->codeAppendf(\"%s = half4(1.0);\\n\", args.fOutputColor);\n"
|
|
" }\n"
|
|
"private:\n"
|
|
" void onSetData(const GrGLSLProgramDataManager& pdman, "
|
|
"const GrFragmentProcessor& _proc) override {\n"
|
|
" }\n"
|
|
"};\n"
|
|
"GrGLSLFragmentProcessor* GrTest::onCreateGLSLInstance() const {\n"
|
|
" return new GrGLSLTest();\n"
|
|
"}\n"
|
|
"void GrTest::onGetGLSLProcessorKey(const GrShaderCaps& caps, "
|
|
"GrProcessorKeyBuilder* b) const {\n"
|
|
"}\n"
|
|
"bool GrTest::onIsEqual(const GrFragmentProcessor& other) const {\n"
|
|
" const GrTest& that = other.cast<GrTest>();\n"
|
|
" (void) that;\n"
|
|
" return true;\n"
|
|
"}\n"
|
|
"GrTest::GrTest(const GrTest& src)\n"
|
|
": INHERITED(kGrTest_ClassID, src.optimizationFlags()) {\n"
|
|
"}\n"
|
|
"std::unique_ptr<GrFragmentProcessor> GrTest::clone() const {\n"
|
|
" return std::unique_ptr<GrFragmentProcessor>(new GrTest(*this));\n"
|
|
"}\n"
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPInput, r) {
|
|
test(r,
|
|
"in half2 point;"
|
|
"void main() {"
|
|
"sk_OutColor = half4(point, point);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"static std::unique_ptr<GrFragmentProcessor> Make(SkPoint point) {",
|
|
"return std::unique_ptr<GrFragmentProcessor>(new GrTest(point));",
|
|
"GrTest(SkPoint point)",
|
|
", point(point)"
|
|
},
|
|
{
|
|
"fragBuilder->codeAppendf(\"%s = half4(half2(%f, %f), half2(%f, %f));\\n\", "
|
|
"args.fOutputColor, _outer.point.fX, _outer.point.fY, "
|
|
"_outer.point.fX, _outer.point.fY);",
|
|
"if (point != that.point) return false;"
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPUniform, r) {
|
|
test(r,
|
|
"uniform half4 color;"
|
|
"void main() {"
|
|
"sk_OutColor = color;"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"static std::unique_ptr<GrFragmentProcessor> Make()"
|
|
},
|
|
{
|
|
"colorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, "
|
|
"\"color\");",
|
|
});
|
|
}
|
|
|
|
// SkSLFPInUniform tests the simplest plumbing case, default type, no tracking
|
|
// with a setUniform template that supports inlining the value call with no
|
|
// local variable.
|
|
DEF_TEST(SkSLFPInUniform, r) {
|
|
test(r,
|
|
"in uniform half4 color;"
|
|
"void main() {"
|
|
"sk_OutColor = color;"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"static std::unique_ptr<GrFragmentProcessor> Make(SkRect color) {",
|
|
},
|
|
{
|
|
"colorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, "
|
|
"\"color\");",
|
|
"pdman.set4fv(colorVar, 1, reinterpret_cast<const float*>(&(_outer.color)));"
|
|
});
|
|
}
|
|
|
|
// As above, but tests in uniform's ability to override the default ctype.
|
|
DEF_TEST(SkSLFPInUniformCType, r) {
|
|
test(r,
|
|
"layout(ctype=SkPMColor4f) in uniform half4 color;"
|
|
"void main() {"
|
|
"sk_OutColor = color;"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"static std::unique_ptr<GrFragmentProcessor> Make(SkPMColor4f color) {",
|
|
},
|
|
{
|
|
"colorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, "
|
|
"\"color\");",
|
|
"pdman.set4fv(colorVar, 1, (_outer.color).vec());"
|
|
});
|
|
}
|
|
|
|
// Add state tracking to the default typed SkRect <-> half4 uniform. But since
|
|
// it now has to track state, the value inlining previously done for the
|
|
// setUniform call is removed in favor of a local variable.
|
|
DEF_TEST(SkSLFPTrackedInUniform, r) {
|
|
test(r,
|
|
"layout(tracked) in uniform half4 color;"
|
|
"void main() {"
|
|
"sk_OutColor = color;"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"static std::unique_ptr<GrFragmentProcessor> Make(SkRect color) {",
|
|
},
|
|
{
|
|
"SkRect colorPrev = SkRect::MakeEmpty();",
|
|
"colorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, "
|
|
"\"color\");",
|
|
"const SkRect& colorValue = _outer.color;",
|
|
"if (colorPrev.isEmpty() || colorPrev != colorValue) {",
|
|
"colorPrev = colorValue;",
|
|
"pdman.set4fv(colorVar, 1, reinterpret_cast<const float*>(&colorValue));"
|
|
});
|
|
}
|
|
|
|
// Test the case where the template does not support variable inlining in
|
|
// setUniform (i.e. it references the value multiple times).
|
|
DEF_TEST(SkSLFPNonInlinedInUniform, r) {
|
|
test(r,
|
|
"in uniform half2 point;"
|
|
"void main() {"
|
|
"sk_OutColor = half4(point, point);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"static std::unique_ptr<GrFragmentProcessor> Make(SkPoint point) {",
|
|
},
|
|
{
|
|
"pointVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType, "
|
|
"\"point\");",
|
|
"const SkPoint& pointValue = _outer.point;",
|
|
"pdman.set2f(pointVar, pointValue.fX, pointValue.fY);"
|
|
});
|
|
}
|
|
|
|
// Test handling conditional uniforms (that use when= in layout), combined with
|
|
// state tracking and custom ctypes to really put the code generation through its paces.
|
|
DEF_TEST(SkSLFPConditionalInUniform, r) {
|
|
test(r,
|
|
"in bool test;"
|
|
"layout(ctype=SkPMColor4f, tracked, when=test) in uniform half4 color;"
|
|
"void main() {"
|
|
" if (test) {"
|
|
" sk_OutColor = color;"
|
|
" } else {"
|
|
" sk_OutColor = half4(1);"
|
|
" }"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"static std::unique_ptr<GrFragmentProcessor> Make(bool test, SkPMColor4f color) {",
|
|
},
|
|
{
|
|
"SkPMColor4f colorPrev = {SK_FloatNaN, SK_FloatNaN, SK_FloatNaN, SK_FloatNaN}",
|
|
"auto test = _outer.test;",
|
|
"if (test) {",
|
|
"colorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, "
|
|
"\"color\");",
|
|
"if (colorVar.isValid()) {",
|
|
"const SkPMColor4f& colorValue = _outer.color;",
|
|
"if (colorPrev != colorValue) {",
|
|
"colorPrev = colorValue;",
|
|
"pdman.set4fv(colorVar, 1, colorValue.vec());"
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPSections, r) {
|
|
test(r,
|
|
"@header { header section }"
|
|
"void main() {"
|
|
"sk_OutColor = half4(1);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"header section"
|
|
},
|
|
{});
|
|
test(r,
|
|
"@class { class section }"
|
|
"void main() {"
|
|
"sk_OutColor = half4(1);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"class GrTest : public GrFragmentProcessor {\n"
|
|
"public:\n"
|
|
" class section"
|
|
},
|
|
{});
|
|
test(r,
|
|
"@cpp { cpp section }"
|
|
"void main() {"
|
|
"sk_OutColor = half4(1);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{},
|
|
{"cpp section"});
|
|
test(r,
|
|
"@constructorParams { int x, float y, std::vector<float> z }"
|
|
"in float w;"
|
|
"void main() {"
|
|
"sk_OutColor = half4(1);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"Make(float w, int x, float y, std::vector<float> z )",
|
|
"return std::unique_ptr<GrFragmentProcessor>(new GrTest(w, x, y, z));",
|
|
"GrTest(float w, int x, float y, std::vector<float> z )",
|
|
", w(w) {"
|
|
},
|
|
{});
|
|
test(r,
|
|
"@constructor { constructor section }"
|
|
"void main() {"
|
|
"sk_OutColor = half4(1);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"private:\n constructor section"
|
|
},
|
|
{});
|
|
test(r,
|
|
"@initializers { initializers section }"
|
|
"void main() {"
|
|
"sk_OutColor = half4(1);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
": INHERITED(kGrTest_ClassID, kNone_OptimizationFlags)\n , initializers section"
|
|
},
|
|
{});
|
|
test(r,
|
|
"half x = 10;"
|
|
"@emitCode { fragBuilder->codeAppendf(\"half y = %d\\n\", x * 2); }"
|
|
"void main() {"
|
|
"sk_OutColor = half4(1);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{},
|
|
{
|
|
"x = 10.0;\n"
|
|
" fragBuilder->codeAppendf(\"half y = %d\\n\", x * 2);"
|
|
});
|
|
test(r,
|
|
"@fields { fields section }"
|
|
"@clone { }"
|
|
"void main() {"
|
|
"sk_OutColor = half4(1);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"const char* name() const override { return \"Test\"; }\n"
|
|
" fields section private:"
|
|
},
|
|
{});
|
|
test(r,
|
|
"@make { make section }"
|
|
"void main() {"
|
|
"sk_OutColor = half4(1);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"public:\n"
|
|
" make section"
|
|
},
|
|
{});
|
|
test(r,
|
|
"uniform half calculated;"
|
|
"in half provided;"
|
|
"@setData(varName) { varName.set1f(calculated, provided * 2); }"
|
|
"void main() {"
|
|
"sk_OutColor = half4(1);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{},
|
|
{
|
|
"void onSetData(const GrGLSLProgramDataManager& varName, "
|
|
"const GrFragmentProcessor& _proc) override {\n",
|
|
"UniformHandle& calculated = calculatedVar;",
|
|
"auto provided = _outer.provided;",
|
|
"varName.set1f(calculated, provided * 2);"
|
|
});
|
|
test(r,
|
|
"@test(testDataName) { testDataName section }"
|
|
"void main() {"
|
|
"sk_OutColor = half4(1);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{},
|
|
{
|
|
"#if GR_TEST_UTILS\n"
|
|
"std::unique_ptr<GrFragmentProcessor> GrTest::TestCreate(GrProcessorTestData* testDataName) {\n"
|
|
" testDataName section }\n"
|
|
"#endif"
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPTransformedCoords, r) {
|
|
test(r,
|
|
"void main() {"
|
|
"sk_OutColor = half4(sk_TransformedCoords2D[0], sk_TransformedCoords2D[0]);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{},
|
|
{
|
|
"SkString sk_TransformedCoords2D_0 = "
|
|
"fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);",
|
|
"fragBuilder->codeAppendf(\"%s = half4(%s, %s);\\n\", args.fOutputColor, "
|
|
"sk_TransformedCoords2D_0.c_str(), sk_TransformedCoords2D_0.c_str());"
|
|
});
|
|
|
|
}
|
|
|
|
DEF_TEST(SkSLFPLayoutWhen, r) {
|
|
test(r,
|
|
"layout(when=someExpression(someOtherExpression())) uniform half sometimes;"
|
|
"void main() {"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{},
|
|
{
|
|
"if (someExpression(someOtherExpression())) {\n"
|
|
" sometimesVar = args.fUniformHandler->addUniform"
|
|
});
|
|
|
|
}
|
|
|
|
DEF_TEST(SkSLFPChildProcessors, r) {
|
|
test(r,
|
|
"in fragmentProcessor child1;"
|
|
"in fragmentProcessor child2;"
|
|
"void main() {"
|
|
" sk_OutColor = process(child1) * process(child2);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"this->registerChildProcessor(std::move(child1));",
|
|
"this->registerChildProcessor(std::move(child2));"
|
|
},
|
|
{
|
|
"SkString _child0(\"_child0\");",
|
|
"this->emitChild(_outer.child1_index, &_child0, args);",
|
|
"SkString _child1(\"_child1\");",
|
|
"this->emitChild(_outer.child2_index, &_child1, args);",
|
|
"this->registerChildProcessor(src.childProcessor(child1_index).clone());",
|
|
"this->registerChildProcessor(src.childProcessor(child2_index).clone());"
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPChildProcessorsWithInput, r) {
|
|
test(r,
|
|
"in fragmentProcessor child1;"
|
|
"in fragmentProcessor child2;"
|
|
"void main() {"
|
|
" half4 childIn = sk_InColor;"
|
|
" half4 childOut1 = process(child1, childIn);"
|
|
" half4 childOut2 = process(child2, childOut1);"
|
|
" sk_OutColor = childOut2;"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"this->registerChildProcessor(std::move(child1));",
|
|
"this->registerChildProcessor(std::move(child2));"
|
|
},
|
|
{
|
|
"SkString _input0(\"childIn\");",
|
|
"SkString _child0(\"_child0\");",
|
|
"this->emitChild(_outer.child1_index, _input0.c_str(), &_child0, args);",
|
|
"SkString _input1(\"childOut1\");",
|
|
"SkString _child1(\"_child1\");",
|
|
"this->emitChild(_outer.child2_index, _input1.c_str(), &_child1, args);",
|
|
"this->registerChildProcessor(src.childProcessor(child1_index).clone());",
|
|
"this->registerChildProcessor(src.childProcessor(child2_index).clone());"
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPChildProcessorWithInputExpression, r) {
|
|
test(r,
|
|
"in fragmentProcessor child;"
|
|
"void main() {"
|
|
" sk_OutColor = process(child, sk_InColor * half4(0.5));"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"this->registerChildProcessor(std::move(child));",
|
|
},
|
|
{
|
|
"SkString _input0 = SkStringPrintf(\"%s * half4(0.5)\", args.fInputColor);",
|
|
"SkString _child0(\"_child0\");",
|
|
"this->emitChild(_outer.child_index, _input0.c_str(), &_child0, args);",
|
|
"this->registerChildProcessor(src.childProcessor(child_index).clone());",
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPNestedChildProcessors, r) {
|
|
test(r,
|
|
"in fragmentProcessor child1;"
|
|
"in fragmentProcessor child2;"
|
|
"void main() {"
|
|
" sk_OutColor = process(child2, sk_InColor * process(child1, sk_InColor * half4(0.5)));"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"this->registerChildProcessor(std::move(child1));",
|
|
"this->registerChildProcessor(std::move(child2));"
|
|
},
|
|
{
|
|
"SkString _input0 = SkStringPrintf(\"%s * half4(0.5)\", args.fInputColor);",
|
|
"SkString _child0(\"_child0\");",
|
|
"this->emitChild(_outer.child1_index, _input0.c_str(), &_child0, args);",
|
|
"SkString _input1 = SkStringPrintf(\"%s * %s\", args.fInputColor, _child0.c_str());",
|
|
"SkString _child1(\"_child1\");",
|
|
"this->emitChild(_outer.child2_index, _input1.c_str(), &_child1, args);",
|
|
"this->registerChildProcessor(src.childProcessor(child1_index).clone());",
|
|
"this->registerChildProcessor(src.childProcessor(child2_index).clone());"
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPChildFPAndGlobal, r) {
|
|
test(r,
|
|
"in fragmentProcessor child;"
|
|
"bool hasCap = sk_Caps.externalTextureSupport;"
|
|
"void main() {"
|
|
" if (hasCap) {"
|
|
" sk_OutColor = process(child, sk_InColor);"
|
|
" } else {"
|
|
" sk_OutColor = half4(1);"
|
|
" }"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"this->registerChildProcessor(std::move(child));"
|
|
},
|
|
{
|
|
"hasCap = sk_Caps.externalTextureSupport;",
|
|
"fragBuilder->codeAppendf(\"bool hasCap = %s;\\nif (hasCap) {\", "
|
|
"(hasCap ? \"true\" : \"false\"));",
|
|
"SkString _input0 = SkStringPrintf(\"%s\", args.fInputColor);",
|
|
"SkString _child0(\"_child0\");",
|
|
"this->emitChild(_outer.child_index, _input0.c_str(), &_child0, args);",
|
|
"fragBuilder->codeAppendf(\"\\n %s = %s;\\n} else {\\n %s = half4(1.0);\\n}"
|
|
"\\n\", args.fOutputColor, _child0.c_str(), args.fOutputColor);",
|
|
"this->registerChildProcessor(src.childProcessor(child_index).clone());"
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPChildProcessorInlineFieldAccess, r) {
|
|
test(r,
|
|
"in fragmentProcessor child;"
|
|
"void main() {"
|
|
" if (child.preservesOpaqueInput) {"
|
|
" sk_OutColor = process(child, sk_InColor);"
|
|
" } else {"
|
|
" sk_OutColor = half4(1);"
|
|
" }"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"this->registerChildProcessor(std::move(child));"
|
|
},
|
|
{
|
|
"fragBuilder->codeAppendf(\"if (%s) {\", "
|
|
"(_outer.childProcessor(_outer.child_index).preservesOpaqueInput() ? "
|
|
"\"true\" : \"false\"));",
|
|
"SkString _input0 = SkStringPrintf(\"%s\", args.fInputColor);",
|
|
"SkString _child0(\"_child0\");",
|
|
"this->emitChild(_outer.child_index, _input0.c_str(), &_child0, args);",
|
|
"fragBuilder->codeAppendf(\"\\n %s = %s;\\n} else {\\n %s = half4(1.0);\\n}\\n\""
|
|
", args.fOutputColor, _child0.c_str(), args.fOutputColor);",
|
|
"this->registerChildProcessor(src.childProcessor(child_index).clone());"
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPChildProcessorFieldAccess, r) {
|
|
test(r,
|
|
"in fragmentProcessor child;"
|
|
"bool opaque = child.preservesOpaqueInput;"
|
|
"void main() {"
|
|
" if (opaque) {"
|
|
" sk_OutColor = process(child);"
|
|
" } else {"
|
|
" sk_OutColor = half4(0.5);"
|
|
" }"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"this->registerChildProcessor(std::move(child));"
|
|
},
|
|
{
|
|
"opaque = _outer.childProcessor(_outer.child_index).preservesOpaqueInput();",
|
|
"fragBuilder->codeAppendf(\"bool opaque = %s;\\nif (opaque) {\", "
|
|
"(opaque ? \"true\" : \"false\"));",
|
|
"SkString _child0(\"_child0\");",
|
|
"this->emitChild(_outer.child_index, &_child0, args);",
|
|
"fragBuilder->codeAppendf(\"\\n %s = %s;\\n} else {\\n %s = half4(0.5);\\n}\\n\""
|
|
", args.fOutputColor, _child0.c_str(), args.fOutputColor);",
|
|
"this->registerChildProcessor(src.childProcessor(child_index).clone());"
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPNullableChildProcessor, r) {
|
|
test(r,
|
|
"in fragmentProcessor? child;"
|
|
"void main() {"
|
|
" if (child != null) {"
|
|
" sk_OutColor = process(child);"
|
|
" } else {"
|
|
" sk_OutColor = half4(0.5);"
|
|
" }"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{},
|
|
{
|
|
"SkString _child0(\"_child0\");",
|
|
"if (_outer.child_index >= 0) {",
|
|
"this->emitChild(_outer.child_index, &_child0, args);",
|
|
"} else {",
|
|
"fragBuilder->codeAppendf(\"half4 %s;\", _child0.c_str());",
|
|
"}",
|
|
"fragBuilder->codeAppendf(\"\\n %s = %s;\\n} else {\\n %s = half4(0.5);\\n}\\n\""
|
|
", args.fOutputColor, _child0.c_str(), args.fOutputColor);",
|
|
});
|
|
}
|