blob: dde55f64d11e1cc0519f01fe8e3aebd5509da146 [file] [log] [blame]
/*
* Copyright 2018 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/SkSLPipelineStageCodeGenerator.h"
#include "src/sksl/SkSLCompiler.h"
#include "src/sksl/SkSLHCodeGenerator.h"
#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
namespace SkSL {
PipelineStageCodeGenerator::PipelineStageCodeGenerator(
const Context* context,
const Program* program,
ErrorReporter* errors,
OutputStream* out,
std::vector<Compiler::FormatArg>* outFormatArgs,
std::vector<Compiler::GLSLFunction>* outFunctions)
: INHERITED(context, program, errors, out)
, fName("Temp")
, fFullName(String::printf("Gr%s", fName.c_str()))
, fSectionAndParameterHelper(program, *errors)
, fFormatArgs(outFormatArgs)
, fFunctions(outFunctions) {}
void PipelineStageCodeGenerator::writef(const char* s, va_list va) {
static constexpr int BUFFER_SIZE = 1024;
va_list copy;
va_copy(copy, va);
char buffer[BUFFER_SIZE];
int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
if (length < BUFFER_SIZE) {
fOut->write(buffer, length);
} else {
std::unique_ptr<char[]> heap(new char[length + 1]);
vsprintf(heap.get(), s, copy);
fOut->write(heap.get(), length);
}
va_end(copy);
}
void PipelineStageCodeGenerator::writef(const char* s, ...) {
va_list va;
va_start(va, s);
this->writef(s, va);
va_end(va);
}
void PipelineStageCodeGenerator::writeHeader() {
}
bool PipelineStageCodeGenerator::usesPrecisionModifiers() const {
return false;
}
String PipelineStageCodeGenerator::getTypeName(const Type& type) {
return type.name();
}
void PipelineStageCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
Precedence parentPrecedence) {
if (b.fOperator == Token::PERCENT) {
// need to use "%%" instead of "%" b/c the code will be inside of a printf
Precedence precedence = GetBinaryPrecedence(b.fOperator);
if (precedence >= parentPrecedence) {
this->write("(");
}
this->writeExpression(*b.fLeft, precedence);
this->write(" %% ");
this->writeExpression(*b.fRight, precedence);
if (precedence >= parentPrecedence) {
this->write(")");
}
} else {
INHERITED::writeBinaryExpression(b, parentPrecedence);
}
}
void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
if (c.fFunction.fBuiltin && c.fFunction.fName == "sample" &&
c.fArguments[0]->fType.kind() != Type::Kind::kSampler_Kind) {
SkASSERT(c.fArguments.size() == 1);
SkASSERT("fragmentProcessor" == c.fArguments[0]->fType.name() ||
"fragmentProcessor?" == c.fArguments[0]->fType.name());
SkASSERT(Expression::kVariableReference_Kind == c.fArguments[0]->fKind);
int index = 0;
bool found = false;
for (const auto& p : fProgram) {
if (ProgramElement::kVar_Kind == p.fKind) {
const VarDeclarations& decls = (const VarDeclarations&) p;
for (const auto& raw : decls.fVars) {
VarDeclaration& decl = (VarDeclaration&) *raw;
if (decl.fVar == &((VariableReference&) *c.fArguments[0]).fVariable) {
found = true;
} else if (decl.fVar->fType == *fContext.fFragmentProcessor_Type) {
++index;
}
}
}
if (found) {
break;
}
}
SkASSERT(found);
this->write("%s");
fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kChildProcessor,
index));
return;
}
if (c.fFunction.fBuiltin) {
INHERITED::writeFunctionCall(c);
} else {
this->write("%s");
int index = 0;
for (const auto& e : fProgram) {
if (e.fKind == ProgramElement::kFunction_Kind) {
if (&((FunctionDefinition&) e).fDeclaration == &c.fFunction) {
break;
}
++index;
}
}
fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kFunctionName,
index));
this->write("(");
const char* separator = "";
for (const auto& arg : c.fArguments) {
this->write(separator);
separator = ", ";
this->writeExpression(*arg, kSequence_Precedence);
}
this->write(")");
}
}
void PipelineStageCodeGenerator::writeIntLiteral(const IntLiteral& i) {
this->write(to_string((int32_t) i.fValue));
}
void PipelineStageCodeGenerator::writeVariableReference(const VariableReference& ref) {
switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
case SK_INCOLOR_BUILTIN:
this->write("%s");
fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kInput));
break;
case SK_OUTCOLOR_BUILTIN:
this->write("%s");
fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kOutput));
break;
case SK_MAIN_X_BUILTIN:
this->write("%s");
fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kCoordX));
break;
case SK_MAIN_Y_BUILTIN:
this->write("%s");
fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kCoordY));
break;
default:
if (ref.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag) {
this->write("%s");
int index = 0;
bool found = false;
for (const auto& e : fProgram) {
if (found) {
break;
}
if (e.fKind == ProgramElement::Kind::kVar_Kind) {
const VarDeclarations& decls = (const VarDeclarations&) e;
for (const auto& decl : decls.fVars) {
const Variable& var = *((VarDeclaration&) *decl).fVar;
if (&var == &ref.fVariable) {
found = true;
break;
}
if (var.fModifiers.fFlags & Modifiers::kUniform_Flag) {
++index;
}
}
}
}
SkASSERT(found);
fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kUniform,
index));
} else {
this->write(ref.fVariable.fName);
}
}
}
void PipelineStageCodeGenerator::writeIfStatement(const IfStatement& s) {
if (s.fIsStatic) {
this->write("@");
}
INHERITED::writeIfStatement(s);
}
void PipelineStageCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
if (s.fIsStatic) {
this->write("@");
}
INHERITED::writeSwitchStatement(s);
}
static GrSLType glsltype(const Context& context, const Type& type) {
if (type == *context.fFloat_Type) {
return GrSLType::kFloat_GrSLType;
} else if (type == *context.fHalf_Type) {
return GrSLType::kHalf_GrSLType;
} else if (type == *context.fFloat2_Type) {
return GrSLType::kFloat2_GrSLType;
} else if (type == *context.fHalf2_Type) {
return GrSLType::kHalf2_GrSLType;
} else if (type == *context.fFloat4_Type) {
return GrSLType::kFloat4_GrSLType;
} else if (type == *context.fHalf4_Type) {
return GrSLType::kHalf4_GrSLType;
} else if (type == *context.fFloat4x4_Type) {
return GrSLType::kFloat4x4_GrSLType;
} else if (type == *context.fHalf4x4_Type) {
return GrSLType::kHalf4x4_GrSLType;
} else if (type == *context.fVoid_Type) {
return GrSLType::kVoid_GrSLType;
}
SkASSERT(false);
return GrSLType::kVoid_GrSLType;
}
void PipelineStageCodeGenerator::writeFunction(const FunctionDefinition& f) {
fCurrentFunction = &f.fDeclaration;
fFunctionHeader = "";
OutputStream* oldOut = fOut;
StringStream buffer;
fOut = &buffer;
if (f.fDeclaration.fName == "main") {
this->write("%s = %s;\n");
fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kOutput));
fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kInput));
for (const auto& s : ((Block&) *f.fBody).fStatements) {
this->writeStatement(*s);
this->writeLine();
}
fOut = oldOut;
this->write(fFunctionHeader);
this->writef("%s", buffer.str().c_str());
} else {
const FunctionDeclaration& decl = f.fDeclaration;
Compiler::GLSLFunction result;
result.fReturnType = glsltype(fContext, decl.fReturnType);
result.fName = decl.fName;
for (const Variable* v : decl.fParameters) {
result.fParameters.emplace_back(v->fName, glsltype(fContext, v->fType));
}
for (const auto& s : ((Block&) *f.fBody).fStatements) {
this->writeStatement(*s);
this->writeLine();
}
fOut = oldOut;
result.fBody = buffer.str();
fFunctions->push_back(result);
}
}
bool PipelineStageCodeGenerator::writeSection(const char* name, const char* prefix) {
const Section* s = fSectionAndParameterHelper.getSection(name);
if (s) {
this->writef("%s%s", prefix, s->fText.c_str());
return true;
}
return false;
}
void PipelineStageCodeGenerator::writeProgramElement(const ProgramElement& p) {
if (p.fKind == ProgramElement::kSection_Kind) {
return;
}
if (p.fKind == ProgramElement::kVar_Kind) {
const VarDeclarations& decls = (const VarDeclarations&) p;
if (!decls.fVars.size()) {
return;
}
const Variable& var = *((VarDeclaration&) *decls.fVars[0]).fVar;
if (var.fModifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kUniform_Flag) ||
-1 != var.fModifiers.fLayout.fBuiltin) {
return;
}
}
INHERITED::writeProgramElement(p);
}
} // namespace
#endif