• 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 "src/sksl/SkSLCPPCodeGenerator.h"
9 
10 #include "src/sksl/SkSLCPPUniformCTypes.h"
11 #include "src/sksl/SkSLCompiler.h"
12 #include "src/sksl/SkSLHCodeGenerator.h"
13 
14 #include <algorithm>
15 
16 namespace SkSL {
17 
needs_uniform_var(const Variable & var)18 static bool needs_uniform_var(const Variable& var) {
19     return (var.fModifiers.fFlags & Modifiers::kUniform_Flag) &&
20            var.fType.kind() != Type::kSampler_Kind;
21 }
22 
CPPCodeGenerator(const Context * context,const Program * program,ErrorReporter * errors,String name,OutputStream * out)23 CPPCodeGenerator::CPPCodeGenerator(const Context* context, const Program* program,
24                                    ErrorReporter* errors, String name, OutputStream* out)
25 : INHERITED(context, program, errors, out)
26 , fName(std::move(name))
27 , fFullName(String::printf("Gr%s", fName.c_str()))
28 , fSectionAndParameterHelper(*program, *errors) {
29     fLineEnding = "\\n";
30     fTextureFunctionOverride = "sample";
31 }
32 
writef(const char * s,va_list va)33 void CPPCodeGenerator::writef(const char* s, va_list va) {
34     static constexpr int BUFFER_SIZE = 1024;
35     va_list copy;
36     va_copy(copy, va);
37     char buffer[BUFFER_SIZE];
38     int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
39     if (length < BUFFER_SIZE) {
40         fOut->write(buffer, length);
41     } else {
42         std::unique_ptr<char[]> heap(new char[length + 1]);
43         vsprintf(heap.get(), s, copy);
44         fOut->write(heap.get(), length);
45     }
46     va_end(copy);
47 }
48 
writef(const char * s,...)49 void CPPCodeGenerator::writef(const char* s, ...) {
50     va_list va;
51     va_start(va, s);
52     this->writef(s, va);
53     va_end(va);
54 }
55 
writeHeader()56 void CPPCodeGenerator::writeHeader() {
57 }
58 
usesPrecisionModifiers() const59 bool CPPCodeGenerator::usesPrecisionModifiers() const {
60     return false;
61 }
62 
getTypeName(const Type & type)63 String CPPCodeGenerator::getTypeName(const Type& type) {
64     return type.name();
65 }
66 
writeBinaryExpression(const BinaryExpression & b,Precedence parentPrecedence)67 void CPPCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
68                                              Precedence parentPrecedence) {
69     if (b.fOperator == Token::PERCENT) {
70         // need to use "%%" instead of "%" b/c the code will be inside of a printf
71         Precedence precedence = GetBinaryPrecedence(b.fOperator);
72         if (precedence >= parentPrecedence) {
73             this->write("(");
74         }
75         this->writeExpression(*b.fLeft, precedence);
76         this->write(" %% ");
77         this->writeExpression(*b.fRight, precedence);
78         if (precedence >= parentPrecedence) {
79             this->write(")");
80         }
81     } else if (b.fLeft->fKind == Expression::kNullLiteral_Kind ||
82                b.fRight->fKind == Expression::kNullLiteral_Kind) {
83         const Variable* var;
84         if (b.fLeft->fKind != Expression::kNullLiteral_Kind) {
85             SkASSERT(b.fLeft->fKind == Expression::kVariableReference_Kind);
86             var = &((VariableReference&) *b.fLeft).fVariable;
87         } else {
88             SkASSERT(b.fRight->fKind == Expression::kVariableReference_Kind);
89             var = &((VariableReference&) *b.fRight).fVariable;
90         }
91         SkASSERT(var->fType.kind() == Type::kNullable_Kind &&
92                  var->fType.componentType() == *fContext.fFragmentProcessor_Type);
93         this->write("%s");
94         const char* op;
95         switch (b.fOperator) {
96             case Token::EQEQ:
97                 op = "<";
98                 break;
99             case Token::NEQ:
100                 op = ">=";
101                 break;
102             default:
103                 SkASSERT(false);
104         }
105         fFormatArgs.push_back("_outer." + String(var->fName) + "_index " + op + " 0 ? \"true\" "
106                               ": \"false\"");
107     } else {
108         INHERITED::writeBinaryExpression(b, parentPrecedence);
109     }
110 }
111 
writeIndexExpression(const IndexExpression & i)112 void CPPCodeGenerator::writeIndexExpression(const IndexExpression& i) {
113     const Expression& base = *i.fBase;
114     if (base.fKind == Expression::kVariableReference_Kind) {
115         int builtin = ((VariableReference&) base).fVariable.fModifiers.fLayout.fBuiltin;
116         if (SK_TRANSFORMEDCOORDS2D_BUILTIN == builtin) {
117             this->write("%s");
118             if (i.fIndex->fKind != Expression::kIntLiteral_Kind) {
119                 fErrors.error(i.fIndex->fOffset,
120                               "index into sk_TransformedCoords2D must be an integer literal");
121                 return;
122             }
123             int64_t index = ((IntLiteral&) *i.fIndex).fValue;
124             String name = "sk_TransformedCoords2D_" + to_string(index);
125             fFormatArgs.push_back(name + ".c_str()");
126             if (fWrittenTransformedCoords.find(index) == fWrittenTransformedCoords.end()) {
127                 addExtraEmitCodeLine("SkString " + name +
128                                      " = fragBuilder->ensureCoords2D(args.fTransformedCoords[" +
129                                      to_string(index) + "]);");
130                 fWrittenTransformedCoords.insert(index);
131             }
132             return;
133         } else if (SK_TEXTURESAMPLERS_BUILTIN == builtin) {
134             this->write("%s");
135             if (i.fIndex->fKind != Expression::kIntLiteral_Kind) {
136                 fErrors.error(i.fIndex->fOffset,
137                               "index into sk_TextureSamplers must be an integer literal");
138                 return;
139             }
140             int64_t index = ((IntLiteral&) *i.fIndex).fValue;
141             fFormatArgs.push_back("        fragBuilder->getProgramBuilder()->samplerVariable("
142                                             "args.fTexSamplers[" + to_string(index) + "])");
143             return;
144         }
145     }
146     INHERITED::writeIndexExpression(i);
147 }
148 
default_value(const Type & type)149 static String default_value(const Type& type) {
150     if (type.fName == "bool") {
151         return "false";
152     }
153     switch (type.kind()) {
154         case Type::kScalar_Kind: return "0";
155         case Type::kVector_Kind: return type.name() + "(0)";
156         case Type::kMatrix_Kind: return type.name() + "(1)";
157         default: ABORT("unsupported default_value type\n");
158     }
159 }
160 
default_value(const Variable & var)161 static String default_value(const Variable& var) {
162     if (var.fModifiers.fLayout.fCType == SkSL::Layout::CType::kSkPMColor4f) {
163         return "{SK_FloatNaN, SK_FloatNaN, SK_FloatNaN, SK_FloatNaN}";
164     }
165     return default_value(var.fType);
166 }
167 
is_private(const Variable & var)168 static bool is_private(const Variable& var) {
169     return !(var.fModifiers.fFlags & Modifiers::kUniform_Flag) &&
170            !(var.fModifiers.fFlags & Modifiers::kIn_Flag) &&
171            var.fStorage == Variable::kGlobal_Storage &&
172            var.fModifiers.fLayout.fBuiltin == -1;
173 }
174 
is_uniform_in(const Variable & var)175 static bool is_uniform_in(const Variable& var) {
176     return (var.fModifiers.fFlags & Modifiers::kUniform_Flag) &&
177            (var.fModifiers.fFlags & Modifiers::kIn_Flag) &&
178            var.fType.kind() != Type::kSampler_Kind;
179 }
180 
writeRuntimeValue(const Type & type,const Layout & layout,const String & cppCode)181 void CPPCodeGenerator::writeRuntimeValue(const Type& type, const Layout& layout,
182                                          const String& cppCode) {
183     if (type.isFloat()) {
184         this->write("%f");
185         fFormatArgs.push_back(cppCode);
186     } else if (type == *fContext.fInt_Type) {
187         this->write("%d");
188         fFormatArgs.push_back(cppCode);
189     } else if (type == *fContext.fBool_Type) {
190         this->write("%s");
191         fFormatArgs.push_back("(" + cppCode + " ? \"true\" : \"false\")");
192     } else if (type == *fContext.fFloat2_Type || type == *fContext.fHalf2_Type) {
193         this->write(type.name() + "(%f, %f)");
194         fFormatArgs.push_back(cppCode + ".fX");
195         fFormatArgs.push_back(cppCode + ".fY");
196     } else if (type == *fContext.fFloat4_Type || type == *fContext.fHalf4_Type) {
197         this->write(type.name() + "(%f, %f, %f, %f)");
198         switch (layout.fCType) {
199             case Layout::CType::kSkPMColor:
200                 fFormatArgs.push_back("SkGetPackedR32(" + cppCode + ") / 255.0");
201                 fFormatArgs.push_back("SkGetPackedG32(" + cppCode + ") / 255.0");
202                 fFormatArgs.push_back("SkGetPackedB32(" + cppCode + ") / 255.0");
203                 fFormatArgs.push_back("SkGetPackedA32(" + cppCode + ") / 255.0");
204                 break;
205             case Layout::CType::kSkPMColor4f:
206                 fFormatArgs.push_back(cppCode + ".fR");
207                 fFormatArgs.push_back(cppCode + ".fG");
208                 fFormatArgs.push_back(cppCode + ".fB");
209                 fFormatArgs.push_back(cppCode + ".fA");
210                 break;
211             case Layout::CType::kSkVector4:
212                 fFormatArgs.push_back(cppCode + ".fData[0]");
213                 fFormatArgs.push_back(cppCode + ".fData[1]");
214                 fFormatArgs.push_back(cppCode + ".fData[2]");
215                 fFormatArgs.push_back(cppCode + ".fData[3]");
216                 break;
217             case Layout::CType::kSkRect: // fall through
218             case Layout::CType::kDefault:
219                 fFormatArgs.push_back(cppCode + ".left()");
220                 fFormatArgs.push_back(cppCode + ".top()");
221                 fFormatArgs.push_back(cppCode + ".right()");
222                 fFormatArgs.push_back(cppCode + ".bottom()");
223                 break;
224             default:
225                 SkASSERT(false);
226         }
227     } else if (type.kind() == Type::kEnum_Kind) {
228         this->write("%d");
229         fFormatArgs.push_back("(int) " + cppCode);
230     } else if (type == *fContext.fInt4_Type ||
231                type == *fContext.fShort4_Type ||
232                type == *fContext.fByte4_Type) {
233         this->write(type.name() + "(%d, %d, %d, %d)");
234         fFormatArgs.push_back(cppCode + ".left()");
235         fFormatArgs.push_back(cppCode + ".top()");
236         fFormatArgs.push_back(cppCode + ".right()");
237         fFormatArgs.push_back(cppCode + ".bottom()");
238     } else {
239         printf("unsupported runtime value type '%s'\n", String(type.fName).c_str());
240         SkASSERT(false);
241     }
242 }
243 
writeVarInitializer(const Variable & var,const Expression & value)244 void CPPCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
245     if (is_private(var)) {
246         this->writeRuntimeValue(var.fType, var.fModifiers.fLayout, var.fName);
247     } else {
248         this->writeExpression(value, kTopLevel_Precedence);
249     }
250 }
251 
getSamplerHandle(const Variable & var)252 String CPPCodeGenerator::getSamplerHandle(const Variable& var) {
253     int samplerCount = 0;
254     for (const auto param : fSectionAndParameterHelper.getParameters()) {
255         if (&var == param) {
256             return "args.fTexSamplers[" + to_string(samplerCount) + "]";
257         }
258         if (param->fType.kind() == Type::kSampler_Kind) {
259             ++samplerCount;
260         }
261     }
262     ABORT("should have found sampler in parameters\n");
263 }
264 
writeIntLiteral(const IntLiteral & i)265 void CPPCodeGenerator::writeIntLiteral(const IntLiteral& i) {
266     this->write(to_string((int32_t) i.fValue));
267 }
268 
writeSwizzle(const Swizzle & swizzle)269 void CPPCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
270     if (fCPPMode) {
271         SkASSERT(swizzle.fComponents.size() == 1); // no support for multiple swizzle components yet
272         this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
273         switch (swizzle.fComponents[0]) {
274             case 0: this->write(".left()");   break;
275             case 1: this->write(".top()");    break;
276             case 2: this->write(".right()");  break;
277             case 3: this->write(".bottom()"); break;
278         }
279     } else {
280         INHERITED::writeSwizzle(swizzle);
281     }
282 }
283 
writeVariableReference(const VariableReference & ref)284 void CPPCodeGenerator::writeVariableReference(const VariableReference& ref) {
285     if (fCPPMode) {
286         this->write(ref.fVariable.fName);
287         return;
288     }
289     switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
290         case SK_INCOLOR_BUILTIN:
291             this->write("%s");
292             // EmitArgs.fInputColor is automatically set to half4(1) if
293             // no input was specified
294             fFormatArgs.push_back(String("args.fInputColor"));
295             break;
296         case SK_OUTCOLOR_BUILTIN:
297             this->write("%s");
298             fFormatArgs.push_back(String("args.fOutputColor"));
299             break;
300         case SK_WIDTH_BUILTIN:
301             this->write("sk_Width");
302             break;
303         case SK_HEIGHT_BUILTIN:
304             this->write("sk_Height");
305             break;
306         default:
307             if (ref.fVariable.fType.kind() == Type::kSampler_Kind) {
308                 this->write("%s");
309                 fFormatArgs.push_back("fragBuilder->getProgramBuilder()->samplerVariable(" +
310                                       this->getSamplerHandle(ref.fVariable) + ")");
311                 return;
312             }
313             if (ref.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag) {
314                 this->write("%s");
315                 String name = ref.fVariable.fName;
316                 String var = String::printf("args.fUniformHandler->getUniformCStr(%sVar)",
317                                             HCodeGenerator::FieldName(name.c_str()).c_str());
318                 String code;
319                 if (ref.fVariable.fModifiers.fLayout.fWhen.fLength) {
320                     code = String::printf("%sVar.isValid() ? %s : \"%s\"",
321                                           HCodeGenerator::FieldName(name.c_str()).c_str(),
322                                           var.c_str(),
323                                           default_value(ref.fVariable.fType).c_str());
324                 } else {
325                     code = var;
326                 }
327                 fFormatArgs.push_back(code);
328             } else if (SectionAndParameterHelper::IsParameter(ref.fVariable)) {
329                 String name(ref.fVariable.fName);
330                 this->writeRuntimeValue(ref.fVariable.fType, ref.fVariable.fModifiers.fLayout,
331                                         String::printf("_outer.%s", name.c_str()).c_str());
332             } else {
333                 this->write(ref.fVariable.fName);
334             }
335     }
336 }
337 
writeIfStatement(const IfStatement & s)338 void CPPCodeGenerator::writeIfStatement(const IfStatement& s) {
339     if (s.fIsStatic) {
340         this->write("@");
341     }
342     INHERITED::writeIfStatement(s);
343 }
344 
writeReturnStatement(const ReturnStatement & s)345 void CPPCodeGenerator::writeReturnStatement(const ReturnStatement& s) {
346     if (fInMain) {
347         fErrors.error(s.fOffset, "fragmentProcessor main() may not contain return statements");
348     }
349     INHERITED::writeReturnStatement(s);
350 }
351 
writeSwitchStatement(const SwitchStatement & s)352 void CPPCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
353     if (s.fIsStatic) {
354         this->write("@");
355     }
356     INHERITED::writeSwitchStatement(s);
357 }
358 
writeFieldAccess(const FieldAccess & access)359 void CPPCodeGenerator::writeFieldAccess(const FieldAccess& access) {
360     if (access.fBase->fType.name() == "fragmentProcessor") {
361         // Special field access on fragment processors are converted into function calls on
362         // GrFragmentProcessor's getters.
363         if (access.fBase->fKind != Expression::kVariableReference_Kind) {
364             fErrors.error(access.fBase->fOffset, "fragmentProcessor must be a reference\n");
365             return;
366         }
367 
368         const Type::Field& field = fContext.fFragmentProcessor_Type->fields()[access.fFieldIndex];
369         const Variable& var = ((const VariableReference&) *access.fBase).fVariable;
370         String cppAccess = String::printf("_outer.childProcessor(_outer.%s_index).%s()",
371                                           String(var.fName).c_str(),
372                                           String(field.fName).c_str());
373 
374         if (fCPPMode) {
375             this->write(cppAccess.c_str());
376         } else {
377             writeRuntimeValue(*field.fType, Layout(), cppAccess);
378         }
379         return;
380     }
381     INHERITED::writeFieldAccess(access);
382 }
383 
getChildFPIndex(const Variable & var) const384 int CPPCodeGenerator::getChildFPIndex(const Variable& var) const {
385     int index = 0;
386     bool found = false;
387     for (const auto& p : fProgram) {
388         if (ProgramElement::kVar_Kind == p.fKind) {
389             const VarDeclarations& decls = (const VarDeclarations&) p;
390             for (const auto& raw : decls.fVars) {
391                 const VarDeclaration& decl = (VarDeclaration&) *raw;
392                 if (decl.fVar == &var) {
393                     found = true;
394                 } else if (decl.fVar->fType.nonnullable() == *fContext.fFragmentProcessor_Type) {
395                     ++index;
396                 }
397             }
398         }
399         if (found) {
400             break;
401         }
402     }
403     SkASSERT(found);
404     return index;
405 }
406 
writeFunctionCall(const FunctionCall & c)407 void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) {
408     if (c.fFunction.fBuiltin && c.fFunction.fName == "sample" &&
409         c.fArguments[0]->fType.kind() != Type::Kind::kSampler_Kind) {
410         // Sanity checks that are detected by function definition in sksl_fp.inc
411         SkASSERT(c.fArguments.size() == 1 || c.fArguments.size() == 2);
412         SkASSERT("fragmentProcessor"  == c.fArguments[0]->fType.name() ||
413                  "fragmentProcessor?" == c.fArguments[0]->fType.name());
414 
415         // Actually fail during compilation if arguments with valid types are
416         // provided that are not variable references, since sample() is a
417         // special function that impacts code emission.
418         if (c.fArguments[0]->fKind != Expression::kVariableReference_Kind) {
419             fErrors.error(c.fArguments[0]->fOffset,
420                     "sample()'s fragmentProcessor argument must be a variable reference\n");
421             return;
422         }
423         if (c.fArguments.size() > 1) {
424             // Second argument must also be a half4 expression
425             SkASSERT("half4" == c.fArguments[1]->fType.name());
426         }
427         const Variable& child = ((const VariableReference&) *c.fArguments[0]).fVariable;
428         int index = getChildFPIndex(child);
429 
430         // Start a new extra emit code section so that the emitted child processor can depend on
431         // sksl variables defined in earlier sksl code.
432         this->newExtraEmitCodeBlock();
433 
434         // Set to the empty string when no input color parameter should be emitted, which means this
435         // must be properly formatted with a prefixed comma when the parameter should be inserted
436         // into the invokeChild() parameter list.
437         String inputArg;
438         if (c.fArguments.size() > 1) {
439             SkASSERT(c.fArguments.size() == 2);
440             // Use the invokeChild() variant that accepts an input color, so convert the 2nd
441             // argument's expression into C++ code that produces sksl stored in an SkString.
442             String inputName = "_input" + to_string(index);
443             addExtraEmitCodeLine(convertSKSLExpressionToCPP(*c.fArguments[1], inputName));
444 
445             // invokeChild() needs a char*
446             inputArg = ", " + inputName + ".c_str()";
447         }
448 
449         // Write the output handling after the possible input handling
450         String childName = "_sample" + to_string(c.fOffset);
451         addExtraEmitCodeLine("SkString " + childName + "(\"" + childName + "\");");
452         if (c.fArguments[0]->fType.kind() == Type::kNullable_Kind) {
453             addExtraEmitCodeLine("if (_outer." + String(child.fName) + "_index >= 0) {\n    ");
454         }
455         addExtraEmitCodeLine("this->invokeChild(_outer." + String(child.fName) + "_index" +
456                              inputArg + ", &" + childName + ", args);");
457         if (c.fArguments[0]->fType.kind() == Type::kNullable_Kind) {
458             // Null FPs are not emitted, but their output can still be referenced in dependent
459             // expressions - thus we always declare the variable.
460             // Note: this is essentially dead code required to satisfy the compiler, because
461             // 'process' function calls should always be guarded at a higher level, in the .fp
462             // source.
463             addExtraEmitCodeLine(
464                 "} else {"
465                 "   fragBuilder->codeAppendf(\"half4 %s;\", " + childName + ".c_str());"
466                 "}");
467         }
468         this->write("%s");
469         fFormatArgs.push_back(childName + ".c_str()");
470         return;
471     }
472     INHERITED::writeFunctionCall(c);
473     if (c.fFunction.fBuiltin && c.fFunction.fName == "sample") {
474         this->write(".%s");
475         SkASSERT(c.fArguments.size() >= 1);
476         SkASSERT(c.fArguments[0]->fKind == Expression::kVariableReference_Kind);
477         String sampler = this->getSamplerHandle(((VariableReference&) *c.fArguments[0]).fVariable);
478         fFormatArgs.push_back("fragBuilder->getProgramBuilder()->samplerSwizzle(" + sampler +
479                               ").c_str()");
480     }
481 }
482 
writeFunction(const FunctionDefinition & f)483 void CPPCodeGenerator::writeFunction(const FunctionDefinition& f) {
484     if (f.fDeclaration.fName == "main") {
485         fFunctionHeader = "";
486         OutputStream* oldOut = fOut;
487         StringStream buffer;
488         fOut = &buffer;
489         fInMain = true;
490         for (const auto& s : ((Block&) *f.fBody).fStatements) {
491             this->writeStatement(*s);
492             this->writeLine();
493         }
494         fInMain = false;
495 
496         fOut = oldOut;
497         this->write(fFunctionHeader);
498         this->write(buffer.str());
499     } else {
500         INHERITED::writeFunction(f);
501     }
502 }
503 
writeSetting(const Setting & s)504 void CPPCodeGenerator::writeSetting(const Setting& s) {
505     static constexpr const char* kPrefix = "sk_Args.";
506     if (!strncmp(s.fName.c_str(), kPrefix, strlen(kPrefix))) {
507         const char* name = s.fName.c_str() + strlen(kPrefix);
508         this->writeRuntimeValue(s.fType, Layout(), HCodeGenerator::FieldName(name).c_str());
509     } else {
510         this->write(s.fName.c_str());
511     }
512 }
513 
writeSection(const char * name,const char * prefix)514 bool CPPCodeGenerator::writeSection(const char* name, const char* prefix) {
515     const Section* s = fSectionAndParameterHelper.getSection(name);
516     if (s) {
517         this->writef("%s%s", prefix, s->fText.c_str());
518         return true;
519     }
520     return false;
521 }
522 
writeProgramElement(const ProgramElement & p)523 void CPPCodeGenerator::writeProgramElement(const ProgramElement& p) {
524     if (p.fKind == ProgramElement::kSection_Kind) {
525         return;
526     }
527     if (p.fKind == ProgramElement::kVar_Kind) {
528         const VarDeclarations& decls = (const VarDeclarations&) p;
529         if (!decls.fVars.size()) {
530             return;
531         }
532         const Variable& var = *((VarDeclaration&) *decls.fVars[0]).fVar;
533         if (var.fModifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kUniform_Flag) ||
534             -1 != var.fModifiers.fLayout.fBuiltin) {
535             return;
536         }
537     }
538     INHERITED::writeProgramElement(p);
539 }
540 
addUniform(const Variable & var)541 void CPPCodeGenerator::addUniform(const Variable& var) {
542     if (!needs_uniform_var(var)) {
543         return;
544     }
545     const char* type;
546     if (var.fType == *fContext.fFloat_Type) {
547         type = "kFloat_GrSLType";
548     } else if (var.fType == *fContext.fHalf_Type) {
549         type = "kHalf_GrSLType";
550     } else if (var.fType == *fContext.fFloat2_Type) {
551         type = "kFloat2_GrSLType";
552     } else if (var.fType == *fContext.fHalf2_Type) {
553         type = "kHalf2_GrSLType";
554     } else if (var.fType == *fContext.fFloat4_Type) {
555         type = "kFloat4_GrSLType";
556     } else if (var.fType == *fContext.fHalf4_Type) {
557         type = "kHalf4_GrSLType";
558     } else if (var.fType == *fContext.fFloat4x4_Type) {
559         type = "kFloat4x4_GrSLType";
560     } else if (var.fType == *fContext.fHalf4x4_Type) {
561         type = "kHalf4x4_GrSLType";
562     } else {
563         ABORT("unsupported uniform type: %s %s;\n", String(var.fType.fName).c_str(),
564               String(var.fName).c_str());
565     }
566     if (var.fModifiers.fLayout.fWhen.fLength) {
567         this->writef("        if (%s) {\n    ", String(var.fModifiers.fLayout.fWhen).c_str());
568     }
569     String name(var.fName);
570     this->writef("        %sVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, %s, "
571                  "\"%s\");\n", HCodeGenerator::FieldName(name.c_str()).c_str(), type,
572                  name.c_str());
573     if (var.fModifiers.fLayout.fWhen.fLength) {
574         this->write("        }\n");
575     }
576 }
577 
writeInputVars()578 void CPPCodeGenerator::writeInputVars() {
579 }
580 
writePrivateVars()581 void CPPCodeGenerator::writePrivateVars() {
582     for (const auto& p : fProgram) {
583         if (ProgramElement::kVar_Kind == p.fKind) {
584             const VarDeclarations& decls = (const VarDeclarations&) p;
585             for (const auto& raw : decls.fVars) {
586                 VarDeclaration& decl = (VarDeclaration&) *raw;
587                 if (is_private(*decl.fVar)) {
588                     if (decl.fVar->fType == *fContext.fFragmentProcessor_Type) {
589                         fErrors.error(decl.fOffset,
590                                       "fragmentProcessor variables must be declared 'in'");
591                         return;
592                     }
593                     this->writef("%s %s = %s;\n",
594                                  HCodeGenerator::FieldType(fContext, decl.fVar->fType,
595                                                            decl.fVar->fModifiers.fLayout).c_str(),
596                                  String(decl.fVar->fName).c_str(),
597                                  default_value(*decl.fVar).c_str());
598                 } else if (decl.fVar->fModifiers.fLayout.fFlags & Layout::kTracked_Flag) {
599                     // An auto-tracked uniform in variable, so add a field to hold onto the prior
600                     // state. Note that tracked variables must be uniform in's and that is validated
601                     // before writePrivateVars() is called.
602                     const UniformCTypeMapper* mapper = UniformCTypeMapper::Get(fContext, *decl.fVar);
603                     SkASSERT(mapper && mapper->supportsTracking());
604 
605                     String name = HCodeGenerator::FieldName(String(decl.fVar->fName).c_str());
606                     // The member statement is different if the mapper reports a default value
607                     if (mapper->defaultValue().size() > 0) {
608                         this->writef("%s %sPrev = %s;\n",
609                                      Layout::CTypeToStr(mapper->ctype()), name.c_str(),
610                                      mapper->defaultValue().c_str());
611                     } else {
612                         this->writef("%s %sPrev;\n",
613                                      Layout::CTypeToStr(mapper->ctype()), name.c_str());
614                     }
615                 }
616             }
617         }
618     }
619 }
620 
writePrivateVarValues()621 void CPPCodeGenerator::writePrivateVarValues() {
622     for (const auto& p : fProgram) {
623         if (ProgramElement::kVar_Kind == p.fKind) {
624             const VarDeclarations& decls = (const VarDeclarations&) p;
625             for (const auto& raw : decls.fVars) {
626                 VarDeclaration& decl = (VarDeclaration&) *raw;
627                 if (is_private(*decl.fVar) && decl.fValue) {
628                     this->writef("%s = ", String(decl.fVar->fName).c_str());
629                     fCPPMode = true;
630                     this->writeExpression(*decl.fValue, kAssignment_Precedence);
631                     fCPPMode = false;
632                     this->write(";\n");
633                 }
634             }
635         }
636     }
637 }
638 
is_accessible(const Variable & var)639 static bool is_accessible(const Variable& var) {
640     const Type& type = var.fType.nonnullable();
641     return Type::kSampler_Kind != type.kind() &&
642            Type::kOther_Kind != type.kind();
643 }
644 
newExtraEmitCodeBlock()645 void CPPCodeGenerator::newExtraEmitCodeBlock() {
646     // This should only be called when emitting SKSL for emitCode(), which can be detected if the
647     // cpp buffer is not null, and the cpp buffer is not the current output.
648     SkASSERT(fCPPBuffer && fCPPBuffer != fOut);
649 
650     // Start a new block as an empty string
651     fExtraEmitCodeBlocks.push_back("");
652     // Mark its location in the output buffer, uses ${\d} for the token since ${} will not occur in
653     // valid sksl and makes detection trivial.
654     this->writef("${%zu}", fExtraEmitCodeBlocks.size() - 1);
655 }
656 
addExtraEmitCodeLine(const String & toAppend)657 void CPPCodeGenerator::addExtraEmitCodeLine(const String& toAppend) {
658     SkASSERT(fExtraEmitCodeBlocks.size() > 0);
659     String& currentBlock = fExtraEmitCodeBlocks[fExtraEmitCodeBlocks.size() - 1];
660     // Automatically add indentation and newline
661     currentBlock += "        " + toAppend + "\n";
662 }
663 
flushEmittedCode()664 void CPPCodeGenerator::flushEmittedCode() {
665     if (fCPPBuffer == nullptr) {
666         // Not actually within writeEmitCode() so nothing to flush
667         return;
668     }
669 
670     StringStream* skslBuffer = static_cast<StringStream*>(fOut);
671 
672     String sksl = skslBuffer->str();
673     // Empty the accumulation buffer since its current contents are consumed.
674     skslBuffer->reset();
675 
676     // Switch to the cpp buffer
677     fOut = fCPPBuffer;
678 
679     // Iterate through the sksl, keeping track of where the last statement ended (e.g. the latest
680     // encountered ';', '{', or '}'). If an extra emit code block token is encountered then the
681     // code from 0 to last statement end is sent to writeCodeAppend, the extra code block is
682     // appended to the cpp buffer, and then the sksl string is trimmed to start where the last
683     // statement left off (minus the encountered token).
684     size_t i = 0;
685     int flushPoint = -1;
686     int tokenStart = -1;
687     while (i < sksl.size()) {
688         if (tokenStart >= 0) {
689             // Looking for the end of the token
690             if (sksl[i] == '}') {
691                 // Must append the sksl from 0 to flushPoint (inclusive) then the extra code
692                 // accumulated in the block with index parsed from chars [tokenStart+2, i-1]
693                 String toFlush = String(sksl.c_str(), flushPoint + 1);
694                 // writeCodeAppend automatically removes the format args that it consumed, so
695                 // fFormatArgs will be in a valid state for any future sksl
696                 this->writeCodeAppend(toFlush);
697 
698                 int codeBlock = stoi(String(sksl.c_str() + tokenStart + 2, i - tokenStart - 2));
699                 SkASSERT(codeBlock < (int) fExtraEmitCodeBlocks.size());
700                 if (fExtraEmitCodeBlocks[codeBlock].size() > 0) {
701                     this->write(fExtraEmitCodeBlocks[codeBlock].c_str());
702                 }
703 
704                 // Now reset the sksl buffer to start after the flush point, but remove the token.
705                 String compacted = String(sksl.c_str() + flushPoint + 1,
706                                           tokenStart - flushPoint - 1);
707                 if (i < sksl.size() - 1) {
708                     compacted += String(sksl.c_str() + i + 1, sksl.size() - i - 1);
709                 }
710                 sksl = compacted;
711 
712                 // And reset iteration
713                 i = -1;
714                 flushPoint = -1;
715                 tokenStart = -1;
716             }
717         } else {
718             // Looking for the start of extra emit block tokens, and tracking when statements end
719             if (sksl[i] == ';' || sksl[i] == '{' || sksl[i] == '}') {
720                 flushPoint = i;
721             } else if (i < sksl.size() - 1 && sksl[i] == '$' && sksl[i + 1] == '{') {
722                 // found an extra emit code block token
723                 tokenStart = i++;
724             }
725         }
726         i++;
727     }
728 
729     // Once we've gone through the sksl string to this point, there are no remaining extra emit
730     // code blocks to interleave, so append the remainder as usual.
731     this->writeCodeAppend(sksl);
732 
733     // After appending, switch back to the emptied sksl buffer and reset the extra code blocks
734     fOut = skslBuffer;
735     fExtraEmitCodeBlocks.clear();
736 }
737 
writeCodeAppend(const String & code)738 void CPPCodeGenerator::writeCodeAppend(const String& code) {
739     // codeAppendf can only handle appending 1024 bytes at a time, so we need to break the string
740     // into chunks. Unfortunately we can't tell exactly how long the string is going to end up,
741     // because printf escape sequences get replaced by strings of unknown length, but keeping the
742     // format string below 512 bytes is probably safe.
743     static constexpr size_t maxChunkSize = 512;
744     size_t start = 0;
745     size_t index = 0;
746     size_t argStart = 0;
747     size_t argCount;
748     while (index < code.size()) {
749         argCount = 0;
750         this->write("        fragBuilder->codeAppendf(\"");
751         while (index < code.size() && index < start + maxChunkSize) {
752             if ('%' == code[index]) {
753                 if (index == start + maxChunkSize - 1 || index == code.size() - 1) {
754                     break;
755                 }
756                 if (code[index + 1] != '%') {
757                     ++argCount;
758                 }
759             } else if ('\\' == code[index] && index == start + maxChunkSize - 1) {
760                 // avoid splitting an escape sequence that happens to fall across a chunk boundary
761                 break;
762             }
763             ++index;
764         }
765         fOut->write(code.c_str() + start, index - start);
766         this->write("\"");
767         for (size_t i = argStart; i < argStart + argCount; ++i) {
768             this->writef(", %s", fFormatArgs[i].c_str());
769         }
770         this->write(");\n");
771         argStart += argCount;
772         start = index;
773     }
774 
775     // argStart is equal to the number of fFormatArgs that were consumed
776     // so they should be removed from the list
777     if (argStart > 0) {
778         fFormatArgs.erase(fFormatArgs.begin(), fFormatArgs.begin() + argStart);
779     }
780 }
781 
convertSKSLExpressionToCPP(const Expression & e,const String & cppVar)782 String CPPCodeGenerator::convertSKSLExpressionToCPP(const Expression& e,
783                                                     const String& cppVar) {
784     // To do this conversion, we temporarily switch the sksl output stream
785     // to an empty stringstream and reset the format args to empty.
786     OutputStream* oldSKSL = fOut;
787     StringStream exprBuffer;
788     fOut = &exprBuffer;
789 
790     std::vector<String> oldArgs(fFormatArgs);
791     fFormatArgs.clear();
792 
793     // Convert the argument expression into a format string and args
794     this->writeExpression(e, Precedence::kTopLevel_Precedence);
795     std::vector<String> newArgs(fFormatArgs);
796     String expr = exprBuffer.str();
797 
798     // After generating, restore the original output stream and format args
799     fFormatArgs = oldArgs;
800     fOut = oldSKSL;
801 
802     // The sksl written to exprBuffer is not processed by flushEmittedCode(), so any extra emit code
803     // block tokens won't get handled. So we need to strip them from the expression and stick them
804     // to the end of the original sksl stream.
805     String exprFormat = "";
806     int tokenStart = -1;
807     for (size_t i = 0; i < expr.size(); i++) {
808         if (tokenStart >= 0) {
809             if (expr[i] == '}') {
810                 // End of the token, so append the token to fOut
811                 fOut->write(expr.c_str() + tokenStart, i - tokenStart + 1);
812                 tokenStart = -1;
813             }
814         } else {
815             if (i < expr.size() - 1 && expr[i] == '$' && expr[i + 1] == '{') {
816                 tokenStart = i++;
817             } else {
818                 exprFormat += expr[i];
819             }
820         }
821     }
822 
823     // Now build the final C++ code snippet from the format string and args
824     String cppExpr;
825     if (newArgs.size() == 0) {
826         // This was a static expression, so we can simplify the input
827         // color declaration in the emitted code to just a static string
828         cppExpr = "SkString " + cppVar + "(\"" + exprFormat + "\");";
829     } else {
830         // String formatting must occur dynamically, so have the C++ declaration
831         // use SkStringPrintf with the format args that were accumulated
832         // when the expression was written.
833         cppExpr = "SkString " + cppVar + " = SkStringPrintf(\"" + exprFormat + "\"";
834         for (size_t i = 0; i < newArgs.size(); i++) {
835             cppExpr += ", " + newArgs[i];
836         }
837         cppExpr += ");";
838     }
839     return cppExpr;
840 }
841 
writeEmitCode(std::vector<const Variable * > & uniforms)842 bool CPPCodeGenerator::writeEmitCode(std::vector<const Variable*>& uniforms) {
843     this->write("    void emitCode(EmitArgs& args) override {\n"
844                 "        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;\n");
845     this->writef("        const %s& _outer = args.fFp.cast<%s>();\n"
846                  "        (void) _outer;\n",
847                  fFullName.c_str(), fFullName.c_str());
848     for (const auto& p : fProgram) {
849         if (ProgramElement::kVar_Kind == p.fKind) {
850             const VarDeclarations& decls = (const VarDeclarations&) p;
851             for (const auto& raw : decls.fVars) {
852                 VarDeclaration& decl = (VarDeclaration&) *raw;
853                 String nameString(decl.fVar->fName);
854                 const char* name = nameString.c_str();
855                 if (SectionAndParameterHelper::IsParameter(*decl.fVar) &&
856                     is_accessible(*decl.fVar)) {
857                     this->writef("        auto %s = _outer.%s;\n"
858                                  "        (void) %s;\n",
859                                  name, name, name);
860                 }
861             }
862         }
863     }
864     this->writePrivateVarValues();
865     for (const auto u : uniforms) {
866         this->addUniform(*u);
867     }
868     this->writeSection(EMIT_CODE_SECTION);
869 
870     // Save original buffer as the CPP buffer for flushEmittedCode()
871     fCPPBuffer = fOut;
872     StringStream skslBuffer;
873     fOut = &skslBuffer;
874 
875     this->newExtraEmitCodeBlock();
876     bool result = INHERITED::generateCode();
877     this->flushEmittedCode();
878 
879     // Then restore the original CPP buffer and close the function
880     fOut = fCPPBuffer;
881     fCPPBuffer = nullptr;
882     this->write("    }\n");
883     return result;
884 }
885 
writeSetData(std::vector<const Variable * > & uniforms)886 void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
887     const char* fullName = fFullName.c_str();
888     const Section* section = fSectionAndParameterHelper.getSection(SET_DATA_SECTION);
889     const char* pdman = section ? section->fArgument.c_str() : "pdman";
890     this->writef("    void onSetData(const GrGLSLProgramDataManager& %s, "
891                                     "const GrFragmentProcessor& _proc) override {\n",
892                  pdman);
893     bool wroteProcessor = false;
894     for (const auto u : uniforms) {
895         if (is_uniform_in(*u)) {
896             if (!wroteProcessor) {
897                 this->writef("        const %s& _outer = _proc.cast<%s>();\n", fullName, fullName);
898                 wroteProcessor = true;
899                 this->writef("        {\n");
900             }
901 
902             const UniformCTypeMapper* mapper = UniformCTypeMapper::Get(fContext, *u);
903             SkASSERT(mapper);
904 
905             String nameString(u->fName);
906             const char* name = nameString.c_str();
907 
908             // Switches for setData behavior in the generated code
909             bool conditionalUniform = u->fModifiers.fLayout.fWhen != "";
910             bool isTracked = u->fModifiers.fLayout.fFlags & Layout::kTracked_Flag;
911             bool needsValueDeclaration = isTracked || !mapper->canInlineUniformValue();
912 
913             String uniformName = HCodeGenerator::FieldName(name) + "Var";
914 
915             String indent = "        "; // 8 by default, 12 when nested for conditional uniforms
916             if (conditionalUniform) {
917                 // Add a pre-check to make sure the uniform was emitted
918                 // before trying to send any data to the GPU
919                 this->writef("        if (%s.isValid()) {\n", uniformName.c_str());
920                 indent += "    ";
921             }
922 
923             String valueVar = "";
924             if (needsValueDeclaration) {
925                 valueVar.appendf("%sValue", name);
926                 // Use AccessType since that will match the return type of _outer's public API.
927                 String valueType = HCodeGenerator::AccessType(fContext, u->fType,
928                                                               u->fModifiers.fLayout);
929                 this->writef("%s%s %s = _outer.%s;\n",
930                              indent.c_str(), valueType.c_str(), valueVar.c_str(), name);
931             } else {
932                 // Not tracked and the mapper only needs to use the value once
933                 // so send it a safe expression instead of the variable name
934                 valueVar.appendf("(_outer.%s)", name);
935             }
936 
937             if (isTracked) {
938                 SkASSERT(mapper->supportsTracking());
939 
940                 String prevVar = HCodeGenerator::FieldName(name) + "Prev";
941                 this->writef("%sif (%s) {\n"
942                              "%s    %s;\n"
943                              "%s    %s;\n"
944                              "%s}\n", indent.c_str(),
945                         mapper->dirtyExpression(valueVar, prevVar).c_str(), indent.c_str(),
946                         mapper->saveState(valueVar, prevVar).c_str(), indent.c_str(),
947                         mapper->setUniform(pdman, uniformName, valueVar).c_str(), indent.c_str());
948             } else {
949                 this->writef("%s%s;\n", indent.c_str(),
950                         mapper->setUniform(pdman, uniformName, valueVar).c_str());
951             }
952 
953             if (conditionalUniform) {
954                 // Close the earlier precheck block
955                 this->writef("        }\n");
956             }
957         }
958     }
959     if (wroteProcessor) {
960         this->writef("        }\n");
961     }
962     if (section) {
963         int samplerIndex = 0;
964         for (const auto& p : fProgram) {
965             if (ProgramElement::kVar_Kind == p.fKind) {
966                 const VarDeclarations& decls = (const VarDeclarations&) p;
967                 for (const auto& raw : decls.fVars) {
968                     VarDeclaration& decl = (VarDeclaration&) *raw;
969                     String nameString(decl.fVar->fName);
970                     const char* name = nameString.c_str();
971                     if (decl.fVar->fType.kind() == Type::kSampler_Kind) {
972                         this->writef("        GrSurfaceProxy& %sProxy = "
973                                      "*_outer.textureSampler(%d).proxy();\n",
974                                      name, samplerIndex);
975                         this->writef("        GrTexture& %s = *%sProxy.peekTexture();\n",
976                                      name, name);
977                         this->writef("        (void) %s;\n", name);
978                         ++samplerIndex;
979                     } else if (needs_uniform_var(*decl.fVar)) {
980                         this->writef("        UniformHandle& %s = %sVar;\n"
981                                      "        (void) %s;\n",
982                                      name, HCodeGenerator::FieldName(name).c_str(), name);
983                     } else if (SectionAndParameterHelper::IsParameter(*decl.fVar) &&
984                                decl.fVar->fType != *fContext.fFragmentProcessor_Type) {
985                         if (!wroteProcessor) {
986                             this->writef("        const %s& _outer = _proc.cast<%s>();\n", fullName,
987                                          fullName);
988                             wroteProcessor = true;
989                         }
990                         this->writef("        auto %s = _outer.%s;\n"
991                                      "        (void) %s;\n",
992                                      name, name, name);
993                     }
994                 }
995             }
996         }
997         this->writeSection(SET_DATA_SECTION);
998     }
999     this->write("    }\n");
1000 }
1001 
writeOnTextureSampler()1002 void CPPCodeGenerator::writeOnTextureSampler() {
1003     bool foundSampler = false;
1004     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
1005         if (param->fType.kind() == Type::kSampler_Kind) {
1006             if (!foundSampler) {
1007                 this->writef(
1008                         "const GrFragmentProcessor::TextureSampler& %s::onTextureSampler(int "
1009                         "index) const {\n",
1010                         fFullName.c_str());
1011                 this->writef("    return IthTextureSampler(index, %s",
1012                              HCodeGenerator::FieldName(String(param->fName).c_str()).c_str());
1013                 foundSampler = true;
1014             } else {
1015                 this->writef(", %s",
1016                              HCodeGenerator::FieldName(String(param->fName).c_str()).c_str());
1017             }
1018         }
1019     }
1020     if (foundSampler) {
1021         this->write(");\n}\n");
1022     }
1023 }
1024 
writeClone()1025 void CPPCodeGenerator::writeClone() {
1026     if (!this->writeSection(CLONE_SECTION)) {
1027         if (fSectionAndParameterHelper.getSection(FIELDS_SECTION)) {
1028             fErrors.error(0, "fragment processors with custom @fields must also have a custom"
1029                              "@clone");
1030         }
1031         this->writef("%s::%s(const %s& src)\n"
1032                      ": INHERITED(k%s_ClassID, src.optimizationFlags())", fFullName.c_str(),
1033                      fFullName.c_str(), fFullName.c_str(), fFullName.c_str());
1034         const auto transforms = fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION);
1035         for (size_t i = 0; i < transforms.size(); ++i) {
1036             const Section& s = *transforms[i];
1037             String fieldName = HCodeGenerator::CoordTransformName(s.fArgument, i);
1038             this->writef("\n, %s(src.%s)", fieldName.c_str(), fieldName.c_str());
1039         }
1040         for (const auto& param : fSectionAndParameterHelper.getParameters()) {
1041             String fieldName = HCodeGenerator::FieldName(String(param->fName).c_str());
1042             if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type) {
1043                 this->writef("\n, %s_index(src.%s_index)",
1044                              fieldName.c_str(),
1045                              fieldName.c_str());
1046             } else {
1047                 this->writef("\n, %s(src.%s)",
1048                              fieldName.c_str(),
1049                              fieldName.c_str());
1050             }
1051         }
1052         this->writef(" {\n");
1053         int samplerCount = 0;
1054         for (const auto& param : fSectionAndParameterHelper.getParameters()) {
1055             if (param->fType.kind() == Type::kSampler_Kind) {
1056                 ++samplerCount;
1057             } else if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type) {
1058                 String fieldName = HCodeGenerator::FieldName(String(param->fName).c_str());
1059                 if (param->fType.kind() == Type::kNullable_Kind) {
1060                     this->writef("    if (%s_index >= 0) {\n    ", fieldName.c_str());
1061                 }
1062                 this->writef("    this->registerChildProcessor(src.childProcessor(%s_index)."
1063                              "clone());\n", fieldName.c_str());
1064                 if (param->fType.kind() == Type::kNullable_Kind) {
1065                     this->writef("    }\n");
1066                 }
1067             }
1068         }
1069         if (samplerCount) {
1070             this->writef("     this->setTextureSamplerCnt(%d);", samplerCount);
1071         }
1072         for (size_t i = 0; i < transforms.size(); ++i) {
1073             const Section& s = *transforms[i];
1074             String fieldName = HCodeGenerator::CoordTransformName(s.fArgument, i);
1075             this->writef("    this->addCoordTransform(&%s);\n", fieldName.c_str());
1076         }
1077         this->write("}\n");
1078         this->writef("std::unique_ptr<GrFragmentProcessor> %s::clone() const {\n",
1079                      fFullName.c_str());
1080         this->writef("    return std::unique_ptr<GrFragmentProcessor>(new %s(*this));\n",
1081                      fFullName.c_str());
1082         this->write("}\n");
1083     }
1084 }
1085 
writeTest()1086 void CPPCodeGenerator::writeTest() {
1087     const Section* test = fSectionAndParameterHelper.getSection(TEST_CODE_SECTION);
1088     if (test) {
1089         this->writef(
1090                 "GR_DEFINE_FRAGMENT_PROCESSOR_TEST(%s);\n"
1091                 "#if GR_TEST_UTILS\n"
1092                 "std::unique_ptr<GrFragmentProcessor> %s::TestCreate(GrProcessorTestData* %s) {\n",
1093                 fFullName.c_str(),
1094                 fFullName.c_str(),
1095                 test->fArgument.c_str());
1096         this->writeSection(TEST_CODE_SECTION);
1097         this->write("}\n"
1098                     "#endif\n");
1099     }
1100 }
1101 
writeGetKey()1102 void CPPCodeGenerator::writeGetKey() {
1103     this->writef("void %s::onGetGLSLProcessorKey(const GrShaderCaps& caps, "
1104                                                 "GrProcessorKeyBuilder* b) const {\n",
1105                  fFullName.c_str());
1106     for (const auto& p : fProgram) {
1107         if (ProgramElement::kVar_Kind == p.fKind) {
1108             const VarDeclarations& decls = (const VarDeclarations&) p;
1109             for (const auto& raw : decls.fVars) {
1110                 const VarDeclaration& decl = (VarDeclaration&) *raw;
1111                 const Variable& var = *decl.fVar;
1112                 String nameString(var.fName);
1113                 const char* name = nameString.c_str();
1114                 if (var.fModifiers.fLayout.fKey != Layout::kNo_Key &&
1115                     (var.fModifiers.fFlags & Modifiers::kUniform_Flag)) {
1116                     fErrors.error(var.fOffset,
1117                                   "layout(key) may not be specified on uniforms");
1118                 }
1119                 switch (var.fModifiers.fLayout.fKey) {
1120                     case Layout::kKey_Key:
1121                         if (is_private(var)) {
1122                             this->writef("%s %s =",
1123                                          HCodeGenerator::FieldType(fContext, var.fType,
1124                                                                    var.fModifiers.fLayout).c_str(),
1125                                          String(var.fName).c_str());
1126                             if (decl.fValue) {
1127                                 fCPPMode = true;
1128                                 this->writeExpression(*decl.fValue, kAssignment_Precedence);
1129                                 fCPPMode = false;
1130                             } else {
1131                                 this->writef("%s", default_value(var).c_str());
1132                             }
1133                             this->write(";\n");
1134                         }
1135                         if (var.fModifiers.fLayout.fWhen.fLength) {
1136                             this->writef("if (%s) {", String(var.fModifiers.fLayout.fWhen).c_str());
1137                         }
1138                         if (var.fType == *fContext.fFloat4x4_Type) {
1139                             ABORT("no automatic key handling for float4x4\n");
1140                         } else if (var.fType == *fContext.fFloat2_Type) {
1141                             this->writef("    b->add32(%s.fX);\n",
1142                                          HCodeGenerator::FieldName(name).c_str());
1143                             this->writef("    b->add32(%s.fY);\n",
1144                                          HCodeGenerator::FieldName(name).c_str());
1145                         } else if (var.fType == *fContext.fFloat4_Type) {
1146                             this->writef("    b->add32(%s.x());\n",
1147                                          HCodeGenerator::FieldName(name).c_str());
1148                             this->writef("    b->add32(%s.y());\n",
1149                                          HCodeGenerator::FieldName(name).c_str());
1150                             this->writef("    b->add32(%s.width());\n",
1151                                          HCodeGenerator::FieldName(name).c_str());
1152                             this->writef("    b->add32(%s.height());\n",
1153                                          HCodeGenerator::FieldName(name).c_str());
1154                         } else if (var.fType == *fContext.fHalf4_Type) {
1155                             this->writef("    uint16_t red = SkFloatToHalf(%s.fR);\n",
1156                                          HCodeGenerator::FieldName(name).c_str());
1157                             this->writef("    uint16_t green = SkFloatToHalf(%s.fG);\n",
1158                                          HCodeGenerator::FieldName(name).c_str());
1159                             this->writef("    uint16_t blue = SkFloatToHalf(%s.fB);\n",
1160                                          HCodeGenerator::FieldName(name).c_str());
1161                             this->writef("    uint16_t alpha = SkFloatToHalf(%s.fA);\n",
1162                                          HCodeGenerator::FieldName(name).c_str());
1163                             this->write("    b->add32(((uint32_t)red << 16) | green);\n");
1164                             this->write("    b->add32(((uint32_t)blue << 16) | alpha);\n");
1165                         } else {
1166                             this->writef("    b->add32((int32_t) %s);\n",
1167                                          HCodeGenerator::FieldName(name).c_str());
1168                         }
1169                         if (var.fModifiers.fLayout.fWhen.fLength) {
1170                             this->write("}");
1171                         }
1172                         break;
1173                     case Layout::kIdentity_Key:
1174                         if (var.fType.kind() != Type::kMatrix_Kind) {
1175                             fErrors.error(var.fOffset,
1176                                           "layout(key=identity) requires matrix type");
1177                         }
1178                         this->writef("    b->add32(%s.isIdentity() ? 1 : 0);\n",
1179                                      HCodeGenerator::FieldName(name).c_str());
1180                         break;
1181                     case Layout::kNo_Key:
1182                         break;
1183                 }
1184             }
1185         }
1186     }
1187     this->write("}\n");
1188 }
1189 
generateCode()1190 bool CPPCodeGenerator::generateCode() {
1191     std::vector<const Variable*> uniforms;
1192     for (const auto& p : fProgram) {
1193         if (ProgramElement::kVar_Kind == p.fKind) {
1194             const VarDeclarations& decls = (const VarDeclarations&) p;
1195             for (const auto& raw : decls.fVars) {
1196                 VarDeclaration& decl = (VarDeclaration&) *raw;
1197                 if ((decl.fVar->fModifiers.fFlags & Modifiers::kUniform_Flag) &&
1198                            decl.fVar->fType.kind() != Type::kSampler_Kind) {
1199                     uniforms.push_back(decl.fVar);
1200                 }
1201 
1202                 if (is_uniform_in(*decl.fVar)) {
1203                     // Validate the "uniform in" declarations to make sure they are fully supported,
1204                     // instead of generating surprising C++
1205                     const UniformCTypeMapper* mapper =
1206                             UniformCTypeMapper::Get(fContext, *decl.fVar);
1207                     if (mapper == nullptr) {
1208                         fErrors.error(decl.fOffset, String(decl.fVar->fName)
1209                                 + "'s type is not supported for use as a 'uniform in'");
1210                         return false;
1211                     }
1212                     if (decl.fVar->fModifiers.fLayout.fFlags & Layout::kTracked_Flag) {
1213                         if (!mapper->supportsTracking()) {
1214                             fErrors.error(decl.fOffset, String(decl.fVar->fName)
1215                                     + "'s type does not support state tracking");
1216                             return false;
1217                         }
1218                     }
1219 
1220                 } else {
1221                     // If it's not a uniform_in, it's an error to be tracked
1222                     if (decl.fVar->fModifiers.fLayout.fFlags & Layout::kTracked_Flag) {
1223                         fErrors.error(decl.fOffset, "Non-'in uniforms' cannot be tracked");
1224                         return false;
1225                     }
1226                 }
1227             }
1228         }
1229     }
1230     const char* baseName = fName.c_str();
1231     const char* fullName = fFullName.c_str();
1232     this->writef("%s\n", HCodeGenerator::GetHeader(fProgram, fErrors).c_str());
1233     this->writef(kFragmentProcessorHeader, fullName);
1234     this->writef("#include \"%s.h\"\n\n", fullName);
1235     this->writeSection(CPP_SECTION);
1236     this->writef("#include \"include/gpu/GrTexture.h\"\n"
1237                  "#include \"src/gpu/glsl/GrGLSLFragmentProcessor.h\"\n"
1238                  "#include \"src/gpu/glsl/GrGLSLFragmentShaderBuilder.h\"\n"
1239                  "#include \"src/gpu/glsl/GrGLSLProgramBuilder.h\"\n"
1240                  "#include \"src/sksl/SkSLCPP.h\"\n"
1241                  "#include \"src/sksl/SkSLUtil.h\"\n"
1242                  "class GrGLSL%s : public GrGLSLFragmentProcessor {\n"
1243                  "public:\n"
1244                  "    GrGLSL%s() {}\n",
1245                  baseName, baseName);
1246     bool result = this->writeEmitCode(uniforms);
1247     this->write("private:\n");
1248     this->writeSetData(uniforms);
1249     this->writePrivateVars();
1250     for (const auto& u : uniforms) {
1251         if (needs_uniform_var(*u) && !(u->fModifiers.fFlags & Modifiers::kIn_Flag)) {
1252             this->writef("    UniformHandle %sVar;\n",
1253                          HCodeGenerator::FieldName(String(u->fName).c_str()).c_str());
1254         }
1255     }
1256     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
1257         if (needs_uniform_var(*param)) {
1258             this->writef("    UniformHandle %sVar;\n",
1259                          HCodeGenerator::FieldName(String(param->fName).c_str()).c_str());
1260         }
1261     }
1262     this->writef("};\n"
1263                  "GrGLSLFragmentProcessor* %s::onCreateGLSLInstance() const {\n"
1264                  "    return new GrGLSL%s();\n"
1265                  "}\n",
1266                  fullName, baseName);
1267     this->writeGetKey();
1268     this->writef("bool %s::onIsEqual(const GrFragmentProcessor& other) const {\n"
1269                  "    const %s& that = other.cast<%s>();\n"
1270                  "    (void) that;\n",
1271                  fullName, fullName, fullName);
1272     for (const auto& param : fSectionAndParameterHelper.getParameters()) {
1273         if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type) {
1274             continue;
1275         }
1276         String nameString(param->fName);
1277         const char* name = nameString.c_str();
1278         this->writef("    if (%s != that.%s) return false;\n",
1279                      HCodeGenerator::FieldName(name).c_str(),
1280                      HCodeGenerator::FieldName(name).c_str());
1281     }
1282     this->write("    return true;\n"
1283                 "}\n");
1284     this->writeClone();
1285     this->writeOnTextureSampler();
1286     this->writeTest();
1287     this->writeSection(CPP_END_SECTION);
1288 
1289     result &= 0 == fErrors.errorCount();
1290     return result;
1291 }
1292 
1293 } // namespace
1294