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