skia2/tests/SkSLFPTest.cpp
Ethan Nicholas 765d2feaa7 optimized SkSL inlining output
We were previously defensively copying the arguments to inline functions
into temporary values in all cases. We now detect some cases where that
is not necessary and use the arguments directly.

Change-Id: I9739643157743fdbcefbac9f36be93ea6ecde6f7
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/312489
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
2020-08-26 13:08:53 +00:00

1508 lines
50 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 GrShaderCaps& caps, const char* src,
std::vector<const char*> expectedH, std::vector<const char*> expectedCPP) {
SkSL::Program::Settings settings;
settings.fCaps = &caps;
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;
{
_inlineResulthalf4fliphalf40 = %s.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 result;
switch (int(%s.x)) {
case 0:
result = %s.yyyy;
}
result = %s.zzzz;
_inlineResulthalf4switchyhalf40 = result;
}
%s = _inlineResulthalf4switchyhalf40;
)SkSL"
, args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), 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 result;
switch (int(%s.x)) {
case 1:
result = %s.yyyy;
break;
default:
result = %s.zzzz;
break;
}
_inlineResulthalf4switchyhalf40 = result;
}
%s = _inlineResulthalf4switchyhalf40;
)SkSL"
, args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), 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 pix;
for (int x = 0;x < 5; ++x) {
if (x == int(%s.w)) pix = %s.yyyy;
}
pix = %s.zzzz;
_inlineResulthalf4loopyhalf40 = pix;
}
%s = _inlineResulthalf4loopyhalf40;
)SkSL"
, args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), 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;
do {
if (%s.z == %s.w) {
_inlineResulthalf4branchyhalf40 = %s.yyyy;
break;
} else {
_inlineResulthalf4branchyhalf40 = %s.zzzz;
break;
}
} while (false);
%s = _inlineResulthalf4branchyhalf40;
)SkSL"
, args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), args.fOutputColor);
)__Cpp__",
});
}
DEF_TEST(SkSLFPUnnecessaryBlocksDoNotAffectEarlyReturnDetection, r) {
test(r,
*SkSL::ShaderCapsFactory::Default(),
R"__SkSL__(
uniform half4 color;
half4 blocky(half4 c) {
{
return c;
}
}
void main() {
sk_OutColor = blocky(color);
}
)__SkSL__",
/*expectedH=*/{},
/*expectedCPP=*/{
R"__Cpp__(fragBuilder->codeAppendf(
R"SkSL(half4 _inlineResulthalf4blockyhalf40;
{
{
_inlineResulthalf4blockyhalf40 = %s;
}
}
%s = _inlineResulthalf4blockyhalf40;
)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__"
});
}
DEF_TEST(SkSLUniformArrays, r) {
test(r,
*SkSL::ShaderCapsFactory::Default(),
R"__SkSL__(
uniform half scalarArray[4];
uniform half2 pointArray[2];
void main() {
sk_OutColor = half4(scalarArray[0] * pointArray[0].x +
scalarArray[1] * pointArray[0].y +
scalarArray[2] * pointArray[1].x +
scalarArray[3] * pointArray[1].y);
}
)__SkSL__",
/*expectedH=*/{
"Make()",
},
/*expectedCPP=*/{
"void onSetData(const GrGLSLProgramDataManager& pdman, "
"const GrFragmentProcessor& _proc) override {\n }"
});
test(r,
*SkSL::ShaderCapsFactory::Default(),
R"__SkSL__(
in uniform half scalarArray[4];
in uniform half2 pointArray[2];
void main() {
sk_OutColor = half4(scalarArray[0] * pointArray[0].x +
scalarArray[1] * pointArray[0].y +
scalarArray[2] * pointArray[1].x +
scalarArray[3] * pointArray[1].y);
}
)__SkSL__",
/*expectedH=*/{
"Make(std::array<float> scalarArray, std::array<SkPoint> pointArray)",
"std::array<float> scalarArray;",
"std::array<SkPoint> pointArray;",
},
/*expectedCPP=*/{
"pdman.set1fv(scalarArrayVar, 4, &(_outer.scalarArray)[0]);",
"pdman.set2fv(pointArrayVar, 2, &pointArrayValue[0].fX);",
});
}