blob: 9d09a87335b03a93eedfcf892f59206ef0704811 [file] [log] [blame]
Ethan Nicholas762466e2017-06-29 10:03:38 -04001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkSLCPPCodeGenerator.h"
9
10#include "SkSLCompiler.h"
11#include "SkSLHCodeGenerator.h"
12
13namespace SkSL {
14
15static bool needs_uniform_var(const Variable& var) {
16 return (var.fModifiers.fFlags & Modifiers::kUniform_Flag) &&
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070017 var.fType.fName != "colorSpaceXform";
Ethan Nicholas762466e2017-06-29 10:03:38 -040018}
19
20CPPCodeGenerator::CPPCodeGenerator(const Context* context, const Program* program,
21 ErrorReporter* errors, String name, OutputStream* out)
22: INHERITED(context, program, errors, out)
23, fName(std::move(name))
24, fFullName(String::printf("Gr%s", fName.c_str()))
25, fSectionAndParameterHelper(*program, *errors) {
26 fLineEnding = "\\n";
27}
28
29void CPPCodeGenerator::writef(const char* s, va_list va) {
30 static constexpr int BUFFER_SIZE = 1024;
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040031 va_list copy;
32 va_copy(copy, va);
Ethan Nicholas762466e2017-06-29 10:03:38 -040033 char buffer[BUFFER_SIZE];
34 int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
35 if (length < BUFFER_SIZE) {
36 fOut->write(buffer, length);
37 } else {
38 std::unique_ptr<char[]> heap(new char[length + 1]);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -040039 vsprintf(heap.get(), s, copy);
Ethan Nicholas762466e2017-06-29 10:03:38 -040040 fOut->write(heap.get(), length);
41 }
42}
43
44void CPPCodeGenerator::writef(const char* s, ...) {
45 va_list va;
46 va_start(va, s);
47 this->writef(s, va);
48 va_end(va);
49}
50
51void CPPCodeGenerator::writeHeader() {
52}
53
Ethan Nicholasf7b88202017-09-18 14:10:39 -040054bool CPPCodeGenerator::usesPrecisionModifiers() const {
55 return false;
Ethan Nicholas762466e2017-06-29 10:03:38 -040056}
57
Ethan Nicholasf7b88202017-09-18 14:10:39 -040058String CPPCodeGenerator::getTypeName(const Type& type) {
59 return type.name();
Ethan Nicholas5af9ea32017-07-28 15:19:46 -040060}
Ethan Nicholasf7b88202017-09-18 14:10:39 -040061
Ethan Nicholas762466e2017-06-29 10:03:38 -040062void CPPCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
63 Precedence parentPrecedence) {
64 if (b.fOperator == Token::PERCENT) {
65 // need to use "%%" instead of "%" b/c the code will be inside of a printf
66 Precedence precedence = GetBinaryPrecedence(b.fOperator);
67 if (precedence >= parentPrecedence) {
68 this->write("(");
69 }
70 this->writeExpression(*b.fLeft, precedence);
71 this->write(" %% ");
72 this->writeExpression(*b.fRight, precedence);
73 if (precedence >= parentPrecedence) {
74 this->write(")");
75 }
76 } else {
77 INHERITED::writeBinaryExpression(b, parentPrecedence);
78 }
79}
80
81void CPPCodeGenerator::writeIndexExpression(const IndexExpression& i) {
82 const Expression& base = *i.fBase;
83 if (base.fKind == Expression::kVariableReference_Kind) {
84 int builtin = ((VariableReference&) base).fVariable.fModifiers.fLayout.fBuiltin;
85 if (SK_TRANSFORMEDCOORDS2D_BUILTIN == builtin) {
86 this->write("%s");
87 if (i.fIndex->fKind != Expression::kIntLiteral_Kind) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070088 fErrors.error(i.fIndex->fOffset,
Ethan Nicholas762466e2017-06-29 10:03:38 -040089 "index into sk_TransformedCoords2D must be an integer literal");
90 return;
91 }
92 int64_t index = ((IntLiteral&) *i.fIndex).fValue;
93 String name = "sk_TransformedCoords2D_" + to_string(index);
94 fFormatArgs.push_back(name + ".c_str()");
95 if (fWrittenTransformedCoords.find(index) == fWrittenTransformedCoords.end()) {
Brian Osman72a37be2017-08-15 09:19:53 -040096 fExtraEmitCodeCode += " SkString " + name +
Ethan Nicholas762466e2017-06-29 10:03:38 -040097 " = fragBuilder->ensureCoords2D(args.fTransformedCoords[" +
98 to_string(index) + "]);\n";
99 fWrittenTransformedCoords.insert(index);
100 }
101 return;
102 } else if (SK_TEXTURESAMPLERS_BUILTIN == builtin) {
103 this->write("%s");
104 if (i.fIndex->fKind != Expression::kIntLiteral_Kind) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700105 fErrors.error(i.fIndex->fOffset,
Ethan Nicholas762466e2017-06-29 10:03:38 -0400106 "index into sk_TextureSamplers must be an integer literal");
107 return;
108 }
109 int64_t index = ((IntLiteral&) *i.fIndex).fValue;
110 fFormatArgs.push_back(" fragBuilder->getProgramBuilder()->samplerVariable("
111 "args.fTexSamplers[" + to_string(index) + "]).c_str()");
112 return;
113 }
114 }
115 INHERITED::writeIndexExpression(i);
116}
117
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400118static String default_value(const Type& type) {
119 if (type.fName == "colorSpaceXform") {
Brian Salomon1d816b92017-08-17 11:07:59 -0400120 return "float4x4(1.0)";
Ethan Nicholas762466e2017-06-29 10:03:38 -0400121 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400122 switch (type.kind()) {
123 case Type::kScalar_Kind: return "0";
124 case Type::kVector_Kind: return type.name() + "(0)";
125 case Type::kMatrix_Kind: return type.name() + "(1)";
126 default: ABORT("unsupported default_value type\n");
127 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400128}
129
130static bool is_private(const Variable& var) {
131 return !(var.fModifiers.fFlags & Modifiers::kUniform_Flag) &&
132 !(var.fModifiers.fFlags & Modifiers::kIn_Flag) &&
133 var.fStorage == Variable::kGlobal_Storage &&
134 var.fModifiers.fLayout.fBuiltin == -1;
135}
136
137void CPPCodeGenerator::writeRuntimeValue(const Type& type, const String& cppCode) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400138 if (type.isFloat()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400139 this->write("%f");
140 fFormatArgs.push_back(cppCode);
141 } else if (type == *fContext.fInt_Type) {
142 this->write("%d");
143 fFormatArgs.push_back(cppCode);
144 } else if (type == *fContext.fBool_Type) {
145 this->write("%s");
146 fFormatArgs.push_back("(" + cppCode + " ? \"true\" : \"false\")");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400147 } else if (type == *fContext.fFloat2_Type || type == *fContext.fHalf2_Type) {
148 this->write(type.name() + "(%f, %f)");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400149 fFormatArgs.push_back(cppCode + ".fX");
150 fFormatArgs.push_back(cppCode + ".fY");
151 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400152 this->write(type.name());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700153 this->write("\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400154 ABORT("unsupported runtime value type\n");
155 }
156}
157
158void CPPCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
159 if (is_private(var)) {
160 this->writeRuntimeValue(var.fType, var.fName);
161 } else {
162 this->writeExpression(value, kTopLevel_Precedence);
163 }
164}
165
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400166String CPPCodeGenerator::getSamplerHandle(const Variable& var) {
167 int samplerCount = 0;
Ethan Nicholas68990be2017-07-13 09:36:52 -0400168 for (const auto param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400169 if (&var == param) {
170 return "args.fTexSamplers[" + to_string(samplerCount) + "]";
171 }
172 if (param->fType.kind() == Type::kSampler_Kind) {
173 ++samplerCount;
174 }
175 }
176 ABORT("should have found sampler in parameters\n");
177}
178
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400179void CPPCodeGenerator::writeIntLiteral(const IntLiteral& i) {
180 this->write(to_string((int32_t) i.fValue));
181}
182
Ethan Nicholas762466e2017-06-29 10:03:38 -0400183void CPPCodeGenerator::writeVariableReference(const VariableReference& ref) {
184 switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
185 case SK_INCOLOR_BUILTIN:
186 this->write("%s");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400187 fFormatArgs.push_back(String("args.fInputColor ? args.fInputColor : \"half4(1)\""));
Ethan Nicholas762466e2017-06-29 10:03:38 -0400188 break;
189 case SK_OUTCOLOR_BUILTIN:
190 this->write("%s");
191 fFormatArgs.push_back(String("args.fOutputColor"));
192 break;
193 default:
194 if (ref.fVariable.fType.kind() == Type::kSampler_Kind) {
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400195 this->write("%s");
196 fFormatArgs.push_back("fragBuilder->getProgramBuilder()->samplerVariable(" +
197 this->getSamplerHandle(ref.fVariable) + ").c_str()");
198 return;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400199 }
200 if (ref.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag) {
201 this->write("%s");
202 String name = ref.fVariable.fName;
203 String var;
204 if (ref.fVariable.fType == *fContext.fColorSpaceXform_Type) {
205 ASSERT(fNeedColorSpaceHelper);
206 var = String::printf("fColorSpaceHelper.isValid() ? "
207 "args.fUniformHandler->getUniformCStr("
208 "fColorSpaceHelper.gamutXformUniform()) : \"%s\"",
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400209 default_value(ref.fVariable.fType).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400210 } else {
211 var = String::printf("args.fUniformHandler->getUniformCStr(%sVar)",
212 HCodeGenerator::FieldName(name.c_str()).c_str());
213 }
214 String code;
215 if (ref.fVariable.fModifiers.fLayout.fWhen.size()) {
216 code = String::printf("%sVar.isValid() ? %s : \"%s\"",
217 HCodeGenerator::FieldName(name.c_str()).c_str(),
218 var.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400219 default_value(ref.fVariable.fType).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400220 } else {
221 code = var;
222 }
223 fFormatArgs.push_back(code);
224 } else if (SectionAndParameterHelper::IsParameter(ref.fVariable)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700225 String name(ref.fVariable.fName);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400226 this->writeRuntimeValue(ref.fVariable.fType,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700227 String::printf("_outer.%s()", name.c_str()).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400228 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700229 this->write(ref.fVariable.fName);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400230 }
231 }
232}
233
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -0400234void CPPCodeGenerator::writeIfStatement(const IfStatement& s) {
235 if (s.fIsStatic) {
236 this->write("@");
237 }
238 INHERITED::writeIfStatement(s);
239}
240
241void CPPCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
242 if (s.fIsStatic) {
243 this->write("@");
244 }
245 INHERITED::writeSwitchStatement(s);
246}
247
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400248void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400249 if (c.fFunction.fBuiltin && c.fFunction.fName == "COLORSPACE") {
250 String tmpVar = "_tmpVar" + to_string(++fVarCount);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400251 fFunctionHeader += "half4 " + tmpVar + ";";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400252 ASSERT(c.fArguments.size() == 2);
253 this->write("%s");
254 fFormatArgs.push_back("fColorSpaceHelper.isValid() ? \"(" + tmpVar + " = \" : \"\"");
255 this->writeExpression(*c.fArguments[0], kTopLevel_Precedence);
256 ASSERT(c.fArguments[1]->fKind == Expression::kVariableReference_Kind);
257 String xform("args.fUniformHandler->getUniformCStr(fColorSpaceHelper.gamutXformUniform())");
258 this->write("%s");
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400259 fFormatArgs.push_back("fColorSpaceHelper.isValid() ? SkStringPrintf(\", "
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400260 "half4(clamp((%s * half4(" + tmpVar + ".rgb, 1.0)).rgb, 0.0, " +
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400261 tmpVar + ".a), " + tmpVar + ".a))\", " + xform + ").c_str() : \"\"");
Ethan Nicholas68990be2017-07-13 09:36:52 -0400262 return;
263 }
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400264 INHERITED::writeFunctionCall(c);
265 if (c.fFunction.fBuiltin && c.fFunction.fName == "texture") {
266 this->write(".%s");
267 ASSERT(c.fArguments.size() >= 1);
268 ASSERT(c.fArguments[0]->fKind == Expression::kVariableReference_Kind);
269 String sampler = this->getSamplerHandle(((VariableReference&) *c.fArguments[0]).fVariable);
270 fFormatArgs.push_back("fragBuilder->getProgramBuilder()->samplerSwizzle(" + sampler +
271 ").c_str()");
272 }
273}
274
Ethan Nicholas762466e2017-06-29 10:03:38 -0400275void CPPCodeGenerator::writeFunction(const FunctionDefinition& f) {
276 if (f.fDeclaration.fName == "main") {
277 fFunctionHeader = "";
278 OutputStream* oldOut = fOut;
279 StringStream buffer;
280 fOut = &buffer;
281 for (const auto& s : ((Block&) *f.fBody).fStatements) {
282 this->writeStatement(*s);
283 this->writeLine();
284 }
285
286 fOut = oldOut;
287 this->write(fFunctionHeader);
288 this->write(buffer.str());
289 } else {
290 INHERITED::writeFunction(f);
291 }
292}
293
294void CPPCodeGenerator::writeSetting(const Setting& s) {
295 static constexpr const char* kPrefix = "sk_Args.";
296 if (!strncmp(s.fName.c_str(), kPrefix, strlen(kPrefix))) {
297 const char* name = s.fName.c_str() + strlen(kPrefix);
298 this->writeRuntimeValue(s.fType, HCodeGenerator::FieldName(name).c_str());
299 } else {
300 this->write(s.fName.c_str());
301 }
302}
303
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400304bool CPPCodeGenerator::writeSection(const char* name, const char* prefix) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400305 const Section* s = fSectionAndParameterHelper.getSection(name);
306 if (s) {
307 this->writef("%s%s", prefix, s->fText.c_str());
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400308 return true;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400309 }
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400310 return false;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400311}
312
313void CPPCodeGenerator::writeProgramElement(const ProgramElement& p) {
314 if (p.fKind == ProgramElement::kSection_Kind) {
315 return;
316 }
317 if (p.fKind == ProgramElement::kVar_Kind) {
318 const VarDeclarations& decls = (const VarDeclarations&) p;
319 if (!decls.fVars.size()) {
320 return;
321 }
322 const Variable& var = *((VarDeclaration&) *decls.fVars[0]).fVar;
323 if (var.fModifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kUniform_Flag) ||
324 -1 != var.fModifiers.fLayout.fBuiltin) {
325 return;
326 }
327 }
328 INHERITED::writeProgramElement(p);
329}
330
331void CPPCodeGenerator::addUniform(const Variable& var) {
332 if (!needs_uniform_var(var)) {
333 return;
334 }
335 const char* precision;
336 if (var.fModifiers.fFlags & Modifiers::kHighp_Flag) {
337 precision = "kHigh_GrSLPrecision";
338 } else if (var.fModifiers.fFlags & Modifiers::kMediump_Flag) {
339 precision = "kMedium_GrSLPrecision";
340 } else if (var.fModifiers.fFlags & Modifiers::kLowp_Flag) {
341 precision = "kLow_GrSLPrecision";
342 } else {
343 precision = "kDefault_GrSLPrecision";
344 }
345 const char* type;
346 if (var.fType == *fContext.fFloat_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400347 type = "kHighFloat_GrSLType";
348 } else if (var.fType == *fContext.fHalf_Type) {
349 type = "kHalf_GrSLType";
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400350 } else if (var.fType == *fContext.fFloat2_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400351 type = "kHighFloat2_GrSLType";
352 } else if (var.fType == *fContext.fHalf2_Type) {
353 type = "kHalf2_GrSLType";
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400354 } else if (var.fType == *fContext.fFloat4_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400355 type = "kHighFloat4_GrSLType";
356 } else if (var.fType == *fContext.fHalf4_Type) {
357 type = "kHalf4_GrSLType";
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400358 } else if (var.fType == *fContext.fFloat4x4_Type ||
Ethan Nicholas762466e2017-06-29 10:03:38 -0400359 var.fType == *fContext.fColorSpaceXform_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400360 type = "kHighFloat4x4_GrSLType";
361 } else if (var.fType == *fContext.fHalf4x4_Type) {
362 type = "kHalf4x4_GrSLType";
Ethan Nicholas762466e2017-06-29 10:03:38 -0400363 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700364 ABORT("unsupported uniform type: %s %s;\n", String(var.fType.fName).c_str(),
365 String(var.fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400366 }
367 if (var.fModifiers.fLayout.fWhen.size()) {
368 this->writef(" if (%s) {\n ", var.fModifiers.fLayout.fWhen.c_str());
369 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700370 String name(var.fName);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400371 this->writef(" %sVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, %s, "
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700372 "%s, \"%s\");\n", HCodeGenerator::FieldName(name.c_str()).c_str(), type, precision,
373 name.c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400374 if (var.fModifiers.fLayout.fWhen.size()) {
375 this->write(" }\n");
376 }
377}
378
379void CPPCodeGenerator::writePrivateVars() {
380 for (const auto& p : fProgram.fElements) {
381 if (ProgramElement::kVar_Kind == p->fKind) {
382 const VarDeclarations* decls = (const VarDeclarations*) p.get();
383 for (const auto& raw : decls->fVars) {
384 VarDeclaration& decl = (VarDeclaration&) *raw;
385 if (is_private(*decl.fVar)) {
386 this->writef("%s %s;\n",
387 HCodeGenerator::FieldType(decl.fVar->fType).c_str(),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700388 String(decl.fVar->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400389 }
390 }
391 }
392 }
393}
394
395void CPPCodeGenerator::writePrivateVarValues() {
396 for (const auto& p : fProgram.fElements) {
397 if (ProgramElement::kVar_Kind == p->fKind) {
398 const VarDeclarations* decls = (const VarDeclarations*) p.get();
399 for (const auto& raw : decls->fVars) {
400 VarDeclaration& decl = (VarDeclaration&) *raw;
401 if (is_private(*decl.fVar) && decl.fValue) {
402 this->writef("%s = %s;\n",
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700403 String(decl.fVar->fName).c_str(),
Ethan Nicholas762466e2017-06-29 10:03:38 -0400404 decl.fValue->description().c_str());
405 }
406 }
407 }
408 }
409}
410
411bool CPPCodeGenerator::writeEmitCode(std::vector<const Variable*>& uniforms) {
412 this->write(" void emitCode(EmitArgs& args) override {\n"
413 " GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;\n");
414 this->writef(" const %s& _outer = args.fFp.cast<%s>();\n"
415 " (void) _outer;\n",
416 fFullName.c_str(), fFullName.c_str());
417 this->writePrivateVarValues();
418 for (const auto u : uniforms) {
419 this->addUniform(*u);
420 if (u->fType == *fContext.fColorSpaceXform_Type) {
421 if (fNeedColorSpaceHelper) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700422 fErrors.error(u->fOffset, "only a single ColorSpaceXform is supported");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400423 }
424 fNeedColorSpaceHelper = true;
425 this->writef(" fColorSpaceHelper.emitCode(args.fUniformHandler, "
426 "_outer.%s().get());\n",
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700427 String(u->fName).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400428 }
429 }
430 this->writeSection(EMIT_CODE_SECTION);
431 OutputStream* old = fOut;
432 StringStream mainBuffer;
433 fOut = &mainBuffer;
434 bool result = INHERITED::generateCode();
435 fOut = old;
436 this->writef("%s fragBuilder->codeAppendf(\"%s\"", fExtraEmitCodeCode.c_str(),
437 mainBuffer.str().c_str());
438 for (const auto& s : fFormatArgs) {
439 this->writef(", %s", s.c_str());
440 }
441 this->write(");\n"
442 " }\n");
443 return result;
444}
445
446void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
447 const char* fullName = fFullName.c_str();
Ethan Nicholas68990be2017-07-13 09:36:52 -0400448 const Section* section = fSectionAndParameterHelper.getSection(SET_DATA_SECTION);
449 const char* pdman = section ? section->fArgument.c_str() : "pdman";
Ethan Nicholas762466e2017-06-29 10:03:38 -0400450 this->writef(" void onSetData(const GrGLSLProgramDataManager& %s, "
451 "const GrFragmentProcessor& _proc) override {\n",
452 pdman);
453 bool wroteProcessor = false;
454 for (const auto u : uniforms) {
455 if (u->fModifiers.fFlags & Modifiers::kIn_Flag) {
456 if (!wroteProcessor) {
457 this->writef(" const %s& _outer = _proc.cast<%s>();\n", fullName, fullName);
458 wroteProcessor = true;
459 this->writef(" {\n");
460 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700461 String nameString(u->fName);
462 const char* name = nameString.c_str();
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400463 if (u->fType == *fContext.fFloat4_Type || u->fType == *fContext.fHalf4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400464 this->writef(" const SkRect %sValue = _outer.%s();\n"
Ethan Nicholasee338732017-07-17 15:13:45 -0400465 " %s.set4fv(%sVar, 1, (float*) &%sValue);\n",
Ethan Nicholas762466e2017-06-29 10:03:38 -0400466 name, name, pdman, HCodeGenerator::FieldName(name).c_str(), name);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400467 } else if (u->fType == *fContext.fFloat4x4_Type ||
468 u->fType == *fContext.fHalf4x4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400469 this->writef(" float %sValue[16];\n"
470 " _outer.%s().asColMajorf(%sValue);\n"
471 " %s.setMatrix4f(%sVar, %sValue);\n",
472 name, name, name, pdman, HCodeGenerator::FieldName(name).c_str(),
473 name);
474 } else if (u->fType == *fContext.fColorSpaceXform_Type) {
475 ASSERT(fNeedColorSpaceHelper);
476 this->writef(" if (fColorSpaceHelper.isValid()) {\n"
477 " fColorSpaceHelper.setData(%s, _outer.%s().get());\n"
478 " }\n",
479 pdman, name);
480 } else {
481 this->writef(" %s.set1f(%sVar, _outer.%s());\n",
482 pdman, HCodeGenerator::FieldName(name).c_str(), name);
483 }
484 }
485 }
486 if (wroteProcessor) {
487 this->writef(" }\n");
488 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400489 if (section) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400490 for (const auto& p : fProgram.fElements) {
491 if (ProgramElement::kVar_Kind == p->fKind) {
492 const VarDeclarations* decls = (const VarDeclarations*) p.get();
493 for (const auto& raw : decls->fVars) {
494 VarDeclaration& decl = (VarDeclaration&) *raw;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700495 String nameString(decl.fVar->fName);
496 const char* name = nameString.c_str();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400497 if (needs_uniform_var(*decl.fVar)) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400498 this->writef(" UniformHandle& %s = %sVar;\n"
499 " (void) %s;\n",
500 name, HCodeGenerator::FieldName(name).c_str(), name);
501 } else if (SectionAndParameterHelper::IsParameter(*decl.fVar)) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400502 if (!wroteProcessor) {
503 this->writef(" const %s& _outer = _proc.cast<%s>();\n", fullName,
504 fullName);
505 wroteProcessor = true;
506 }
507 this->writef(" auto %s = _outer.%s();\n"
508 " (void) %s;\n",
509 name, name, name);
510 }
511 }
512 }
513 }
514 this->writeSection(SET_DATA_SECTION);
515 }
516 this->write(" }\n");
517}
518
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400519void CPPCodeGenerator::writeClone() {
520 if (!this->writeSection(CLONE_SECTION)) {
521 if (fSectionAndParameterHelper.getSection(FIELDS_SECTION)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700522 fErrors.error(0, "fragment processors with custom @fields must also have a custom"
523 "@clone");
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400524 }
525 this->writef("%s::%s(const %s& src)\n"
526 ": INHERITED(src.optimizationFlags())", fFullName.c_str(), fFullName.c_str(),
527 fFullName.c_str());
528 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700529 String fieldName = HCodeGenerator::FieldName(String(param->fName).c_str());
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400530 this->writef("\n, %s(%s)",
531 fieldName.c_str(),
532 ("src." + fieldName).c_str());
533 }
534 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
535 String fieldName = HCodeGenerator::FieldName(s->fArgument.c_str());
536 this->writef("\n, %sCoordTransform(src.%sCoordTransform)", fieldName.c_str(),
537 fieldName.c_str());
538 }
539 this->writef(" {\n"
540 " this->initClassID<%s>();\n",
541 fFullName.c_str());
542 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
543 if (param->fType.kind() == Type::kSampler_Kind) {
544 this->writef(" this->addTextureSampler(&%s);\n",
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700545 HCodeGenerator::FieldName(String(param->fName).c_str()).c_str());
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400546 }
547 }
548 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
549 String field = HCodeGenerator::FieldName(s->fArgument.c_str());
550 this->writef(" this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
551 }
552 this->write("}\n");
Brian Salomonaff329b2017-08-11 09:40:37 -0400553 this->writef("std::unique_ptr<GrFragmentProcessor> %s::clone() const {\n",
554 fFullName.c_str());
555 this->writef(" return std::unique_ptr<GrFragmentProcessor>(new %s(*this));\n",
556 fFullName.c_str());
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400557 this->write("}\n");
558 }
559}
560
Ethan Nicholas762466e2017-06-29 10:03:38 -0400561void CPPCodeGenerator::writeTest() {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400562 const Section* test = fSectionAndParameterHelper.getSection(TEST_CODE_SECTION);
563 if (test) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400564 this->writef(
565 "GR_DEFINE_FRAGMENT_PROCESSOR_TEST(%s);\n"
566 "#if GR_TEST_UTILS\n"
567 "std::unique_ptr<GrFragmentProcessor> %s::TestCreate(GrProcessorTestData* %s) {\n",
568 fFullName.c_str(),
569 fFullName.c_str(),
570 test->fArgument.c_str());
Ethan Nicholas68990be2017-07-13 09:36:52 -0400571 this->writeSection(TEST_CODE_SECTION);
572 this->write("}\n"
573 "#endif\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400574 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400575}
576
577void CPPCodeGenerator::writeGetKey() {
578 this->writef("void %s::onGetGLSLProcessorKey(const GrShaderCaps& caps, "
579 "GrProcessorKeyBuilder* b) const {\n",
580 fFullName.c_str());
Ethan Nicholas68990be2017-07-13 09:36:52 -0400581 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700582 String nameString(param->fName);
583 const char* name = nameString.c_str();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400584 if (param->fType == *fContext.fColorSpaceXform_Type) {
585 this->writef(" b->add32(GrColorSpaceXform::XformKey(%s.get()));\n",
586 HCodeGenerator::FieldName(name).c_str());
587 continue;
588 }
589 if (param->fModifiers.fLayout.fKey != Layout::kNo_Key &&
590 (param->fModifiers.fFlags & Modifiers::kUniform_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700591 fErrors.error(param->fOffset,
Ethan Nicholas762466e2017-06-29 10:03:38 -0400592 "layout(key) may not be specified on uniforms");
593 }
594 switch (param->fModifiers.fLayout.fKey) {
595 case Layout::kKey_Key:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400596 if (param->fType == *fContext.fFloat4x4_Type) {
597 ABORT("no automatic key handling for float4x4\n");
598 } else if (param->fType == *fContext.fFloat2_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400599 this->writef(" b->add32(%s.fX);\n",
600 HCodeGenerator::FieldName(name).c_str());
601 this->writef(" b->add32(%s.fY);\n",
602 HCodeGenerator::FieldName(name).c_str());
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400603 } else if (param->fType == *fContext.fFloat4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400604 this->writef(" b->add32(%s.x());\n",
605 HCodeGenerator::FieldName(name).c_str());
606 this->writef(" b->add32(%s.y());\n",
607 HCodeGenerator::FieldName(name).c_str());
608 this->writef(" b->add32(%s.width());\n",
609 HCodeGenerator::FieldName(name).c_str());
610 this->writef(" b->add32(%s.height());\n",
611 HCodeGenerator::FieldName(name).c_str());
612 } else {
613 this->writef(" b->add32(%s);\n",
614 HCodeGenerator::FieldName(name).c_str());
615 }
616 break;
617 case Layout::kIdentity_Key:
618 if (param->fType.kind() != Type::kMatrix_Kind) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700619 fErrors.error(param->fOffset,
Ethan Nicholas762466e2017-06-29 10:03:38 -0400620 "layout(key=identity) requires matrix type");
621 }
622 this->writef(" b->add32(%s.isIdentity() ? 1 : 0);\n",
623 HCodeGenerator::FieldName(name).c_str());
624 break;
625 case Layout::kNo_Key:
626 break;
627 }
628 }
629 this->write("}\n");
630}
631
632bool CPPCodeGenerator::generateCode() {
633 std::vector<const Variable*> uniforms;
634 for (const auto& p : fProgram.fElements) {
635 if (ProgramElement::kVar_Kind == p->fKind) {
636 const VarDeclarations* decls = (const VarDeclarations*) p.get();
637 for (const auto& raw : decls->fVars) {
638 VarDeclaration& decl = (VarDeclaration&) *raw;
639 if ((decl.fVar->fModifiers.fFlags & Modifiers::kUniform_Flag) &&
640 decl.fVar->fType.kind() != Type::kSampler_Kind) {
641 uniforms.push_back(decl.fVar);
642 }
643 }
644 }
645 }
646 const char* baseName = fName.c_str();
647 const char* fullName = fFullName.c_str();
648 this->writef(kFragmentProcessorHeader, fullName);
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400649 this->writef("#include \"%s.h\"\n"
650 "#if SK_SUPPORT_GPU\n", fullName);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400651 this->writeSection(CPP_SECTION);
652 this->writef("#include \"glsl/GrGLSLColorSpaceXformHelper.h\"\n"
Ethan Nicholas762466e2017-06-29 10:03:38 -0400653 "#include \"glsl/GrGLSLFragmentProcessor.h\"\n"
654 "#include \"glsl/GrGLSLFragmentShaderBuilder.h\"\n"
655 "#include \"glsl/GrGLSLProgramBuilder.h\"\n"
Ethan Nicholas762466e2017-06-29 10:03:38 -0400656 "#include \"SkSLCPP.h\"\n"
657 "#include \"SkSLUtil.h\"\n"
658 "class GrGLSL%s : public GrGLSLFragmentProcessor {\n"
659 "public:\n"
660 " GrGLSL%s() {}\n",
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400661 baseName, baseName);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400662 bool result = this->writeEmitCode(uniforms);
663 this->write("private:\n");
664 this->writeSetData(uniforms);
665 this->writePrivateVars();
666 for (const auto& u : uniforms) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400667 if (needs_uniform_var(*u) && !(u->fModifiers.fFlags & Modifiers::kIn_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700668 this->writef(" UniformHandle %sVar;\n",
669 HCodeGenerator::FieldName(String(u->fName).c_str()).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400670 }
671 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400672 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400673 if (needs_uniform_var(*param)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700674 this->writef(" UniformHandle %sVar;\n",
675 HCodeGenerator::FieldName(String(param->fName).c_str()).c_str());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400676 }
677 }
678 if (fNeedColorSpaceHelper) {
679 this->write(" GrGLSLColorSpaceXformHelper fColorSpaceHelper;\n");
680 }
681 this->writef("};\n"
682 "GrGLSLFragmentProcessor* %s::onCreateGLSLInstance() const {\n"
683 " return new GrGLSL%s();\n"
684 "}\n",
685 fullName, baseName);
686 this->writeGetKey();
687 this->writef("bool %s::onIsEqual(const GrFragmentProcessor& other) const {\n"
688 " const %s& that = other.cast<%s>();\n"
689 " (void) that;\n",
690 fullName, fullName, fullName);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400691 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700692 String nameString(param->fName);
693 const char* name = nameString.c_str();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400694 this->writef(" if (%s != that.%s) return false;\n",
695 HCodeGenerator::FieldName(name).c_str(),
696 HCodeGenerator::FieldName(name).c_str());
697 }
698 this->write(" return true;\n"
699 "}\n");
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400700 this->writeClone();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400701 this->writeTest();
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400702 this->writeSection(CPP_END_SECTION);
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400703 this->write("#endif\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400704 result &= 0 == fErrors.errorCount();
705 return result;
706}
707
708} // namespace