Detach pipeline-stage generator from SkSL compiler

This is now structured like the VM generator: Just a function that does
the conversion. Moved all relevant types and constants out of the
compiler, too. The key thing is that we don't need/want an error
handler, because it's too late to fail. We *must* catch all errors
during IR generation.

This is also another step along the path of directly emitting to the
fragment shader builder, rather than generating strings with
placeholders.

Bug: skia:11127
Change-Id: I18591270aa6e56dae1f040275a4b7d4a245007db
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/366956
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
This commit is contained in:
Brian Osman 2021-02-05 12:15:29 -05:00 committed by Skia Commit-Bot
parent 001850105e
commit 236ddb3e1d
9 changed files with 196 additions and 236 deletions

View File

@ -7,6 +7,7 @@
#include "src/gpu/GrShaderCaps.h"
#include "src/sksl/SkSLCompiler.h"
#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
#include "fuzz/Fuzz.h"
@ -19,10 +20,12 @@ bool FuzzSKSL2Pipeline(sk_sp<SkData> bytes) {
SkSL::String((const char*) bytes->data(),
bytes->size()),
settings);
SkSL::PipelineStageArgs args;
if (!program || !compiler.toPipelineStage(*program, &args)) {
if (!program) {
return false;
}
SkSL::PipelineStage::Args args;
SkSL::PipelineStage::ConvertProgram(*program, &args);
return true;
}

View File

@ -26,9 +26,7 @@ class SkShader;
namespace SkSL {
class FunctionDefinition;
struct PipelineStageArgs;
struct Program;
class SharedCompiler;
} // namespace SkSL
/*
@ -164,11 +162,8 @@ private:
bool usesSampleCoords() const { return fUsesSampleCoords; }
#if SK_SUPPORT_GPU
friend class GrSkSLFP; // toPipelineStage
friend class GrGLSLSkSLFP; // fSampleUsages
bool toPipelineStage(GrContextOptions::ShaderErrorHandler* errorHandler,
SkSL::PipelineStageArgs* outArgs);
friend class GrSkSLFP; // fBaseProgram, fSampleUsages
friend class GrGLSLSkSLFP; //
#endif
friend class SkRTShader; // fBaseProgram, fMain

View File

@ -315,20 +315,6 @@ int SkRuntimeEffect::findChild(const char* name) const {
return iter == fChildren.end() ? -1 : static_cast<int>(iter - fChildren.begin());
}
#if SK_SUPPORT_GPU
bool SkRuntimeEffect::toPipelineStage(GrContextOptions::ShaderErrorHandler* errorHandler,
SkSL::PipelineStageArgs* outArgs) {
SkSL::SharedCompiler compiler;
if (!compiler->toPipelineStage(*fBaseProgram, outArgs)) {
errorHandler->compileError(fSkSL.c_str(), compiler->errorText().c_str());
return false;
}
return true;
}
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////
static sk_sp<SkData> get_xformed_uniforms(const SkRuntimeEffect* effect,

View File

@ -12,6 +12,7 @@
#include "src/gpu/GrBaseContextPriv.h"
#include "src/gpu/GrColorInfo.h"
#include "src/gpu/GrTexture.h"
#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
#include "src/sksl/SkSLUtil.h"
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
@ -20,36 +21,37 @@
class GrGLSLSkSLFP : public GrGLSLFragmentProcessor {
public:
GrGLSLSkSLFP(SkSL::PipelineStageArgs&& args) : fArgs(std::move(args)) {}
GrGLSLSkSLFP(SkSL::PipelineStage::Args&& args) : fArgs(std::move(args)) {}
SkSL::String expandFormatArgs(const SkSL::String& raw,
EmitArgs& args,
const char* sampleCoords,
std::vector<SkSL::Compiler::FormatArg>::const_iterator& fmtArg) {
SkSL::String expandFormatArgs(
const SkSL::String& raw,
EmitArgs& args,
const char* sampleCoords,
std::vector<SkSL::PipelineStage::FormatArg>::const_iterator& fmtArg) {
SkSL::String result;
int substringStartIndex = 0;
for (size_t i = 0; i < raw.length(); ++i) {
char c = raw[i];
if (c == SkSL::Compiler::kFormatArgPlaceholder) {
if (c == SkSL::PipelineStage::kFormatArgPlaceholder) {
result += SkSL::StringFragment(raw.c_str() + substringStartIndex,
i - substringStartIndex);
const SkSL::Compiler::FormatArg& arg = *fmtArg++;
const SkSL::PipelineStage::FormatArg& arg = *fmtArg++;
switch (arg.fKind) {
case SkSL::Compiler::FormatArg::Kind::kCoords:
case SkSL::PipelineStage::FormatArg::Kind::kCoords:
// See note about helper functions in emitCode
SkASSERT(sampleCoords);
result += sampleCoords ? sampleCoords : "float2(0)";
break;
case SkSL::Compiler::FormatArg::Kind::kUniform:
case SkSL::PipelineStage::FormatArg::Kind::kUniform:
result += args.fUniformHandler->getUniformCStr(fUniformHandles[arg.fIndex]);
break;
case SkSL::Compiler::FormatArg::Kind::kChildProcessor: {
case SkSL::PipelineStage::FormatArg::Kind::kChildProcessor: {
SkSL::String coords =
this->expandFormatArgs(arg.fCoords, args, sampleCoords, fmtArg);
result += this->invokeChild(arg.fIndex, args, coords).c_str();
break;
}
case SkSL::Compiler::FormatArg::Kind::kChildProcessorWithMatrix: {
case SkSL::PipelineStage::FormatArg::Kind::kChildProcessorWithMatrix: {
const auto& fp(args.fFp.cast<GrSkSLFP>());
const auto& sampleUsages(fp.fEffect->fSampleUsages);
@ -64,7 +66,7 @@ public:
.c_str();
break;
}
case SkSL::Compiler::FormatArg::Kind::kFunctionName:
case SkSL::PipelineStage::FormatArg::Kind::kFunctionName:
SkASSERT((int) fFunctionNames.size() > arg.fIndex);
result += fFunctionNames[arg.fIndex].c_str();
break;
@ -156,10 +158,9 @@ public:
}
}
// nearly-finished GLSL; still contains printf-style "%s" format tokens
SkSL::PipelineStageArgs fArgs;
SkSL::PipelineStage::Args fArgs;
std::vector<UniformHandle> fUniformHandles;
std::vector<SkString> fFunctionNames;
std::vector<SkString> fFunctionNames;
};
std::unique_ptr<GrSkSLFP> GrSkSLFP::Make(GrContext_Base* context, sk_sp<SkRuntimeEffect> effect,
@ -208,8 +209,8 @@ void GrSkSLFP::addChild(std::unique_ptr<GrFragmentProcessor> child) {
GrGLSLFragmentProcessor* GrSkSLFP::onCreateGLSLInstance() const {
// Note: This is actually SkSL (again) but with inline format specifiers.
SkSL::PipelineStageArgs args;
SkAssertResult(fEffect->toPipelineStage(fShaderErrorHandler, &args));
SkSL::PipelineStage::Args args;
SkSL::PipelineStage::ConvertProgram(*fEffect->fBaseProgram, &args);
return new GrGLSLSkSLFP(std::move(args));
}

View File

@ -11,16 +11,8 @@
#include "include/core/SkRefCnt.h"
#include "include/gpu/GrContextOptions.h"
#include "src/gpu/GrFragmentProcessor.h"
#include "src/sksl/SkSLCompiler.h"
#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
#include <atomic>
#if GR_TEST_UTILS
#define GR_FP_SRC_STRING const char*
#else
#define GR_FP_SRC_STRING static const char*
#endif
class GrContext_Base;
class GrShaderCaps;
class SkData;

View File

@ -18,7 +18,6 @@
#include "src/sksl/SkSLIRGenerator.h"
#include "src/sksl/SkSLMetalCodeGenerator.h"
#include "src/sksl/SkSLOperators.h"
#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
#include "src/sksl/SkSLRehydrator.h"
#include "src/sksl/SkSLSPIRVCodeGenerator.h"
#include "src/sksl/SkSLSPIRVtoHLSL.h"
@ -2006,19 +2005,6 @@ bool Compiler::toH(Program& program, String name, OutputStream& out) {
#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
AutoSource as(this, program.fSource.get());
StringStream buffer;
PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
bool result = cg.generateCode();
if (result) {
outArgs->fCode = buffer.str();
}
return result;
}
#endif
Position Compiler::position(int offset) {
if (fSource && offset >= 0) {
int line = 1;

View File

@ -52,7 +52,6 @@ class ExternalFunction;
class FunctionDeclaration;
class IRGenerator;
class IRIntrinsicMap;
struct PipelineStageArgs;
class ProgramUsage;
struct LoadedModule {
@ -87,31 +86,6 @@ public:
kPermitInvalidStaticTests_Flag = 1,
};
// An invalid (otherwise unused) character to mark where FormatArgs are inserted
static constexpr char kFormatArgPlaceholder = '\001';
static constexpr const char* kFormatArgPlaceholderStr = "\001";
struct FormatArg {
enum class Kind {
kCoords,
kUniform,
kChildProcessor,
kChildProcessorWithMatrix,
kFunctionName
};
FormatArg(Kind kind)
: fKind(kind) {}
FormatArg(Kind kind, int index)
: fKind(kind)
, fIndex(index) {}
Kind fKind;
int fIndex;
String fCoords;
};
struct OptimizationContext {
// nodes we have already reported errors for and should not error on again
std::unordered_set<const IRNode*> fSilences;
@ -125,17 +99,6 @@ public:
StatementArray fOwnedStatements;
};
#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
/**
* Represents the arguments to GrGLSLShaderBuilder::emitFunction.
*/
struct GLSLFunction {
const FunctionDeclaration* fDecl;
String fBody;
std::vector<Compiler::FormatArg> fFormatArgs;
};
#endif
Compiler(const ShaderCapsClass* caps, Flags flags = kNone_Flags);
~Compiler() override;
@ -173,10 +136,6 @@ public:
bool toH(Program& program, String name, OutputStream& out);
#endif
#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
bool toPipelineStage(Program& program, PipelineStageArgs* outArgs);
#endif
void error(int offset, String msg) override;
String errorText(bool showCount = true);
@ -301,14 +260,6 @@ private:
friend class dsl::DSLWriter;
};
#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
struct PipelineStageArgs {
String fCode;
std::vector<Compiler::FormatArg> fFormatArgs;
std::vector<Compiler::GLSLFunction> fFunctions;
};
#endif
} // namespace SkSL
#endif

View File

@ -8,36 +8,114 @@
#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
#include "src/sksl/SkSLCompiler.h"
#include "src/sksl/SkSLHCodeGenerator.h"
#include "src/sksl/SkSLOperators.h"
#include "src/sksl/SkSLStringStream.h"
#include "src/sksl/ir/SkSLBinaryExpression.h"
#include "src/sksl/ir/SkSLConstructor.h"
#include "src/sksl/ir/SkSLExpressionStatement.h"
#include "src/sksl/ir/SkSLFieldAccess.h"
#include "src/sksl/ir/SkSLForStatement.h"
#include "src/sksl/ir/SkSLFunctionCall.h"
#include "src/sksl/ir/SkSLFunctionDeclaration.h"
#include "src/sksl/ir/SkSLFunctionDefinition.h"
#include "src/sksl/ir/SkSLIfStatement.h"
#include "src/sksl/ir/SkSLIndexExpression.h"
#include "src/sksl/ir/SkSLPostfixExpression.h"
#include "src/sksl/ir/SkSLPrefixExpression.h"
#include "src/sksl/ir/SkSLProgramElement.h"
#include "src/sksl/ir/SkSLReturnStatement.h"
#include "src/sksl/ir/SkSLStatement.h"
#include "src/sksl/ir/SkSLSwizzle.h"
#include "src/sksl/ir/SkSLTernaryExpression.h"
#include "src/sksl/ir/SkSLVarDeclarations.h"
#include "src/sksl/ir/SkSLVariableReference.h"
#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
namespace SkSL {
PipelineStageCodeGenerator::PipelineStageCodeGenerator(const Context* context,
const Program* program,
ErrorReporter* errors,
OutputStream* out,
PipelineStageArgs* outArgs)
: INHERITED(program, errors, out), fContext(*context), fArgs(outArgs) {}
class PipelineStageCodeGenerator {
public:
PipelineStageCodeGenerator(const Program& program, PipelineStage::Args* outArgs)
: fProgram(program), fArgs(outArgs) {}
void generateCode();
private:
using Precedence = Operators::Precedence;
void write(const char* s);
void writeLine(const char* s = nullptr);
void write(const String& s);
void write(StringFragment s);
void writeType(const Type& type);
void writeFunctionDeclaration(const FunctionDeclaration& f);
void writeFunction(const FunctionDefinition& f);
void writeModifiers(const Modifiers& modifiers);
void writeVarDeclaration(const VarDeclaration& var);
void writeExpression(const Expression& expr, Precedence parentPrecedence);
void writeFunctionCall(const FunctionCall& c);
void writeConstructor(const Constructor& c, Precedence parentPrecedence);
void writeFieldAccess(const FieldAccess& f);
void writeSwizzle(const Swizzle& swizzle);
void writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence);
void writeTernaryExpression(const TernaryExpression& t, Precedence parentPrecedence);
void writeIndexExpression(const IndexExpression& expr);
void writePrefixExpression(const PrefixExpression& p, Precedence parentPrecedence);
void writePostfixExpression(const PostfixExpression& p, Precedence parentPrecedence);
void writeVariableReference(const VariableReference& ref);
void writeStatement(const Statement& s);
void writeBlock(const Block& b);
void writeIfStatement(const IfStatement& stmt);
void writeForStatement(const ForStatement& f);
void writeReturnStatement(const ReturnStatement& r);
void writeProgramElement(const ProgramElement& e);
struct AutoOutputBuffer {
AutoOutputBuffer(PipelineStageCodeGenerator* generator) : fGenerator(generator) {
fOldBuffer = fGenerator->fBuffer;
fGenerator->fBuffer = &fBuffer;
}
~AutoOutputBuffer() {
fGenerator->fBuffer = fOldBuffer;
}
PipelineStageCodeGenerator* fGenerator;
StringStream* fOldBuffer;
StringStream fBuffer;
};
const Program& fProgram;
PipelineStage::Args* fArgs;
StringStream* fBuffer;
bool fCastReturnsToHalf = false;
};
void PipelineStageCodeGenerator::write(const char* s) {
fOut->writeText(s);
fBuffer->writeText(s);
}
void PipelineStageCodeGenerator::writeLine(const char* s) {
if (s) {
fOut->writeText(s);
fBuffer->writeText(s);
}
fOut->writeText("\n");
fBuffer->writeText("\n");
}
void PipelineStageCodeGenerator::write(const String& s) {
fOut->write(s.data(), s.length());
fBuffer->write(s.data(), s.length());
}
void PipelineStageCodeGenerator::write(StringFragment s) {
fOut->write(s.fChars, s.fLength);
fBuffer->write(s.fChars, s.fLength);
}
void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
@ -57,7 +135,7 @@ void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
const VarDeclaration& decl = global.declaration()->as<VarDeclaration>();
if (&decl.var() == arguments[0]->as<VariableReference>().variable()) {
found = true;
} else if (decl.var().type() == *fContext.fTypes.fFragmentProcessor) {
} else if (decl.var().type() == *fProgram.fContext->fTypes.fFragmentProcessor) {
++index;
}
}
@ -67,17 +145,16 @@ void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
}
SkASSERT(found);
size_t childCallIndex = fArgs->fFormatArgs.size();
this->write(Compiler::kFormatArgPlaceholderStr);
this->write(PipelineStage::kFormatArgPlaceholderStr);
bool matrixCall = arguments.size() == 2 && arguments[1]->type().isMatrix();
fArgs->fFormatArgs.push_back(Compiler::FormatArg(
matrixCall ? Compiler::FormatArg::Kind::kChildProcessorWithMatrix
: Compiler::FormatArg::Kind::kChildProcessor,
fArgs->fFormatArgs.push_back(PipelineStage::FormatArg(
matrixCall ? PipelineStage::FormatArg::Kind::kChildProcessorWithMatrix
: PipelineStage::FormatArg::Kind::kChildProcessor,
index));
if (arguments.size() > 1) {
StringStream buffer;
AutoOutputStream outputToBuffer(this, &buffer);
AutoOutputBuffer outputToBuffer(this);
this->writeExpression(*arguments[1], Precedence::kSequence);
fArgs->fFormatArgs[childCallIndex].fCoords = buffer.str();
fArgs->fFormatArgs[childCallIndex].fCoords = outputToBuffer.fBuffer.str();
}
return;
}
@ -101,9 +178,9 @@ void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
++index;
}
}
this->write(Compiler::kFormatArgPlaceholderStr);
this->write(PipelineStage::kFormatArgPlaceholderStr);
fArgs->fFormatArgs.push_back(
Compiler::FormatArg(Compiler::FormatArg::Kind::kFunctionName, index));
PipelineStage::FormatArg(PipelineStage::FormatArg::Kind::kFunctionName, index));
this->write("(");
const char* separator = "";
for (const std::unique_ptr<Expression>& arg : arguments) {
@ -118,8 +195,9 @@ void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
void PipelineStageCodeGenerator::writeVariableReference(const VariableReference& ref) {
switch (ref.variable()->modifiers().fLayout.fBuiltin) {
case SK_MAIN_COORDS_BUILTIN:
this->write(Compiler::kFormatArgPlaceholderStr);
fArgs->fFormatArgs.push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kCoords));
this->write(PipelineStage::kFormatArgPlaceholderStr);
fArgs->fFormatArgs.push_back(
PipelineStage::FormatArg(PipelineStage::FormatArg::Kind::kCoords));
break;
default: {
auto varIndexByFlag = [this, &ref](uint32_t flag) {
@ -139,7 +217,7 @@ void PipelineStageCodeGenerator::writeVariableReference(const VariableReference&
// Skip over fragmentProcessors (shaders).
// These are indexed separately from other globals.
if (var.modifiers().fFlags & flag &&
var.type() != *fContext.fTypes.fFragmentProcessor) {
var.type() != *fProgram.fContext->fTypes.fFragmentProcessor) {
++index;
}
}
@ -149,10 +227,10 @@ void PipelineStageCodeGenerator::writeVariableReference(const VariableReference&
};
if (ref.variable()->modifiers().fFlags & Modifiers::kUniform_Flag) {
this->write(Compiler::kFormatArgPlaceholderStr);
this->write(PipelineStage::kFormatArgPlaceholderStr);
fArgs->fFormatArgs.push_back(
Compiler::FormatArg(Compiler::FormatArg::Kind::kUniform,
varIndexByFlag(Modifiers::kUniform_Flag)));
PipelineStage::FormatArg(PipelineStage::FormatArg::Kind::kUniform,
varIndexByFlag(Modifiers::kUniform_Flag)));
} else if (ref.variable()->modifiers().fFlags & Modifiers::kVarying_Flag) {
this->write("_vtx_attr_");
this->write(to_string(varIndexByFlag(Modifiers::kVarying_Flag)));
@ -193,34 +271,28 @@ void PipelineStageCodeGenerator::writeReturnStatement(const ReturnStatement& r)
}
void PipelineStageCodeGenerator::writeFunction(const FunctionDefinition& f) {
StringStream buffer;
Compiler::GLSLFunction result;
PipelineStage::Function result;
if (f.declaration().name() == "main") {
{
AutoOutputStream streamToBuffer(this, &buffer);
// We allow public SkSL's main() to return half4 -or- float4 (ie vec4). When we emit
// our code in the processor, the surrounding code is going to expect half4, so we
// explicitly cast any returns (from main) to half4. This is only strictly necessary
// if the return type is float4 - injecting it unconditionally reduces the risk of an
// obscure bug.
fCastReturnsToHalf = true;
for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
this->writeStatement(*stmt);
this->writeLine();
}
fCastReturnsToHalf = false;
// We allow public SkSL's main() to return half4 -or- float4 (ie vec4). When we emit
// our code in the processor, the surrounding code is going to expect half4, so we
// explicitly cast any returns (from main) to half4. This is only strictly necessary
// if the return type is float4 - injecting it unconditionally reduces the risk of an
// obscure bug.
fCastReturnsToHalf = true;
for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
this->writeStatement(*stmt);
this->writeLine();
}
this->write(buffer.str());
fCastReturnsToHalf = false;
} else {
{
AutoOutputStream streamToBuffer(this, &buffer);
result.fDecl = &f.declaration();
for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
this->writeStatement(*stmt);
this->writeLine();
}
AutoOutputBuffer outputToBuffer(this);
result.fDecl = &f.declaration();
for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
this->writeStatement(*stmt);
this->writeLine();
}
result.fBody = buffer.str();
result.fBody = outputToBuffer.fBuffer.str();
result.fFormatArgs = std::move(fArgs->fFormatArgs);
fArgs->fFunctions.push_back(std::move(result));
}
@ -574,16 +646,17 @@ void PipelineStageCodeGenerator::writeForStatement(const ForStatement& f) {
this->writeStatement(*f.statement());
}
bool PipelineStageCodeGenerator::generateCode() {
OutputStream* rawOut = fOut;
StringStream body;
fOut = &body;
void PipelineStageCodeGenerator::generateCode() {
StringStream mainBody;
fBuffer = &mainBody;
// Write all the program elements except for functions.
for (const ProgramElement* e : fProgram.elements()) {
if (!e->is<FunctionDefinition>()) {
this->writeProgramElement(*e);
}
}
// Write the functions last.
// Why don't we write things in their original order? Because the Inliner likes to move function
// bodies around. After inlining, code can inadvertently move upwards, above ProgramElements
@ -593,10 +666,13 @@ bool PipelineStageCodeGenerator::generateCode() {
this->writeProgramElement(*e);
}
}
fOut = rawOut;
write_stringstream(body, *rawOut);
return 0 == fErrors.errorCount();
fArgs->fCode = mainBody.str();
}
void PipelineStage::ConvertProgram(const Program& program, Args* outArgs) {
PipelineStageCodeGenerator generator(program, outArgs);
generator.generateCode();
}
} // namespace SkSL

View File

@ -8,85 +8,55 @@
#ifndef SKSL_PIPELINESTAGECODEGENERATOR
#define SKSL_PIPELINESTAGECODEGENERATOR
#include "src/sksl/SkSLCodeGenerator.h"
#include "src/sksl/SkSLOperators.h"
#include "src/sksl/SkSLStringStream.h"
#include "src/sksl/ir/SkSLBinaryExpression.h"
#include "src/sksl/ir/SkSLConstructor.h"
#include "src/sksl/ir/SkSLExpressionStatement.h"
#include "src/sksl/ir/SkSLFieldAccess.h"
#include "src/sksl/ir/SkSLForStatement.h"
#include "src/sksl/ir/SkSLFunctionCall.h"
#include "src/sksl/ir/SkSLFunctionDeclaration.h"
#include "src/sksl/ir/SkSLFunctionDefinition.h"
#include "src/sksl/ir/SkSLIfStatement.h"
#include "src/sksl/ir/SkSLIndexExpression.h"
#include "src/sksl/ir/SkSLPostfixExpression.h"
#include "src/sksl/ir/SkSLPrefixExpression.h"
#include "src/sksl/ir/SkSLProgramElement.h"
#include "src/sksl/ir/SkSLReturnStatement.h"
#include "src/sksl/ir/SkSLStatement.h"
#include "src/sksl/ir/SkSLSwizzle.h"
#include "src/sksl/ir/SkSLTernaryExpression.h"
#include "src/sksl/ir/SkSLVarDeclarations.h"
#include "src/sksl/ir/SkSLVariableReference.h"
#include "src/sksl/SkSLString.h"
#include <vector>
#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
namespace SkSL {
struct PipelineStageArgs;
class FunctionDeclaration;
struct Program;
class PipelineStageCodeGenerator : public CodeGenerator {
class PipelineStage {
public:
PipelineStageCodeGenerator(const Context* context, const Program* program,
ErrorReporter* errors, OutputStream* out,
PipelineStageArgs* outArgs);
// An invalid (otherwise unused) character to mark where FormatArgs are inserted
static constexpr char kFormatArgPlaceholder = '\001';
static constexpr const char* kFormatArgPlaceholderStr = "\001";
bool generateCode() override;
struct FormatArg {
enum class Kind {
kCoords,
kUniform,
kChildProcessor,
kChildProcessorWithMatrix,
kFunctionName
};
private:
using Precedence = Operators::Precedence;
FormatArg(Kind kind, int index = 0) : fKind(kind), fIndex(index) {}
void write(const char* s);
void writeLine(const char* s = nullptr);
void write(const String& s);
void write(StringFragment s);
Kind fKind;
int fIndex;
String fCoords;
};
void writeType(const Type& type);
/**
* Represents the arguments to GrGLSLShaderBuilder::emitFunction.
*/
struct Function {
const FunctionDeclaration* fDecl;
String fBody;
std::vector<FormatArg> fFormatArgs;
};
void writeFunctionDeclaration(const FunctionDeclaration& f);
void writeFunction(const FunctionDefinition& f);
struct Args {
String fCode;
std::vector<FormatArg> fFormatArgs;
std::vector<Function> fFunctions;
};
void writeModifiers(const Modifiers& modifiers);
void writeVarDeclaration(const VarDeclaration& var);
void writeExpression(const Expression& expr, Precedence parentPrecedence);
void writeFunctionCall(const FunctionCall& c);
void writeConstructor(const Constructor& c, Precedence parentPrecedence);
void writeFieldAccess(const FieldAccess& f);
void writeSwizzle(const Swizzle& swizzle);
void writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence);
void writeTernaryExpression(const TernaryExpression& t, Precedence parentPrecedence);
void writeIndexExpression(const IndexExpression& expr);
void writePrefixExpression(const PrefixExpression& p, Precedence parentPrecedence);
void writePostfixExpression(const PostfixExpression& p, Precedence parentPrecedence);
void writeVariableReference(const VariableReference& ref);
void writeStatement(const Statement& s);
void writeBlock(const Block& b);
void writeIfStatement(const IfStatement& stmt);
void writeForStatement(const ForStatement& f);
void writeReturnStatement(const ReturnStatement& r);
void writeProgramElement(const ProgramElement& e);
const Context& fContext;
PipelineStageArgs* fArgs;
bool fCastReturnsToHalf = false;
using INHERITED = CodeGenerator;
static void ConvertProgram(const Program& program, Args* outArgs);
};
} // namespace SkSL