Add unit test for nested function calls in FP files.
`func1` and `func2` emit bad code, `return %s()`, and because they don't consume their `%s` format argument. This leaves the format argument list unbalanced and all future args are wrong. Another serious problem is that we don't actually know the names of the functions that they need to call, because we haven't emitted them yet. `func3` is not emitted at all. Sampling from a fragment processor apparently fails in this context. This is a more general case repro for skia:10684--it turns out that recursion in particular wasn't the issue, but nested function calls just don't work properly at all in FP files. This wasn't an issue in practice because we don't have any existing FP files which nest function calls, and the inliner also tends to aggressively flatten everything out if we don't explicitly disable it. Change-Id: Iff029c459c7d90be566f9b4c9be0e3150e459866 Bug: skia:10684 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/329367 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Brian Osman <brianosman@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
This commit is contained in:
parent
65dc579f13
commit
8744a5c820
@ -45,6 +45,7 @@ sksl_fp_tests = [
|
||||
"$_tests/sksl/fp/GrKeyIn.fp",
|
||||
"$_tests/sksl/fp/GrLayoutWhen.fp",
|
||||
"$_tests/sksl/fp/GrMainCoords.fp",
|
||||
"$_tests/sksl/fp/GrNestedCall.fp",
|
||||
"$_tests/sksl/fp/GrNestedChildProcessors.fp",
|
||||
"$_tests/sksl/fp/GrNonInlinedInUniform.fp",
|
||||
"$_tests/sksl/fp/GrNullableChildProcessor.fp",
|
||||
|
23
tests/sksl/fp/GrNestedCall.fp
Normal file
23
tests/sksl/fp/GrNestedCall.fp
Normal file
@ -0,0 +1,23 @@
|
||||
/*#pragma settings NoInline*/
|
||||
|
||||
in fragmentProcessor fp;
|
||||
|
||||
half4 func1();
|
||||
half4 func2();
|
||||
half4 func3();
|
||||
|
||||
half4 func1() {
|
||||
return func2();
|
||||
}
|
||||
|
||||
half4 func2() {
|
||||
return func3();
|
||||
}
|
||||
|
||||
half4 func3() {
|
||||
return sample(fp);
|
||||
}
|
||||
|
||||
void main() {
|
||||
sk_OutColor = func1();
|
||||
}
|
67
tests/sksl/fp/golden/GrNestedCall.cpp
Normal file
67
tests/sksl/fp/golden/GrNestedCall.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
/*#pragma settings NoInline*/
|
||||
|
||||
/**************************************************************************************************
|
||||
*** This file was autogenerated from GrNestedCall.fp; do not modify.
|
||||
**************************************************************************************************/
|
||||
#include "GrNestedCall.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 GrGLSLNestedCall : public GrGLSLFragmentProcessor {
|
||||
public:
|
||||
GrGLSLNestedCall() {}
|
||||
void emitCode(EmitArgs& args) override {
|
||||
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
|
||||
const GrNestedCall& _outer = args.fFp.cast<GrNestedCall>();
|
||||
(void) _outer;
|
||||
SkString func1_name;
|
||||
const GrShaderVar func1_args[] = { };
|
||||
fragBuilder->emitFunction(kHalf4_GrSLType, "func1", 0, func1_args,
|
||||
R"SkSL(return %s();
|
||||
)SkSL", &func1_name);
|
||||
SkString func2_name;
|
||||
const GrShaderVar func2_args[] = { };
|
||||
fragBuilder->emitFunction(kHalf4_GrSLType, "func2", 0, func2_args,
|
||||
R"SkSL(return %s();
|
||||
)SkSL", &func2_name);
|
||||
SkString func3_name;
|
||||
const GrShaderVar func3_args[] = { };
|
||||
fragBuilder->codeAppendf(
|
||||
R"SkSL(%s = %s();
|
||||
)SkSL"
|
||||
, func2_name.c_str(), func3_name.c_str());
|
||||
}
|
||||
private:
|
||||
void onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& _proc) override {
|
||||
}
|
||||
};
|
||||
GrGLSLFragmentProcessor* GrNestedCall::onCreateGLSLInstance() const {
|
||||
return new GrGLSLNestedCall();
|
||||
}
|
||||
void GrNestedCall::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
|
||||
}
|
||||
bool GrNestedCall::onIsEqual(const GrFragmentProcessor& other) const {
|
||||
const GrNestedCall& that = other.cast<GrNestedCall>();
|
||||
(void) that;
|
||||
return true;
|
||||
}
|
||||
bool GrNestedCall::usesExplicitReturn() const {
|
||||
return false;
|
||||
}
|
||||
GrNestedCall::GrNestedCall(const GrNestedCall& src)
|
||||
: INHERITED(kGrNestedCall_ClassID, src.optimizationFlags()) {
|
||||
this->cloneAndRegisterAllChildProcessors(src);
|
||||
}
|
||||
std::unique_ptr<GrFragmentProcessor> GrNestedCall::clone() const {
|
||||
return std::make_unique<GrNestedCall>(*this);
|
||||
}
|
||||
#if GR_TEST_UTILS
|
||||
SkString GrNestedCall::onDumpInfo() const {
|
||||
return SkString();
|
||||
}
|
||||
#endif
|
37
tests/sksl/fp/golden/GrNestedCall.h
Normal file
37
tests/sksl/fp/golden/GrNestedCall.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*#pragma settings NoInline*/
|
||||
|
||||
/**************************************************************************************************
|
||||
*** This file was autogenerated from GrNestedCall.fp; do not modify.
|
||||
**************************************************************************************************/
|
||||
#ifndef GrNestedCall_DEFINED
|
||||
#define GrNestedCall_DEFINED
|
||||
|
||||
#include "include/core/SkM44.h"
|
||||
#include "include/core/SkTypes.h"
|
||||
|
||||
|
||||
#include "src/gpu/GrFragmentProcessor.h"
|
||||
|
||||
class GrNestedCall : public GrFragmentProcessor {
|
||||
public:
|
||||
static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
|
||||
return std::unique_ptr<GrFragmentProcessor>(new GrNestedCall(std::move(fp)));
|
||||
}
|
||||
GrNestedCall(const GrNestedCall& src);
|
||||
std::unique_ptr<GrFragmentProcessor> clone() const override;
|
||||
const char* name() const override { return "NestedCall"; }
|
||||
bool usesExplicitReturn() const override;
|
||||
private:
|
||||
GrNestedCall(std::unique_ptr<GrFragmentProcessor> fp)
|
||||
: INHERITED(kGrNestedCall_ClassID, kNone_OptimizationFlags) {
|
||||
SkASSERT(fp); this->registerChild(std::move(fp), SkSL::SampleUsage::PassThrough()); }
|
||||
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
|
||||
using INHERITED = GrFragmentProcessor;
|
||||
};
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user