Home | History | Annotate | Download | only in sksl
      1 /*
      2  * Copyright 2018 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkSLPipelineStageCodeGenerator.h"
      9 
     10 #include "SkSLCompiler.h"
     11 #include "SkSLHCodeGenerator.h"
     12 
     13 namespace SkSL {
     14 
     15 PipelineStageCodeGenerator::PipelineStageCodeGenerator(
     16                                                     const Context* context,
     17                                                     const Program* program,
     18                                                     ErrorReporter* errors,
     19                                                     OutputStream* out,
     20                                                     std::vector<Compiler::FormatArg>* outFormatArgs)
     21 : INHERITED(context, program, errors, out)
     22 , fName("Temp")
     23 , fFullName(String::printf("Gr%s", fName.c_str()))
     24 , fSectionAndParameterHelper(*program, *errors)
     25 , fFormatArgs(outFormatArgs) {}
     26 
     27 void PipelineStageCodeGenerator::writef(const char* s, va_list va) {
     28     static constexpr int BUFFER_SIZE = 1024;
     29     va_list copy;
     30     va_copy(copy, va);
     31     char buffer[BUFFER_SIZE];
     32     int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
     33     if (length < BUFFER_SIZE) {
     34         fOut->write(buffer, length);
     35     } else {
     36         std::unique_ptr<char[]> heap(new char[length + 1]);
     37         vsprintf(heap.get(), s, copy);
     38         fOut->write(heap.get(), length);
     39     }
     40 }
     41 
     42 void PipelineStageCodeGenerator::writef(const char* s, ...) {
     43     va_list va;
     44     va_start(va, s);
     45     this->writef(s, va);
     46     va_end(va);
     47 }
     48 
     49 void PipelineStageCodeGenerator::writeHeader() {
     50 }
     51 
     52 bool PipelineStageCodeGenerator::usesPrecisionModifiers() const {
     53     return false;
     54 }
     55 
     56 String PipelineStageCodeGenerator::getTypeName(const Type& type) {
     57     return type.name();
     58 }
     59 
     60 void PipelineStageCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
     61                                              Precedence parentPrecedence) {
     62     if (b.fOperator == Token::PERCENT) {
     63         // need to use "%%" instead of "%" b/c the code will be inside of a printf
     64         Precedence precedence = GetBinaryPrecedence(b.fOperator);
     65         if (precedence >= parentPrecedence) {
     66             this->write("(");
     67         }
     68         this->writeExpression(*b.fLeft, precedence);
     69         this->write(" %% ");
     70         this->writeExpression(*b.fRight, precedence);
     71         if (precedence >= parentPrecedence) {
     72             this->write(")");
     73         }
     74     } else {
     75         INHERITED::writeBinaryExpression(b, parentPrecedence);
     76     }
     77 }
     78 
     79 void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
     80     if (c.fFunction.fBuiltin && c.fFunction.fName == "process") {
     81         SkASSERT(c.fArguments.size() == 1);
     82         SkASSERT(Expression::kVariableReference_Kind == c.fArguments[0]->fKind);
     83         int index = 0;
     84         bool found = false;
     85         for (const auto& p : fProgram) {
     86             if (ProgramElement::kVar_Kind == p.fKind) {
     87                 const VarDeclarations& decls = (const VarDeclarations&) p;
     88                 for (const auto& raw : decls.fVars) {
     89                     VarDeclaration& decl = (VarDeclaration&) *raw;
     90                     if (decl.fVar == &((VariableReference&) *c.fArguments[0]).fVariable) {
     91                         found = true;
     92                     } else if (decl.fVar->fType == *fContext.fFragmentProcessor_Type) {
     93                         ++index;
     94                     }
     95                 }
     96             }
     97             if (found) {
     98                 break;
     99             }
    100         }
    101         SkASSERT(found);
    102         fExtraEmitCodeCode += "        this->emitChild(" + to_string(index) + ", fChildren[" +
    103                               to_string(index) + "], args);\n";
    104         this->write("%s");
    105         fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kChildProcessor,
    106                                                    index));
    107         return;
    108     }
    109     INHERITED::writeFunctionCall(c);
    110 }
    111 
    112 void PipelineStageCodeGenerator::writeIntLiteral(const IntLiteral& i) {
    113     this->write(to_string((int32_t) i.fValue));
    114 }
    115 
    116 void PipelineStageCodeGenerator::writeVariableReference(const VariableReference& ref) {
    117     switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
    118         case SK_INCOLOR_BUILTIN:
    119             this->write("%s");
    120             fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kInput));
    121             break;
    122         case SK_OUTCOLOR_BUILTIN:
    123             this->write("%s");
    124             fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kOutput));
    125             break;
    126         case SK_MAIN_X_BUILTIN:
    127             this->write("sk_FragCoord.x");
    128             break;
    129         case SK_MAIN_Y_BUILTIN:
    130             this->write("sk_FragCoord.y");
    131             break;
    132         default:
    133             if (ref.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag) {
    134                 this->write("%s");
    135                 int index = 0;
    136                 bool found = false;
    137                 for (const auto& e : fProgram) {
    138                     if (found) {
    139                         break;
    140                     }
    141                     if (e.fKind == ProgramElement::Kind::kVar_Kind) {
    142                         const VarDeclarations& decls = (const VarDeclarations&) e;
    143                         for (const auto& decl : decls.fVars) {
    144                             const Variable& var = *((VarDeclaration&) *decl).fVar;
    145                             if (&var == &ref.fVariable) {
    146                                 found = true;
    147                                 break;
    148                             }
    149                             if (var.fModifiers.fFlags & (Modifiers::kIn_Flag |
    150                                                          Modifiers::kUniform_Flag)) {
    151                                 ++index;
    152                             }
    153                         }
    154                     }
    155                 }
    156                 SkASSERT(found);
    157                 fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kUniform,
    158                                                            index));
    159             }
    160             else {
    161                 this->write(ref.fVariable.fName);
    162             }
    163     }
    164 }
    165 
    166 void PipelineStageCodeGenerator::writeIfStatement(const IfStatement& s) {
    167     if (s.fIsStatic) {
    168         this->write("@");
    169     }
    170     INHERITED::writeIfStatement(s);
    171 }
    172 
    173 void PipelineStageCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
    174     if (s.fIsStatic) {
    175         this->write("@");
    176     }
    177     INHERITED::writeSwitchStatement(s);
    178 }
    179 
    180 void PipelineStageCodeGenerator::writeFunction(const FunctionDefinition& f) {
    181     if (f.fDeclaration.fName == "main") {
    182         fFunctionHeader = "";
    183         OutputStream* oldOut = fOut;
    184         StringStream buffer;
    185         fOut = &buffer;
    186         this->write("%s = %s;\n");
    187         fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kOutput));
    188         fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kInput));
    189         for (const auto& s : ((Block&) *f.fBody).fStatements) {
    190             this->writeStatement(*s);
    191             this->writeLine();
    192         }
    193 
    194         fOut = oldOut;
    195         this->write(fFunctionHeader);
    196         this->writef("%s", buffer.str().c_str());
    197     } else {
    198         INHERITED::writeFunction(f);
    199     }
    200 }
    201 
    202 bool PipelineStageCodeGenerator::writeSection(const char* name, const char* prefix) {
    203     const Section* s = fSectionAndParameterHelper.getSection(name);
    204     if (s) {
    205         this->writef("%s%s", prefix, s->fText.c_str());
    206         return true;
    207     }
    208     return false;
    209 }
    210 
    211 void PipelineStageCodeGenerator::writeProgramElement(const ProgramElement& p) {
    212     if (p.fKind == ProgramElement::kSection_Kind) {
    213         return;
    214     }
    215     if (p.fKind == ProgramElement::kVar_Kind) {
    216         const VarDeclarations& decls = (const VarDeclarations&) p;
    217         if (!decls.fVars.size()) {
    218             return;
    219         }
    220         const Variable& var = *((VarDeclaration&) *decls.fVars[0]).fVar;
    221         if (var.fModifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kUniform_Flag) ||
    222             -1 != var.fModifiers.fLayout.fBuiltin) {
    223             return;
    224         }
    225     }
    226     INHERITED::writeProgramElement(p);
    227 }
    228 
    229 } // namespace
    230