| /* |
| * 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 GrShaderCaps& caps, const char* src, |
| std::vector<const char*> expectedH, std::vector<const char*> expectedCPP) { |
| SkSL::Program::Settings settings; |
| settings.fCaps = ∩︀ |
| settings.fRemoveDeadFunctions = false; |
| 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\n" |
| "header expected:\n'%s'\n\n" |
| "header received:\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\n" |
| "cpp expected:\n'%s'\n\n" |
| "cpp received:\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, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| /* HELLO WORLD */ |
| void main() { |
| sk_OutColor = half4(1); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| R"__Header__(/* HELLO WORLD */ |
| |
| /************************************************************************************************** |
| *** This file was autogenerated from GrTest.fp; do not modify. |
| **************************************************************************************************/ |
| #ifndef GrTest_DEFINED |
| #define GrTest_DEFINED |
| |
| #include "include/core/SkM44.h" |
| #include "include/core/SkTypes.h" |
| |
| |
| #include "src/gpu/GrFragmentProcessor.h" |
| |
| class GrTest : public GrFragmentProcessor { |
| public: |
| static std::unique_ptr<GrFragmentProcessor> Make() { |
| return std::unique_ptr<GrFragmentProcessor>(new GrTest()); |
| } |
| GrTest(const GrTest& src); |
| std::unique_ptr<GrFragmentProcessor> clone() const override; |
| const char* name() const override { return "Test"; } |
| private: |
| GrTest() |
| : INHERITED(kGrTest_ClassID, kNone_OptimizationFlags) { |
| } |
| GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; |
| void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; |
| bool onIsEqual(const GrFragmentProcessor&) const override; |
| #if GR_TEST_UTILS |
| SkString onDumpInfo() const override; |
| #endif |
| GR_DECLARE_FRAGMENT_PROCESSOR_TEST |
| typedef GrFragmentProcessor INHERITED; |
| }; |
| #endif |
| )__Header__" |
| }, |
| /*expectedCPP=*/{ |
| R"__Cpp__(/* HELLO WORLD */ |
| |
| /************************************************************************************************** |
| *** This file was autogenerated from GrTest.fp; do not modify. |
| **************************************************************************************************/ |
| #include "GrTest.h" |
| |
| #include "src/core/SkUtils.h" |
| #include "src/gpu/GrTexture.h" |
| #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" |
| #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
| #include "src/gpu/glsl/GrGLSLProgramBuilder.h" |
| #include "src/sksl/SkSLCPP.h" |
| #include "src/sksl/SkSLUtil.h" |
| class GrGLSLTest : public GrGLSLFragmentProcessor { |
| public: |
| GrGLSLTest() {} |
| void emitCode(EmitArgs& args) override { |
| GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; |
| const GrTest& _outer = args.fFp.cast<GrTest>(); |
| (void) _outer; |
| fragBuilder->codeAppendf( |
| R"SkSL(%s = half4(1.0); |
| )SkSL" |
| , args.fOutputColor); |
| } |
| private: |
| void onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& _proc) override { |
| } |
| }; |
| GrGLSLFragmentProcessor* GrTest::onCreateGLSLInstance() const { |
| return new GrGLSLTest(); |
| } |
| void GrTest::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { |
| } |
| bool GrTest::onIsEqual(const GrFragmentProcessor& other) const { |
| const GrTest& that = other.cast<GrTest>(); |
| (void) that; |
| return true; |
| } |
| GrTest::GrTest(const GrTest& src) |
| : INHERITED(kGrTest_ClassID, src.optimizationFlags()) { |
| this->cloneAndRegisterAllChildProcessors(src); |
| } |
| std::unique_ptr<GrFragmentProcessor> GrTest::clone() const { |
| return std::make_unique<GrTest>(*this); |
| } |
| #if GR_TEST_UTILS |
| SkString GrTest::onDumpInfo() const { |
| return SkString(); |
| } |
| #endif |
| )__Cpp__" |
| }); |
| } |
| |
| DEF_TEST(SkSLFPInputHalf2, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in uniform half2 point; |
| void main() { |
| sk_OutColor = half4(point, point); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "static std::unique_ptr<GrFragmentProcessor> Make(SkPoint point) {", |
| "return std::unique_ptr<GrFragmentProcessor>(new GrTest(point));", |
| "GrTest(SkPoint point)", |
| ", point(point)" |
| }, |
| /*expectedCPP=*/{ |
| R"__Cpp__(fragBuilder->codeAppendf( |
| R"SkSL(%s = half4(%s, %s); |
| )SkSL" |
| , args.fOutputColor, args.fUniformHandler->getUniformCStr(pointVar), args.fUniformHandler->getUniformCStr(pointVar)); |
| )__Cpp__", |
| "if (point != that.point) return false;" |
| }); |
| } |
| |
| DEF_TEST(SkSLFPInputHalf1, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| layout(key) in half value; |
| void main() { |
| sk_OutColor = half4(value); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| R"__Cpp__(static std::unique_ptr<GrFragmentProcessor> Make(float value) { |
| return std::unique_ptr<GrFragmentProcessor>(new GrTest(value)); |
| } |
| )__Cpp__", |
| R"__Cpp__(GrTest(float value) |
| : INHERITED(kGrTest_ClassID, kNone_OptimizationFlags) |
| , value(value) { |
| } |
| )__Cpp__", |
| }, |
| /*expectedCPP=*/{ |
| R"__Cpp__(void GrTest::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { |
| b->add32(sk_bit_cast<uint32_t>(value)); |
| } |
| )__Cpp__", |
| R"__Cpp__(bool GrTest::onIsEqual(const GrFragmentProcessor& other) const { |
| const GrTest& that = other.cast<GrTest>(); |
| (void) that; |
| if (value != that.value) return false; |
| return true; |
| } |
| )__Cpp__", |
| R"__Cpp__(GrTest::GrTest(const GrTest& src) |
| : INHERITED(kGrTest_ClassID, src.optimizationFlags()) |
| , value(src.value) { |
| this->cloneAndRegisterAllChildProcessors(src); |
| } |
| )__Cpp__", |
| R"__Cpp__(std::unique_ptr<GrFragmentProcessor> GrTest::clone() const { |
| return std::make_unique<GrTest>(*this); |
| } |
| )__Cpp__", |
| R"__Cpp__(#if GR_TEST_UTILS |
| SkString GrTest::onDumpInfo() const { |
| return SkStringPrintf("(value=%f)", value); |
| } |
| )__Cpp__", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPUniform, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| uniform half4 color; |
| void main() { |
| sk_OutColor = color; |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "static std::unique_ptr<GrFragmentProcessor> Make()" |
| }, |
| /*expectedCPP=*/{ |
| "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, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in uniform half4 color; |
| void main() { |
| sk_OutColor = color; |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "static std::unique_ptr<GrFragmentProcessor> Make(SkRect color) {", |
| }, |
| /*expectedCPP=*/{ |
| "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, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| layout(ctype=SkPMColor4f) in uniform half4 color; |
| void main() { |
| sk_OutColor = color; |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "static std::unique_ptr<GrFragmentProcessor> Make(SkPMColor4f color) {", |
| }, |
| /*expectedCPP=*/{ |
| "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, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| layout(tracked) in uniform half4 color; |
| void main() { |
| sk_OutColor = color; |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "static std::unique_ptr<GrFragmentProcessor> Make(SkRect color) {", |
| }, |
| /*expectedCPP=*/{ |
| "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, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in uniform half2 point; |
| void main() { |
| sk_OutColor = half4(point, point); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "static std::unique_ptr<GrFragmentProcessor> Make(SkPoint point) {", |
| }, |
| /*expectedCPP=*/{ |
| "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, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| 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__", |
| /*expectedH=*/{ |
| "static std::unique_ptr<GrFragmentProcessor> Make(bool test, SkPMColor4f color) {", |
| }, |
| /*expectedCPP=*/{ |
| "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, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| @header { header section } |
| void main() { |
| sk_OutColor = half4(1); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "header section" |
| }, |
| /*expectedCPP=*/{}); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| @class { class section } |
| void main() { |
| sk_OutColor = half4(1); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "class GrTest : public GrFragmentProcessor {\n" |
| "public:\n" |
| " class section" |
| }, |
| /*expectedCPP=*/{}); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| @cpp { cpp section } |
| void main() { |
| sk_OutColor = half4(1); |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| "cpp section" |
| }); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| @constructorParams { int x, float y, std::vector<float> z } |
| in float w; |
| void main() { |
| sk_OutColor = half4(1); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "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) {" |
| }, |
| /*expectedCPP=*/{}); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| @constructor { constructor section } |
| void main() { |
| sk_OutColor = half4(1); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "private:\n constructor section" |
| }, |
| /*expectedCPP=*/{}); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| @initializers { initializers section } |
| void main() { |
| sk_OutColor = half4(1); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| ": INHERITED(kGrTest_ClassID, kNone_OptimizationFlags)\n , initializers section" |
| }, |
| /*expectedCPP=*/{}); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| half x = 10; |
| @emitCode { fragBuilder->codeAppendf("half y = %d\n", x * 2); } |
| void main() { |
| sk_OutColor = half4(1); |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| "x = 10.0;\n" |
| " fragBuilder->codeAppendf(\"half y = %d\\n\", x * 2);" |
| }); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| @fields { fields section } |
| @clone { } |
| @dumpInfo { } |
| void main() { |
| sk_OutColor = half4(1); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "const char* name() const override { return \"Test\"; }\n" |
| " fields section private:" |
| }, |
| /*expectedCPP=*/{}); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| @make { make section } |
| void main() { |
| sk_OutColor = half4(1); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "public:\n" |
| " make section" |
| }, |
| /*expectedCPP=*/{}); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| uniform half calculated; |
| layout(key) in half provided; |
| @setData(varName) { varName.set1f(calculated, provided * 2); } |
| void main() { |
| sk_OutColor = half4(1); |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| "void onSetData(const GrGLSLProgramDataManager& varName, " |
| "const GrFragmentProcessor& _proc) override {\n", |
| "UniformHandle& calculated = calculatedVar;", |
| "auto provided = _outer.provided;", |
| "varName.set1f(calculated, provided * 2);" |
| }); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| @test(testDataName) { testDataName section } |
| void main() { |
| sk_OutColor = half4(1); |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| "#if GR_TEST_UTILS\n" |
| "std::unique_ptr<GrFragmentProcessor> GrTest::TestCreate(GrProcessorTestData* testDataName) {\n" |
| " testDataName section }\n" |
| "#endif" |
| }); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| @dumpInfo {dump all the fields} |
| void main() { |
| sk_OutColor = half4(1); |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| R"__Cpp__(#if GR_TEST_UTILS |
| SkString GrTest::onDumpInfo() const { |
| dump all the fields |
| } |
| #endif)__Cpp__" |
| }); |
| } |
| |
| DEF_TEST(SkSLFPMainCoords, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| void main(float2 coord) { |
| sk_OutColor = half4(coord, coord); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "this->setUsesSampleCoordsDirectly();" |
| }, |
| /*expectedCPP=*/{ |
| "fragBuilder->codeAppendf(\n" |
| "R\"SkSL(%s = half4(%s, %s);\n" |
| ")SkSL\"\n" |
| ", args.fOutputColor, args.fSampleCoord, args.fSampleCoord);" |
| }); |
| } |
| |
| DEF_TEST(SkSLFPLayoutWhen, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| layout(when=someExpression(someOtherExpression())) uniform half sometimes; |
| void main() { |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| "if (someExpression(someOtherExpression())) {\n" |
| " sometimesVar = args.fUniformHandler->addUniform" |
| }); |
| } |
| |
| DEF_TEST(SkSLFPChildProcessors, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in fragmentProcessor child1; |
| in fragmentProcessor child2; |
| void main() { |
| sk_OutColor = sample(child1) * sample(child2); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "this->registerChild(std::move(child1), SkSL::SampleUsage::PassThrough());", |
| "this->registerChild(std::move(child2), SkSL::SampleUsage::PassThrough());" |
| }, |
| /*expectedCPP=*/{ |
| "SkString _sample149 = this->invokeChild(0, args);\n", |
| "SkString _sample166 = this->invokeChild(1, args);\n", |
| "fragBuilder->codeAppendf(\n" |
| "R\"SkSL(%s = %s * %s;\n" |
| ")SkSL\"\n" |
| ", args.fOutputColor, _sample149.c_str(), _sample166.c_str());", |
| "this->cloneAndRegisterAllChildProcessors(src);", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPChildProcessorsWithInput, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| uniform half4 color; |
| in fragmentProcessor child1; |
| in fragmentProcessor child2; |
| void main() { |
| half4 childIn = color; |
| half4 childOut1 = sample(child1, childIn); |
| half4 childOut2 = sample(child2, childOut1); |
| sk_OutColor = childOut2; |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "this->registerChild(std::move(child1), SkSL::SampleUsage::PassThrough());", |
| "this->registerChild(std::move(child2), SkSL::SampleUsage::PassThrough());" |
| }, |
| /*expectedCPP=*/{ |
| "this->cloneAndRegisterAllChildProcessors(src);", |
| R"__Cpp__( |
| SkString _input227("childIn"); |
| SkString _sample227 = this->invokeChild(0, _input227.c_str(), args); |
| fragBuilder->codeAppendf( |
| R"SkSL( |
| half4 childOut1 = %s;)SkSL" |
| , _sample227.c_str()); |
| SkString _input287("childOut1"); |
| SkString _sample287 = this->invokeChild(1, _input287.c_str(), args); |
| fragBuilder->codeAppendf( |
| R"SkSL( |
| half4 childOut2 = %s; |
| %s = childOut2; |
| )SkSL" |
| , _sample287.c_str(), args.fOutputColor); |
| )__Cpp__"}); |
| } |
| |
| DEF_TEST(SkSLFPChildProcessorWithInputExpression, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| uniform half4 color; |
| in fragmentProcessor child; |
| void main() { |
| sk_OutColor = sample(child, color * half4(0.5)); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "this->registerChild(std::move(child), SkSL::SampleUsage::PassThrough());", |
| }, |
| /*expectedCPP=*/{ |
| "this->cloneAndRegisterAllChildProcessors(src);", |
| R"__Cpp__( |
| SkString _input140 = SkStringPrintf("%s * half4(0.5)", args.fUniformHandler->getUniformCStr(colorVar)); |
| SkString _sample140 = this->invokeChild(0, _input140.c_str(), args); |
| fragBuilder->codeAppendf( |
| R"SkSL(%s = %s; |
| )SkSL" |
| , args.fOutputColor, _sample140.c_str()); |
| )__Cpp__"}); |
| } |
| |
| DEF_TEST(SkSLFPNestedChildProcessors, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| uniform half4 color; |
| in fragmentProcessor child1; |
| in fragmentProcessor child2; |
| void main() { |
| sk_OutColor = sample(child2, color * sample(child1, color * half4(0.5))); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "this->registerChild(std::move(child1), SkSL::SampleUsage::PassThrough());", |
| "this->registerChild(std::move(child2), SkSL::SampleUsage::PassThrough());" |
| }, |
| /*expectedCPP=*/{ |
| "this->cloneAndRegisterAllChildProcessors(src);", |
| R"__Cpp__( |
| SkString _input206 = SkStringPrintf("%s * half4(0.5)", args.fUniformHandler->getUniformCStr(colorVar)); |
| SkString _sample206 = this->invokeChild(0, _input206.c_str(), args); |
| SkString _input183 = SkStringPrintf("%s * %s", args.fUniformHandler->getUniformCStr(colorVar), _sample206.c_str()); |
| SkString _sample183 = this->invokeChild(1, _input183.c_str(), args); |
| fragBuilder->codeAppendf( |
| R"SkSL(%s = %s; |
| )SkSL" |
| , args.fOutputColor, _sample183.c_str()); |
| )__Cpp__", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPChildFPAndGlobal, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in fragmentProcessor child; |
| bool hasCap = sk_Caps.externalTextureSupport; |
| void main() { |
| if (hasCap) { |
| sk_OutColor = sample(child); |
| } else { |
| sk_OutColor = half4(1); |
| } |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "this->registerChild(std::move(child), SkSL::SampleUsage::PassThrough());" |
| }, |
| /*expectedCPP=*/{ |
| "this->cloneAndRegisterAllChildProcessors(src);", |
| R"__Cpp__( |
| hasCap = sk_Caps.externalTextureSupport; |
| fragBuilder->codeAppendf( |
| R"SkSL(bool hasCap = %s; |
| if (hasCap) {)SkSL" |
| , (hasCap ? "true" : "false")); |
| SkString _sample200 = this->invokeChild(0, args); |
| fragBuilder->codeAppendf( |
| R"SkSL( |
| %s = %s; |
| } else { |
| %s = half4(1.0); |
| } |
| )SkSL" |
| , args.fOutputColor, _sample200.c_str(), args.fOutputColor); |
| )__Cpp__", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPChildProcessorInlineFieldAccess, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in fragmentProcessor child; |
| void main() { |
| if (child.preservesOpaqueInput) { |
| sk_OutColor = sample(child); |
| } else { |
| sk_OutColor = half4(1); |
| } |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "this->registerChild(std::move(child), SkSL::SampleUsage::PassThrough());" |
| }, |
| /*expectedCPP=*/{ |
| "this->cloneAndRegisterAllChildProcessors(src);", |
| R"__Cpp__( |
| fragBuilder->codeAppendf( |
| R"SkSL(if (%s) {)SkSL" |
| , (_outer.childProcessor(0)->preservesOpaqueInput() ? "true" : "false")); |
| SkString _sample161 = this->invokeChild(0, args); |
| fragBuilder->codeAppendf( |
| R"SkSL( |
| %s = %s; |
| } else { |
| %s = half4(1.0); |
| } |
| )SkSL" |
| , args.fOutputColor, _sample161.c_str(), args.fOutputColor); |
| )__Cpp__", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPChildProcessorFieldAccess, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in fragmentProcessor child; |
| bool opaque = child.preservesOpaqueInput; |
| void main() { |
| if (opaque) { |
| sk_OutColor = sample(child); |
| } else { |
| sk_OutColor = half4(0.5); |
| } |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "this->registerChild(std::move(child), SkSL::SampleUsage::PassThrough());" |
| }, |
| /*expectedCPP=*/{ |
| "opaque = _outer.childProcessor(0)->preservesOpaqueInput();", |
| "fragBuilder->codeAppendf(\n" |
| "R\"SkSL(bool opaque = %s;\n" |
| "if (opaque) {)SkSL\"\n" |
| ", (opaque ? \"true\" : \"false\"));", |
| "SkString _sample196 = this->invokeChild(0, args);", |
| "fragBuilder->codeAppendf(\n" |
| "R\"SkSL(\n" |
| " %s = %s;\n" |
| "} else {\n" |
| " %s = half4(0.5);\n" |
| "}\n" |
| ")SkSL\"\n" |
| ", args.fOutputColor, _sample196.c_str(), args.fOutputColor);", |
| "this->cloneAndRegisterAllChildProcessors(src);", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPNullableChildProcessor, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in fragmentProcessor? child; |
| void main() { |
| if (child != null) { |
| sk_OutColor = sample(child); |
| } else { |
| sk_OutColor = half4(0.5); |
| } |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| "fragBuilder->codeAppendf(\n" |
| "R\"SkSL(if (%s) {)SkSL\"\n" |
| ", _outer.childProcessor(0) ? \"true\" : \"false\");", |
| "SkString _sample149 = this->invokeChild(0, args);", |
| "fragBuilder->codeAppendf(\n" |
| "R\"SkSL(\n" |
| " %s = %s;\n" |
| "} else {\n" |
| " %s = half4(0.5);\n" |
| "}\n" |
| ")SkSL\"\n" |
| ", args.fOutputColor, _sample149.c_str(), args.fOutputColor);", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPBadIn, r) { |
| test_failure(r, |
| R"__SkSL__( |
| in half4 c; |
| void main() { |
| sk_OutColor = c; |
| } |
| )__SkSL__", |
| "error: 4: 'in' variable must be either 'uniform' or 'layout(key)', or there must be a " |
| "custom @setData function\n1 error\n"); |
| } |
| |
| DEF_TEST(SkSLFPNoFPLocals, r) { |
| test_failure(r, |
| R"__SkSL__( |
| void main() { |
| fragmentProcessor child; |
| } |
| )__SkSL__", |
| "error: 1: variables of type 'fragmentProcessor' must be global\n" |
| "1 error\n"); |
| } |
| |
| DEF_TEST(SkSLFPNoFPParams, r) { |
| test_failure(r, |
| R"__SkSL__( |
| in fragmentProcessor child; |
| half4 helper(fragmentProcessor fp) { return sample(fp); } |
| void main() { |
| sk_OutColor = helper(child); |
| } |
| )__SkSL__", |
| "error: 3: parameters of type 'fragmentProcessor' not allowed\n" |
| "error: 5: unknown identifier 'helper'\n" |
| "2 errors\n"); |
| } |
| |
| DEF_TEST(SkSLFPNoFPReturns, r) { |
| test_failure(r, |
| R"__SkSL__( |
| in fragmentProcessor child; |
| fragmentProcessor get_child() { return child; } |
| void main() { |
| sk_OutColor = sample(get_child()); |
| } |
| )__SkSL__", |
| "error: 3: functions may not return type 'fragmentProcessor'\n" |
| "error: 5: unknown identifier 'get_child'\n" |
| "2 errors\n"); |
| } |
| |
| DEF_TEST(SkSLFPNoFPConstructors, r) { |
| test_failure(r, |
| R"__SkSL__( |
| in fragmentProcessor child; |
| void main() { |
| sk_OutColor = sample(fragmentProcessor(child)); |
| } |
| )__SkSL__", |
| "error: 4: cannot construct 'fragmentProcessor'\n" |
| "1 error\n"); |
| } |
| |
| DEF_TEST(SkSLFPNoFPExpressions, r) { |
| test_failure(r, |
| R"__SkSL__( |
| in fragmentProcessor child1; |
| in fragmentProcessor child2; |
| void main(float2 coord) { |
| sk_OutColor = sample(coord.x > 10 ? child1 : child2); |
| } |
| )__SkSL__", |
| "error: 5: ternary expression of type 'fragmentProcessor' not allowed\n" |
| "1 error\n"); |
| } |
| |
| DEF_TEST(SkSLFPSampleCoords, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in fragmentProcessor child; |
| void main(float2 coord) { |
| sk_OutColor = sample(child) + sample(child, coord / 2); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "this->registerChild(std::move(child), SkSL::SampleUsage(SkSL::SampleUsage::Kind::kNone, \"\", false, true, true));", |
| "this->setUsesSampleCoordsDirectly();" |
| }, |
| /*expectedCPP=*/{ |
| "SkString _sample118 = this->invokeChild(0, args);\n", |
| "SkString _coords134 = SkStringPrintf(\"%s / 2.0\", args.fSampleCoord);\n", |
| "SkString _sample134 = this->invokeChild(0, args, _coords134.c_str());\n", |
| "fragBuilder->codeAppendf(\n" |
| "R\"SkSL(%s = %s + %s;\n" |
| ")SkSL\"\n" |
| ", args.fOutputColor, _sample118.c_str(), _sample134.c_str());" |
| }); |
| } |
| |
| DEF_TEST(SkSLFPFunction, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| uniform half4 color; |
| half4 flip(half4 c) { return c.abgr; } |
| void main() { |
| sk_OutColor = flip(color); |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| R"__Cpp__( |
| SkString flip_name; |
| const GrShaderVar flip_args[] = { GrShaderVar("c", kHalf4_GrSLType)}; |
| fragBuilder->emitFunction(kHalf4_GrSLType, "flip", 1, flip_args, |
| R"SkSL(return c.wzyx; |
| )SkSL", &flip_name); |
| fragBuilder->codeAppendf( |
| R"SkSL(half4 _inlineResulthalf4fliphalf40; |
| half4 _inlineArghalf4fliphalf41_0 = %s; |
| { |
| _inlineResulthalf4fliphalf40 = _inlineArghalf4fliphalf41_0.wzyx; |
| } |
| %s = _inlineResulthalf4fliphalf40; |
| |
| )SkSL" |
| , args.fUniformHandler->getUniformCStr(colorVar), args.fOutputColor); |
| )__Cpp__"}); |
| } |
| |
| DEF_TEST(SkSLFPSwitchWithReturnInsideCannotBeInlined, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| uniform half4 color; |
| half4 switchy(half4 c) { |
| switch (int(c.x)) { |
| case 0: return c.yyyy; |
| } |
| return c.zzzz; |
| } |
| void main() { |
| sk_OutColor = switchy(color); |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| R"__Cpp__(fragBuilder->emitFunction(kHalf4_GrSLType, "switchy", 1, switchy_args, |
| R"SkSL(switch (int(c.x)) { |
| case 0: |
| return c.yyyy; |
| } |
| return c.zzzz; |
| )SkSL", &switchy_name); |
| fragBuilder->codeAppendf( |
| R"SkSL(%s = %s(%s); |
| )SkSL" |
| , args.fOutputColor, switchy_name.c_str(), args.fUniformHandler->getUniformCStr(colorVar)); |
| )__Cpp__", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPSwitchWithoutReturnInsideCanBeInlined, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| uniform half4 color; |
| half4 switchy(half4 c) { |
| half4 result; |
| switch (int(c.x)) { |
| case 0: result = c.yyyy; |
| } |
| result = c.zzzz; |
| return result; |
| } |
| void main() { |
| sk_OutColor = switchy(color); |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| R"__Cpp__(fragBuilder->codeAppendf( |
| R"SkSL(half4 _inlineResulthalf4switchyhalf40; |
| half4 _inlineArghalf4switchyhalf41_0 = %s; |
| { |
| half4 result; |
| switch (int(_inlineArghalf4switchyhalf41_0.x)) { |
| case 0: |
| result = _inlineArghalf4switchyhalf41_0.yyyy; |
| } |
| result = _inlineArghalf4switchyhalf41_0.zzzz; |
| _inlineResulthalf4switchyhalf40 = result; |
| } |
| %s = _inlineResulthalf4switchyhalf40; |
| |
| )SkSL" |
| , args.fUniformHandler->getUniformCStr(colorVar), args.fOutputColor); |
| )__Cpp__", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPForLoopWithReturnInsideCannotBeInlined, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| uniform half4 color; |
| half4 loopy(half4 c) { |
| for (int x=0; x<5; ++x) { |
| if (x == int(c.w)) return c.yyyy; |
| } |
| return c.zzzz; |
| } |
| void main() { |
| sk_OutColor = loopy(color); |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| R"__Cpp__(fragBuilder->emitFunction(kHalf4_GrSLType, "loopy", 1, loopy_args, |
| R"SkSL(for (int x = 0;x < 5; ++x) { |
| if (x == int(c.w)) return c.yyyy; |
| } |
| return c.zzzz; |
| )SkSL", &loopy_name); |
| fragBuilder->codeAppendf( |
| R"SkSL(%s = %s(%s); |
| )SkSL" |
| , args.fOutputColor, loopy_name.c_str(), args.fUniformHandler->getUniformCStr(colorVar)); |
| )__Cpp__", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPSwitchWithCastCanBeInlined, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| uniform half4 color; |
| half4 switchy(half4 c) { |
| half4 result; |
| switch (int(c.x)) { |
| case 1: result = c.yyyy; break; |
| default: result = c.zzzz; break; |
| } |
| return result; |
| } |
| void main() { |
| sk_OutColor = switchy(color); |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{R"__Cpp__(fragBuilder->codeAppendf( |
| R"SkSL(half4 _inlineResulthalf4switchyhalf40; |
| half4 _inlineArghalf4switchyhalf41_0 = %s; |
| { |
| half4 result; |
| switch (int(_inlineArghalf4switchyhalf41_0.x)) { |
| case 1: |
| result = _inlineArghalf4switchyhalf41_0.yyyy; |
| break; |
| default: |
| result = _inlineArghalf4switchyhalf41_0.zzzz; |
| break; |
| } |
| _inlineResulthalf4switchyhalf40 = result; |
| } |
| %s = _inlineResulthalf4switchyhalf40; |
| |
| )SkSL" |
| , args.fUniformHandler->getUniformCStr(colorVar), args.fOutputColor); |
| )__Cpp__"}); |
| } |
| |
| DEF_TEST(SkSLFPForLoopWithoutReturnInsideCanBeInlined, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| uniform half4 color; |
| half4 loopy(half4 c) { |
| half4 pix; |
| for (int x=0; x<5; ++x) { |
| if (x == int(c.w)) pix = c.yyyy; |
| } |
| pix = c.zzzz; |
| return pix; |
| } |
| void main() { |
| sk_OutColor = loopy(color); |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| R"__Cpp__(fragBuilder->codeAppendf( |
| R"SkSL(half4 _inlineResulthalf4loopyhalf40; |
| half4 _inlineArghalf4loopyhalf41_0 = %s; |
| { |
| half4 pix; |
| for (int x = 0;x < 5; ++x) { |
| if (x == int(_inlineArghalf4loopyhalf41_0.w)) pix = _inlineArghalf4loopyhalf41_0.yyyy; |
| } |
| pix = _inlineArghalf4loopyhalf41_0.zzzz; |
| _inlineResulthalf4loopyhalf40 = pix; |
| } |
| %s = _inlineResulthalf4loopyhalf40; |
| |
| )SkSL" |
| , args.fUniformHandler->getUniformCStr(colorVar), args.fOutputColor); |
| )__Cpp__", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPIfStatementWithReturnInsideCanBeInlined, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| uniform half4 color; |
| half4 branchy(half4 c) { |
| if (c.z == c.w) return c.yyyy; else return c.zzzz; |
| } |
| void main() { |
| sk_OutColor = branchy(color); |
| } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| R"__Cpp__(fragBuilder->codeAppendf( |
| R"SkSL(half4 _inlineResulthalf4branchyhalf40; |
| half4 _inlineArghalf4branchyhalf41_0 = %s; |
| do { |
| if (_inlineArghalf4branchyhalf41_0.z == _inlineArghalf4branchyhalf41_0.w) { |
| _inlineResulthalf4branchyhalf40 = _inlineArghalf4branchyhalf41_0.yyyy; |
| break; |
| } else { |
| _inlineResulthalf4branchyhalf40 = _inlineArghalf4branchyhalf41_0.zzzz; |
| break; |
| } |
| } while (false); |
| %s = _inlineResulthalf4branchyhalf40; |
| |
| )SkSL" |
| , args.fUniformHandler->getUniformCStr(colorVar), args.fOutputColor); |
| )__Cpp__", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPGrSLTypesAreSupported, r) { |
| // We thwart the optimizer by wrapping our return statement in a loop, which prevents inlining. |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| int test(int a) { for (;;) { return a; } } |
| void main() { sk_OutColor = test(1).xxxx; } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| R"__Cpp__(const GrShaderVar test_args[] = { GrShaderVar("a", kInt_GrSLType)};)__Cpp__", |
| R"__Cpp__(fragBuilder->emitFunction(kInt_GrSLType, "test", 1, test_args,)__Cpp__", |
| }); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| int2 test(int2 a) { for (;;) { return a; } } |
| void main() { sk_OutColor = test(int2(1)).xyxy; } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| R"__Cpp__(const GrShaderVar test_args[] = { GrShaderVar("a", kInt2_GrSLType)};)__Cpp__", |
| R"__Cpp__(fragBuilder->emitFunction(kInt2_GrSLType, "test", 1, test_args,)__Cpp__", |
| }); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| int3 test(int3 a) { for (;;) { return a; } } |
| void main() { sk_OutColor = test(int3(1)).xyzx; } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| R"__Cpp__(const GrShaderVar test_args[] = { GrShaderVar("a", kInt3_GrSLType)};)__Cpp__", |
| R"__Cpp__(fragBuilder->emitFunction(kInt3_GrSLType, "test", 1, test_args,)__Cpp__", |
| }); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| int4 test(int4 a) { for (;;) { return a; } } |
| void main() { sk_OutColor = test(int4(1)); } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| R"__Cpp__(const GrShaderVar test_args[] = { GrShaderVar("a", kInt4_GrSLType)};)__Cpp__", |
| R"__Cpp__(fragBuilder->emitFunction(kInt4_GrSLType, "test", 1, test_args,)__Cpp__", |
| }); |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| half3x4 test(float3x4 a) { for (;;) { return half3x4(a); } } |
| void main() { sk_OutColor = test(float3x4(0))[0]; } |
| )__SkSL__", |
| /*expectedH=*/{}, |
| /*expectedCPP=*/{ |
| R"__Cpp__(const GrShaderVar test_args[] = { GrShaderVar("a", kFloat3x4_GrSLType)};)__Cpp__", |
| R"__Cpp__(fragBuilder->emitFunction(kHalf3x4_GrSLType, "test", 1, test_args,)__Cpp__", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPMatrixSampleConstant, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in fragmentProcessor? child; |
| void main() { |
| sk_OutColor = sample(child, float3x3(2)); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "this->registerChild(std::move(child), " |
| "SkSL::SampleUsage::UniformMatrix(\"float3x3(2.0)\", true));" |
| }, |
| /*expectedCPP=*/{ |
| "this->invokeChildWithMatrix(0, args)" |
| }); |
| } |
| |
| DEF_TEST(SkSLFPMatrixSampleUniform, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in fragmentProcessor? child; |
| uniform float3x3 matrix; |
| void main() { |
| sk_OutColor = sample(child, matrix); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| // Since 'matrix' is just a uniform, the generated code can't determine perspective. |
| "this->registerChild(std::move(child), " |
| "SkSL::SampleUsage::UniformMatrix(\"matrix\", true));" |
| }, |
| /*expectedCPP=*/{ |
| "this->invokeChildWithMatrix(0, args)" |
| }); |
| } |
| |
| DEF_TEST(SkSLFPMatrixSampleInUniform, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in fragmentProcessor? child; |
| in uniform float3x3 matrix; |
| void main() { |
| sk_OutColor = sample(child, matrix); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| // Since 'matrix' is marked 'in', we can detect perspective at runtime |
| "this->registerChild(std::move(child), " |
| "SkSL::SampleUsage::UniformMatrix(\"matrix\", matrix.hasPerspective()));" |
| }, |
| /*expectedCPP=*/{ |
| "this->invokeChildWithMatrix(0, args)" |
| }); |
| } |
| |
| DEF_TEST(SkSLFPMatrixSampleMultipleInUniforms, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in fragmentProcessor? child; |
| in uniform float3x3 matrixA; |
| in uniform float3x3 matrixB; |
| void main() { |
| sk_OutColor = sample(child, matrixA); |
| sk_OutColor += sample(child, matrixB); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| // FIXME it would be nice if codegen can produce |
| // (matrixA.hasPerspective() || matrixB.hasPerspective()) even though it's variable. |
| "this->registerChild(std::move(child), " |
| "SkSL::SampleUsage::VariableMatrix(true));" |
| }, |
| /*expectedCPP=*/{ |
| "SkString _matrix191(args.fUniformHandler->getUniformCStr(matrixAVar));", |
| "this->invokeChildWithMatrix(0, args, _matrix191.c_str());", |
| "SkString _matrix247(args.fUniformHandler->getUniformCStr(matrixBVar));", |
| "this->invokeChildWithMatrix(0, args, _matrix247.c_str());" |
| }); |
| } |
| |
| DEF_TEST(SkSLFPMatrixSampleConstUniformExpression, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in fragmentProcessor? child; |
| uniform float3x3 matrix; |
| void main() { |
| sk_OutColor = sample(child, 0.5 * matrix); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| // FIXME: "0.5 * matrix" is a uniform expression and could be lifted to the vertex |
| // shader, once downstream code is able to properly map 'matrix' within the expression. |
| "this->registerChild(std::move(child), " |
| "SkSL::SampleUsage::VariableMatrix(true));" |
| }, |
| /*expectedCPP=*/{ |
| "SkString _matrix145 = SkStringPrintf(\"0.5 * %s\", " |
| "args.fUniformHandler->getUniformCStr(matrixVar));", |
| "this->invokeChildWithMatrix(0, args, _matrix145.c_str());" |
| }); |
| } |
| |
| DEF_TEST(SkSLFPMatrixSampleConstantAndExplicitly, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| in fragmentProcessor? child; |
| void main(float2 coord) { |
| sk_OutColor = sample(child, float3x3(0.5)); |
| sk_OutColor = sample(child, coord / 2); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "this->registerChild(std::move(child), " |
| "SkSL::SampleUsage(SkSL::SampleUsage::Kind::kUniform, \"float3x3(0.5)\", true, true, false));" |
| }, |
| /*expectedCPP=*/{ |
| "this->invokeChildWithMatrix(0, args)", |
| "SkString _coords180 = SkStringPrintf(\"%s / 2.0\", args.fSampleCoord);", |
| "this->invokeChild(0, args, _coords180.c_str())", |
| }); |
| } |
| |
| DEF_TEST(SkSLFPMatrixSampleVariableAndExplicitly, r) { |
| test(r, |
| *SkSL::ShaderCapsFactory::Default(), |
| R"__SkSL__( |
| uniform half4 color; |
| in fragmentProcessor? child; |
| void main(float2 coord) { |
| float3x3 matrix = float3x3(color.a); |
| sk_OutColor = sample(child, matrix); |
| sk_OutColor = sample(child, coord / 2); |
| } |
| )__SkSL__", |
| /*expectedH=*/{ |
| "this->registerChild(std::move(child), " |
| "SkSL::SampleUsage(SkSL::SampleUsage::Kind::kVariable, \"\", true, true, false));" |
| }, |
| /*expectedCPP=*/{ |
| R"__Cpp__( |
| colorVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kHalf4_GrSLType, "color"); |
| fragBuilder->codeAppendf( |
| R"SkSL(float3x3 matrix = float3x3(float(%s.w));)SkSL" |
| , args.fUniformHandler->getUniformCStr(colorVar)); |
| SkString _matrix207("matrix"); |
| SkString _sample207 = this->invokeChildWithMatrix(0, args, _matrix207.c_str()); |
| fragBuilder->codeAppendf( |
| R"SkSL( |
| %s = %s;)SkSL" |
| , args.fOutputColor, _sample207.c_str()); |
| SkString _coords261 = SkStringPrintf("%s / 2.0", args.fSampleCoord); |
| SkString _sample261 = this->invokeChild(0, args, _coords261.c_str()); |
| fragBuilder->codeAppendf( |
| R"SkSL( |
| %s = %s; |
| )SkSL" |
| , args.fOutputColor, _sample261.c_str()); |
| )__Cpp__" |
| }); |
| } |