skia2/tests/SkSLFPTest.cpp

1483 lines
49 KiB
C++
Raw Normal View History

/*
* 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__",
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
/*expectedH=*/{
"this->setUsesSampleCoordsDirectly();"
},
/*expectedCPP=*/{
"fragBuilder->codeAppendf(\n"
"R\"SkSL(%s = half4(%s, %s);\n"
")SkSL\"\n"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
", 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);",
});
}
Support input color argument to process() function in sksl .fp files -- This expands sksl's capabilities with .fp files. Previously, it was possible to declare "in fragmentProcessor foo" and emit it automatically when "process(foo);" was called. This adds a variant of process that takes a second argument, which must be a half4 expression. This argument specifies the value, or dynamic expression calculated earlier in the parent shader, to use as sk_InColor by the child. The CL is longer than anticipated because of properly handling dependencies between previous sksl statements and the input to the child. The original writeEmitCode() collected all extra emission code (the calls to build->emitChild) and put them before any call to codeAppendf. This makes it impossible to use a parent's variable, or the output of another child, as the input for process. To solve this, there is now a flushEmittedCode() function that takes over the logic of outputting the extra emission code and the necessary codeAppendf calls. When invoked, it (by default) only appends completed sksl statements, and places any current expression back at the beginning of the output stream. It now updates fFormatArgs and fExtraEmitCodeCode as it consumes their contents. This allows writeFunctionCall() for a call to "process" to flush all previous statements before it adds its emit child code. Bug: skia: Change-Id: I63c41af6f3e0620aa890d10d14436ee6244f0051 Reviewed-on: https://skia-review.googlesource.com/148395 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
2018-08-30 20:08:18 +00:00
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());"
Support input color argument to process() function in sksl .fp files -- This expands sksl's capabilities with .fp files. Previously, it was possible to declare "in fragmentProcessor foo" and emit it automatically when "process(foo);" was called. This adds a variant of process that takes a second argument, which must be a half4 expression. This argument specifies the value, or dynamic expression calculated earlier in the parent shader, to use as sk_InColor by the child. The CL is longer than anticipated because of properly handling dependencies between previous sksl statements and the input to the child. The original writeEmitCode() collected all extra emission code (the calls to build->emitChild) and put them before any call to codeAppendf. This makes it impossible to use a parent's variable, or the output of another child, as the input for process. To solve this, there is now a flushEmittedCode() function that takes over the logic of outputting the extra emission code and the necessary codeAppendf calls. When invoked, it (by default) only appends completed sksl statements, and places any current expression back at the beginning of the output stream. It now updates fFormatArgs and fExtraEmitCodeCode as it consumes their contents. This allows writeFunctionCall() for a call to "process" to flush all previous statements before it adds its emit child code. Bug: skia: Change-Id: I63c41af6f3e0620aa890d10d14436ee6244f0051 Reviewed-on: https://skia-review.googlesource.com/148395 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
2018-08-30 20:08:18 +00:00
},
/*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__"});
Support input color argument to process() function in sksl .fp files -- This expands sksl's capabilities with .fp files. Previously, it was possible to declare "in fragmentProcessor foo" and emit it automatically when "process(foo);" was called. This adds a variant of process that takes a second argument, which must be a half4 expression. This argument specifies the value, or dynamic expression calculated earlier in the parent shader, to use as sk_InColor by the child. The CL is longer than anticipated because of properly handling dependencies between previous sksl statements and the input to the child. The original writeEmitCode() collected all extra emission code (the calls to build->emitChild) and put them before any call to codeAppendf. This makes it impossible to use a parent's variable, or the output of another child, as the input for process. To solve this, there is now a flushEmittedCode() function that takes over the logic of outputting the extra emission code and the necessary codeAppendf calls. When invoked, it (by default) only appends completed sksl statements, and places any current expression back at the beginning of the output stream. It now updates fFormatArgs and fExtraEmitCodeCode as it consumes their contents. This allows writeFunctionCall() for a call to "process" to flush all previous statements before it adds its emit child code. Bug: skia: Change-Id: I63c41af6f3e0620aa890d10d14436ee6244f0051 Reviewed-on: https://skia-review.googlesource.com/148395 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
2018-08-30 20:08:18 +00:00
}
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());",
Support input color argument to process() function in sksl .fp files -- This expands sksl's capabilities with .fp files. Previously, it was possible to declare "in fragmentProcessor foo" and emit it automatically when "process(foo);" was called. This adds a variant of process that takes a second argument, which must be a half4 expression. This argument specifies the value, or dynamic expression calculated earlier in the parent shader, to use as sk_InColor by the child. The CL is longer than anticipated because of properly handling dependencies between previous sksl statements and the input to the child. The original writeEmitCode() collected all extra emission code (the calls to build->emitChild) and put them before any call to codeAppendf. This makes it impossible to use a parent's variable, or the output of another child, as the input for process. To solve this, there is now a flushEmittedCode() function that takes over the logic of outputting the extra emission code and the necessary codeAppendf calls. When invoked, it (by default) only appends completed sksl statements, and places any current expression back at the beginning of the output stream. It now updates fFormatArgs and fExtraEmitCodeCode as it consumes their contents. This allows writeFunctionCall() for a call to "process" to flush all previous statements before it adds its emit child code. Bug: skia: Change-Id: I63c41af6f3e0620aa890d10d14436ee6244f0051 Reviewed-on: https://skia-review.googlesource.com/148395 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
2018-08-30 20:08:18 +00:00
},
/*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__"});
Support input color argument to process() function in sksl .fp files -- This expands sksl's capabilities with .fp files. Previously, it was possible to declare "in fragmentProcessor foo" and emit it automatically when "process(foo);" was called. This adds a variant of process that takes a second argument, which must be a half4 expression. This argument specifies the value, or dynamic expression calculated earlier in the parent shader, to use as sk_InColor by the child. The CL is longer than anticipated because of properly handling dependencies between previous sksl statements and the input to the child. The original writeEmitCode() collected all extra emission code (the calls to build->emitChild) and put them before any call to codeAppendf. This makes it impossible to use a parent's variable, or the output of another child, as the input for process. To solve this, there is now a flushEmittedCode() function that takes over the logic of outputting the extra emission code and the necessary codeAppendf calls. When invoked, it (by default) only appends completed sksl statements, and places any current expression back at the beginning of the output stream. It now updates fFormatArgs and fExtraEmitCodeCode as it consumes their contents. This allows writeFunctionCall() for a call to "process" to flush all previous statements before it adds its emit child code. Bug: skia: Change-Id: I63c41af6f3e0620aa890d10d14436ee6244f0051 Reviewed-on: https://skia-review.googlesource.com/148395 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
2018-08-30 20:08:18 +00:00
}
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());"
Support input color argument to process() function in sksl .fp files -- This expands sksl's capabilities with .fp files. Previously, it was possible to declare "in fragmentProcessor foo" and emit it automatically when "process(foo);" was called. This adds a variant of process that takes a second argument, which must be a half4 expression. This argument specifies the value, or dynamic expression calculated earlier in the parent shader, to use as sk_InColor by the child. The CL is longer than anticipated because of properly handling dependencies between previous sksl statements and the input to the child. The original writeEmitCode() collected all extra emission code (the calls to build->emitChild) and put them before any call to codeAppendf. This makes it impossible to use a parent's variable, or the output of another child, as the input for process. To solve this, there is now a flushEmittedCode() function that takes over the logic of outputting the extra emission code and the necessary codeAppendf calls. When invoked, it (by default) only appends completed sksl statements, and places any current expression back at the beginning of the output stream. It now updates fFormatArgs and fExtraEmitCodeCode as it consumes their contents. This allows writeFunctionCall() for a call to "process" to flush all previous statements before it adds its emit child code. Bug: skia: Change-Id: I63c41af6f3e0620aa890d10d14436ee6244f0051 Reviewed-on: https://skia-review.googlesource.com/148395 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
2018-08-30 20:08:18 +00:00
},
/*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__",
});
Support input color argument to process() function in sksl .fp files -- This expands sksl's capabilities with .fp files. Previously, it was possible to declare "in fragmentProcessor foo" and emit it automatically when "process(foo);" was called. This adds a variant of process that takes a second argument, which must be a half4 expression. This argument specifies the value, or dynamic expression calculated earlier in the parent shader, to use as sk_InColor by the child. The CL is longer than anticipated because of properly handling dependencies between previous sksl statements and the input to the child. The original writeEmitCode() collected all extra emission code (the calls to build->emitChild) and put them before any call to codeAppendf. This makes it impossible to use a parent's variable, or the output of another child, as the input for process. To solve this, there is now a flushEmittedCode() function that takes over the logic of outputting the extra emission code and the necessary codeAppendf calls. When invoked, it (by default) only appends completed sksl statements, and places any current expression back at the beginning of the output stream. It now updates fFormatArgs and fExtraEmitCodeCode as it consumes their contents. This allows writeFunctionCall() for a call to "process" to flush all previous statements before it adds its emit child code. Bug: skia: Change-Id: I63c41af6f3e0620aa890d10d14436ee6244f0051 Reviewed-on: https://skia-review.googlesource.com/148395 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
2018-08-30 20:08:18 +00:00
}
Reland "Redo how extra emit code flushing operates" with type fix. This reverts commit d0440195d5cc049062238d02b8a962ae49c7f4ff. Reason for revert: Fixes size_t -> int that was triggering ASAN failures. Original change's description: > Revert "Redo how extra emit code flushing operates" > > This reverts commit 9b8181b05a84e7dd24234c46c87d0bb2c73a7c08. > > Reason for revert: <INSERT REASONING HERE> > > Original change's description: > > Redo how extra emit code flushing operates > > > > The previous implementation of flushEmittedCode(), that flushed on > > demand when a process() was encountered, was brittle and susceptible to > > mangling the expected sksl when fOut was modified outside of its > > control. Given that writeFunction() and generateCode() in the parent > > class all do this, it's possible to generate a simple SkSL snippet that > > would generate a CPP file that builds invalid final SkSL: > > > > ``` > > in fragmentProcessor child; > > bool someGlobalVar = ...; > > void main() { > > if (someGlobalVar) { > > sk_OutColor = process(child, sk_InColor); > > } else { > > sk_OutColor = half4(1); > > } > > } > > ``` > > > > The CPP generated code *should* insert 'bool someGlobalVar' at the start > > but because of the early flush from the child process and because of > > how fOut was overwritten, someGlobalVar's declaration is put into a > > stream that is not visible to the flush and ends up being inserted into > > the output sksl in an incorrect location (namely after the if condition > > that depends on it). > > > > This CL updates the extra emitted code logic to support multiple blocks > > of extra CPP code. When a flush point occurs in SkSL writing, a special > > token is inserted into the SkSL and a new CPP code buffer is associated > > with that token. Then once all of the SkSL is accumulated into the root > > output stream, it is processed into sections for each extra CPP block. > > Special logic is done so that the SkSL that is emitted before the next > > CPP block terminates at the end of the last valid statement before the > > special token. > > > > A unit test demonstrating this failure condition is added to SkSLFPTest > > and the CL properly passes. Since this bug did not trigger on existing > > .fp files, the updated generator does not modify the generated FPs. > > > > Bug: skia: > > Change-Id: Ib74911942080f1b964159807a06805bc52898789 > > Reviewed-on: https://skia-review.googlesource.com/152321 > > Commit-Queue: Michael Ludwig <michaelludwig@google.com> > > Reviewed-by: Ethan Nicholas <ethannicholas@google.com> > > TBR=ethannicholas@google.com,michaelludwig@google.com > > Change-Id: Id0f908453b596873f43b86a1c14eed48b2474a76 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Bug: skia: > Reviewed-on: https://skia-review.googlesource.com/152660 > Reviewed-by: Michael Ludwig <michaelludwig@google.com> > Commit-Queue: Michael Ludwig <michaelludwig@google.com> TBR=ethannicholas@google.com,michaelludwig@google.com Change-Id: I3ccf2fee6ef96c6102dbe1c2c2ef6c14a701b8fd No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: skia: Reviewed-on: https://skia-review.googlesource.com/152663 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
2018-09-07 17:13:06 +00:00
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());"
Reland "Redo how extra emit code flushing operates" with type fix. This reverts commit d0440195d5cc049062238d02b8a962ae49c7f4ff. Reason for revert: Fixes size_t -> int that was triggering ASAN failures. Original change's description: > Revert "Redo how extra emit code flushing operates" > > This reverts commit 9b8181b05a84e7dd24234c46c87d0bb2c73a7c08. > > Reason for revert: <INSERT REASONING HERE> > > Original change's description: > > Redo how extra emit code flushing operates > > > > The previous implementation of flushEmittedCode(), that flushed on > > demand when a process() was encountered, was brittle and susceptible to > > mangling the expected sksl when fOut was modified outside of its > > control. Given that writeFunction() and generateCode() in the parent > > class all do this, it's possible to generate a simple SkSL snippet that > > would generate a CPP file that builds invalid final SkSL: > > > > ``` > > in fragmentProcessor child; > > bool someGlobalVar = ...; > > void main() { > > if (someGlobalVar) { > > sk_OutColor = process(child, sk_InColor); > > } else { > > sk_OutColor = half4(1); > > } > > } > > ``` > > > > The CPP generated code *should* insert 'bool someGlobalVar' at the start > > but because of the early flush from the child process and because of > > how fOut was overwritten, someGlobalVar's declaration is put into a > > stream that is not visible to the flush and ends up being inserted into > > the output sksl in an incorrect location (namely after the if condition > > that depends on it). > > > > This CL updates the extra emitted code logic to support multiple blocks > > of extra CPP code. When a flush point occurs in SkSL writing, a special > > token is inserted into the SkSL and a new CPP code buffer is associated > > with that token. Then once all of the SkSL is accumulated into the root > > output stream, it is processed into sections for each extra CPP block. > > Special logic is done so that the SkSL that is emitted before the next > > CPP block terminates at the end of the last valid statement before the > > special token. > > > > A unit test demonstrating this failure condition is added to SkSLFPTest > > and the CL properly passes. Since this bug did not trigger on existing > > .fp files, the updated generator does not modify the generated FPs. > > > > Bug: skia: > > Change-Id: Ib74911942080f1b964159807a06805bc52898789 > > Reviewed-on: https://skia-review.googlesource.com/152321 > > Commit-Queue: Michael Ludwig <michaelludwig@google.com> > > Reviewed-by: Ethan Nicholas <ethannicholas@google.com> > > TBR=ethannicholas@google.com,michaelludwig@google.com > > Change-Id: Id0f908453b596873f43b86a1c14eed48b2474a76 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Bug: skia: > Reviewed-on: https://skia-review.googlesource.com/152660 > Reviewed-by: Michael Ludwig <michaelludwig@google.com> > Commit-Queue: Michael Ludwig <michaelludwig@google.com> TBR=ethannicholas@google.com,michaelludwig@google.com Change-Id: I3ccf2fee6ef96c6102dbe1c2c2ef6c14a701b8fd No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: skia: Reviewed-on: https://skia-review.googlesource.com/152663 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
2018-09-07 17:13:06 +00:00
},
/*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__",
});
Reland "Redo how extra emit code flushing operates" with type fix. This reverts commit d0440195d5cc049062238d02b8a962ae49c7f4ff. Reason for revert: Fixes size_t -> int that was triggering ASAN failures. Original change's description: > Revert "Redo how extra emit code flushing operates" > > This reverts commit 9b8181b05a84e7dd24234c46c87d0bb2c73a7c08. > > Reason for revert: <INSERT REASONING HERE> > > Original change's description: > > Redo how extra emit code flushing operates > > > > The previous implementation of flushEmittedCode(), that flushed on > > demand when a process() was encountered, was brittle and susceptible to > > mangling the expected sksl when fOut was modified outside of its > > control. Given that writeFunction() and generateCode() in the parent > > class all do this, it's possible to generate a simple SkSL snippet that > > would generate a CPP file that builds invalid final SkSL: > > > > ``` > > in fragmentProcessor child; > > bool someGlobalVar = ...; > > void main() { > > if (someGlobalVar) { > > sk_OutColor = process(child, sk_InColor); > > } else { > > sk_OutColor = half4(1); > > } > > } > > ``` > > > > The CPP generated code *should* insert 'bool someGlobalVar' at the start > > but because of the early flush from the child process and because of > > how fOut was overwritten, someGlobalVar's declaration is put into a > > stream that is not visible to the flush and ends up being inserted into > > the output sksl in an incorrect location (namely after the if condition > > that depends on it). > > > > This CL updates the extra emitted code logic to support multiple blocks > > of extra CPP code. When a flush point occurs in SkSL writing, a special > > token is inserted into the SkSL and a new CPP code buffer is associated > > with that token. Then once all of the SkSL is accumulated into the root > > output stream, it is processed into sections for each extra CPP block. > > Special logic is done so that the SkSL that is emitted before the next > > CPP block terminates at the end of the last valid statement before the > > special token. > > > > A unit test demonstrating this failure condition is added to SkSLFPTest > > and the CL properly passes. Since this bug did not trigger on existing > > .fp files, the updated generator does not modify the generated FPs. > > > > Bug: skia: > > Change-Id: Ib74911942080f1b964159807a06805bc52898789 > > Reviewed-on: https://skia-review.googlesource.com/152321 > > Commit-Queue: Michael Ludwig <michaelludwig@google.com> > > Reviewed-by: Ethan Nicholas <ethannicholas@google.com> > > TBR=ethannicholas@google.com,michaelludwig@google.com > > Change-Id: Id0f908453b596873f43b86a1c14eed48b2474a76 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Bug: skia: > Reviewed-on: https://skia-review.googlesource.com/152660 > Reviewed-by: Michael Ludwig <michaelludwig@google.com> > Commit-Queue: Michael Ludwig <michaelludwig@google.com> TBR=ethannicholas@google.com,michaelludwig@google.com Change-Id: I3ccf2fee6ef96c6102dbe1c2c2ef6c14a701b8fd No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: skia: Reviewed-on: https://skia-review.googlesource.com/152663 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
2018-09-07 17:13:06 +00:00
}
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));",
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
"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__",
});
}
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
DEF_TEST(SkSLFPMatrixSampleConstant, r) {
test(r,
*SkSL::ShaderCapsFactory::Default(),
R"__SkSL__(
in fragmentProcessor? child;
void main() {
sk_OutColor = sample(child, float3x3(2));
}
)__SkSL__",
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
/*expectedH=*/{
"this->registerChild(std::move(child), "
"SkSL::SampleUsage::UniformMatrix(\"float3x3(2.0)\", true));"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
},
/*expectedCPP=*/{
"this->invokeChildWithMatrix(0, args)"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
});
}
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));"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
},
/*expectedCPP=*/{
"this->invokeChildWithMatrix(0, args)"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
});
}
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()));"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
},
/*expectedCPP=*/{
"this->invokeChildWithMatrix(0, args)"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
});
}
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));"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
},
/*expectedCPP=*/{
"SkString _matrix191(args.fUniformHandler->getUniformCStr(matrixAVar));",
"this->invokeChildWithMatrix(0, args, _matrix191.c_str());",
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
"SkString _matrix247(args.fUniformHandler->getUniformCStr(matrixBVar));",
"this->invokeChildWithMatrix(0, args, _matrix247.c_str());"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
});
}
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.
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
"this->registerChild(std::move(child), "
"SkSL::SampleUsage::VariableMatrix(true));"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
},
/*expectedCPP=*/{
"SkString _matrix145 = SkStringPrintf(\"0.5 * %s\", "
"args.fUniformHandler->getUniformCStr(matrixVar));",
"this->invokeChildWithMatrix(0, args, _matrix145.c_str());"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
});
}
DEF_TEST(SkSLFPMatrixSampleConstantAndExplicitly, r) {
test(r,
*SkSL::ShaderCapsFactory::Default(),
R"__SkSL__(
in fragmentProcessor? child;
void main(float2 coord) {
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
sk_OutColor = sample(child, float3x3(0.5));
sk_OutColor = sample(child, coord / 2);
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
}
)__SkSL__",
/*expectedH=*/{
"this->registerChild(std::move(child), "
"SkSL::SampleUsage(SkSL::SampleUsage::Kind::kUniform, \"float3x3(0.5)\", true, true, false));"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
},
/*expectedCPP=*/{
"this->invokeChildWithMatrix(0, args)",
"SkString _coords180 = SkStringPrintf(\"%s / 2.0\", args.fSampleCoord);",
"this->invokeChild(0, args, _coords180.c_str())",
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
});
}
DEF_TEST(SkSLFPMatrixSampleVariableAndExplicitly, r) {
test(r,
*SkSL::ShaderCapsFactory::Default(),
R"__SkSL__(
uniform half4 color;
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
in fragmentProcessor? child;
void main(float2 coord) {
float3x3 matrix = float3x3(color.a);
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
sk_OutColor = sample(child, matrix);
sk_OutColor = sample(child, coord / 2);
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
}
)__SkSL__",
/*expectedH=*/{
"this->registerChild(std::move(child), "
"SkSL::SampleUsage(SkSL::SampleUsage::Kind::kVariable, \"\", true, true, false));"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
},
/*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__"
Update how sample(matrix) calls are invoked in SkSL This removes the kMixed type of SkSL::SampleMatrix. All analysis of FP sampling due to parent-child relationships is tracked in flags on GrFragmentProcessor now. The sample strategy is tracked as follows: - An FP marks itself as using the local coordinate builtin directly (automatically done for .fp code based on reference to sk_TransformedCoords2D[0]). - This state propagates up the parent towards the root, marking FPs as using coordinates indirectly. We stop the propagation when we hit a parent FP that explicitly samples the child because it becomes the source of the child's coordinates. - If that parent references its local coordinates directly, that kicks off its own upwards propagation. - Being sampled explicitly propagates down to all children, and effectively disables vertex-shader evaluation of transforms. - A variable matrix automatically marks this flag as well, since it's essentially a shortcut to (matrix expression) * coords. - The matrix type also propagates down, but right now that's only for whether or not there's perspective. - This doesn't affect FS coord evaluation since each FP applies its action independently. - But for VS-promoted transforms, the child's varying may inherit perspective (or other more general matrix types) from the parent and switch from a float2 to a float3. - A SampleMatrix no longer tracks a base or owner, GrFragmentProcessor exposes its parent FP. An FP's sample matrix is always owned by its immediate parent. - This means that you can have a hierarchy from root to leaf like: [uniform, none, none, uses local coords], and that leaf will have a SampleMatrix of kNone type. However, because of parent tracking, the coordinate generation can walk up to the root and detect the proper transform expression it needs to produce, and automatically de-duplicate across children. Currently, all FP's that are explicitly sampled have a signature of (color, float2 coord). FP's that don't use local coords, or whose coords are promoted to a varying have a signature of (color). - In this case, the shader builder either updates args.fLocalCoords to point to the varying directly, or adds a float2 local to the function body that includes the perspective divide. GrFragmentProcessor automatically pretends it has an identity coord transform if the FP is marked as referencing the local coord builtin. This allows these FPs to still be processed as part of GrGLSLGeometryProcessor::collectTransforms, but removes the need for FP implementations to declare an identity GrCoordTransform. - To test this theory, GrTextureEffect and GrSkSLFP no longer have coord transforms explicitly. - Later CLs can trivially remove them from a lot of the other effects. - The coord generation should not change because it detects in both cases that the coord transform matrices were identity. GrGLSLGeometryProcessor's collectTransforms and emitTransformCode has been completely overhauled to recurse up an FP's parent pointers and collect the expressions that affect the result. It de-duplicates expressions between siblings, and is able to produce a single varying for the base local coord (either when there are no intervening transforms, or the root FP needs an explicit coordinate to start off with). This also adds the fp_sample_chaining GM from Brian, with a few more configurations to fill out the cells. Bug: skia:10396 Change-Id: I86acc0c34c9f29d6371b34370bee9a18c2acf1c1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297868 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
2020-06-24 13:04:56 +00:00
});
}
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);",
});
}