/* * 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" namespace SkSL { PipelineStageCodeGenerator::PipelineStageCodeGenerator( const Context* context, const Program* program, ErrorReporter* errors, OutputStream* out, std::vector* outFormatArgs) : INHERITED(context, program, errors, out) , fName("Temp") , fFullName(String::printf("Gr%s", fName.c_str())) , fSectionAndParameterHelper(*program, *errors) , fFormatArgs(outFormatArgs) {} 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 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 == "process") { SkASSERT(c.fArguments.size() == 1); 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); fExtraEmitCodeCode += " this->emitChild(" + to_string(index) + ", fChildren[" + to_string(index) + "], args);\n"; this->write("%s"); fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kChildProcessor, index)); return; } INHERITED::writeFunctionCall(c); } 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("sk_FragCoord.x"); break; case SK_MAIN_Y_BUILTIN: this->write("sk_FragCoord.y"); 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); } void PipelineStageCodeGenerator::writeFunction(const FunctionDefinition& f) { fCurrentFunction = &f.fDeclaration; if (f.fDeclaration.fName == "main") { fFunctionHeader = ""; OutputStream* oldOut = fOut; StringStream buffer; fOut = &buffer; 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 { INHERITED::writeFunction(f); } } 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