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 "SkSLUtil.h"
     11 #include "ir/SkSLFunctionDeclaration.h"
     12 #include "ir/SkSLFunctionDefinition.h"
     13 #include "ir/SkSLSection.h"
     14 #include "ir/SkSLVarDeclarations.h"
     15 
     16 namespace SkSL {
     17 
     18 HCodeGenerator::HCodeGenerator(const Program* program, ErrorReporter* errors, String name,
     19                                OutputStream* out)
     20 : INHERITED(program, errors, out)
     21 , fName(std::move(name))
     22 , fFullName(String::printf("Gr%s", fName.c_str()))
     23 , fSectionAndParameterHelper(*program, *errors) {}
     24 
     25 String HCodeGenerator::ParameterType(const Type& type) {
     26     if (type.fName == "vec2") {
     27         return "SkPoint";
     28     } else if (type.fName == "ivec4") {
     29         return "SkIRect";
     30     } else if (type.fName == "vec4") {
     31         return "SkRect";
     32     } else if (type.fName == "mat4") {
     33         return "SkMatrix44";
     34     } else if (type.kind() == Type::kSampler_Kind) {
     35         return "sk_sp<GrTextureProxy>";
     36     } else if (type.fName == "colorSpaceXform") {
     37         return "sk_sp<GrColorSpaceXform>";
     38     }
     39     return type.name();
     40 }
     41 
     42 String HCodeGenerator::FieldType(const Type& type) {
     43     if (type.kind() == Type::kSampler_Kind) {
     44         return "TextureSampler";
     45     }
     46     return ParameterType(type);
     47 }
     48 
     49 void HCodeGenerator::writef(const char* s, va_list va) {
     50     static constexpr int BUFFER_SIZE = 1024;
     51     va_list copy;
     52     va_copy(copy, va);
     53     char buffer[BUFFER_SIZE];
     54     int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
     55     if (length < BUFFER_SIZE) {
     56         fOut->write(buffer, length);
     57     } else {
     58         std::unique_ptr<char[]> heap(new char[length + 1]);
     59         vsprintf(heap.get(), s, copy);
     60         fOut->write(heap.get(), length);
     61     }
     62 }
     63 
     64 void HCodeGenerator::writef(const char* s, ...) {
     65     va_list va;
     66     va_start(va, s);
     67     this->writef(s, va);
     68     va_end(va);
     69 }
     70 
     71 bool HCodeGenerator::writeSection(const char* name, const char* prefix) {
     72     const Section* s = fSectionAndParameterHelper.getSection(name);
     73     if (s) {
     74         this->writef("%s%s", prefix, s->fText.c_str());
     75         return true;
     76     }
     77     return false;
     78 }
     79 
     80 void HCodeGenerator::writeExtraConstructorParams(const char* separator) {
     81     // super-simple parse, just assume the last token before a comma is the name of a parameter
     82     // (which is true as long as there are no multi-parameter template types involved). Will replace
     83     // this with something more robust if the need arises.
     84     const Section* section = fSectionAndParameterHelper.getSection(CONSTRUCTOR_PARAMS_SECTION);
     85     if (section) {
     86         const char* s = section->fText.c_str();
     87         #define BUFFER_SIZE 64
     88         char lastIdentifier[BUFFER_SIZE];
     89         int lastIdentifierLength = 0;
     90         bool foundBreak = false;
     91         while (*s) {
     92             char c = *s;
     93             ++s;
     94             if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
     95                 c == '_') {
     96                 if (foundBreak) {
     97                     lastIdentifierLength = 0;
     98                     foundBreak = false;
     99                 }
    100                 ASSERT(lastIdentifierLength < BUFFER_SIZE);
    101                 lastIdentifier[lastIdentifierLength] = c;
    102                 ++lastIdentifierLength;
    103             } else {
    104                 foundBreak = true;
    105                 if (c == ',') {
    106                     ASSERT(lastIdentifierLength < BUFFER_SIZE);
    107                     lastIdentifier[lastIdentifierLength] = 0;
    108                     this->writef("%s%s", separator, lastIdentifier);
    109                     separator = ", ";
    110                 } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
    111                     lastIdentifierLength = 0;
    112                 }
    113             }
    114         }
    115         if (lastIdentifierLength) {
    116             ASSERT(lastIdentifierLength < BUFFER_SIZE);
    117             lastIdentifier[lastIdentifierLength] = 0;
    118             this->writef("%s%s", separator, lastIdentifier);
    119         }
    120     }
    121 }
    122 
    123 void HCodeGenerator::writeMake() {
    124     const char* separator;
    125     if (!this->writeSection(MAKE_SECTION)) {
    126         this->writef("    static sk_sp<GrFragmentProcessor> Make(");
    127         separator = "";
    128         for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    129             this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
    130                          param->fName.c_str());
    131             separator = ", ";
    132         }
    133         this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
    134         this->writef(") {\n"
    135                      "        return sk_sp<GrFragmentProcessor>(new %s(",
    136                      fFullName.c_str());
    137         separator = "";
    138         for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    139             this->writef("%s%s", separator, param->fName.c_str());
    140             separator = ", ";
    141         }
    142         this->writeExtraConstructorParams(separator);
    143         this->writef("));\n"
    144                      "    }\n");
    145     }
    146 }
    147 
    148 void HCodeGenerator::failOnSection(const char* section, const char* msg) {
    149     std::vector<const Section*> s = fSectionAndParameterHelper.getSections(section);
    150     if (s.size()) {
    151         fErrors.error(s[0]->fPosition, String("@") + section + " " + msg);
    152     }
    153 }
    154 
    155 void HCodeGenerator::writeConstructor() {
    156     if (this->writeSection(CONSTRUCTOR_SECTION)) {
    157         const char* msg = "may not be present when constructor is overridden";
    158         this->failOnSection(CONSTRUCTOR_CODE_SECTION, msg);
    159         this->failOnSection(CONSTRUCTOR_PARAMS_SECTION, msg);
    160         this->failOnSection(COORD_TRANSFORM_SECTION, msg);
    161         this->failOnSection(INITIALIZERS_SECTION, msg);
    162         this->failOnSection(OPTIMIZATION_FLAGS_SECTION, msg);
    163     }
    164     this->writef("    %s(", fFullName.c_str());
    165     const char* separator = "";
    166     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    167         this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
    168                      param->fName.c_str());
    169         separator = ", ";
    170     }
    171     this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
    172     this->writef(")\n"
    173                  "    : INHERITED(");
    174     if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, "(OptimizationFlags) ")) {
    175         this->writef("kNone_OptimizationFlags");
    176     }
    177     this->writef(")");
    178     this->writeSection(INITIALIZERS_SECTION, "\n    , ");
    179     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    180         const char* name = param->fName.c_str();
    181         if (param->fType.kind() == Type::kSampler_Kind) {
    182             this->writef("\n    , %s(std::move(%s)", FieldName(name).c_str(), name);
    183             for (const Section* s : fSectionAndParameterHelper.getSections(
    184                                                                           SAMPLER_PARAMS_SECTION)) {
    185                 if (s->fArgument == name) {
    186                     this->writef(", %s", s->fText.c_str());
    187                 }
    188             }
    189             this->writef(")");
    190         } else {
    191             this->writef("\n    , %s(%s)", FieldName(name).c_str(), name);
    192         }
    193     }
    194     for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
    195         String field = FieldName(s->fArgument.c_str());
    196         this->writef("\n    , %sCoordTransform(%s, %s.proxy())", field.c_str(), s->fText.c_str(),
    197                      field.c_str());
    198     }
    199     this->writef(" {\n");
    200     this->writeSection(CONSTRUCTOR_CODE_SECTION);
    201     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    202         if (param->fType.kind() == Type::kSampler_Kind) {
    203             this->writef("        this->addTextureSampler(&%s);\n",
    204                          FieldName(param->fName.c_str()).c_str());
    205         }
    206     }
    207     for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
    208         String field = FieldName(s->fArgument.c_str());
    209         this->writef("        this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
    210     }
    211     this->writef("        this->initClassID<%s>();\n"
    212                  "    }\n",
    213                  fFullName.c_str());
    214 }
    215 
    216 void HCodeGenerator::writeFields() {
    217     this->writeSection(FIELDS_SECTION);
    218     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    219         const char* name = param->fName.c_str();
    220         this->writef("    %s %s;\n", FieldType(param->fType).c_str(), FieldName(name).c_str());
    221     }
    222     for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
    223         this->writef("    GrCoordTransform %sCoordTransform;\n",
    224                      FieldName(s->fArgument.c_str()).c_str());
    225     }
    226 }
    227 
    228 bool HCodeGenerator::generateCode() {
    229     this->writef(kFragmentProcessorHeader, fFullName.c_str());
    230     this->writef("#ifndef %s_DEFINED\n"
    231                  "#define %s_DEFINED\n",
    232                  fFullName.c_str(),
    233                  fFullName.c_str());
    234     this->writef("#include \"SkTypes.h\"\n"
    235                  "#if SK_SUPPORT_GPU\n");
    236     this->writeSection(HEADER_SECTION);
    237     this->writef("#include \"GrFragmentProcessor.h\"\n"
    238                  "#include \"GrCoordTransform.h\"\n"
    239                  "#include \"GrColorSpaceXform.h\"\n"
    240                  "#include \"effects/GrProxyMove.h\"\n");
    241     this->writef("class %s : public GrFragmentProcessor {\n"
    242                  "public:\n",
    243                  fFullName.c_str());
    244     this->writeSection(CLASS_SECTION);
    245     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    246         if (param->fType.kind() == Type::kSampler_Kind) {
    247             continue;
    248         }
    249         const char* name = param->fName.c_str();
    250         this->writef("    %s %s() const { return %s; }\n",
    251                      FieldType(param->fType).c_str(), name, FieldName(name).c_str());
    252     }
    253     this->writeMake();
    254     this->writef("    const char* name() const override { return \"%s\"; }\n"
    255                  "private:\n",
    256                  fName.c_str());
    257     this->writeConstructor();
    258     this->writef("    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
    259                  "    void onGetGLSLProcessorKey(const GrShaderCaps&,"
    260                                                 "GrProcessorKeyBuilder*) const override;\n"
    261                  "    bool onIsEqual(const GrFragmentProcessor&) const override;\n"
    262                  "    GR_DECLARE_FRAGMENT_PROCESSOR_TEST\n");
    263     this->writeFields();
    264     this->writef("    typedef GrFragmentProcessor INHERITED;\n"
    265                 "};\n");
    266     this->writeSection(HEADER_END_SECTION);
    267     this->writef("#endif\n"
    268                  "#endif\n");
    269     return 0 == fErrors.errorCount();
    270 }
    271 
    272 } // namespace
    273