b65024b5f2
This first pass adds "one size fits all" function inlining, without any allowances for simple functions that don't need all of this machinery in place. Followup CLs will simplify common cases by e.g. not storing arguments in variables if they're already variables and not wrapping the function body in a loop when it isn't necessary. Change-Id: I4fd8c1655ff48b9e4708bcca03a506df34ceadd9 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/290127 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
806 lines
32 KiB
C++
806 lines
32 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 "src/sksl/SkSLStringStream.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);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void test_failure(skiatest::Reporter* r, const char* src, const char* error) {
|
|
SkSL::Compiler compiler;
|
|
SkSL::Program::Settings settings;
|
|
sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
|
|
settings.fCaps = caps.get();
|
|
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
|
|
SkSL::Program::kFragmentProcessor_Kind,
|
|
SkSL::String(src),
|
|
settings);
|
|
if (!compiler.errorCount()) {
|
|
compiler.optimize(*program);
|
|
}
|
|
SkSL::String skError(error);
|
|
if (compiler.errorText() != skError) {
|
|
SkDebugf("SKSL ERROR:\n source: %s\n expected: %s received: %s", src, error,
|
|
compiler.errorText().c_str());
|
|
}
|
|
REPORTER_ASSERT(r, compiler.errorText() == skError);
|
|
}
|
|
|
|
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"
|
|
"#include \"include/core/SkM44.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 \"src/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,
|
|
"layout(key) 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(&_outer, 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(&_outer, 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(&_outer, 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(&_outer, 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(&_outer, 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,
|
|
"layout(key) 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(&_outer, 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;"
|
|
"layout(key) 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].fVaryingPoint, "
|
|
"_outer.sampleMatrix());",
|
|
"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 = sample(child1) * sample(child2);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"this->registerChildProcessor(std::move(child1));",
|
|
"this->registerChildProcessor(std::move(child2));"
|
|
},
|
|
{
|
|
"SkString _sample93;\n",
|
|
"_sample93 = this->invokeChild(_outer.child1_index, args);\n",
|
|
"SkString _sample110;\n",
|
|
"_sample110 = this->invokeChild(_outer.child2_index, args);\n",
|
|
"fragBuilder->codeAppendf(\"%s = %s * %s;\\n\", args.fOutputColor, _sample93.c_str(), "
|
|
"_sample110.c_str());\n",
|
|
"{",
|
|
" auto clone = src.childProcessor(child1_index).clone();",
|
|
" if (src.childProcessor(child1_index).isSampledWithExplicitCoords()) {",
|
|
" clone->setSampledWithExplicitCoords();",
|
|
" }",
|
|
" this->registerChildProcessor(std::move(clone));",
|
|
"}",
|
|
"{",
|
|
" auto clone = src.childProcessor(child2_index).clone();",
|
|
" if (src.childProcessor(child2_index).isSampledWithExplicitCoords()) {",
|
|
" clone->setSampledWithExplicitCoords();",
|
|
" }",
|
|
" this->registerChildProcessor(std::move(clone));",
|
|
"}",
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPChildProcessorsWithInput, r) {
|
|
test(r,
|
|
"in fragmentProcessor child1;"
|
|
"in fragmentProcessor child2;"
|
|
"void main() {"
|
|
" half4 childIn = sk_InColor;"
|
|
" half4 childOut1 = sample(child1, childIn);"
|
|
" half4 childOut2 = sample(child2, childOut1);"
|
|
" sk_OutColor = childOut2;"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"this->registerChildProcessor(std::move(child1));",
|
|
"this->registerChildProcessor(std::move(child2));"
|
|
},
|
|
{
|
|
"SkString _input128(\"childIn\");",
|
|
"SkString _sample128;",
|
|
"_sample128 = this->invokeChild(_outer.child1_index, _input128.c_str(), args);",
|
|
"fragBuilder->codeAppendf(\"\\nhalf4 childOut1 = %s;\", _sample128.c_str());",
|
|
"SkString _input174(\"childOut1\");",
|
|
"SkString _sample174;",
|
|
"_sample174 = this->invokeChild(_outer.child2_index, _input174.c_str(), args);",
|
|
"{",
|
|
" auto clone = src.childProcessor(child1_index).clone();",
|
|
" if (src.childProcessor(child1_index).isSampledWithExplicitCoords()) {",
|
|
" clone->setSampledWithExplicitCoords();",
|
|
" }",
|
|
" this->registerChildProcessor(std::move(clone));",
|
|
"}",
|
|
"{",
|
|
" auto clone = src.childProcessor(child2_index).clone();",
|
|
" if (src.childProcessor(child2_index).isSampledWithExplicitCoords()) {",
|
|
" clone->setSampledWithExplicitCoords();",
|
|
" }",
|
|
" this->registerChildProcessor(std::move(clone));",
|
|
"}"
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPChildProcessorWithInputExpression, r) {
|
|
test(r,
|
|
"in fragmentProcessor child;"
|
|
"void main() {"
|
|
" sk_OutColor = sample(child, sk_InColor * half4(0.5));"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"this->registerChildProcessor(std::move(child));",
|
|
},
|
|
{
|
|
"SkString _input64 = SkStringPrintf(\"%s * half4(0.5)\", args.fInputColor);",
|
|
"SkString _sample64;",
|
|
"_sample64 = this->invokeChild(_outer.child_index, _input64.c_str(), args);",
|
|
"fragBuilder->codeAppendf(\"%s = %s;\\n\", args.fOutputColor, _sample64.c_str());",
|
|
"{",
|
|
" auto clone = src.childProcessor(child_index).clone();",
|
|
" if (src.childProcessor(child_index).isSampledWithExplicitCoords()) {",
|
|
" clone->setSampledWithExplicitCoords();",
|
|
" }",
|
|
" this->registerChildProcessor(std::move(clone));",
|
|
"}",
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPNestedChildProcessors, r) {
|
|
test(r,
|
|
"in fragmentProcessor child1;"
|
|
"in fragmentProcessor child2;"
|
|
"void main() {"
|
|
" sk_OutColor = sample(child2, sk_InColor * sample(child1, sk_InColor * half4(0.5)));"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{
|
|
"this->registerChildProcessor(std::move(child1));",
|
|
"this->registerChildProcessor(std::move(child2));"
|
|
},
|
|
{
|
|
"SkString _input121 = SkStringPrintf(\"%s * half4(0.5)\", args.fInputColor);",
|
|
"SkString _sample121;",
|
|
"_sample121 = this->invokeChild(_outer.child1_index, _input121.c_str(), args);",
|
|
"SkString _input93 = SkStringPrintf(\"%s * %s\", args.fInputColor, _sample121.c_str());",
|
|
"SkString _sample93;",
|
|
"_sample93 = this->invokeChild(_outer.child2_index, _input93.c_str(), args);",
|
|
"fragBuilder->codeAppendf(\"%s = %s;\\n\", args.fOutputColor, _sample93.c_str());",
|
|
"{",
|
|
" auto clone = src.childProcessor(child1_index).clone();",
|
|
" if (src.childProcessor(child1_index).isSampledWithExplicitCoords()) {",
|
|
" clone->setSampledWithExplicitCoords();",
|
|
" }",
|
|
" this->registerChildProcessor(std::move(clone));",
|
|
"}",
|
|
"{",
|
|
" auto clone = src.childProcessor(child2_index).clone();",
|
|
" if (src.childProcessor(child2_index).isSampledWithExplicitCoords()) {",
|
|
" clone->setSampledWithExplicitCoords();",
|
|
" }",
|
|
" this->registerChildProcessor(std::move(clone));",
|
|
"}",
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPChildFPAndGlobal, r) {
|
|
test(r,
|
|
"in fragmentProcessor child;"
|
|
"bool hasCap = sk_Caps.externalTextureSupport;"
|
|
"void main() {"
|
|
" if (hasCap) {"
|
|
" sk_OutColor = sample(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 _input130 = SkStringPrintf(\"%s\", args.fInputColor);",
|
|
"SkString _sample130;",
|
|
"_sample130 = this->invokeChild(_outer.child_index, _input130.c_str(), args);",
|
|
"fragBuilder->codeAppendf(\"\\n %s = %s;\\n} else {\\n %s = half4(1.0);\\n}\\n\","
|
|
" args.fOutputColor, _sample130.c_str(), args.fOutputColor);",
|
|
"{",
|
|
" auto clone = src.childProcessor(child_index).clone();",
|
|
" if (src.childProcessor(child_index).isSampledWithExplicitCoords()) {",
|
|
" clone->setSampledWithExplicitCoords();",
|
|
" }",
|
|
" this->registerChildProcessor(std::move(clone));",
|
|
"}",
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPChildProcessorInlineFieldAccess, r) {
|
|
test(r,
|
|
"in fragmentProcessor child;"
|
|
"void main() {"
|
|
" if (child.preservesOpaqueInput) {"
|
|
" sk_OutColor = sample(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() ? ",
|
|
"SkString _input105 = SkStringPrintf(\"%s\", args.fInputColor);",
|
|
"SkString _sample105;",
|
|
"_sample105 = this->invokeChild(_outer.child_index, _input105.c_str(), args);",
|
|
"fragBuilder->codeAppendf(\"\\n %s = %s;\\n} else {\\n %s = half4(1.0);\\n}\\n\","
|
|
" args.fOutputColor, _sample105.c_str(), args.fOutputColor);",
|
|
"{",
|
|
" auto clone = src.childProcessor(child_index).clone();",
|
|
" if (src.childProcessor(child_index).isSampledWithExplicitCoords()) {",
|
|
" clone->setSampledWithExplicitCoords();",
|
|
" }",
|
|
" this->registerChildProcessor(std::move(clone));",
|
|
"}",
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPChildProcessorFieldAccess, r) {
|
|
test(r,
|
|
"in fragmentProcessor child;"
|
|
"bool opaque = child.preservesOpaqueInput;"
|
|
"void main() {"
|
|
" if (opaque) {"
|
|
" sk_OutColor = sample(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 _sample126;",
|
|
"_sample126 = this->invokeChild(_outer.child_index, args);",
|
|
"fragBuilder->codeAppendf(\"\\n %s = %s;\\n} else {\\n %s = half4(0.5);\\n}\\n\","
|
|
" args.fOutputColor, _sample126.c_str(), args.fOutputColor);",
|
|
"{",
|
|
" auto clone = src.childProcessor(child_index).clone();",
|
|
" if (src.childProcessor(child_index).isSampledWithExplicitCoords()) {",
|
|
" clone->setSampledWithExplicitCoords();",
|
|
" }",
|
|
" this->registerChildProcessor(std::move(clone));",
|
|
"}",
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPNullableChildProcessor, r) {
|
|
test(r,
|
|
"in fragmentProcessor? child;"
|
|
"void main() {"
|
|
" if (child != null) {"
|
|
" sk_OutColor = sample(child);"
|
|
" } else {"
|
|
" sk_OutColor = half4(0.5);"
|
|
" }"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{},
|
|
{
|
|
"fragBuilder->codeAppendf(\"if (%s) {\", _outer.child_index >= 0 ? \"true\" : "
|
|
"\"false\");",
|
|
"SkString _sample93;",
|
|
"if (_outer.child_index >= 0) {",
|
|
"_sample93 = this->invokeChild(_outer.child_index, args);",
|
|
"}",
|
|
"fragBuilder->codeAppendf(\"\\n %s = %s;\\n} else {\\n %s = half4(0.5);\\n}\\n\","
|
|
" args.fOutputColor, _sample93.c_str(), args.fOutputColor);"
|
|
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPBadIn, r) {
|
|
test_failure(r,
|
|
"in half4 c;"
|
|
"void main() {"
|
|
" sk_OutColor = c;"
|
|
"}",
|
|
"error: 1: 'in' variable must be either 'uniform' or 'layout(key)', or there must be a "
|
|
"custom @setData function\n1 error\n");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPSampleCoords, r) {
|
|
test(r,
|
|
"in fragmentProcessor child;"
|
|
"@coordTransform { SkMatrix() }"
|
|
"void main() {"
|
|
" sk_OutColor = sample(child) + sample(child, sk_TransformedCoords2D[0] / 2);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{},
|
|
{
|
|
"SkString _sample94;\n",
|
|
"_sample94 = this->invokeChild(_outer.child_index, args);\n",
|
|
"SkString _sample110;\n",
|
|
"SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D("
|
|
"args.fTransformedCoords[0].fVaryingPoint, "
|
|
"_outer.sampleMatrix());\n",
|
|
"SkString _coords110 = SkStringPrintf(\"%s / 2.0\", "
|
|
"sk_TransformedCoords2D_0.c_str());\n",
|
|
"_sample110 = this->invokeChild(_outer.child_index, args, _coords110.c_str());\n",
|
|
"fragBuilder->codeAppendf(\"%s = %s + %s;\\n\", args.fOutputColor, _sample94.c_str(), "
|
|
"_sample110.c_str());\n"
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPFunction, r) {
|
|
test(r,
|
|
"in fragmentProcessor? child;"
|
|
"half4 flip(half4 c) { return c.abgr; }"
|
|
"void main() {"
|
|
" sk_OutColor = flip(sk_InColor);"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{},
|
|
{
|
|
"SkString flip_name;",
|
|
"const GrShaderVar flip_args[] = { GrShaderVar(\"c\", kHalf4_GrSLType)};",
|
|
"fragBuilder->emitFunction(kHalf4_GrSLType, \"flip\", 1, flip_args, "
|
|
"\"return c.wzyx;\\n\", &flip_name);",
|
|
"fragBuilder->codeAppendf(\"half4 inlineResult101;\\nhalf4 inlineArg101_0 = %s;\\ndo {"
|
|
"\\n {\\n inlineResult101 = inlineArg101_0.wzyx;\\n"
|
|
" break;\\n }\\n} while (false);\\n%s = "
|
|
"inlineResult101;\\n\\n\", args.fInputColor, "
|
|
"args.fOutputColor);"
|
|
});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPMatrixSample, r) {
|
|
test(r,
|
|
"in fragmentProcessor? child;"
|
|
"void main() {"
|
|
" sk_OutColor = sample(child, float3x3(2));"
|
|
"}",
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
{},
|
|
{
|
|
});
|
|
}
|