Home | History | Annotate | Download | only in sksl
      1 /*
      2  * Copyright 2016 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 "SkSLHCodeGenerator.h"
      9 
     10 #include "SkSLParser.h"
     11 #include "SkSLUtil.h"
     12 #include "ir/SkSLEnum.h"
     13 #include "ir/SkSLFunctionDeclaration.h"
     14 #include "ir/SkSLFunctionDefinition.h"
     15 #include "ir/SkSLSection.h"
     16 #include "ir/SkSLVarDeclarations.h"
     17 
     18 #include <set>
     19 
     20 namespace SkSL {
     21 
     22 HCodeGenerator::HCodeGenerator(const Context* context, const Program* program,
     23                                ErrorReporter* errors, String name, OutputStream* out)
     24 : INHERITED(program, errors, out)
     25 , fContext(*context)
     26 , fName(std::move(name))
     27 , fFullName(String::printf("Gr%s", fName.c_str()))
     28 , fSectionAndParameterHelper(*program, *errors) {}
     29 
     30 String HCodeGenerator::ParameterType(const Context& context, const Type& type,
     31                                      const Layout& layout) {
     32     Layout::CType ctype = ParameterCType(context, type, layout);
     33     if (ctype != Layout::CType::kDefault) {
     34         return Layout::CTypeToStr(ctype);
     35     }
     36     return type.name();
     37 }
     38 
     39 Layout::CType HCodeGenerator::ParameterCType(const Context& context, const Type& type,
     40                                      const Layout& layout) {
     41     if (layout.fCType != Layout::CType::kDefault) {
     42         return layout.fCType;
     43     }
     44     if (type == *context.fFloat_Type || type == *context.fHalf_Type) {
     45         return Layout::CType::kFloat;
     46     } else if (type == *context.fInt_Type ||
     47                type == *context.fShort_Type ||
     48                type == *context.fByte_Type) {
     49         return Layout::CType::kInt32;
     50     } else if (type == *context.fFloat2_Type || type == *context.fHalf2_Type) {
     51         return Layout::CType::kSkPoint;
     52     } else if (type == *context.fInt2_Type ||
     53                type == *context.fShort2_Type ||
     54                type == *context.fByte2_Type) {
     55         return Layout::CType::kSkIPoint;
     56     } else if (type == *context.fInt4_Type ||
     57                type == *context.fShort4_Type ||
     58                type == *context.fByte4_Type) {
     59         return Layout::CType::kSkIRect;
     60     } else if (type == *context.fFloat4_Type || type == *context.fHalf4_Type) {
     61         return Layout::CType::kSkRect;
     62     } else if (type == *context.fFloat3x3_Type || type == *context.fHalf3x3_Type) {
     63         return Layout::CType::kSkMatrix;
     64     } else if (type == *context.fFloat4x4_Type || type == *context.fHalf4x4_Type) {
     65         return Layout::CType::kSkMatrix44;
     66     } else if (type.kind() == Type::kSampler_Kind) {
     67         return Layout::CType::kGrTextureProxy;
     68     } else if (type == *context.fFragmentProcessor_Type) {
     69         return Layout::CType::kGrFragmentProcessor;
     70     }
     71     return Layout::CType::kDefault;
     72 }
     73 
     74 String HCodeGenerator::FieldType(const Context& context, const Type& type,
     75                                  const Layout& layout) {
     76     if (type.kind() == Type::kSampler_Kind) {
     77         return "TextureSampler";
     78     } else if (type == *context.fFragmentProcessor_Type) {
     79         // we don't store fragment processors in fields, they get registered via
     80         // registerChildProcessor instead
     81         SkASSERT(false);
     82         return "<error>";
     83     }
     84     return ParameterType(context, type, layout);
     85 }
     86 
     87 String HCodeGenerator::AccessType(const Context& context, const Type& type,
     88                                   const Layout& layout) {
     89     static const std::set<String> primitiveTypes = { "int32_t", "float", "bool", "SkPMColor" };
     90 
     91     String fieldType = FieldType(context, type, layout);
     92     bool isPrimitive = primitiveTypes.find(fieldType) != primitiveTypes.end();
     93     if (isPrimitive) {
     94         return fieldType;
     95     } else {
     96         return String::printf("const %s&", fieldType.c_str());
     97     }
     98 }
     99 
    100 void HCodeGenerator::writef(const char* s, va_list va) {
    101     static constexpr int BUFFER_SIZE = 1024;
    102     va_list copy;
    103     va_copy(copy, va);
    104     char buffer[BUFFER_SIZE];
    105     int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
    106     if (length < BUFFER_SIZE) {
    107         fOut->write(buffer, length);
    108     } else {
    109         std::unique_ptr<char[]> heap(new char[length + 1]);
    110         vsprintf(heap.get(), s, copy);
    111         fOut->write(heap.get(), length);
    112     }
    113 }
    114 
    115 void HCodeGenerator::writef(const char* s, ...) {
    116     va_list va;
    117     va_start(va, s);
    118     this->writef(s, va);
    119     va_end(va);
    120 }
    121 
    122 bool HCodeGenerator::writeSection(const char* name, const char* prefix) {
    123     const Section* s = fSectionAndParameterHelper.getSection(name);
    124     if (s) {
    125         this->writef("%s%s", prefix, s->fText.c_str());
    126         return true;
    127     }
    128     return false;
    129 }
    130 
    131 void HCodeGenerator::writeExtraConstructorParams(const char* separator) {
    132     // super-simple parse, just assume the last token before a comma is the name of a parameter
    133     // (which is true as long as there are no multi-parameter template types involved). Will replace
    134     // this with something more robust if the need arises.
    135     const Section* section = fSectionAndParameterHelper.getSection(CONSTRUCTOR_PARAMS_SECTION);
    136     if (section) {
    137         const char* s = section->fText.c_str();
    138         #define BUFFER_SIZE 64
    139         char lastIdentifier[BUFFER_SIZE];
    140         int lastIdentifierLength = 0;
    141         bool foundBreak = false;
    142         while (*s) {
    143             char c = *s;
    144             ++s;
    145             if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
    146                 c == '_') {
    147                 if (foundBreak) {
    148                     lastIdentifierLength = 0;
    149                     foundBreak = false;
    150                 }
    151                 SkASSERT(lastIdentifierLength < BUFFER_SIZE);
    152                 lastIdentifier[lastIdentifierLength] = c;
    153                 ++lastIdentifierLength;
    154             } else {
    155                 foundBreak = true;
    156                 if (c == ',') {
    157                     SkASSERT(lastIdentifierLength < BUFFER_SIZE);
    158                     lastIdentifier[lastIdentifierLength] = 0;
    159                     this->writef("%s%s", separator, lastIdentifier);
    160                     separator = ", ";
    161                 } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
    162                     lastIdentifierLength = 0;
    163                 }
    164             }
    165         }
    166         if (lastIdentifierLength) {
    167             SkASSERT(lastIdentifierLength < BUFFER_SIZE);
    168             lastIdentifier[lastIdentifierLength] = 0;
    169             this->writef("%s%s", separator, lastIdentifier);
    170         }
    171     }
    172 }
    173 
    174 void HCodeGenerator::writeMake() {
    175     const char* separator;
    176     if (!this->writeSection(MAKE_SECTION)) {
    177         this->writef("    static std::unique_ptr<GrFragmentProcessor> Make(");
    178         separator = "";
    179         for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    180             this->writef("%s%s %s", separator, ParameterType(fContext, param->fType,
    181                                                              param->fModifiers.fLayout).c_str(),
    182                          String(param->fName).c_str());
    183             separator = ", ";
    184         }
    185         this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
    186         this->writef(") {\n"
    187                      "        return std::unique_ptr<GrFragmentProcessor>(new %s(",
    188                      fFullName.c_str());
    189         separator = "";
    190         for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    191             if (param->fType == *fContext.fFragmentProcessor_Type) {
    192                 this->writef("%sstd::move(%s)", separator, String(param->fName).c_str());
    193             } else {
    194                 this->writef("%s%s", separator, String(param->fName).c_str());
    195             }
    196             separator = ", ";
    197         }
    198         this->writeExtraConstructorParams(separator);
    199         this->writef("));\n"
    200                      "    }\n");
    201     }
    202 }
    203 
    204 void HCodeGenerator::failOnSection(const char* section, const char* msg) {
    205     std::vector<const Section*> s = fSectionAndParameterHelper.getSections(section);
    206     if (s.size()) {
    207         fErrors.error(s[0]->fOffset, String("@") + section + " " + msg);
    208     }
    209 }
    210 
    211 void HCodeGenerator::writeConstructor() {
    212     if (this->writeSection(CONSTRUCTOR_SECTION)) {
    213         const char* msg = "may not be present when constructor is overridden";
    214         this->failOnSection(CONSTRUCTOR_CODE_SECTION, msg);
    215         this->failOnSection(CONSTRUCTOR_PARAMS_SECTION, msg);
    216         this->failOnSection(INITIALIZERS_SECTION, msg);
    217         this->failOnSection(OPTIMIZATION_FLAGS_SECTION, msg);
    218         return;
    219     }
    220     this->writef("    %s(", fFullName.c_str());
    221     const char* separator = "";
    222     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    223         this->writef("%s%s %s", separator, ParameterType(fContext, param->fType,
    224                                                          param->fModifiers.fLayout).c_str(),
    225                      String(param->fName).c_str());
    226         separator = ", ";
    227     }
    228     this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
    229     this->writef(")\n"
    230                  "    : INHERITED(k%s_ClassID", fFullName.c_str());
    231     if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, ", (OptimizationFlags) ")) {
    232         this->writef(", kNone_OptimizationFlags");
    233     }
    234     this->writef(")");
    235     this->writeSection(INITIALIZERS_SECTION, "\n    , ");
    236     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    237         String nameString(param->fName);
    238         const char* name = nameString.c_str();
    239         if (param->fType.kind() == Type::kSampler_Kind) {
    240             this->writef("\n    , %s(std::move(%s)", FieldName(name).c_str(), name);
    241             for (const Section* s : fSectionAndParameterHelper.getSections(
    242                                                                           SAMPLER_PARAMS_SECTION)) {
    243                 if (s->fArgument == name) {
    244                     this->writef(", %s", s->fText.c_str());
    245                 }
    246             }
    247             this->writef(")");
    248         } else if (param->fType == *fContext.fFragmentProcessor_Type) {
    249             // do nothing
    250         } else {
    251             this->writef("\n    , %s(%s)", FieldName(name).c_str(), name);
    252         }
    253     }
    254     const auto transforms = fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION);
    255     for (size_t i = 0; i < transforms.size(); ++i) {
    256         const Section& s = *transforms[i];
    257         String field = CoordTransformName(s.fArgument.c_str(), i);
    258         if (s.fArgument.size()) {
    259             this->writef("\n    , %s(%s, %s.proxy())", field.c_str(), s.fText.c_str(),
    260                          FieldName(s.fArgument.c_str()).c_str());
    261         }
    262         else {
    263             this->writef("\n    , %s(%s)", field.c_str(), s.fText.c_str());
    264         }
    265     }
    266     this->writef(" {\n");
    267     this->writeSection(CONSTRUCTOR_CODE_SECTION);
    268     int samplerCount = 0;
    269     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    270         if (param->fType.kind() == Type::kSampler_Kind) {
    271             ++samplerCount;
    272         } else if (param->fType == *fContext.fFragmentProcessor_Type) {
    273             this->writef("        this->registerChildProcessor(std::move(%s));",
    274                          String(param->fName).c_str());
    275         }
    276     }
    277     if (samplerCount) {
    278         this->writef("        this->setTextureSamplerCnt(%d);", samplerCount);
    279     }
    280     for (size_t i = 0; i < transforms.size(); ++i) {
    281         const Section& s = *transforms[i];
    282         String field = CoordTransformName(s.fArgument.c_str(), i);
    283         this->writef("        this->addCoordTransform(&%s);\n", field.c_str());
    284     }
    285     this->writef("    }\n");
    286 }
    287 
    288 void HCodeGenerator::writeFields() {
    289     this->writeSection(FIELDS_SECTION);
    290     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    291         if (param->fType == *fContext.fFragmentProcessor_Type) {
    292             continue;
    293         }
    294         this->writef("    %s %s;\n", FieldType(fContext, param->fType,
    295                                                param->fModifiers.fLayout).c_str(),
    296                      FieldName(String(param->fName).c_str()).c_str());
    297     }
    298     const auto transforms = fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION);
    299     for (size_t i = 0; i < transforms.size(); ++i) {
    300         const Section& s = *transforms[i];
    301         this->writef("    GrCoordTransform %s;\n",
    302                      CoordTransformName(s.fArgument.c_str(), i).c_str());
    303     }
    304 }
    305 
    306 String HCodeGenerator::GetHeader(const Program& program, ErrorReporter& errors) {
    307     SymbolTable types(&errors);
    308     Parser parser(program.fSource->c_str(), program.fSource->length(), types, errors);
    309     for (;;) {
    310         Token header = parser.nextRawToken();
    311         switch (header.fKind) {
    312             case Token::WHITESPACE:
    313                 break;
    314             case Token::BLOCK_COMMENT:
    315                 return String(program.fSource->c_str() + header.fOffset, header.fLength);
    316             default:
    317                 return "";
    318         }
    319     }
    320 }
    321 
    322 bool HCodeGenerator::generateCode() {
    323     this->writef("%s\n", GetHeader(fProgram, fErrors).c_str());
    324     this->writef(kFragmentProcessorHeader, fFullName.c_str());
    325     this->writef("#ifndef %s_DEFINED\n"
    326                  "#define %s_DEFINED\n",
    327                  fFullName.c_str(),
    328                  fFullName.c_str());
    329     this->writef("#include \"SkTypes.h\"\n");
    330     this->writeSection(HEADER_SECTION);
    331     this->writef("#include \"GrFragmentProcessor.h\"\n"
    332                  "#include \"GrCoordTransform.h\"\n");
    333     this->writef("class %s : public GrFragmentProcessor {\n"
    334                  "public:\n",
    335                  fFullName.c_str());
    336     for (const auto& p : fProgram) {
    337         if (ProgramElement::kEnum_Kind == p.fKind && !((Enum&) p).fBuiltin) {
    338             this->writef("%s\n", p.description().c_str());
    339         }
    340     }
    341     this->writeSection(CLASS_SECTION);
    342     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    343         if (param->fType.kind() == Type::kSampler_Kind ||
    344             param->fType.kind() == Type::kOther_Kind) {
    345             continue;
    346         }
    347         String nameString(param->fName);
    348         const char* name = nameString.c_str();
    349         this->writef("    %s %s() const { return %s; }\n",
    350                      AccessType(fContext, param->fType, param->fModifiers.fLayout).c_str(), name,
    351                      FieldName(name).c_str());
    352     }
    353     this->writeMake();
    354     this->writef("    %s(const %s& src);\n"
    355                  "    std::unique_ptr<GrFragmentProcessor> clone() const override;\n"
    356                  "    const char* name() const override { return \"%s\"; }\n"
    357                  "private:\n",
    358                  fFullName.c_str(), fFullName.c_str(), fName.c_str());
    359     this->writeConstructor();
    360     this->writef("    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
    361                  "    void onGetGLSLProcessorKey(const GrShaderCaps&,"
    362                                                 "GrProcessorKeyBuilder*) const override;\n"
    363                  "    bool onIsEqual(const GrFragmentProcessor&) const override;\n");
    364     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    365         if (param->fType.kind() == Type::kSampler_Kind) {
    366             this->writef("    const TextureSampler& onTextureSampler(int) const override;");
    367             break;
    368         }
    369     }
    370     this->writef("    GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n");
    371     this->writeFields();
    372     this->writef("    typedef GrFragmentProcessor INHERITED;\n"
    373                 "};\n");
    374     this->writeSection(HEADER_END_SECTION);
    375     this->writef("#endif\n");
    376     return 0 == fErrors.errorCount();
    377 }
    378 
    379 } // namespace
    380