318ad4bb19
Previously, early-return detection worked by ensuring that a function had a maximum of one return statement, positioned at the end of the function. However, this technique did not support if-else statements: if (a) { ...; return x; } else { ...; return y; } This meant that many simple cases were unnecessarily wrapped in a do- while loop to handle control flow issues that didn't actually occur. Our early-return detection logic is now more flexible and looks for any return statements that aren't at an exit point in the control flow, instead of looking for exactly one return at the end of the code. Change-Id: Iffe71adf2b9349ce8de42ba8301ccc52abe2882b Reviewed-on: https://skia-review.googlesource.com/c/skia/+/313418 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
1703 lines
56 KiB
C++
1703 lines
56 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 = ∩︀
|
|
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);
|
|
}
|
|
if (!compiler.errorCount()) {
|
|
SkSL::StringStream output;
|
|
compiler.toH(*program, "Test", output);
|
|
}
|
|
if (!compiler.errorCount()) {
|
|
SkSL::StringStream output;
|
|
compiler.toCPP(*program, "Test", output);
|
|
}
|
|
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"; }
|
|
bool usesExplicitReturn() const override;
|
|
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;
|
|
}
|
|
bool GrTest::usesExplicitReturn() const {
|
|
return false;
|
|
}
|
|
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(SkSLFPUseExplicitReturn, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
R"__SkSL__(
|
|
half4 main() {
|
|
return half4(0, 1, 0, 1);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedH=*/{},
|
|
/*expectedCPP=*/{R"__Cpp__(
|
|
fragBuilder->codeAppendf(
|
|
R"SkSL(return half4(0.0, 1.0, 0.0, 1.0);
|
|
)SkSL"
|
|
);
|
|
)__Cpp__", R"__Cpp__(
|
|
bool GrTest::usesExplicitReturn() const {
|
|
return true;
|
|
}
|
|
)__Cpp__"});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPBothExplicitReturnAndSkOutColor, r) {
|
|
test_failure(r,
|
|
R"__SkSL__(
|
|
half4 main() {
|
|
sk_OutColor = half4(1, 0, 1, 0);
|
|
return half4(0, 1, 0, 1);
|
|
}
|
|
)__SkSL__",
|
|
"error: 4: Fragment processors must not mix sk_OutColor and return statements\n\n"
|
|
"1 error\n");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPCannotReturnWithSkOutColor, r) {
|
|
// We don't support returns with sk_OutColor at all, even when it conceptually makes sense.
|
|
// sk_OutColor is going away, so there's no need to add engineering effort to that path.
|
|
test_failure(r,
|
|
R"__SkSL__(
|
|
void main() {
|
|
sk_OutColor = half4(1, 0, 1, 0);
|
|
return;
|
|
}
|
|
)__SkSL__",
|
|
"error: 4: Fragment processors must not mix sk_OutColor and return statements\n\n"
|
|
"1 error\n");
|
|
}
|
|
|
|
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=*/{
|
|
"bool usesExplicitReturn() const override;\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(SkSLFPSwitchWithMultipleReturnsInside, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
R"__SkSL__(
|
|
uniform half4 color;
|
|
half4 switchy(half4 c) {
|
|
switch (int(c.x)) {
|
|
case 0: return c.yyyy;
|
|
default: 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;
|
|
default:
|
|
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(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;
|
|
{
|
|
if (%s.z == %s.w) _inlineResulthalf4branchyhalf40 = %s.yyyy; else _inlineResulthalf4branchyhalf40 = %s.zzzz;
|
|
}
|
|
%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(SkSLFPInlinedEarlyReturnsAreWrappedInDoWhileBlock, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
R"__SkSL__(
|
|
uniform half4 color;
|
|
inline half4 returny(half4 c) {
|
|
if (c.x > c.y) return c.xxxx;
|
|
if (c.y > c.z) return c.yyyy;
|
|
return c.zzzz;
|
|
}
|
|
void main() {
|
|
sk_OutColor = returny(color);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedH=*/{},
|
|
/*expectedCPP=*/{
|
|
R"__Cpp__(fragBuilder->codeAppendf(
|
|
R"SkSL(half4 _inlineResulthalf4returnyhalf40;
|
|
do {
|
|
if (%s.x > %s.y) {
|
|
_inlineResulthalf4returnyhalf40 = %s.xxxx;
|
|
break;
|
|
}
|
|
if (%s.y > %s.z) {
|
|
_inlineResulthalf4returnyhalf40 = %s.yyyy;
|
|
break;
|
|
}
|
|
{
|
|
_inlineResulthalf4returnyhalf40 = %s.zzzz;
|
|
break;
|
|
}
|
|
} while (false);
|
|
%s = _inlineResulthalf4returnyhalf40;
|
|
|
|
)SkSL"
|
|
, args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), args.fOutputColor);
|
|
)__Cpp__"});
|
|
}
|
|
|
|
DEF_TEST(SkSLFPEarlyReturnDetectionSupportsIfElse, r) {
|
|
// An if-else statement at the end of a function, with a return as the last statement on all
|
|
// paths, are not actually "early" returns. The inliner is able to recognize this pattern.
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
R"__SkSL__(
|
|
uniform half4 color;
|
|
inline half4 branchy(half4 c) {
|
|
c *= 0.5;
|
|
if (c.x > 0)
|
|
return c.xxxx;
|
|
else if (c.y > 0)
|
|
return c.yyyy;
|
|
else if (c.z > 0)
|
|
return c.zzzz;
|
|
else
|
|
return c.wwww;
|
|
}
|
|
inline half4 branchyAndBlocky(half4 c) {{{
|
|
if (c.x > 0) {
|
|
half4 d = c * 0.5;
|
|
return d.xxxx;
|
|
} else {{{
|
|
if (c.x < 0) {
|
|
return c.wwww;
|
|
} else {
|
|
return c.yyyy;
|
|
}
|
|
}}}
|
|
}}}
|
|
void main() {
|
|
sk_OutColor = branchy(color) * branchyAndBlocky(color);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedH=*/{},
|
|
/*expectedCPP=*/{
|
|
R"__Cpp__(fragBuilder->codeAppendf(
|
|
R"SkSL(half4 _inlineResulthalf4branchyhalf40;
|
|
half4 _inlineArghalf4branchyhalf41_0 = %s;
|
|
{
|
|
_inlineArghalf4branchyhalf41_0 *= 0.5;
|
|
if (_inlineArghalf4branchyhalf41_0.x > 0.0) _inlineResulthalf4branchyhalf40 = _inlineArghalf4branchyhalf41_0.xxxx; else if (_inlineArghalf4branchyhalf41_0.y > 0.0) _inlineResulthalf4branchyhalf40 = _inlineArghalf4branchyhalf41_0.yyyy; else if (_inlineArghalf4branchyhalf41_0.z > 0.0) _inlineResulthalf4branchyhalf40 = _inlineArghalf4branchyhalf41_0.zzzz; else _inlineResulthalf4branchyhalf40 = _inlineArghalf4branchyhalf41_0.wwww;
|
|
}
|
|
half4 _inlineResulthalf4branchyAndBlockyhalf42;
|
|
{
|
|
{
|
|
{
|
|
if (%s.x > 0.0) {
|
|
half4 d = %s * 0.5;
|
|
_inlineResulthalf4branchyAndBlockyhalf42 = d.xxxx;
|
|
} else {
|
|
{
|
|
{
|
|
if (%s.x < 0.0) {
|
|
_inlineResulthalf4branchyAndBlockyhalf42 = %s.wwww;
|
|
} else {
|
|
_inlineResulthalf4branchyAndBlockyhalf42 = %s.yyyy;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
%s = _inlineResulthalf4branchyhalf40 * _inlineResulthalf4branchyAndBlockyhalf42;
|
|
|
|
)SkSL"
|
|
, args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), args.fUniformHandler->getUniformCStr(colorVar), 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);",
|
|
});
|
|
}
|