• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
needs_uniform_var(const Variable & var)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 
CPPCodeGenerator(const Context * context,const Program * program,ErrorReporter * errors,String name,OutputStream * out)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 
writef(const char * s,va_list va)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 
writef(const char * s,...)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 
writeHeader()51 void CPPCodeGenerator::writeHeader() {
52 }
53 
writePrecisionModifier()54 void CPPCodeGenerator::writePrecisionModifier() {
55 }
56 
writeBinaryExpression(const BinaryExpression & b,Precedence parentPrecedence)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 
writeIndexExpression(const IndexExpression & i)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 
default_value(const Type & type)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 
is_private(const Variable & var)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 
writeRuntimeValue(const Type & type,const String & cppCode)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 
writeVarInitializer(const Variable & var,const Expression & value)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 
getSamplerHandle(const Variable & var)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 
writeVariableReference(const VariableReference & ref)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 
writeIfStatement(const IfStatement & s)228 void CPPCodeGenerator::writeIfStatement(const IfStatement& s) {
229     if (s.fIsStatic) {
230         this->write("@");
231     }
232     INHERITED::writeIfStatement(s);
233 }
234 
writeSwitchStatement(const SwitchStatement & s)235 void CPPCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
236     if (s.fIsStatic) {
237         this->write("@");
238     }
239     INHERITED::writeSwitchStatement(s);
240 }
241 
writeFunctionCall(const FunctionCall & c)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 
writeFunction(const FunctionDefinition & f)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 
writeSetting(const Setting & s)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 
writeSection(const char * name,const char * prefix)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 
writeProgramElement(const ProgramElement & p)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 
addUniform(const Variable & var)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 
writePrivateVars()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 
writePrivateVarValues()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 
writeEmitCode(std::vector<const Variable * > & uniforms)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 
writeSetData(std::vector<const Variable * > & uniforms)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 
writeTest()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 
writeGetKey()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 
generateCode()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