blob: 17bcf0d11f144c2811e5bd01706f9bc773e18a48 [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) &&
17 strcmp(var.fType.fName.c_str(), "colorSpaceXform");
18}
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
Brian Salomon1d816b92017-08-17 11:07:59 -040054void CPPCodeGenerator::writePrecisionModifier() {
Ethan Nicholas762466e2017-06-29 10:03:38 -040055}
56
Brian Salomon1d816b92017-08-17 11:07:59 -040057void CPPCodeGenerator::writeType(const Type& type) {
58 if (type.kind() == Type::kStruct_Kind) {
59 INHERITED::writeType(type);
60 } else {
61 this->write(type.name());
62 }
Ethan Nicholas5af9ea32017-07-28 15:19:46 -040063}
Ethan Nicholas762466e2017-06-29 10:03:38 -040064void CPPCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
65 Precedence parentPrecedence) {
66 if (b.fOperator == Token::PERCENT) {
67 // need to use "%%" instead of "%" b/c the code will be inside of a printf
68 Precedence precedence = GetBinaryPrecedence(b.fOperator);
69 if (precedence >= parentPrecedence) {
70 this->write("(");
71 }
72 this->writeExpression(*b.fLeft, precedence);
73 this->write(" %% ");
74 this->writeExpression(*b.fRight, precedence);
75 if (precedence >= parentPrecedence) {
76 this->write(")");
77 }
78 } else {
79 INHERITED::writeBinaryExpression(b, parentPrecedence);
80 }
81}
82
83void CPPCodeGenerator::writeIndexExpression(const IndexExpression& i) {
84 const Expression& base = *i.fBase;
85 if (base.fKind == Expression::kVariableReference_Kind) {
86 int builtin = ((VariableReference&) base).fVariable.fModifiers.fLayout.fBuiltin;
87 if (SK_TRANSFORMEDCOORDS2D_BUILTIN == builtin) {
88 this->write("%s");
89 if (i.fIndex->fKind != Expression::kIntLiteral_Kind) {
90 fErrors.error(i.fIndex->fPosition,
91 "index into sk_TransformedCoords2D must be an integer literal");
92 return;
93 }
94 int64_t index = ((IntLiteral&) *i.fIndex).fValue;
95 String name = "sk_TransformedCoords2D_" + to_string(index);
96 fFormatArgs.push_back(name + ".c_str()");
97 if (fWrittenTransformedCoords.find(index) == fWrittenTransformedCoords.end()) {
Brian Osman72a37be2017-08-15 09:19:53 -040098 fExtraEmitCodeCode += " SkString " + name +
Ethan Nicholas762466e2017-06-29 10:03:38 -040099 " = fragBuilder->ensureCoords2D(args.fTransformedCoords[" +
100 to_string(index) + "]);\n";
101 fWrittenTransformedCoords.insert(index);
102 }
103 return;
104 } else if (SK_TEXTURESAMPLERS_BUILTIN == builtin) {
105 this->write("%s");
106 if (i.fIndex->fKind != Expression::kIntLiteral_Kind) {
107 fErrors.error(i.fIndex->fPosition,
108 "index into sk_TextureSamplers must be an integer literal");
109 return;
110 }
111 int64_t index = ((IntLiteral&) *i.fIndex).fValue;
112 fFormatArgs.push_back(" fragBuilder->getProgramBuilder()->samplerVariable("
113 "args.fTexSamplers[" + to_string(index) + "]).c_str()");
114 return;
115 }
116 }
117 INHERITED::writeIndexExpression(i);
118}
119
Brian Salomon1d816b92017-08-17 11:07:59 -0400120static const char* default_value(const Type& type) {
121 const char* name = type.name().c_str();
122 if (!strcmp(name, "float")) {
123 return "0.0";
124 } else if (!strcmp(name, "float2")) {
125 return "float2(0.0)";
126 } else if (!strcmp(name, "float3")) {
127 return "float30.0)";
128 } else if (!strcmp(name, "float4")) {
129 return "float4(0.0)";
130 } else if (!strcmp(name, "floatt4x4") || !strcmp(name, "colorSpaceXform")) {
131 return "float4x4(1.0)";
Ethan Nicholas762466e2017-06-29 10:03:38 -0400132 }
Brian Salomon1d816b92017-08-17 11:07:59 -0400133 ABORT("unsupported default_value type\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400134}
135
136static bool is_private(const Variable& var) {
137 return !(var.fModifiers.fFlags & Modifiers::kUniform_Flag) &&
138 !(var.fModifiers.fFlags & Modifiers::kIn_Flag) &&
139 var.fStorage == Variable::kGlobal_Storage &&
140 var.fModifiers.fLayout.fBuiltin == -1;
141}
142
143void CPPCodeGenerator::writeRuntimeValue(const Type& type, const String& cppCode) {
Brian Salomon1d816b92017-08-17 11:07:59 -0400144 if (type == *fContext.fFloat_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400145 this->write("%f");
146 fFormatArgs.push_back(cppCode);
147 } else if (type == *fContext.fInt_Type) {
148 this->write("%d");
149 fFormatArgs.push_back(cppCode);
150 } else if (type == *fContext.fBool_Type) {
151 this->write("%s");
152 fFormatArgs.push_back("(" + cppCode + " ? \"true\" : \"false\")");
Brian Salomon1d816b92017-08-17 11:07:59 -0400153 } else if (type == *fContext.fFloat2_Type) {
154 this->write("float2(%f, %f)");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400155 fFormatArgs.push_back(cppCode + ".fX");
156 fFormatArgs.push_back(cppCode + ".fY");
157 } else {
158 printf("%s\n", type.name().c_str());
159 ABORT("unsupported runtime value type\n");
160 }
161}
162
163void CPPCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
164 if (is_private(var)) {
165 this->writeRuntimeValue(var.fType, var.fName);
166 } else {
167 this->writeExpression(value, kTopLevel_Precedence);
168 }
169}
170
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400171String CPPCodeGenerator::getSamplerHandle(const Variable& var) {
172 int samplerCount = 0;
Ethan Nicholas68990be2017-07-13 09:36:52 -0400173 for (const auto param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400174 if (&var == param) {
175 return "args.fTexSamplers[" + to_string(samplerCount) + "]";
176 }
177 if (param->fType.kind() == Type::kSampler_Kind) {
178 ++samplerCount;
179 }
180 }
181 ABORT("should have found sampler in parameters\n");
182}
183
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400184void CPPCodeGenerator::writeIntLiteral(const IntLiteral& i) {
185 this->write(to_string((int32_t) i.fValue));
186}
187
Ethan Nicholas762466e2017-06-29 10:03:38 -0400188void CPPCodeGenerator::writeVariableReference(const VariableReference& ref) {
189 switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
190 case SK_INCOLOR_BUILTIN:
191 this->write("%s");
Brian Salomon1d816b92017-08-17 11:07:59 -0400192 fFormatArgs.push_back(String("args.fInputColor ? args.fInputColor : \"float4(1)\""));
Ethan Nicholas762466e2017-06-29 10:03:38 -0400193 break;
194 case SK_OUTCOLOR_BUILTIN:
195 this->write("%s");
196 fFormatArgs.push_back(String("args.fOutputColor"));
197 break;
198 default:
199 if (ref.fVariable.fType.kind() == Type::kSampler_Kind) {
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400200 this->write("%s");
201 fFormatArgs.push_back("fragBuilder->getProgramBuilder()->samplerVariable(" +
202 this->getSamplerHandle(ref.fVariable) + ").c_str()");
203 return;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400204 }
205 if (ref.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag) {
206 this->write("%s");
207 String name = ref.fVariable.fName;
208 String var;
209 if (ref.fVariable.fType == *fContext.fColorSpaceXform_Type) {
210 ASSERT(fNeedColorSpaceHelper);
211 var = String::printf("fColorSpaceHelper.isValid() ? "
212 "args.fUniformHandler->getUniformCStr("
213 "fColorSpaceHelper.gamutXformUniform()) : \"%s\"",
Brian Salomon1d816b92017-08-17 11:07:59 -0400214 default_value(ref.fVariable.fType));
Ethan Nicholas762466e2017-06-29 10:03:38 -0400215 } else {
216 var = String::printf("args.fUniformHandler->getUniformCStr(%sVar)",
217 HCodeGenerator::FieldName(name.c_str()).c_str());
218 }
219 String code;
220 if (ref.fVariable.fModifiers.fLayout.fWhen.size()) {
221 code = String::printf("%sVar.isValid() ? %s : \"%s\"",
222 HCodeGenerator::FieldName(name.c_str()).c_str(),
223 var.c_str(),
Brian Salomon1d816b92017-08-17 11:07:59 -0400224 default_value(ref.fVariable.fType));
Ethan Nicholas762466e2017-06-29 10:03:38 -0400225 } else {
226 code = var;
227 }
228 fFormatArgs.push_back(code);
229 } else if (SectionAndParameterHelper::IsParameter(ref.fVariable)) {
230 const char* name = ref.fVariable.fName.c_str();
231 this->writeRuntimeValue(ref.fVariable.fType,
232 String::printf("_outer.%s()", name).c_str());
233 } else {
234 this->write(ref.fVariable.fName.c_str());
235 }
236 }
237}
238
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -0400239void CPPCodeGenerator::writeIfStatement(const IfStatement& s) {
240 if (s.fIsStatic) {
241 this->write("@");
242 }
243 INHERITED::writeIfStatement(s);
244}
245
246void CPPCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
247 if (s.fIsStatic) {
248 this->write("@");
249 }
250 INHERITED::writeSwitchStatement(s);
251}
252
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400253void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400254 if (c.fFunction.fBuiltin && c.fFunction.fName == "COLORSPACE") {
255 String tmpVar = "_tmpVar" + to_string(++fVarCount);
Brian Salomon1d816b92017-08-17 11:07:59 -0400256 fFunctionHeader += "float4 " + tmpVar + ";";
Ethan Nicholas68990be2017-07-13 09:36:52 -0400257 ASSERT(c.fArguments.size() == 2);
258 this->write("%s");
259 fFormatArgs.push_back("fColorSpaceHelper.isValid() ? \"(" + tmpVar + " = \" : \"\"");
260 this->writeExpression(*c.fArguments[0], kTopLevel_Precedence);
261 ASSERT(c.fArguments[1]->fKind == Expression::kVariableReference_Kind);
262 String xform("args.fUniformHandler->getUniformCStr(fColorSpaceHelper.gamutXformUniform())");
263 this->write("%s");
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400264 fFormatArgs.push_back("fColorSpaceHelper.isValid() ? SkStringPrintf(\", "
Brian Salomon1d816b92017-08-17 11:07:59 -0400265 "float4(clamp((%s * float4(" + tmpVar + ".rgb, 1.0)).rgb, 0.0, " +
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400266 tmpVar + ".a), " + tmpVar + ".a))\", " + xform + ").c_str() : \"\"");
Ethan Nicholas68990be2017-07-13 09:36:52 -0400267 return;
268 }
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400269 INHERITED::writeFunctionCall(c);
270 if (c.fFunction.fBuiltin && c.fFunction.fName == "texture") {
271 this->write(".%s");
272 ASSERT(c.fArguments.size() >= 1);
273 ASSERT(c.fArguments[0]->fKind == Expression::kVariableReference_Kind);
274 String sampler = this->getSamplerHandle(((VariableReference&) *c.fArguments[0]).fVariable);
275 fFormatArgs.push_back("fragBuilder->getProgramBuilder()->samplerSwizzle(" + sampler +
276 ").c_str()");
277 }
278}
279
Ethan Nicholas762466e2017-06-29 10:03:38 -0400280void CPPCodeGenerator::writeFunction(const FunctionDefinition& f) {
281 if (f.fDeclaration.fName == "main") {
282 fFunctionHeader = "";
283 OutputStream* oldOut = fOut;
284 StringStream buffer;
285 fOut = &buffer;
286 for (const auto& s : ((Block&) *f.fBody).fStatements) {
287 this->writeStatement(*s);
288 this->writeLine();
289 }
290
291 fOut = oldOut;
292 this->write(fFunctionHeader);
293 this->write(buffer.str());
294 } else {
295 INHERITED::writeFunction(f);
296 }
297}
298
299void CPPCodeGenerator::writeSetting(const Setting& s) {
300 static constexpr const char* kPrefix = "sk_Args.";
301 if (!strncmp(s.fName.c_str(), kPrefix, strlen(kPrefix))) {
302 const char* name = s.fName.c_str() + strlen(kPrefix);
303 this->writeRuntimeValue(s.fType, HCodeGenerator::FieldName(name).c_str());
304 } else {
305 this->write(s.fName.c_str());
306 }
307}
308
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400309bool CPPCodeGenerator::writeSection(const char* name, const char* prefix) {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400310 const Section* s = fSectionAndParameterHelper.getSection(name);
311 if (s) {
312 this->writef("%s%s", prefix, s->fText.c_str());
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400313 return true;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400314 }
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400315 return false;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400316}
317
318void CPPCodeGenerator::writeProgramElement(const ProgramElement& p) {
319 if (p.fKind == ProgramElement::kSection_Kind) {
320 return;
321 }
322 if (p.fKind == ProgramElement::kVar_Kind) {
323 const VarDeclarations& decls = (const VarDeclarations&) p;
324 if (!decls.fVars.size()) {
325 return;
326 }
327 const Variable& var = *((VarDeclaration&) *decls.fVars[0]).fVar;
328 if (var.fModifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kUniform_Flag) ||
329 -1 != var.fModifiers.fLayout.fBuiltin) {
330 return;
331 }
332 }
333 INHERITED::writeProgramElement(p);
334}
335
336void CPPCodeGenerator::addUniform(const Variable& var) {
337 if (!needs_uniform_var(var)) {
338 return;
339 }
340 const char* precision;
341 if (var.fModifiers.fFlags & Modifiers::kHighp_Flag) {
342 precision = "kHigh_GrSLPrecision";
343 } else if (var.fModifiers.fFlags & Modifiers::kMediump_Flag) {
344 precision = "kMedium_GrSLPrecision";
345 } else if (var.fModifiers.fFlags & Modifiers::kLowp_Flag) {
346 precision = "kLow_GrSLPrecision";
347 } else {
348 precision = "kDefault_GrSLPrecision";
349 }
350 const char* type;
351 if (var.fType == *fContext.fFloat_Type) {
Brian Salomon1d816b92017-08-17 11:07:59 -0400352 type = "kFloat_GrSLType";
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400353 } else if (var.fType == *fContext.fFloat2_Type) {
Brian Salomon1d816b92017-08-17 11:07:59 -0400354 type = "kVec2f_GrSLType";
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400355 } else if (var.fType == *fContext.fFloat4_Type) {
Brian Salomon1d816b92017-08-17 11:07:59 -0400356 type = "kVec4f_GrSLType";
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400357 } else if (var.fType == *fContext.fFloat4x4_Type ||
Ethan Nicholas762466e2017-06-29 10:03:38 -0400358 var.fType == *fContext.fColorSpaceXform_Type) {
Brian Salomon1d816b92017-08-17 11:07:59 -0400359 type = "kMat44f_GrSLType";
Ethan Nicholas762466e2017-06-29 10:03:38 -0400360 } else {
361 ABORT("unsupported uniform type: %s %s;\n", var.fType.name().c_str(), var.fName.c_str());
362 }
363 if (var.fModifiers.fLayout.fWhen.size()) {
364 this->writef(" if (%s) {\n ", var.fModifiers.fLayout.fWhen.c_str());
365 }
366 const char* name = var.fName.c_str();
367 this->writef(" %sVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, %s, "
368 "%s, \"%s\");\n", HCodeGenerator::FieldName(name).c_str(), type, precision, name);
369 if (var.fModifiers.fLayout.fWhen.size()) {
370 this->write(" }\n");
371 }
372}
373
374void CPPCodeGenerator::writePrivateVars() {
375 for (const auto& p : fProgram.fElements) {
376 if (ProgramElement::kVar_Kind == p->fKind) {
377 const VarDeclarations* decls = (const VarDeclarations*) p.get();
378 for (const auto& raw : decls->fVars) {
379 VarDeclaration& decl = (VarDeclaration&) *raw;
380 if (is_private(*decl.fVar)) {
381 this->writef("%s %s;\n",
382 HCodeGenerator::FieldType(decl.fVar->fType).c_str(),
383 decl.fVar->fName.c_str());
384 }
385 }
386 }
387 }
388}
389
390void CPPCodeGenerator::writePrivateVarValues() {
391 for (const auto& p : fProgram.fElements) {
392 if (ProgramElement::kVar_Kind == p->fKind) {
393 const VarDeclarations* decls = (const VarDeclarations*) p.get();
394 for (const auto& raw : decls->fVars) {
395 VarDeclaration& decl = (VarDeclaration&) *raw;
396 if (is_private(*decl.fVar) && decl.fValue) {
397 this->writef("%s = %s;\n",
398 decl.fVar->fName.c_str(),
399 decl.fValue->description().c_str());
400 }
401 }
402 }
403 }
404}
405
406bool CPPCodeGenerator::writeEmitCode(std::vector<const Variable*>& uniforms) {
407 this->write(" void emitCode(EmitArgs& args) override {\n"
408 " GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;\n");
409 this->writef(" const %s& _outer = args.fFp.cast<%s>();\n"
410 " (void) _outer;\n",
411 fFullName.c_str(), fFullName.c_str());
412 this->writePrivateVarValues();
413 for (const auto u : uniforms) {
414 this->addUniform(*u);
415 if (u->fType == *fContext.fColorSpaceXform_Type) {
416 if (fNeedColorSpaceHelper) {
417 fErrors.error(u->fPosition, "only a single ColorSpaceXform is supported");
418 }
419 fNeedColorSpaceHelper = true;
420 this->writef(" fColorSpaceHelper.emitCode(args.fUniformHandler, "
421 "_outer.%s().get());\n",
422 u->fName.c_str());
423 }
424 }
425 this->writeSection(EMIT_CODE_SECTION);
426 OutputStream* old = fOut;
427 StringStream mainBuffer;
428 fOut = &mainBuffer;
429 bool result = INHERITED::generateCode();
430 fOut = old;
431 this->writef("%s fragBuilder->codeAppendf(\"%s\"", fExtraEmitCodeCode.c_str(),
432 mainBuffer.str().c_str());
433 for (const auto& s : fFormatArgs) {
434 this->writef(", %s", s.c_str());
435 }
436 this->write(");\n"
437 " }\n");
438 return result;
439}
440
441void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
442 const char* fullName = fFullName.c_str();
Ethan Nicholas68990be2017-07-13 09:36:52 -0400443 const Section* section = fSectionAndParameterHelper.getSection(SET_DATA_SECTION);
444 const char* pdman = section ? section->fArgument.c_str() : "pdman";
Ethan Nicholas762466e2017-06-29 10:03:38 -0400445 this->writef(" void onSetData(const GrGLSLProgramDataManager& %s, "
446 "const GrFragmentProcessor& _proc) override {\n",
447 pdman);
448 bool wroteProcessor = false;
449 for (const auto u : uniforms) {
450 if (u->fModifiers.fFlags & Modifiers::kIn_Flag) {
451 if (!wroteProcessor) {
452 this->writef(" const %s& _outer = _proc.cast<%s>();\n", fullName, fullName);
453 wroteProcessor = true;
454 this->writef(" {\n");
455 }
456 const char* name = u->fName.c_str();
Brian Salomon1d816b92017-08-17 11:07:59 -0400457 if (u->fType == *fContext.fFloat4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400458 this->writef(" const SkRect %sValue = _outer.%s();\n"
Ethan Nicholasee338732017-07-17 15:13:45 -0400459 " %s.set4fv(%sVar, 1, (float*) &%sValue);\n",
Ethan Nicholas762466e2017-06-29 10:03:38 -0400460 name, name, pdman, HCodeGenerator::FieldName(name).c_str(), name);
Brian Salomon1d816b92017-08-17 11:07:59 -0400461 } else if (u->fType == *fContext.fFloat4x4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400462 this->writef(" float %sValue[16];\n"
463 " _outer.%s().asColMajorf(%sValue);\n"
464 " %s.setMatrix4f(%sVar, %sValue);\n",
465 name, name, name, pdman, HCodeGenerator::FieldName(name).c_str(),
466 name);
467 } else if (u->fType == *fContext.fColorSpaceXform_Type) {
468 ASSERT(fNeedColorSpaceHelper);
469 this->writef(" if (fColorSpaceHelper.isValid()) {\n"
470 " fColorSpaceHelper.setData(%s, _outer.%s().get());\n"
471 " }\n",
472 pdman, name);
473 } else {
474 this->writef(" %s.set1f(%sVar, _outer.%s());\n",
475 pdman, HCodeGenerator::FieldName(name).c_str(), name);
476 }
477 }
478 }
479 if (wroteProcessor) {
480 this->writef(" }\n");
481 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400482 if (section) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400483 for (const auto& p : fProgram.fElements) {
484 if (ProgramElement::kVar_Kind == p->fKind) {
485 const VarDeclarations* decls = (const VarDeclarations*) p.get();
486 for (const auto& raw : decls->fVars) {
487 VarDeclaration& decl = (VarDeclaration&) *raw;
488 if (needs_uniform_var(*decl.fVar)) {
489 const char* name = decl.fVar->fName.c_str();
490 this->writef(" UniformHandle& %s = %sVar;\n"
491 " (void) %s;\n",
492 name, HCodeGenerator::FieldName(name).c_str(), name);
493 } else if (SectionAndParameterHelper::IsParameter(*decl.fVar)) {
494 const char* name = decl.fVar->fName.c_str();
495 if (!wroteProcessor) {
496 this->writef(" const %s& _outer = _proc.cast<%s>();\n", fullName,
497 fullName);
498 wroteProcessor = true;
499 }
500 this->writef(" auto %s = _outer.%s();\n"
501 " (void) %s;\n",
502 name, name, name);
503 }
504 }
505 }
506 }
507 this->writeSection(SET_DATA_SECTION);
508 }
509 this->write(" }\n");
510}
511
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400512void CPPCodeGenerator::writeClone() {
513 if (!this->writeSection(CLONE_SECTION)) {
514 if (fSectionAndParameterHelper.getSection(FIELDS_SECTION)) {
515 fErrors.error(Position(1, 1), "fragment processors with custom @fields must also have "
516 "a custom @clone");
517 }
518 this->writef("%s::%s(const %s& src)\n"
519 ": INHERITED(src.optimizationFlags())", fFullName.c_str(), fFullName.c_str(),
520 fFullName.c_str());
521 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
522 String fieldName = HCodeGenerator::FieldName(param->fName.c_str());
523 this->writef("\n, %s(%s)",
524 fieldName.c_str(),
525 ("src." + fieldName).c_str());
526 }
527 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
528 String fieldName = HCodeGenerator::FieldName(s->fArgument.c_str());
529 this->writef("\n, %sCoordTransform(src.%sCoordTransform)", fieldName.c_str(),
530 fieldName.c_str());
531 }
532 this->writef(" {\n"
533 " this->initClassID<%s>();\n",
534 fFullName.c_str());
535 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
536 if (param->fType.kind() == Type::kSampler_Kind) {
537 this->writef(" this->addTextureSampler(&%s);\n",
538 HCodeGenerator::FieldName(param->fName.c_str()).c_str());
539 }
540 }
541 for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
542 String field = HCodeGenerator::FieldName(s->fArgument.c_str());
543 this->writef(" this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
544 }
545 this->write("}\n");
Brian Salomonaff329b2017-08-11 09:40:37 -0400546 this->writef("std::unique_ptr<GrFragmentProcessor> %s::clone() const {\n",
547 fFullName.c_str());
548 this->writef(" return std::unique_ptr<GrFragmentProcessor>(new %s(*this));\n",
549 fFullName.c_str());
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400550 this->write("}\n");
551 }
552}
553
Ethan Nicholas762466e2017-06-29 10:03:38 -0400554void CPPCodeGenerator::writeTest() {
Ethan Nicholas68990be2017-07-13 09:36:52 -0400555 const Section* test = fSectionAndParameterHelper.getSection(TEST_CODE_SECTION);
556 if (test) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400557 this->writef(
558 "GR_DEFINE_FRAGMENT_PROCESSOR_TEST(%s);\n"
559 "#if GR_TEST_UTILS\n"
560 "std::unique_ptr<GrFragmentProcessor> %s::TestCreate(GrProcessorTestData* %s) {\n",
561 fFullName.c_str(),
562 fFullName.c_str(),
563 test->fArgument.c_str());
Ethan Nicholas68990be2017-07-13 09:36:52 -0400564 this->writeSection(TEST_CODE_SECTION);
565 this->write("}\n"
566 "#endif\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400567 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400568}
569
570void CPPCodeGenerator::writeGetKey() {
571 this->writef("void %s::onGetGLSLProcessorKey(const GrShaderCaps& caps, "
572 "GrProcessorKeyBuilder* b) const {\n",
573 fFullName.c_str());
Ethan Nicholas68990be2017-07-13 09:36:52 -0400574 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400575 const char* name = param->fName.c_str();
576 if (param->fType == *fContext.fColorSpaceXform_Type) {
577 this->writef(" b->add32(GrColorSpaceXform::XformKey(%s.get()));\n",
578 HCodeGenerator::FieldName(name).c_str());
579 continue;
580 }
581 if (param->fModifiers.fLayout.fKey != Layout::kNo_Key &&
582 (param->fModifiers.fFlags & Modifiers::kUniform_Flag)) {
583 fErrors.error(param->fPosition,
584 "layout(key) may not be specified on uniforms");
585 }
586 switch (param->fModifiers.fLayout.fKey) {
587 case Layout::kKey_Key:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400588 if (param->fType == *fContext.fFloat4x4_Type) {
589 ABORT("no automatic key handling for float4x4\n");
590 } else if (param->fType == *fContext.fFloat2_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400591 this->writef(" b->add32(%s.fX);\n",
592 HCodeGenerator::FieldName(name).c_str());
593 this->writef(" b->add32(%s.fY);\n",
594 HCodeGenerator::FieldName(name).c_str());
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400595 } else if (param->fType == *fContext.fFloat4_Type) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400596 this->writef(" b->add32(%s.x());\n",
597 HCodeGenerator::FieldName(name).c_str());
598 this->writef(" b->add32(%s.y());\n",
599 HCodeGenerator::FieldName(name).c_str());
600 this->writef(" b->add32(%s.width());\n",
601 HCodeGenerator::FieldName(name).c_str());
602 this->writef(" b->add32(%s.height());\n",
603 HCodeGenerator::FieldName(name).c_str());
604 } else {
605 this->writef(" b->add32(%s);\n",
606 HCodeGenerator::FieldName(name).c_str());
607 }
608 break;
609 case Layout::kIdentity_Key:
610 if (param->fType.kind() != Type::kMatrix_Kind) {
611 fErrors.error(param->fPosition,
612 "layout(key=identity) requires matrix type");
613 }
614 this->writef(" b->add32(%s.isIdentity() ? 1 : 0);\n",
615 HCodeGenerator::FieldName(name).c_str());
616 break;
617 case Layout::kNo_Key:
618 break;
619 }
620 }
621 this->write("}\n");
622}
623
624bool CPPCodeGenerator::generateCode() {
625 std::vector<const Variable*> uniforms;
626 for (const auto& p : fProgram.fElements) {
627 if (ProgramElement::kVar_Kind == p->fKind) {
628 const VarDeclarations* decls = (const VarDeclarations*) p.get();
629 for (const auto& raw : decls->fVars) {
630 VarDeclaration& decl = (VarDeclaration&) *raw;
631 if ((decl.fVar->fModifiers.fFlags & Modifiers::kUniform_Flag) &&
632 decl.fVar->fType.kind() != Type::kSampler_Kind) {
633 uniforms.push_back(decl.fVar);
634 }
635 }
636 }
637 }
638 const char* baseName = fName.c_str();
639 const char* fullName = fFullName.c_str();
640 this->writef(kFragmentProcessorHeader, fullName);
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400641 this->writef("#include \"%s.h\"\n"
642 "#if SK_SUPPORT_GPU\n", fullName);
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400643 this->writeSection(CPP_SECTION);
644 this->writef("#include \"glsl/GrGLSLColorSpaceXformHelper.h\"\n"
Ethan Nicholas762466e2017-06-29 10:03:38 -0400645 "#include \"glsl/GrGLSLFragmentProcessor.h\"\n"
646 "#include \"glsl/GrGLSLFragmentShaderBuilder.h\"\n"
647 "#include \"glsl/GrGLSLProgramBuilder.h\"\n"
Ethan Nicholas762466e2017-06-29 10:03:38 -0400648 "#include \"SkSLCPP.h\"\n"
649 "#include \"SkSLUtil.h\"\n"
650 "class GrGLSL%s : public GrGLSLFragmentProcessor {\n"
651 "public:\n"
652 " GrGLSL%s() {}\n",
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400653 baseName, baseName);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400654 bool result = this->writeEmitCode(uniforms);
655 this->write("private:\n");
656 this->writeSetData(uniforms);
657 this->writePrivateVars();
658 for (const auto& u : uniforms) {
659 const char* name = u->fName.c_str();
660 if (needs_uniform_var(*u) && !(u->fModifiers.fFlags & Modifiers::kIn_Flag)) {
661 this->writef(" UniformHandle %sVar;\n", HCodeGenerator::FieldName(name).c_str());
662 }
663 }
Ethan Nicholas68990be2017-07-13 09:36:52 -0400664 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400665 const char* name = param->fName.c_str();
666 if (needs_uniform_var(*param)) {
667 this->writef(" UniformHandle %sVar;\n", HCodeGenerator::FieldName(name).c_str());
668 }
669 }
670 if (fNeedColorSpaceHelper) {
671 this->write(" GrGLSLColorSpaceXformHelper fColorSpaceHelper;\n");
672 }
673 this->writef("};\n"
674 "GrGLSLFragmentProcessor* %s::onCreateGLSLInstance() const {\n"
675 " return new GrGLSL%s();\n"
676 "}\n",
677 fullName, baseName);
678 this->writeGetKey();
679 this->writef("bool %s::onIsEqual(const GrFragmentProcessor& other) const {\n"
680 " const %s& that = other.cast<%s>();\n"
681 " (void) that;\n",
682 fullName, fullName, fullName);
Ethan Nicholas68990be2017-07-13 09:36:52 -0400683 for (const auto& param : fSectionAndParameterHelper.getParameters()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400684 const char* name = param->fName.c_str();
685 this->writef(" if (%s != that.%s) return false;\n",
686 HCodeGenerator::FieldName(name).c_str(),
687 HCodeGenerator::FieldName(name).c_str());
688 }
689 this->write(" return true;\n"
690 "}\n");
Ethan Nicholasf57c0d62017-07-31 11:18:22 -0400691 this->writeClone();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400692 this->writeTest();
Ethan Nicholas9fb036f2017-07-05 16:19:09 -0400693 this->writeSection(CPP_END_SECTION);
Ethan Nicholasceb4d482017-07-10 15:40:20 -0400694 this->write("#endif\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400695 result &= 0 == fErrors.errorCount();
696 return result;
697}
698
699} // namespace