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 "SkSLCPPCodeGenerator.h"
      9 
     10 #include "SkSLCompiler.h"
     11 #include "SkSLHCodeGenerator.h"
     12 
     13 namespace SkSL {
     14 
     15 static bool needs_uniform_var(const Variable& var) {
     16     return (var.fModifiers.fFlags & Modifiers::kUniform_Flag) &&
     17            strcmp(var.fType.fName.c_str(), "colorSpaceXform");
     18 }
     19 
     20 CPPCodeGenerator::CPPCodeGenerator(const Context* context, const Program* program,
     21                                    ErrorReporter* errors, String name, OutputStream* out)
     22 : INHERITED(context, program, errors, out)
     23 , fName(std::move(name))
     24 , fFullName(String::printf("Gr%s", fName.c_str()))
     25 , fSectionAndParameterHelper(*program, *errors) {
     26     fLineEnding = "\\n";
     27 }
     28 
     29 void CPPCodeGenerator::writef(const char* s, va_list va) {
     30     static constexpr int BUFFER_SIZE = 1024;
     31     va_list copy;
     32     va_copy(copy, va);
     33     char buffer[BUFFER_SIZE];
     34     int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
     35     if (length < BUFFER_SIZE) {
     36         fOut->write(buffer, length);
     37     } else {
     38         std::unique_ptr<char[]> heap(new char[length + 1]);
     39         vsprintf(heap.get(), s, copy);
     40         fOut->write(heap.get(), length);
     41     }
     42 }
     43 
     44 void CPPCodeGenerator::writef(const char* s, ...) {
     45     va_list va;
     46     va_start(va, s);
     47     this->writef(s, va);
     48     va_end(va);
     49 }
     50 
     51 void CPPCodeGenerator::writeHeader() {
     52 }
     53 
     54 void CPPCodeGenerator::writePrecisionModifier() {
     55 }
     56 
     57 void CPPCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
     58                                              Precedence parentPrecedence) {
     59     if (b.fOperator == Token::PERCENT) {
     60         // need to use "%%" instead of "%" b/c the code will be inside of a printf
     61         Precedence precedence = GetBinaryPrecedence(b.fOperator);
     62         if (precedence >= parentPrecedence) {
     63             this->write("(");
     64         }
     65         this->writeExpression(*b.fLeft, precedence);
     66         this->write(" %% ");
     67         this->writeExpression(*b.fRight, precedence);
     68         if (precedence >= parentPrecedence) {
     69             this->write(")");
     70         }
     71     } else {
     72         INHERITED::writeBinaryExpression(b, parentPrecedence);
     73     }
     74 }
     75 
     76 void CPPCodeGenerator::writeIndexExpression(const IndexExpression& i) {
     77     const Expression& base = *i.fBase;
     78     if (base.fKind == Expression::kVariableReference_Kind) {
     79         int builtin = ((VariableReference&) base).fVariable.fModifiers.fLayout.fBuiltin;
     80         if (SK_TRANSFORMEDCOORDS2D_BUILTIN == builtin) {
     81             this->write("%s");
     82             if (i.fIndex->fKind != Expression::kIntLiteral_Kind) {
     83                 fErrors.error(i.fIndex->fPosition,
     84                               "index into sk_TransformedCoords2D must be an integer literal");
     85                 return;
     86             }
     87             int64_t index = ((IntLiteral&) *i.fIndex).fValue;
     88             String name = "sk_TransformedCoords2D_" + to_string(index);
     89             fFormatArgs.push_back(name + ".c_str()");
     90             if (fWrittenTransformedCoords.find(index) == fWrittenTransformedCoords.end()) {
     91                 fExtraEmitCodeCode += "        SkSL::String " + name +
     92                                       " = fragBuilder->ensureCoords2D(args.fTransformedCoords[" +
     93                                       to_string(index) + "]);\n";
     94                 fWrittenTransformedCoords.insert(index);
     95             }
     96             return;
     97         } else if (SK_TEXTURESAMPLERS_BUILTIN == builtin) {
     98             this->write("%s");
     99             if (i.fIndex->fKind != Expression::kIntLiteral_Kind) {
    100                 fErrors.error(i.fIndex->fPosition,
    101                               "index into sk_TextureSamplers must be an integer literal");
    102                 return;
    103             }
    104             int64_t index = ((IntLiteral&) *i.fIndex).fValue;
    105             fFormatArgs.push_back("        fragBuilder->getProgramBuilder()->samplerVariable("
    106                                             "args.fTexSamplers[" + to_string(index) + "]).c_str()");
    107             return;
    108         }
    109     }
    110     INHERITED::writeIndexExpression(i);
    111 }
    112 
    113 static const char* default_value(const Type& type) {
    114     const char* name = type.name().c_str();
    115     if (!strcmp(name, "float")) {
    116         return "0.0";
    117     } else if (!strcmp(name, "vec2")) {
    118         return "vec2(0.0)";
    119     } else if (!strcmp(name, "vec3")) {
    120         return "vec3(0.0)";
    121     } else if (!strcmp(name, "vec4")) {
    122         return "vec4(0.0)";
    123     } else if (!strcmp(name, "mat4") || !strcmp(name, "colorSpaceXform")) {
    124         return "mat4(1.0)";
    125     }
    126     ABORT("unsupported default_value type\n");
    127 }
    128 
    129 static bool is_private(const Variable& var) {
    130     return !(var.fModifiers.fFlags & Modifiers::kUniform_Flag) &&
    131            !(var.fModifiers.fFlags & Modifiers::kIn_Flag) &&
    132            var.fStorage == Variable::kGlobal_Storage &&
    133            var.fModifiers.fLayout.fBuiltin == -1;
    134 }
    135 
    136 void CPPCodeGenerator::writeRuntimeValue(const Type& type, const String& cppCode) {
    137     if (type == *fContext.fFloat_Type) {
    138         this->write("%f");
    139         fFormatArgs.push_back(cppCode);
    140     } else if (type == *fContext.fInt_Type) {
    141         this->write("%d");
    142         fFormatArgs.push_back(cppCode);
    143     } else if (type == *fContext.fBool_Type) {
    144         this->write("%s");
    145         fFormatArgs.push_back("(" + cppCode + " ? \"true\" : \"false\")");
    146     } else if (type == *fContext.fVec2_Type) {
    147         this->write("vec2(%f, %f)");
    148         fFormatArgs.push_back(cppCode + ".fX");
    149         fFormatArgs.push_back(cppCode + ".fY");
    150     } else {
    151         printf("%s\n", type.name().c_str());
    152         ABORT("unsupported runtime value type\n");
    153     }
    154 }
    155 
    156 void CPPCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
    157     if (is_private(var)) {
    158         this->writeRuntimeValue(var.fType, var.fName);
    159     } else {
    160         this->writeExpression(value, kTopLevel_Precedence);
    161     }
    162 }
    163 
    164 String CPPCodeGenerator::getSamplerHandle(const Variable& var) {
    165     int samplerCount = 0;
    166     for (const auto param : fSectionAndParameterHelper.getParameters()) {
    167         if (&var == param) {
    168             return "args.fTexSamplers[" + to_string(samplerCount) + "]";
    169         }
    170         if (param->fType.kind() == Type::kSampler_Kind) {
    171             ++samplerCount;
    172         }
    173     }
    174     ABORT("should have found sampler in parameters\n");
    175 }
    176 
    177 void CPPCodeGenerator::writeVariableReference(const VariableReference& ref) {
    178     switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
    179         case SK_INCOLOR_BUILTIN:
    180             this->write("%s");
    181             fFormatArgs.push_back(String("args.fInputColor ? args.fInputColor : \"vec4(1)\""));
    182             break;
    183         case SK_OUTCOLOR_BUILTIN:
    184             this->write("%s");
    185             fFormatArgs.push_back(String("args.fOutputColor"));
    186             break;
    187         default:
    188             if (ref.fVariable.fType.kind() == Type::kSampler_Kind) {
    189                 this->write("%s");
    190                 fFormatArgs.push_back("fragBuilder->getProgramBuilder()->samplerVariable(" +
    191                                       this->getSamplerHandle(ref.fVariable) + ").c_str()");
    192                 return;
    193             }
    194             if (ref.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag) {
    195                 this->write("%s");
    196                 String name = ref.fVariable.fName;
    197                 String var;
    198                 if (ref.fVariable.fType == *fContext.fColorSpaceXform_Type) {
    199                     ASSERT(fNeedColorSpaceHelper);
    200                     var = String::printf("fColorSpaceHelper.isValid() ? "
    201                                          "args.fUniformHandler->getUniformCStr("
    202                                                   "fColorSpaceHelper.gamutXformUniform()) : \"%s\"",
    203                            default_value(ref.fVariable.fType));
    204                 } else {
    205                     var = String::printf("args.fUniformHandler->getUniformCStr(%sVar)",
    206                                          HCodeGenerator::FieldName(name.c_str()).c_str());
    207                 }
    208                 String code;
    209                 if (ref.fVariable.fModifiers.fLayout.fWhen.size()) {
    210                     code = String::printf("%sVar.isValid() ? %s : \"%s\"",
    211                                           HCodeGenerator::FieldName(name.c_str()).c_str(),
    212                                           var.c_str(),
    213                                           default_value(ref.fVariable.fType));
    214                 } else {
    215                     code = var;
    216                 }
    217                 fFormatArgs.push_back(code);
    218             } else if (SectionAndParameterHelper::IsParameter(ref.fVariable)) {
    219                 const char* name = ref.fVariable.fName.c_str();
    220                 this->writeRuntimeValue(ref.fVariable.fType,
    221                                         String::printf("_outer.%s()", name).c_str());
    222             } else {
    223                 this->write(ref.fVariable.fName.c_str());
    224             }
    225     }
    226 }
    227 
    228 void CPPCodeGenerator::writeIfStatement(const IfStatement& s) {
    229     if (s.fIsStatic) {
    230         this->write("@");
    231     }
    232     INHERITED::writeIfStatement(s);
    233 }
    234 
    235 void CPPCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
    236     if (s.fIsStatic) {
    237         this->write("@");
    238     }
    239     INHERITED::writeSwitchStatement(s);
    240 }
    241 
    242 void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) {
    243     if (c.fFunction.fBuiltin && c.fFunction.fName == "COLORSPACE") {
    244         String tmpVar = "_tmpVar" + to_string(++fVarCount);
    245         fFunctionHeader += "vec4 " + tmpVar + ";";
    246         ASSERT(c.fArguments.size() == 2);
    247         this->write("%s");
    248         fFormatArgs.push_back("fColorSpaceHelper.isValid() ? \"(" + tmpVar + " = \" : \"\"");
    249         this->writeExpression(*c.fArguments[0], kTopLevel_Precedence);
    250         ASSERT(c.fArguments[1]->fKind == Expression::kVariableReference_Kind);
    251         String xform("args.fUniformHandler->getUniformCStr(fColorSpaceHelper.gamutXformUniform())");
    252         this->write("%s");
    253         fFormatArgs.push_back("fColorSpaceHelper.isValid() ? SkStringPrintf(\", vec4(clamp((%s * vec4(" + tmpVar + ".rgb, 1.0)).rgb, 0.0, " + tmpVar +
    254                               ".a), " + tmpVar + ".a))\", " + xform + ").c_str() : \"\"");
    255         return;
    256     }
    257     INHERITED::writeFunctionCall(c);
    258     if (c.fFunction.fBuiltin && c.fFunction.fName == "texture") {
    259         this->write(".%s");
    260         ASSERT(c.fArguments.size() >= 1);
    261         ASSERT(c.fArguments[0]->fKind == Expression::kVariableReference_Kind);
    262         String sampler = this->getSamplerHandle(((VariableReference&) *c.fArguments[0]).fVariable);
    263         fFormatArgs.push_back("fragBuilder->getProgramBuilder()->samplerSwizzle(" + sampler +
    264                               ").c_str()");
    265     }
    266 }
    267 
    268 void CPPCodeGenerator::writeFunction(const FunctionDefinition& f) {
    269     if (f.fDeclaration.fName == "main") {
    270         fFunctionHeader = "";
    271         OutputStream* oldOut = fOut;
    272         StringStream buffer;
    273         fOut = &buffer;
    274         for (const auto& s : ((Block&) *f.fBody).fStatements) {
    275             this->writeStatement(*s);
    276             this->writeLine();
    277         }
    278 
    279         fOut = oldOut;
    280         this->write(fFunctionHeader);
    281         this->write(buffer.str());
    282     } else {
    283         INHERITED::writeFunction(f);
    284     }
    285 }
    286 
    287 void CPPCodeGenerator::writeSetting(const Setting& s) {
    288     static constexpr const char* kPrefix = "sk_Args.";
    289     if (!strncmp(s.fName.c_str(), kPrefix, strlen(kPrefix))) {
    290         const char* name = s.fName.c_str() + strlen(kPrefix);
    291         this->writeRuntimeValue(s.fType, HCodeGenerator::FieldName(name).c_str());
    292     } else {
    293         this->write(s.fName.c_str());
    294     }
    295 }
    296 
    297 void CPPCodeGenerator::writeSection(const char* name, const char* prefix) {
    298     const Section* s = fSectionAndParameterHelper.getSection(name);
    299     if (s) {
    300         this->writef("%s%s", prefix, s->fText.c_str());
    301     }
    302 }
    303 
    304 void CPPCodeGenerator::writeProgramElement(const ProgramElement& p) {
    305     if (p.fKind == ProgramElement::kSection_Kind) {
    306         return;
    307     }
    308     if (p.fKind == ProgramElement::kVar_Kind) {
    309         const VarDeclarations& decls = (const VarDeclarations&) p;
    310         if (!decls.fVars.size()) {
    311             return;
    312         }
    313         const Variable& var = *((VarDeclaration&) *decls.fVars[0]).fVar;
    314         if (var.fModifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kUniform_Flag) ||
    315             -1 != var.fModifiers.fLayout.fBuiltin) {
    316             return;
    317         }
    318     }
    319     INHERITED::writeProgramElement(p);
    320 }
    321 
    322 void CPPCodeGenerator::addUniform(const Variable& var) {
    323     if (!needs_uniform_var(var)) {
    324         return;
    325     }
    326     const char* precision;
    327     if (var.fModifiers.fFlags & Modifiers::kHighp_Flag) {
    328         precision = "kHigh_GrSLPrecision";
    329     } else if (var.fModifiers.fFlags & Modifiers::kMediump_Flag) {
    330         precision = "kMedium_GrSLPrecision";
    331     } else if (var.fModifiers.fFlags & Modifiers::kLowp_Flag) {
    332         precision = "kLow_GrSLPrecision";
    333     } else {
    334         precision = "kDefault_GrSLPrecision";
    335     }
    336     const char* type;
    337     if (var.fType == *fContext.fFloat_Type) {
    338         type = "kFloat_GrSLType";
    339     } else if (var.fType == *fContext.fVec2_Type) {
    340         type = "kVec2f_GrSLType";
    341     } else if (var.fType == *fContext.fVec4_Type) {
    342         type = "kVec4f_GrSLType";
    343     } else if (var.fType == *fContext.fMat4x4_Type ||
    344                var.fType == *fContext.fColorSpaceXform_Type) {
    345         type = "kMat44f_GrSLType";
    346     } else {
    347         ABORT("unsupported uniform type: %s %s;\n", var.fType.name().c_str(), var.fName.c_str());
    348     }
    349     if (var.fModifiers.fLayout.fWhen.size()) {
    350         this->writef("        if (%s) {\n    ", var.fModifiers.fLayout.fWhen.c_str());
    351     }
    352     const char* name = var.fName.c_str();
    353     this->writef("        %sVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, %s, "
    354                  "%s, \"%s\");\n", HCodeGenerator::FieldName(name).c_str(), type, precision, name);
    355     if (var.fModifiers.fLayout.fWhen.size()) {
    356         this->write("        }\n");
    357     }
    358 }
    359 
    360 void CPPCodeGenerator::writePrivateVars() {
    361     for (const auto& p : fProgram.fElements) {
    362         if (ProgramElement::kVar_Kind == p->fKind) {
    363             const VarDeclarations* decls = (const VarDeclarations*) p.get();
    364             for (const auto& raw : decls->fVars) {
    365                 VarDeclaration& decl = (VarDeclaration&) *raw;
    366                 if (is_private(*decl.fVar)) {
    367                     this->writef("%s %s;\n",
    368                                  HCodeGenerator::FieldType(decl.fVar->fType).c_str(),
    369                                  decl.fVar->fName.c_str());
    370                 }
    371             }
    372         }
    373     }
    374 }
    375 
    376 void CPPCodeGenerator::writePrivateVarValues() {
    377     for (const auto& p : fProgram.fElements) {
    378         if (ProgramElement::kVar_Kind == p->fKind) {
    379             const VarDeclarations* decls = (const VarDeclarations*) p.get();
    380             for (const auto& raw : decls->fVars) {
    381                 VarDeclaration& decl = (VarDeclaration&) *raw;
    382                 if (is_private(*decl.fVar) && decl.fValue) {
    383                     this->writef("%s = %s;\n",
    384                                  decl.fVar->fName.c_str(),
    385                                  decl.fValue->description().c_str());
    386                 }
    387             }
    388         }
    389     }
    390 }
    391 
    392 bool CPPCodeGenerator::writeEmitCode(std::vector<const Variable*>& uniforms) {
    393     this->write("    void emitCode(EmitArgs& args) override {\n"
    394                 "        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;\n");
    395     this->writef("        const %s& _outer = args.fFp.cast<%s>();\n"
    396                  "        (void) _outer;\n",
    397                  fFullName.c_str(), fFullName.c_str());
    398     this->writePrivateVarValues();
    399     for (const auto u : uniforms) {
    400         this->addUniform(*u);
    401         if (u->fType == *fContext.fColorSpaceXform_Type) {
    402             if (fNeedColorSpaceHelper) {
    403                 fErrors.error(u->fPosition, "only a single ColorSpaceXform is supported");
    404             }
    405             fNeedColorSpaceHelper = true;
    406             this->writef("        fColorSpaceHelper.emitCode(args.fUniformHandler, "
    407                                                             "_outer.%s().get());\n",
    408                          u->fName.c_str());
    409         }
    410     }
    411     this->writeSection(EMIT_CODE_SECTION);
    412     OutputStream* old = fOut;
    413     StringStream mainBuffer;
    414     fOut = &mainBuffer;
    415     bool result = INHERITED::generateCode();
    416     fOut = old;
    417     this->writef("%s        fragBuilder->codeAppendf(\"%s\"", fExtraEmitCodeCode.c_str(),
    418                  mainBuffer.str().c_str());
    419     for (const auto& s : fFormatArgs) {
    420         this->writef(", %s", s.c_str());
    421     }
    422     this->write(");\n"
    423                 "    }\n");
    424     return result;
    425 }
    426 
    427 void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
    428     const char* fullName = fFullName.c_str();
    429     const Section* section = fSectionAndParameterHelper.getSection(SET_DATA_SECTION);
    430     const char* pdman = section ? section->fArgument.c_str() : "pdman";
    431     this->writef("    void onSetData(const GrGLSLProgramDataManager& %s, "
    432                                     "const GrFragmentProcessor& _proc) override {\n",
    433                  pdman);
    434     bool wroteProcessor = false;
    435     for (const auto u : uniforms) {
    436         if (u->fModifiers.fFlags & Modifiers::kIn_Flag) {
    437             if (!wroteProcessor) {
    438                 this->writef("        const %s& _outer = _proc.cast<%s>();\n", fullName, fullName);
    439                 wroteProcessor = true;
    440                 this->writef("        {\n");
    441             }
    442             const char* name = u->fName.c_str();
    443             if (u->fType == *fContext.fVec4_Type) {
    444                 this->writef("        const SkRect %sValue = _outer.%s();\n"
    445                              "        %s.set4fv(%sVar, 1, (float*) &%sValue);\n",
    446                              name, name, pdman, HCodeGenerator::FieldName(name).c_str(), name);
    447             } else if (u->fType == *fContext.fMat4x4_Type) {
    448                 this->writef("        float %sValue[16];\n"
    449                              "        _outer.%s().asColMajorf(%sValue);\n"
    450                              "        %s.setMatrix4f(%sVar, %sValue);\n",
    451                              name, name, name, pdman, HCodeGenerator::FieldName(name).c_str(),
    452                              name);
    453             } else if (u->fType == *fContext.fColorSpaceXform_Type) {
    454                 ASSERT(fNeedColorSpaceHelper);
    455                 this->writef("        if (fColorSpaceHelper.isValid()) {\n"
    456                              "            fColorSpaceHelper.setData(%s, _outer.%s().get());\n"
    457                              "        }\n",
    458                              pdman, name);
    459             } else {
    460                 this->writef("        %s.set1f(%sVar, _outer.%s());\n",
    461                              pdman, HCodeGenerator::FieldName(name).c_str(), name);
    462             }
    463         }
    464     }
    465     if (wroteProcessor) {
    466         this->writef("        }\n");
    467     }
    468     if (section) {
    469         for (const auto& p : fProgram.fElements) {
    470             if (ProgramElement::kVar_Kind == p->fKind) {
    471                 const VarDeclarations* decls = (const VarDeclarations*) p.get();
    472                 for (const auto& raw : decls->fVars) {
    473                     VarDeclaration& decl = (VarDeclaration&) *raw;
    474                     if (needs_uniform_var(*decl.fVar)) {
    475                         const char* name = decl.fVar->fName.c_str();
    476                         this->writef("        UniformHandle& %s = %sVar;\n"
    477                                      "        (void) %s;\n",
    478                                      name, HCodeGenerator::FieldName(name).c_str(), name);
    479                     } else if (SectionAndParameterHelper::IsParameter(*decl.fVar)) {
    480                         const char* name = decl.fVar->fName.c_str();
    481                         if (!wroteProcessor) {
    482                             this->writef("        const %s& _outer = _proc.cast<%s>();\n", fullName,
    483                                          fullName);
    484                             wroteProcessor = true;
    485                         }
    486                         this->writef("        auto %s = _outer.%s();\n"
    487                                      "        (void) %s;\n",
    488                                      name, name, name);
    489                     }
    490                 }
    491             }
    492         }
    493         this->writeSection(SET_DATA_SECTION);
    494     }
    495     this->write("    }\n");
    496 }
    497 
    498 void CPPCodeGenerator::writeTest() {
    499     const Section* test = fSectionAndParameterHelper.getSection(TEST_CODE_SECTION);
    500     if (test) {
    501         this->writef("GR_DEFINE_FRAGMENT_PROCESSOR_TEST(%s);\n"
    502                      "#if GR_TEST_UTILS\n"
    503                      "sk_sp<GrFragmentProcessor> %s::TestCreate(GrProcessorTestData* %s) {\n",
    504                      fFullName.c_str(),
    505                      fFullName.c_str(),
    506                      test->fArgument.c_str());
    507         this->writeSection(TEST_CODE_SECTION);
    508         this->write("}\n"
    509                     "#endif\n");
    510     }
    511 }
    512 
    513 void CPPCodeGenerator::writeGetKey() {
    514     this->writef("void %s::onGetGLSLProcessorKey(const GrShaderCaps& caps, "
    515                                                 "GrProcessorKeyBuilder* b) const {\n",
    516                  fFullName.c_str());
    517     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    518         const char* name = param->fName.c_str();
    519         if (param->fType == *fContext.fColorSpaceXform_Type) {
    520             this->writef("    b->add32(GrColorSpaceXform::XformKey(%s.get()));\n",
    521                          HCodeGenerator::FieldName(name).c_str());
    522             continue;
    523         }
    524         if (param->fModifiers.fLayout.fKey != Layout::kNo_Key &&
    525             (param->fModifiers.fFlags & Modifiers::kUniform_Flag)) {
    526             fErrors.error(param->fPosition,
    527                           "layout(key) may not be specified on uniforms");
    528         }
    529         switch (param->fModifiers.fLayout.fKey) {
    530             case Layout::kKey_Key:
    531                 if (param->fType == *fContext.fMat4x4_Type) {
    532                     ABORT("no automatic key handling for mat4\n");
    533                 } else if (param->fType == *fContext.fVec2_Type) {
    534                     this->writef("    b->add32(%s.fX);\n",
    535                                  HCodeGenerator::FieldName(name).c_str());
    536                     this->writef("    b->add32(%s.fY);\n",
    537                                  HCodeGenerator::FieldName(name).c_str());
    538                 } else if (param->fType == *fContext.fVec4_Type) {
    539                     this->writef("    b->add32(%s.x());\n",
    540                                  HCodeGenerator::FieldName(name).c_str());
    541                     this->writef("    b->add32(%s.y());\n",
    542                                  HCodeGenerator::FieldName(name).c_str());
    543                     this->writef("    b->add32(%s.width());\n",
    544                                  HCodeGenerator::FieldName(name).c_str());
    545                     this->writef("    b->add32(%s.height());\n",
    546                                  HCodeGenerator::FieldName(name).c_str());
    547                 } else {
    548                     this->writef("    b->add32(%s);\n",
    549                                  HCodeGenerator::FieldName(name).c_str());
    550                 }
    551                 break;
    552             case Layout::kIdentity_Key:
    553                 if (param->fType.kind() != Type::kMatrix_Kind) {
    554                     fErrors.error(param->fPosition,
    555                                   "layout(key=identity) requires matrix type");
    556                 }
    557                 this->writef("    b->add32(%s.isIdentity() ? 1 : 0);\n",
    558                              HCodeGenerator::FieldName(name).c_str());
    559                 break;
    560             case Layout::kNo_Key:
    561                 break;
    562         }
    563     }
    564     this->write("}\n");
    565 }
    566 
    567 bool CPPCodeGenerator::generateCode() {
    568     std::vector<const Variable*> uniforms;
    569     for (const auto& p : fProgram.fElements) {
    570         if (ProgramElement::kVar_Kind == p->fKind) {
    571             const VarDeclarations* decls = (const VarDeclarations*) p.get();
    572             for (const auto& raw : decls->fVars) {
    573                 VarDeclaration& decl = (VarDeclaration&) *raw;
    574                 if ((decl.fVar->fModifiers.fFlags & Modifiers::kUniform_Flag) &&
    575                            decl.fVar->fType.kind() != Type::kSampler_Kind) {
    576                     uniforms.push_back(decl.fVar);
    577                 }
    578             }
    579         }
    580     }
    581     const char* baseName = fName.c_str();
    582     const char* fullName = fFullName.c_str();
    583     this->writef(kFragmentProcessorHeader, fullName);
    584     this->writef("#include \"%s.h\"\n"
    585                  "#if SK_SUPPORT_GPU\n", fullName);
    586     this->writeSection(CPP_SECTION);
    587     this->writef("#include \"glsl/GrGLSLColorSpaceXformHelper.h\"\n"
    588                  "#include \"glsl/GrGLSLFragmentProcessor.h\"\n"
    589                  "#include \"glsl/GrGLSLFragmentShaderBuilder.h\"\n"
    590                  "#include \"glsl/GrGLSLProgramBuilder.h\"\n"
    591                  "#include \"SkSLCPP.h\"\n"
    592                  "#include \"SkSLUtil.h\"\n"
    593                  "class GrGLSL%s : public GrGLSLFragmentProcessor {\n"
    594                  "public:\n"
    595                  "    GrGLSL%s() {}\n",
    596                  baseName, baseName);
    597     bool result = this->writeEmitCode(uniforms);
    598     this->write("private:\n");
    599     this->writeSetData(uniforms);
    600     this->writePrivateVars();
    601     for (const auto& u : uniforms) {
    602         const char* name = u->fName.c_str();
    603         if (needs_uniform_var(*u) && !(u->fModifiers.fFlags & Modifiers::kIn_Flag)) {
    604             this->writef("    UniformHandle %sVar;\n", HCodeGenerator::FieldName(name).c_str());
    605         }
    606     }
    607     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    608         const char* name = param->fName.c_str();
    609         if (needs_uniform_var(*param)) {
    610             this->writef("    UniformHandle %sVar;\n", HCodeGenerator::FieldName(name).c_str());
    611         }
    612     }
    613     if (fNeedColorSpaceHelper) {
    614         this->write("    GrGLSLColorSpaceXformHelper fColorSpaceHelper;\n");
    615     }
    616     this->writef("};\n"
    617                  "GrGLSLFragmentProcessor* %s::onCreateGLSLInstance() const {\n"
    618                  "    return new GrGLSL%s();\n"
    619                  "}\n",
    620                  fullName, baseName);
    621     this->writeGetKey();
    622     this->writef("bool %s::onIsEqual(const GrFragmentProcessor& other) const {\n"
    623                  "    const %s& that = other.cast<%s>();\n"
    624                  "    (void) that;\n",
    625                  fullName, fullName, fullName);
    626     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
    627         const char* name = param->fName.c_str();
    628         this->writef("    if (%s != that.%s) return false;\n",
    629                      HCodeGenerator::FieldName(name).c_str(),
    630                      HCodeGenerator::FieldName(name).c_str());
    631     }
    632     this->write("    return true;\n"
    633                 "}\n");
    634     this->writeTest();
    635     this->writeSection(CPP_END_SECTION);
    636     this->write("#endif\n");
    637     result &= 0 == fErrors.errorCount();
    638     return result;
    639 }
    640 
    641 } // namespace
    642