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:
parent
001850105e
commit
236ddb3e1d
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user