Add support for function prototypes in Pipeline stage.
Previously we did not have a Pipeline callback function for prototyping
a function, so prototypes would be discarded during translation. This
failure mode can be seen in http://review.skia.org/454741, where
FunctionPrototype.sksl is made more complex (thwarting the inliner).
This causes us to emit invalid GLSL, and dm asserts/fails in the SkSL
tests: http://screen/4PkEEWn4m4tF5e7
This CL makes the same changes to FunctionPrototype, but does not crash.
Change-Id: Ia342c7811a454f62f52677440d247e628a1bdc4f
Bug: skia:12488
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/454740
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp
index 3239ec4..a31e07e 100644
--- a/src/gpu/effects/GrSkSLFP.cpp
+++ b/src/gpu/effects/GrSkSLFP.cpp
@@ -108,6 +108,10 @@
}
}
+ void declareFunction(const char* decl) override {
+ fArgs.fFragBuilder->emitFunctionPrototype(decl);
+ }
+
void defineStruct(const char* definition) override {
fArgs.fFragBuilder->definitionAppend(definition);
}
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.cpp b/src/gpu/glsl/GrGLSLShaderBuilder.cpp
index 7884c5f..a84d7b9 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.cpp
@@ -85,6 +85,10 @@
this->functions().append(";\n");
}
+void GrGLSLShaderBuilder::emitFunctionPrototype(const char* declaration) {
+ this->functions().appendf("%s;\n", declaration);
+}
+
void GrGLSLShaderBuilder::codeAppend(std::unique_ptr<SkSL::Statement> stmt) {
SkASSERT(SkSL::dsl::DSLWriter::CurrentProcessor());
SkASSERT(stmt);
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.h b/src/gpu/glsl/GrGLSLShaderBuilder.h
index b1f6fbc..0ebf11c 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.h
@@ -143,6 +143,8 @@
const char* mangledName,
SkSpan<const GrShaderVar> args);
+ void emitFunctionPrototype(const char* declaration);
+
/** Emits a helper function outside of main() in the fragment shader. */
void emitFunction(GrSLType returnType,
const char* mangledName,
diff --git a/src/sksl/SkSLMain.cpp b/src/sksl/SkSLMain.cpp
index 4cfde6c..26c9f77 100644
--- a/src/sksl/SkSLMain.cpp
+++ b/src/sksl/SkSLMain.cpp
@@ -408,6 +408,10 @@
fOutput += String(decl) + "{" + body + "}";
}
+ void declareFunction(const char* decl) override {
+ fOutput += String(decl) + ";";
+ }
+
void defineStruct(const char* definition) override {
fOutput += definition;
}
diff --git a/src/sksl/codegen/SkSLPipelineStageCodeGenerator.cpp b/src/sksl/codegen/SkSLPipelineStageCodeGenerator.cpp
index 9e7bcdd..066cad8 100644
--- a/src/sksl/codegen/SkSLPipelineStageCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLPipelineStageCodeGenerator.cpp
@@ -72,6 +72,7 @@
void writeFunctionPrototype(const FunctionPrototype& f);
String modifierString(const Modifiers& modifiers);
+ String functionDeclaration(const FunctionDeclaration& decl);
// Handles arrays correctly, eg: `float x[2]`
String typedVariable(const Type& type, skstd::string_view name);
@@ -338,6 +339,12 @@
fCastReturnsToHalf = false;
}
+ fCallbacks->defineFunction(this->functionDeclaration(decl).c_str(),
+ body.fBuffer.str().c_str(),
+ decl.isMain());
+}
+
+String PipelineStageCodeGenerator::functionDeclaration(const FunctionDeclaration& decl) {
// This is similar to decl.description(), but substitutes a mangled name, and handles modifiers
// on the function (e.g. `inline`) and its parameters (e.g. `inout`).
String declString =
@@ -348,22 +355,18 @@
this->functionName(decl).c_str());
const char* separator = "";
for (const Variable* p : decl.parameters()) {
- // TODO: Handle arrays
- declString.appendf("%s%s%s %s",
- separator,
- this->modifierString(p->modifiers()).c_str(),
- this->typeName(p->type()).c_str(),
- String(p->name()).c_str());
+ declString.append(separator);
+ declString.append(this->modifierString(p->modifiers()));
+ declString.append(this->typedVariable(p->type(), p->name()).c_str());
separator = ", ";
}
- declString.append(")");
- fCallbacks->defineFunction(declString.c_str(), body.fBuffer.str().c_str(), decl.isMain());
+ return declString + ")";
}
void PipelineStageCodeGenerator::writeFunctionPrototype(const FunctionPrototype& f) {
const FunctionDeclaration& decl = f.declaration();
- (void)this->functionName(decl);
+ fCallbacks->declareFunction(this->functionDeclaration(decl).c_str());
}
void PipelineStageCodeGenerator::writeGlobalVarDeclaration(const GlobalVarDeclaration& g) {
diff --git a/src/sksl/codegen/SkSLPipelineStageCodeGenerator.h b/src/sksl/codegen/SkSLPipelineStageCodeGenerator.h
index 8394650..cd5cd31 100644
--- a/src/sksl/codegen/SkSLPipelineStageCodeGenerator.h
+++ b/src/sksl/codegen/SkSLPipelineStageCodeGenerator.h
@@ -24,6 +24,7 @@
virtual String getMangledName(const char* name) { return name; }
virtual void defineFunction(const char* declaration, const char* body, bool isMain) = 0;
+ virtual void declareFunction(const char* declaration) = 0;
virtual void defineStruct(const char* definition) = 0;
virtual void declareGlobal(const char* declaration) = 0;