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 | |
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 | |
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 | |
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 | |
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 | |
56 | void CPPCodeGenerator::() { |
57 | } |
58 | |
59 | bool CPPCodeGenerator::usesPrecisionModifiers() const { |
60 | return false; |
61 | } |
62 | |
63 | String CPPCodeGenerator::getTypeName(const Type& type) { |
64 | return type.name(); |
65 | } |
66 | |
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 | |
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) + "].fVaryingPoint);" ); |
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 | |
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 | |
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 | |
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 | |
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 | |
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::kSkV4: |
212 | fFormatArgs.push_back(cppCode + ".x" ); |
213 | fFormatArgs.push_back(cppCode + ".y" ); |
214 | fFormatArgs.push_back(cppCode + ".z" ); |
215 | fFormatArgs.push_back(cppCode + ".w" ); |
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 | |
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 | |
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 | |
265 | void CPPCodeGenerator::writeIntLiteral(const IntLiteral& i) { |
266 | this->write(to_string((int32_t) i.fValue)); |
267 | } |
268 | |
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 | |
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 | |
338 | void CPPCodeGenerator::writeIfStatement(const IfStatement& s) { |
339 | if (s.fIsStatic) { |
340 | this->write("@" ); |
341 | } |
342 | INHERITED::writeIfStatement(s); |
343 | } |
344 | |
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 | |
352 | void CPPCodeGenerator::writeSwitchStatement(const SwitchStatement& s) { |
353 | if (s.fIsStatic) { |
354 | this->write("@" ); |
355 | } |
356 | INHERITED::writeSwitchStatement(s); |
357 | } |
358 | |
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 | |
384 | 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 | |
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() <= 3); |
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 | const Variable& child = ((const VariableReference&) *c.fArguments[0]).fVariable; |
424 | |
425 | // Start a new extra emit code section so that the emitted child processor can depend on |
426 | // sksl variables defined in earlier sksl code. |
427 | this->newExtraEmitCodeBlock(); |
428 | |
429 | // Set to the empty string when no input color parameter should be emitted, which means this |
430 | // must be properly formatted with a prefixed comma when the parameter should be inserted |
431 | // into the invokeChild() parameter list. |
432 | String inputArg; |
433 | if (c.fArguments.size() > 1 && c.fArguments[1]->fType.name() == "half4" ) { |
434 | // Use the invokeChild() variant that accepts an input color, so convert the 2nd |
435 | // argument's expression into C++ code that produces sksl stored in an SkString. |
436 | String inputName = "_input" + to_string(c.fOffset); |
437 | addExtraEmitCodeLine(convertSKSLExpressionToCPP(*c.fArguments[1], inputName)); |
438 | |
439 | // invokeChild() needs a char* |
440 | inputArg = ", " + inputName + ".c_str()" ; |
441 | } |
442 | |
443 | bool hasCoords = c.fArguments.back()->fType.name() == "float2" ; |
444 | |
445 | // Write the output handling after the possible input handling |
446 | String childName = "_sample" + to_string(c.fOffset); |
447 | addExtraEmitCodeLine("SkString " + childName + ";" ); |
448 | String coordsName; |
449 | if (hasCoords) { |
450 | coordsName = "_coords" + to_string(c.fOffset); |
451 | addExtraEmitCodeLine(convertSKSLExpressionToCPP(*c.fArguments.back(), coordsName)); |
452 | } |
453 | if (c.fArguments[0]->fType.kind() == Type::kNullable_Kind) { |
454 | addExtraEmitCodeLine("if (_outer." + String(child.fName) + "_index >= 0) {\n " ); |
455 | } |
456 | if (hasCoords) { |
457 | addExtraEmitCodeLine(childName + " = this->invokeChild(_outer." + String(child.fName) + |
458 | "_index" + inputArg + ", args, " + coordsName + ".c_str());" ); |
459 | } else { |
460 | addExtraEmitCodeLine(childName + " = this->invokeChild(_outer." + String(child.fName) + |
461 | "_index" + inputArg + ", args);" ); |
462 | } |
463 | |
464 | if (c.fArguments[0]->fType.kind() == Type::kNullable_Kind) { |
465 | // Null FPs are not emitted, but their output can still be referenced in dependent |
466 | // expressions - thus we always fill the variable with something. |
467 | // Note: this is essentially dead code required to satisfy the compiler, because |
468 | // 'process' function calls should always be guarded at a higher level, in the .fp |
469 | // source. |
470 | addExtraEmitCodeLine( |
471 | "} else {" |
472 | " " + childName + " = \"half4(1)\";" |
473 | "}" ); |
474 | } |
475 | this->write("%s" ); |
476 | fFormatArgs.push_back(childName + ".c_str()" ); |
477 | return; |
478 | } |
479 | if (c.fFunction.fBuiltin) { |
480 | INHERITED::writeFunctionCall(c); |
481 | } else { |
482 | this->write("%s" ); |
483 | fFormatArgs.push_back((String(c.fFunction.fName) + "_name.c_str()" ).c_str()); |
484 | this->write("(" ); |
485 | const char* separator = "" ; |
486 | for (const auto& arg : c.fArguments) { |
487 | this->write(separator); |
488 | separator = ", " ; |
489 | this->writeExpression(*arg, kSequence_Precedence); |
490 | } |
491 | this->write(")" ); |
492 | } |
493 | if (c.fFunction.fBuiltin && c.fFunction.fName == "sample" ) { |
494 | this->write(".%s" ); |
495 | SkASSERT(c.fArguments.size() >= 1); |
496 | SkASSERT(c.fArguments[0]->fKind == Expression::kVariableReference_Kind); |
497 | String sampler = this->getSamplerHandle(((VariableReference&) *c.fArguments[0]).fVariable); |
498 | fFormatArgs.push_back("fragBuilder->getProgramBuilder()->samplerSwizzle(" + sampler + |
499 | ").asString().c_str()" ); |
500 | } |
501 | } |
502 | |
503 | static const char* glsltype_string(const Context& context, const Type& type) { |
504 | if (type == *context.fFloat_Type) { |
505 | return "kFloat_GrSLType" ; |
506 | } else if (type == *context.fHalf_Type) { |
507 | return "kHalf_GrSLType" ; |
508 | } else if (type == *context.fFloat2_Type) { |
509 | return "kFloat2_GrSLType" ; |
510 | } else if (type == *context.fHalf2_Type) { |
511 | return "kHalf2_GrSLType" ; |
512 | } else if (type == *context.fFloat3_Type) { |
513 | return "kFloat3_GrSLType" ; |
514 | } else if (type == *context.fHalf3_Type) { |
515 | return "kHalf3_GrSLType" ; |
516 | } else if (type == *context.fFloat4_Type) { |
517 | return "kFloat4_GrSLType" ; |
518 | } else if (type == *context.fHalf4_Type) { |
519 | return "kHalf4_GrSLType" ; |
520 | } else if (type == *context.fFloat4x4_Type) { |
521 | return "kFloat4x4_GrSLType" ; |
522 | } else if (type == *context.fHalf4x4_Type) { |
523 | return "kHalf4x4_GrSLType" ; |
524 | } else if (type == *context.fVoid_Type) { |
525 | return "kVoid_GrSLType" ; |
526 | } else if (type.kind() == Type::kEnum_Kind) { |
527 | return "int" ; |
528 | } |
529 | SkASSERT(false); |
530 | return nullptr; |
531 | } |
532 | |
533 | void CPPCodeGenerator::writeFunction(const FunctionDefinition& f) { |
534 | const FunctionDeclaration& decl = f.fDeclaration; |
535 | fFunctionHeader = "" ; |
536 | OutputStream* oldOut = fOut; |
537 | StringStream buffer; |
538 | fOut = &buffer; |
539 | if (decl.fName == "main" ) { |
540 | fInMain = true; |
541 | for (const auto& s : ((Block&) *f.fBody).fStatements) { |
542 | this->writeStatement(*s); |
543 | this->writeLine(); |
544 | } |
545 | fInMain = false; |
546 | |
547 | fOut = oldOut; |
548 | this->write(fFunctionHeader); |
549 | this->write(buffer.str()); |
550 | } else { |
551 | this->addExtraEmitCodeLine("SkString " + decl.fName + "_name;" ); |
552 | String args = "const GrShaderVar " + decl.fName + "_args[] = { " ; |
553 | const char* separator = "" ; |
554 | for (const auto& param : decl.fParameters) { |
555 | args += String(separator) + "GrShaderVar(\"" + param->fName + "\", " + |
556 | glsltype_string(fContext, param->fType) + ")" ; |
557 | separator = ", " ; |
558 | } |
559 | args += "};" ; |
560 | this->addExtraEmitCodeLine(args.c_str()); |
561 | for (const auto& s : ((Block&) *f.fBody).fStatements) { |
562 | this->writeStatement(*s); |
563 | this->writeLine(); |
564 | } |
565 | |
566 | fOut = oldOut; |
567 | String emit = "fragBuilder->emitFunction(" ; |
568 | emit += glsltype_string(fContext, decl.fReturnType); |
569 | emit += ", \"" + decl.fName + "\"" ; |
570 | emit += ", " + to_string((int64_t) decl.fParameters.size()); |
571 | emit += ", " + decl.fName + "_args" ; |
572 | emit += ", \"" + buffer.str() + "\"" ; |
573 | emit += ", &" + decl.fName + "_name);" ; |
574 | this->addExtraEmitCodeLine(emit.c_str()); |
575 | } |
576 | } |
577 | |
578 | void CPPCodeGenerator::writeSetting(const Setting& s) { |
579 | static constexpr const char* kPrefix = "sk_Args." ; |
580 | if (!strncmp(s.fName.c_str(), kPrefix, strlen(kPrefix))) { |
581 | const char* name = s.fName.c_str() + strlen(kPrefix); |
582 | this->writeRuntimeValue(s.fType, Layout(), HCodeGenerator::FieldName(name).c_str()); |
583 | } else { |
584 | this->write(s.fName.c_str()); |
585 | } |
586 | } |
587 | |
588 | bool CPPCodeGenerator::writeSection(const char* name, const char* prefix) { |
589 | const Section* s = fSectionAndParameterHelper.getSection(name); |
590 | if (s) { |
591 | this->writef("%s%s" , prefix, s->fText.c_str()); |
592 | return true; |
593 | } |
594 | return false; |
595 | } |
596 | |
597 | void CPPCodeGenerator::writeProgramElement(const ProgramElement& p) { |
598 | if (p.fKind == ProgramElement::kSection_Kind) { |
599 | return; |
600 | } |
601 | if (p.fKind == ProgramElement::kVar_Kind) { |
602 | const VarDeclarations& decls = (const VarDeclarations&) p; |
603 | if (!decls.fVars.size()) { |
604 | return; |
605 | } |
606 | const Variable& var = *((VarDeclaration&) *decls.fVars[0]).fVar; |
607 | if (var.fModifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kUniform_Flag) || |
608 | -1 != var.fModifiers.fLayout.fBuiltin) { |
609 | return; |
610 | } |
611 | } |
612 | INHERITED::writeProgramElement(p); |
613 | } |
614 | |
615 | void CPPCodeGenerator::addUniform(const Variable& var) { |
616 | if (!needs_uniform_var(var)) { |
617 | return; |
618 | } |
619 | if (var.fModifiers.fLayout.fWhen.fLength) { |
620 | this->writef(" if (%s) {\n " , String(var.fModifiers.fLayout.fWhen).c_str()); |
621 | } |
622 | const char* type = glsltype_string(fContext, var.fType); |
623 | String name(var.fName); |
624 | this->writef(" %sVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag," |
625 | " %s, \"%s\");\n" , HCodeGenerator::FieldName(name.c_str()).c_str(), type, |
626 | name.c_str()); |
627 | if (var.fModifiers.fLayout.fWhen.fLength) { |
628 | this->write(" }\n" ); |
629 | } |
630 | } |
631 | |
632 | void CPPCodeGenerator::writeInputVars() { |
633 | } |
634 | |
635 | void CPPCodeGenerator::writePrivateVars() { |
636 | for (const auto& p : fProgram) { |
637 | if (ProgramElement::kVar_Kind == p.fKind) { |
638 | const VarDeclarations& decls = (const VarDeclarations&) p; |
639 | for (const auto& raw : decls.fVars) { |
640 | VarDeclaration& decl = (VarDeclaration&) *raw; |
641 | if (is_private(*decl.fVar)) { |
642 | if (decl.fVar->fType == *fContext.fFragmentProcessor_Type) { |
643 | fErrors.error(decl.fOffset, |
644 | "fragmentProcessor variables must be declared 'in'" ); |
645 | return; |
646 | } |
647 | this->writef("%s %s = %s;\n" , |
648 | HCodeGenerator::FieldType(fContext, decl.fVar->fType, |
649 | decl.fVar->fModifiers.fLayout).c_str(), |
650 | String(decl.fVar->fName).c_str(), |
651 | default_value(*decl.fVar).c_str()); |
652 | } else if (decl.fVar->fModifiers.fLayout.fFlags & Layout::kTracked_Flag) { |
653 | // An auto-tracked uniform in variable, so add a field to hold onto the prior |
654 | // state. Note that tracked variables must be uniform in's and that is validated |
655 | // before writePrivateVars() is called. |
656 | const UniformCTypeMapper* mapper = UniformCTypeMapper::Get(fContext, *decl.fVar); |
657 | SkASSERT(mapper && mapper->supportsTracking()); |
658 | |
659 | String name = HCodeGenerator::FieldName(String(decl.fVar->fName).c_str()); |
660 | // The member statement is different if the mapper reports a default value |
661 | if (mapper->defaultValue().size() > 0) { |
662 | this->writef("%s %sPrev = %s;\n" , |
663 | Layout::CTypeToStr(mapper->ctype()), name.c_str(), |
664 | mapper->defaultValue().c_str()); |
665 | } else { |
666 | this->writef("%s %sPrev;\n" , |
667 | Layout::CTypeToStr(mapper->ctype()), name.c_str()); |
668 | } |
669 | } |
670 | } |
671 | } |
672 | } |
673 | } |
674 | |
675 | void CPPCodeGenerator::writePrivateVarValues() { |
676 | for (const auto& p : fProgram) { |
677 | if (ProgramElement::kVar_Kind == p.fKind) { |
678 | const VarDeclarations& decls = (const VarDeclarations&) p; |
679 | for (const auto& raw : decls.fVars) { |
680 | VarDeclaration& decl = (VarDeclaration&) *raw; |
681 | if (is_private(*decl.fVar) && decl.fValue) { |
682 | this->writef("%s = " , String(decl.fVar->fName).c_str()); |
683 | fCPPMode = true; |
684 | this->writeExpression(*decl.fValue, kAssignment_Precedence); |
685 | fCPPMode = false; |
686 | this->write(";\n" ); |
687 | } |
688 | } |
689 | } |
690 | } |
691 | } |
692 | |
693 | static bool is_accessible(const Variable& var) { |
694 | const Type& type = var.fType.nonnullable(); |
695 | return Type::kSampler_Kind != type.kind() && |
696 | Type::kOther_Kind != type.kind(); |
697 | } |
698 | |
699 | void CPPCodeGenerator::() { |
700 | // This should only be called when emitting SKSL for emitCode(), which can be detected if the |
701 | // cpp buffer is not null, and the cpp buffer is not the current output. |
702 | SkASSERT(fCPPBuffer && fCPPBuffer != fOut); |
703 | |
704 | // Start a new block as an empty string |
705 | fExtraEmitCodeBlocks.push_back("" ); |
706 | // Mark its location in the output buffer, uses ${\d} for the token since ${} will not occur in |
707 | // valid sksl and makes detection trivial. |
708 | this->writef("${%zu}" , fExtraEmitCodeBlocks.size() - 1); |
709 | } |
710 | |
711 | void CPPCodeGenerator::(const String& toAppend) { |
712 | SkASSERT(fExtraEmitCodeBlocks.size() > 0); |
713 | String& currentBlock = fExtraEmitCodeBlocks[fExtraEmitCodeBlocks.size() - 1]; |
714 | // Automatically add indentation and newline |
715 | currentBlock += " " + toAppend + "\n" ; |
716 | } |
717 | |
718 | void CPPCodeGenerator::flushEmittedCode() { |
719 | if (fCPPBuffer == nullptr) { |
720 | // Not actually within writeEmitCode() so nothing to flush |
721 | return; |
722 | } |
723 | |
724 | StringStream* skslBuffer = static_cast<StringStream*>(fOut); |
725 | |
726 | String sksl = skslBuffer->str(); |
727 | // Empty the accumulation buffer since its current contents are consumed. |
728 | skslBuffer->reset(); |
729 | |
730 | // Switch to the cpp buffer |
731 | fOut = fCPPBuffer; |
732 | |
733 | // Iterate through the sksl, keeping track of where the last statement ended (e.g. the latest |
734 | // encountered ';', '{', or '}'). If an extra emit code block token is encountered then the |
735 | // code from 0 to last statement end is sent to writeCodeAppend, the extra code block is |
736 | // appended to the cpp buffer, and then the sksl string is trimmed to start where the last |
737 | // statement left off (minus the encountered token). |
738 | size_t i = 0; |
739 | int flushPoint = -1; |
740 | int tokenStart = -1; |
741 | while (i < sksl.size()) { |
742 | if (tokenStart >= 0) { |
743 | // Looking for the end of the token |
744 | if (sksl[i] == '}') { |
745 | // Must append the sksl from 0 to flushPoint (inclusive) then the extra code |
746 | // accumulated in the block with index parsed from chars [tokenStart+2, i-1] |
747 | String toFlush = String(sksl.c_str(), flushPoint + 1); |
748 | // writeCodeAppend automatically removes the format args that it consumed, so |
749 | // fFormatArgs will be in a valid state for any future sksl |
750 | this->writeCodeAppend(toFlush); |
751 | |
752 | int codeBlock = stoi(String(sksl.c_str() + tokenStart + 2, i - tokenStart - 2)); |
753 | SkASSERT(codeBlock < (int) fExtraEmitCodeBlocks.size()); |
754 | if (fExtraEmitCodeBlocks[codeBlock].size() > 0) { |
755 | this->write(fExtraEmitCodeBlocks[codeBlock].c_str()); |
756 | } |
757 | |
758 | // Now reset the sksl buffer to start after the flush point, but remove the token. |
759 | String compacted = String(sksl.c_str() + flushPoint + 1, |
760 | tokenStart - flushPoint - 1); |
761 | if (i < sksl.size() - 1) { |
762 | compacted += String(sksl.c_str() + i + 1, sksl.size() - i - 1); |
763 | } |
764 | sksl = compacted; |
765 | |
766 | // And reset iteration |
767 | i = -1; |
768 | flushPoint = -1; |
769 | tokenStart = -1; |
770 | } |
771 | } else { |
772 | // Looking for the start of extra emit block tokens, and tracking when statements end |
773 | if (sksl[i] == ';' || sksl[i] == '{' || sksl[i] == '}') { |
774 | flushPoint = i; |
775 | } else if (i < sksl.size() - 1 && sksl[i] == '$' && sksl[i + 1] == '{') { |
776 | // found an extra emit code block token |
777 | tokenStart = i++; |
778 | } |
779 | } |
780 | i++; |
781 | } |
782 | |
783 | // Once we've gone through the sksl string to this point, there are no remaining extra emit |
784 | // code blocks to interleave, so append the remainder as usual. |
785 | this->writeCodeAppend(sksl); |
786 | |
787 | // After appending, switch back to the emptied sksl buffer and reset the extra code blocks |
788 | fOut = skslBuffer; |
789 | fExtraEmitCodeBlocks.clear(); |
790 | } |
791 | |
792 | void CPPCodeGenerator::writeCodeAppend(const String& code) { |
793 | // codeAppendf can only handle appending 1024 bytes at a time, so we need to break the string |
794 | // into chunks. Unfortunately we can't tell exactly how long the string is going to end up, |
795 | // because printf escape sequences get replaced by strings of unknown length, but keeping the |
796 | // format string below 512 bytes is probably safe. |
797 | static constexpr size_t maxChunkSize = 512; |
798 | size_t start = 0; |
799 | size_t index = 0; |
800 | size_t argStart = 0; |
801 | size_t argCount; |
802 | while (index < code.size()) { |
803 | argCount = 0; |
804 | this->write(" fragBuilder->codeAppendf(\"" ); |
805 | while (index < code.size() && index < start + maxChunkSize) { |
806 | if ('%' == code[index]) { |
807 | if (index == start + maxChunkSize - 1 || index == code.size() - 1) { |
808 | break; |
809 | } |
810 | if (code[index + 1] != '%') { |
811 | ++argCount; |
812 | } |
813 | } else if ('\\' == code[index] && index == start + maxChunkSize - 1) { |
814 | // avoid splitting an escape sequence that happens to fall across a chunk boundary |
815 | break; |
816 | } |
817 | ++index; |
818 | } |
819 | fOut->write(code.c_str() + start, index - start); |
820 | this->write("\"" ); |
821 | for (size_t i = argStart; i < argStart + argCount; ++i) { |
822 | this->writef(", %s" , fFormatArgs[i].c_str()); |
823 | } |
824 | this->write(");\n" ); |
825 | argStart += argCount; |
826 | start = index; |
827 | } |
828 | |
829 | // argStart is equal to the number of fFormatArgs that were consumed |
830 | // so they should be removed from the list |
831 | if (argStart > 0) { |
832 | fFormatArgs.erase(fFormatArgs.begin(), fFormatArgs.begin() + argStart); |
833 | } |
834 | } |
835 | |
836 | String CPPCodeGenerator::convertSKSLExpressionToCPP(const Expression& e, |
837 | const String& cppVar) { |
838 | // To do this conversion, we temporarily switch the sksl output stream |
839 | // to an empty stringstream and reset the format args to empty. |
840 | OutputStream* oldSKSL = fOut; |
841 | StringStream exprBuffer; |
842 | fOut = &exprBuffer; |
843 | |
844 | std::vector<String> oldArgs(fFormatArgs); |
845 | fFormatArgs.clear(); |
846 | |
847 | // Convert the argument expression into a format string and args |
848 | this->writeExpression(e, Precedence::kTopLevel_Precedence); |
849 | std::vector<String> newArgs(fFormatArgs); |
850 | String expr = exprBuffer.str(); |
851 | |
852 | // After generating, restore the original output stream and format args |
853 | fFormatArgs = oldArgs; |
854 | fOut = oldSKSL; |
855 | |
856 | // The sksl written to exprBuffer is not processed by flushEmittedCode(), so any extra emit code |
857 | // block tokens won't get handled. So we need to strip them from the expression and stick them |
858 | // to the end of the original sksl stream. |
859 | String exprFormat = "" ; |
860 | int tokenStart = -1; |
861 | for (size_t i = 0; i < expr.size(); i++) { |
862 | if (tokenStart >= 0) { |
863 | if (expr[i] == '}') { |
864 | // End of the token, so append the token to fOut |
865 | fOut->write(expr.c_str() + tokenStart, i - tokenStart + 1); |
866 | tokenStart = -1; |
867 | } |
868 | } else { |
869 | if (i < expr.size() - 1 && expr[i] == '$' && expr[i + 1] == '{') { |
870 | tokenStart = i++; |
871 | } else { |
872 | exprFormat += expr[i]; |
873 | } |
874 | } |
875 | } |
876 | |
877 | // Now build the final C++ code snippet from the format string and args |
878 | String cppExpr; |
879 | if (newArgs.size() == 0) { |
880 | // This was a static expression, so we can simplify the input |
881 | // color declaration in the emitted code to just a static string |
882 | cppExpr = "SkString " + cppVar + "(\"" + exprFormat + "\");" ; |
883 | } else { |
884 | // String formatting must occur dynamically, so have the C++ declaration |
885 | // use SkStringPrintf with the format args that were accumulated |
886 | // when the expression was written. |
887 | cppExpr = "SkString " + cppVar + " = SkStringPrintf(\"" + exprFormat + "\"" ; |
888 | for (size_t i = 0; i < newArgs.size(); i++) { |
889 | cppExpr += ", " + newArgs[i]; |
890 | } |
891 | cppExpr += ");" ; |
892 | } |
893 | return cppExpr; |
894 | } |
895 | |
896 | bool CPPCodeGenerator::writeEmitCode(std::vector<const Variable*>& uniforms) { |
897 | this->write(" void emitCode(EmitArgs& args) override {\n" |
898 | " GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;\n" ); |
899 | this->writef(" const %s& _outer = args.fFp.cast<%s>();\n" |
900 | " (void) _outer;\n" , |
901 | fFullName.c_str(), fFullName.c_str()); |
902 | for (const auto& p : fProgram) { |
903 | if (ProgramElement::kVar_Kind == p.fKind) { |
904 | const VarDeclarations& decls = (const VarDeclarations&) p; |
905 | for (const auto& raw : decls.fVars) { |
906 | VarDeclaration& decl = (VarDeclaration&) *raw; |
907 | String nameString(decl.fVar->fName); |
908 | const char* name = nameString.c_str(); |
909 | if (SectionAndParameterHelper::IsParameter(*decl.fVar) && |
910 | is_accessible(*decl.fVar)) { |
911 | this->writef(" auto %s = _outer.%s;\n" |
912 | " (void) %s;\n" , |
913 | name, name, name); |
914 | } |
915 | } |
916 | } |
917 | } |
918 | this->writePrivateVarValues(); |
919 | for (const auto u : uniforms) { |
920 | this->addUniform(*u); |
921 | } |
922 | this->writeSection(EMIT_CODE_SECTION); |
923 | |
924 | // Save original buffer as the CPP buffer for flushEmittedCode() |
925 | fCPPBuffer = fOut; |
926 | StringStream skslBuffer; |
927 | fOut = &skslBuffer; |
928 | |
929 | this->newExtraEmitCodeBlock(); |
930 | bool result = INHERITED::generateCode(); |
931 | this->flushEmittedCode(); |
932 | |
933 | // Then restore the original CPP buffer and close the function |
934 | fOut = fCPPBuffer; |
935 | fCPPBuffer = nullptr; |
936 | this->write(" }\n" ); |
937 | return result; |
938 | } |
939 | |
940 | void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) { |
941 | const char* fullName = fFullName.c_str(); |
942 | const Section* section = fSectionAndParameterHelper.getSection(SET_DATA_SECTION); |
943 | const char* pdman = section ? section->fArgument.c_str() : "pdman" ; |
944 | this->writef(" void onSetData(const GrGLSLProgramDataManager& %s, " |
945 | "const GrFragmentProcessor& _proc) override {\n" , |
946 | pdman); |
947 | bool wroteProcessor = false; |
948 | for (const auto u : uniforms) { |
949 | if (is_uniform_in(*u)) { |
950 | if (!wroteProcessor) { |
951 | this->writef(" const %s& _outer = _proc.cast<%s>();\n" , fullName, fullName); |
952 | wroteProcessor = true; |
953 | this->writef(" {\n" ); |
954 | } |
955 | |
956 | const UniformCTypeMapper* mapper = UniformCTypeMapper::Get(fContext, *u); |
957 | SkASSERT(mapper); |
958 | |
959 | String nameString(u->fName); |
960 | const char* name = nameString.c_str(); |
961 | |
962 | // Switches for setData behavior in the generated code |
963 | bool conditionalUniform = u->fModifiers.fLayout.fWhen != "" ; |
964 | bool isTracked = u->fModifiers.fLayout.fFlags & Layout::kTracked_Flag; |
965 | bool needsValueDeclaration = isTracked || !mapper->canInlineUniformValue(); |
966 | |
967 | String uniformName = HCodeGenerator::FieldName(name) + "Var" ; |
968 | |
969 | String indent = " " ; // 8 by default, 12 when nested for conditional uniforms |
970 | if (conditionalUniform) { |
971 | // Add a pre-check to make sure the uniform was emitted |
972 | // before trying to send any data to the GPU |
973 | this->writef(" if (%s.isValid()) {\n" , uniformName.c_str()); |
974 | indent += " " ; |
975 | } |
976 | |
977 | String valueVar = "" ; |
978 | if (needsValueDeclaration) { |
979 | valueVar.appendf("%sValue" , name); |
980 | // Use AccessType since that will match the return type of _outer's public API. |
981 | String valueType = HCodeGenerator::AccessType(fContext, u->fType, |
982 | u->fModifiers.fLayout); |
983 | this->writef("%s%s %s = _outer.%s;\n" , |
984 | indent.c_str(), valueType.c_str(), valueVar.c_str(), name); |
985 | } else { |
986 | // Not tracked and the mapper only needs to use the value once |
987 | // so send it a safe expression instead of the variable name |
988 | valueVar.appendf("(_outer.%s)" , name); |
989 | } |
990 | |
991 | if (isTracked) { |
992 | SkASSERT(mapper->supportsTracking()); |
993 | |
994 | String prevVar = HCodeGenerator::FieldName(name) + "Prev" ; |
995 | this->writef("%sif (%s) {\n" |
996 | "%s %s;\n" |
997 | "%s %s;\n" |
998 | "%s}\n" , indent.c_str(), |
999 | mapper->dirtyExpression(valueVar, prevVar).c_str(), indent.c_str(), |
1000 | mapper->saveState(valueVar, prevVar).c_str(), indent.c_str(), |
1001 | mapper->setUniform(pdman, uniformName, valueVar).c_str(), indent.c_str()); |
1002 | } else { |
1003 | this->writef("%s%s;\n" , indent.c_str(), |
1004 | mapper->setUniform(pdman, uniformName, valueVar).c_str()); |
1005 | } |
1006 | |
1007 | if (conditionalUniform) { |
1008 | // Close the earlier precheck block |
1009 | this->writef(" }\n" ); |
1010 | } |
1011 | } |
1012 | } |
1013 | if (wroteProcessor) { |
1014 | this->writef(" }\n" ); |
1015 | } |
1016 | if (section) { |
1017 | int samplerIndex = 0; |
1018 | for (const auto& p : fProgram) { |
1019 | if (ProgramElement::kVar_Kind == p.fKind) { |
1020 | const VarDeclarations& decls = (const VarDeclarations&) p; |
1021 | for (const auto& raw : decls.fVars) { |
1022 | VarDeclaration& decl = (VarDeclaration&) *raw; |
1023 | String nameString(decl.fVar->fName); |
1024 | const char* name = nameString.c_str(); |
1025 | if (decl.fVar->fType.kind() == Type::kSampler_Kind) { |
1026 | this->writef(" const GrSurfaceProxyView& %sView = " |
1027 | "_outer.textureSampler(%d).view();\n" , |
1028 | name, samplerIndex); |
1029 | this->writef(" GrTexture& %s = *%sView.proxy()->peekTexture();\n" , |
1030 | name, name); |
1031 | this->writef(" (void) %s;\n" , name); |
1032 | ++samplerIndex; |
1033 | } else if (needs_uniform_var(*decl.fVar)) { |
1034 | this->writef(" UniformHandle& %s = %sVar;\n" |
1035 | " (void) %s;\n" , |
1036 | name, HCodeGenerator::FieldName(name).c_str(), name); |
1037 | } else if (SectionAndParameterHelper::IsParameter(*decl.fVar) && |
1038 | decl.fVar->fType != *fContext.fFragmentProcessor_Type) { |
1039 | if (!wroteProcessor) { |
1040 | this->writef(" const %s& _outer = _proc.cast<%s>();\n" , fullName, |
1041 | fullName); |
1042 | wroteProcessor = true; |
1043 | } |
1044 | this->writef(" auto %s = _outer.%s;\n" |
1045 | " (void) %s;\n" , |
1046 | name, name, name); |
1047 | } |
1048 | } |
1049 | } |
1050 | } |
1051 | this->writeSection(SET_DATA_SECTION); |
1052 | } |
1053 | this->write(" }\n" ); |
1054 | } |
1055 | |
1056 | void CPPCodeGenerator::writeOnTextureSampler() { |
1057 | bool foundSampler = false; |
1058 | for (const auto& param : fSectionAndParameterHelper.getParameters()) { |
1059 | if (param->fType.kind() == Type::kSampler_Kind) { |
1060 | if (!foundSampler) { |
1061 | this->writef( |
1062 | "const GrFragmentProcessor::TextureSampler& %s::onTextureSampler(int " |
1063 | "index) const {\n" , |
1064 | fFullName.c_str()); |
1065 | this->writef(" return IthTextureSampler(index, %s" , |
1066 | HCodeGenerator::FieldName(String(param->fName).c_str()).c_str()); |
1067 | foundSampler = true; |
1068 | } else { |
1069 | this->writef(", %s" , |
1070 | HCodeGenerator::FieldName(String(param->fName).c_str()).c_str()); |
1071 | } |
1072 | } |
1073 | } |
1074 | if (foundSampler) { |
1075 | this->write(");\n}\n" ); |
1076 | } |
1077 | } |
1078 | |
1079 | void CPPCodeGenerator::writeClone() { |
1080 | if (!this->writeSection(CLONE_SECTION)) { |
1081 | if (fSectionAndParameterHelper.getSection(FIELDS_SECTION)) { |
1082 | fErrors.error(0, "fragment processors with custom @fields must also have a custom" |
1083 | "@clone" ); |
1084 | } |
1085 | this->writef("%s::%s(const %s& src)\n" |
1086 | ": INHERITED(k%s_ClassID, src.optimizationFlags())" , fFullName.c_str(), |
1087 | fFullName.c_str(), fFullName.c_str(), fFullName.c_str()); |
1088 | const auto transforms = fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION); |
1089 | for (size_t i = 0; i < transforms.size(); ++i) { |
1090 | const Section& s = *transforms[i]; |
1091 | String fieldName = HCodeGenerator::CoordTransformName(s.fArgument, i); |
1092 | this->writef("\n, %s(src.%s)" , fieldName.c_str(), fieldName.c_str()); |
1093 | } |
1094 | for (const auto& param : fSectionAndParameterHelper.getParameters()) { |
1095 | String fieldName = HCodeGenerator::FieldName(String(param->fName).c_str()); |
1096 | if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type) { |
1097 | this->writef("\n, %s_index(src.%s_index)" , |
1098 | fieldName.c_str(), |
1099 | fieldName.c_str()); |
1100 | } else { |
1101 | this->writef("\n, %s(src.%s)" , |
1102 | fieldName.c_str(), |
1103 | fieldName.c_str()); |
1104 | } |
1105 | } |
1106 | this->writef(" {\n" ); |
1107 | int samplerCount = 0; |
1108 | for (const auto& param : fSectionAndParameterHelper.getParameters()) { |
1109 | if (param->fType.kind() == Type::kSampler_Kind) { |
1110 | ++samplerCount; |
1111 | } else if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type) { |
1112 | String fieldName = HCodeGenerator::FieldName(String(param->fName).c_str()); |
1113 | if (param->fType.kind() == Type::kNullable_Kind) { |
1114 | this->writef(" if (%s_index >= 0) {\n" , fieldName.c_str()); |
1115 | } else { |
1116 | this->write(" {\n" ); |
1117 | } |
1118 | this->writef( |
1119 | " auto clone = src.childProcessor(%s_index).clone();\n" |
1120 | " clone->setSampledWithExplicitCoords(\n" |
1121 | " " |
1122 | "src.childProcessor(%s_index).isSampledWithExplicitCoords());\n" |
1123 | " this->registerChildProcessor(std::move(clone));\n" |
1124 | " }\n" , |
1125 | fieldName.c_str(), fieldName.c_str()); |
1126 | } |
1127 | } |
1128 | if (samplerCount) { |
1129 | this->writef(" this->setTextureSamplerCnt(%d);" , samplerCount); |
1130 | } |
1131 | for (size_t i = 0; i < transforms.size(); ++i) { |
1132 | const Section& s = *transforms[i]; |
1133 | String fieldName = HCodeGenerator::CoordTransformName(s.fArgument, i); |
1134 | this->writef(" this->addCoordTransform(&%s);\n" , fieldName.c_str()); |
1135 | } |
1136 | this->write("}\n" ); |
1137 | this->writef("std::unique_ptr<GrFragmentProcessor> %s::clone() const {\n" , |
1138 | fFullName.c_str()); |
1139 | this->writef(" return std::unique_ptr<GrFragmentProcessor>(new %s(*this));\n" , |
1140 | fFullName.c_str()); |
1141 | this->write("}\n" ); |
1142 | } |
1143 | } |
1144 | |
1145 | void CPPCodeGenerator::writeTest() { |
1146 | const Section* test = fSectionAndParameterHelper.getSection(TEST_CODE_SECTION); |
1147 | if (test) { |
1148 | this->writef( |
1149 | "GR_DEFINE_FRAGMENT_PROCESSOR_TEST(%s);\n" |
1150 | "#if GR_TEST_UTILS\n" |
1151 | "std::unique_ptr<GrFragmentProcessor> %s::TestCreate(GrProcessorTestData* %s) {\n" , |
1152 | fFullName.c_str(), |
1153 | fFullName.c_str(), |
1154 | test->fArgument.c_str()); |
1155 | this->writeSection(TEST_CODE_SECTION); |
1156 | this->write("}\n" |
1157 | "#endif\n" ); |
1158 | } |
1159 | } |
1160 | |
1161 | void CPPCodeGenerator::writeGetKey() { |
1162 | this->writef("void %s::onGetGLSLProcessorKey(const GrShaderCaps& caps, " |
1163 | "GrProcessorKeyBuilder* b) const {\n" , |
1164 | fFullName.c_str()); |
1165 | for (const auto& p : fProgram) { |
1166 | if (ProgramElement::kVar_Kind == p.fKind) { |
1167 | const VarDeclarations& decls = (const VarDeclarations&) p; |
1168 | for (const auto& raw : decls.fVars) { |
1169 | const VarDeclaration& decl = (VarDeclaration&) *raw; |
1170 | const Variable& var = *decl.fVar; |
1171 | String nameString(var.fName); |
1172 | const char* name = nameString.c_str(); |
1173 | if (var.fModifiers.fLayout.fKey != Layout::kNo_Key && |
1174 | (var.fModifiers.fFlags & Modifiers::kUniform_Flag)) { |
1175 | fErrors.error(var.fOffset, |
1176 | "layout(key) may not be specified on uniforms" ); |
1177 | } |
1178 | switch (var.fModifiers.fLayout.fKey) { |
1179 | case Layout::kKey_Key: |
1180 | if (is_private(var)) { |
1181 | this->writef("%s %s =" , |
1182 | HCodeGenerator::FieldType(fContext, var.fType, |
1183 | var.fModifiers.fLayout).c_str(), |
1184 | String(var.fName).c_str()); |
1185 | if (decl.fValue) { |
1186 | fCPPMode = true; |
1187 | this->writeExpression(*decl.fValue, kAssignment_Precedence); |
1188 | fCPPMode = false; |
1189 | } else { |
1190 | this->writef("%s" , default_value(var).c_str()); |
1191 | } |
1192 | this->write(";\n" ); |
1193 | } |
1194 | if (var.fModifiers.fLayout.fWhen.fLength) { |
1195 | this->writef("if (%s) {" , String(var.fModifiers.fLayout.fWhen).c_str()); |
1196 | } |
1197 | if (var.fType == *fContext.fFloat4x4_Type) { |
1198 | ABORT("no automatic key handling for float4x4\n" ); |
1199 | } else if (var.fType == *fContext.fFloat2_Type) { |
1200 | this->writef(" b->add32(%s.fX);\n" , |
1201 | HCodeGenerator::FieldName(name).c_str()); |
1202 | this->writef(" b->add32(%s.fY);\n" , |
1203 | HCodeGenerator::FieldName(name).c_str()); |
1204 | } else if (var.fType == *fContext.fFloat4_Type) { |
1205 | this->writef(" b->add32(%s.x());\n" , |
1206 | HCodeGenerator::FieldName(name).c_str()); |
1207 | this->writef(" b->add32(%s.y());\n" , |
1208 | HCodeGenerator::FieldName(name).c_str()); |
1209 | this->writef(" b->add32(%s.width());\n" , |
1210 | HCodeGenerator::FieldName(name).c_str()); |
1211 | this->writef(" b->add32(%s.height());\n" , |
1212 | HCodeGenerator::FieldName(name).c_str()); |
1213 | } else if (var.fType == *fContext.fHalf4_Type) { |
1214 | this->writef(" uint16_t red = SkFloatToHalf(%s.fR);\n" , |
1215 | HCodeGenerator::FieldName(name).c_str()); |
1216 | this->writef(" uint16_t green = SkFloatToHalf(%s.fG);\n" , |
1217 | HCodeGenerator::FieldName(name).c_str()); |
1218 | this->writef(" uint16_t blue = SkFloatToHalf(%s.fB);\n" , |
1219 | HCodeGenerator::FieldName(name).c_str()); |
1220 | this->writef(" uint16_t alpha = SkFloatToHalf(%s.fA);\n" , |
1221 | HCodeGenerator::FieldName(name).c_str()); |
1222 | this->write(" b->add32(((uint32_t)red << 16) | green);\n" ); |
1223 | this->write(" b->add32(((uint32_t)blue << 16) | alpha);\n" ); |
1224 | } else { |
1225 | this->writef(" b->add32((int32_t) %s);\n" , |
1226 | HCodeGenerator::FieldName(name).c_str()); |
1227 | } |
1228 | if (var.fModifiers.fLayout.fWhen.fLength) { |
1229 | this->write("}" ); |
1230 | } |
1231 | break; |
1232 | case Layout::kIdentity_Key: |
1233 | if (var.fType.kind() != Type::kMatrix_Kind) { |
1234 | fErrors.error(var.fOffset, |
1235 | "layout(key=identity) requires matrix type" ); |
1236 | } |
1237 | this->writef(" b->add32(%s.isIdentity() ? 1 : 0);\n" , |
1238 | HCodeGenerator::FieldName(name).c_str()); |
1239 | break; |
1240 | case Layout::kNo_Key: |
1241 | break; |
1242 | } |
1243 | } |
1244 | } |
1245 | } |
1246 | this->write("}\n" ); |
1247 | } |
1248 | |
1249 | bool CPPCodeGenerator::generateCode() { |
1250 | std::vector<const Variable*> uniforms; |
1251 | for (const auto& p : fProgram) { |
1252 | if (ProgramElement::kVar_Kind == p.fKind) { |
1253 | const VarDeclarations& decls = (const VarDeclarations&) p; |
1254 | for (const auto& raw : decls.fVars) { |
1255 | VarDeclaration& decl = (VarDeclaration&) *raw; |
1256 | if ((decl.fVar->fModifiers.fFlags & Modifiers::kUniform_Flag) && |
1257 | decl.fVar->fType.kind() != Type::kSampler_Kind) { |
1258 | uniforms.push_back(decl.fVar); |
1259 | } |
1260 | |
1261 | if (is_uniform_in(*decl.fVar)) { |
1262 | // Validate the "uniform in" declarations to make sure they are fully supported, |
1263 | // instead of generating surprising C++ |
1264 | const UniformCTypeMapper* mapper = |
1265 | UniformCTypeMapper::Get(fContext, *decl.fVar); |
1266 | if (mapper == nullptr) { |
1267 | fErrors.error(decl.fOffset, String(decl.fVar->fName) |
1268 | + "'s type is not supported for use as a 'uniform in'" ); |
1269 | return false; |
1270 | } |
1271 | if (decl.fVar->fModifiers.fLayout.fFlags & Layout::kTracked_Flag) { |
1272 | if (!mapper->supportsTracking()) { |
1273 | fErrors.error(decl.fOffset, String(decl.fVar->fName) |
1274 | + "'s type does not support state tracking" ); |
1275 | return false; |
1276 | } |
1277 | } |
1278 | |
1279 | } else { |
1280 | // If it's not a uniform_in, it's an error to be tracked |
1281 | if (decl.fVar->fModifiers.fLayout.fFlags & Layout::kTracked_Flag) { |
1282 | fErrors.error(decl.fOffset, "Non-'in uniforms' cannot be tracked" ); |
1283 | return false; |
1284 | } |
1285 | } |
1286 | } |
1287 | } |
1288 | } |
1289 | const char* baseName = fName.c_str(); |
1290 | const char* fullName = fFullName.c_str(); |
1291 | this->writef("%s\n" , HCodeGenerator::GetHeader(fProgram, fErrors).c_str()); |
1292 | this->writef(kFragmentProcessorHeader, fullName); |
1293 | this->writef("#include \"%s.h\"\n\n" , fullName); |
1294 | this->writeSection(CPP_SECTION); |
1295 | this->writef("#include \"src/gpu/GrTexture.h\"\n" |
1296 | "#include \"src/gpu/glsl/GrGLSLFragmentProcessor.h\"\n" |
1297 | "#include \"src/gpu/glsl/GrGLSLFragmentShaderBuilder.h\"\n" |
1298 | "#include \"src/gpu/glsl/GrGLSLProgramBuilder.h\"\n" |
1299 | "#include \"src/sksl/SkSLCPP.h\"\n" |
1300 | "#include \"src/sksl/SkSLUtil.h\"\n" |
1301 | "class GrGLSL%s : public GrGLSLFragmentProcessor {\n" |
1302 | "public:\n" |
1303 | " GrGLSL%s() {}\n" , |
1304 | baseName, baseName); |
1305 | bool result = this->writeEmitCode(uniforms); |
1306 | this->write("private:\n" ); |
1307 | this->writeSetData(uniforms); |
1308 | this->writePrivateVars(); |
1309 | for (const auto& u : uniforms) { |
1310 | if (needs_uniform_var(*u) && !(u->fModifiers.fFlags & Modifiers::kIn_Flag)) { |
1311 | this->writef(" UniformHandle %sVar;\n" , |
1312 | HCodeGenerator::FieldName(String(u->fName).c_str()).c_str()); |
1313 | } |
1314 | } |
1315 | for (const auto& param : fSectionAndParameterHelper.getParameters()) { |
1316 | if (needs_uniform_var(*param)) { |
1317 | this->writef(" UniformHandle %sVar;\n" , |
1318 | HCodeGenerator::FieldName(String(param->fName).c_str()).c_str()); |
1319 | } |
1320 | } |
1321 | this->writef("};\n" |
1322 | "GrGLSLFragmentProcessor* %s::onCreateGLSLInstance() const {\n" |
1323 | " return new GrGLSL%s();\n" |
1324 | "}\n" , |
1325 | fullName, baseName); |
1326 | this->writeGetKey(); |
1327 | this->writef("bool %s::onIsEqual(const GrFragmentProcessor& other) const {\n" |
1328 | " const %s& that = other.cast<%s>();\n" |
1329 | " (void) that;\n" , |
1330 | fullName, fullName, fullName); |
1331 | for (const auto& param : fSectionAndParameterHelper.getParameters()) { |
1332 | if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type) { |
1333 | continue; |
1334 | } |
1335 | String nameString(param->fName); |
1336 | const char* name = nameString.c_str(); |
1337 | this->writef(" if (%s != that.%s) return false;\n" , |
1338 | HCodeGenerator::FieldName(name).c_str(), |
1339 | HCodeGenerator::FieldName(name).c_str()); |
1340 | } |
1341 | this->write(" return true;\n" |
1342 | "}\n" ); |
1343 | this->writeClone(); |
1344 | this->writeOnTextureSampler(); |
1345 | this->writeTest(); |
1346 | this->writeSection(CPP_END_SECTION); |
1347 | |
1348 | result &= 0 == fErrors.errorCount(); |
1349 | return result; |
1350 | } |
1351 | |
1352 | } // namespace |
1353 | |