blob: 70e2e7761c5a7dd19b4d9bb00b261b59886ecb4c [file] [log] [blame]
ethannicholasf789b382016-08-03 12:43:36 -07001/*
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 */
Greg Daniel64773e62016-11-22 09:44:03 -05007
ethannicholasf789b382016-08-03 12:43:36 -07008#include "SkSLGLSLCodeGenerator.h"
9
10#include "string.h"
11
12#include "GLSL.std.450.h"
13
Ethan Nicholas941e7e22016-12-12 15:33:30 -050014#include "SkSLCompiler.h"
ethannicholasf789b382016-08-03 12:43:36 -070015#include "ir/SkSLExpressionStatement.h"
16#include "ir/SkSLExtension.h"
17#include "ir/SkSLIndexExpression.h"
ethannicholas5961bc92016-10-12 06:39:56 -070018#include "ir/SkSLModifiersDeclaration.h"
ethannicholasf789b382016-08-03 12:43:36 -070019#include "ir/SkSLVariableReference.h"
20
21namespace SkSL {
22
23void GLSLCodeGenerator::write(const char* s) {
24 if (s[0] == 0) {
25 return;
26 }
27 if (fAtLineStart) {
28 for (int i = 0; i < fIndentation; i++) {
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050029 fOut->writeText(" ");
ethannicholasf789b382016-08-03 12:43:36 -070030 }
31 }
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050032 fOut->writeText(s);
ethannicholasf789b382016-08-03 12:43:36 -070033 fAtLineStart = false;
34}
35
36void GLSLCodeGenerator::writeLine(const char* s) {
37 this->write(s);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050038 fOut->writeText("\n");
ethannicholasf789b382016-08-03 12:43:36 -070039 fAtLineStart = true;
40}
41
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050042void GLSLCodeGenerator::write(const SkString& s) {
ethannicholasf789b382016-08-03 12:43:36 -070043 this->write(s.c_str());
44}
45
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050046void GLSLCodeGenerator::writeLine(const SkString& s) {
ethannicholasf789b382016-08-03 12:43:36 -070047 this->writeLine(s.c_str());
48}
49
50void GLSLCodeGenerator::writeLine() {
51 this->writeLine("");
52}
53
54void GLSLCodeGenerator::writeExtension(const Extension& ext) {
55 this->writeLine("#extension " + ext.fName + " : enable");
56}
57
58void GLSLCodeGenerator::writeType(const Type& type) {
59 if (type.kind() == Type::kStruct_Kind) {
60 for (const Type* search : fWrittenStructs) {
61 if (*search == type) {
62 // already written
63 this->write(type.name());
64 return;
65 }
66 }
67 fWrittenStructs.push_back(&type);
68 this->writeLine("struct " + type.name() + " {");
69 fIndentation++;
70 for (const auto& f : type.fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -070071 this->writeModifiers(f.fModifiers, false);
ethannicholasf789b382016-08-03 12:43:36 -070072 // sizes (which must be static in structs) are part of the type name here
ethannicholas0730be72016-09-01 07:59:02 -070073 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -070074 this->writeLine(" " + f.fName + ";");
75 }
76 fIndentation--;
Ethan Nicholas19671772016-11-28 16:30:17 -050077 this->write("}");
ethannicholasf789b382016-08-03 12:43:36 -070078 } else {
79 this->write(type.name());
80 }
81}
82
83void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
84 switch (expr.fKind) {
85 case Expression::kBinary_Kind:
86 this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
87 break;
88 case Expression::kBoolLiteral_Kind:
89 this->writeBoolLiteral((BoolLiteral&) expr);
90 break;
91 case Expression::kConstructor_Kind:
92 this->writeConstructor((Constructor&) expr);
93 break;
94 case Expression::kIntLiteral_Kind:
95 this->writeIntLiteral((IntLiteral&) expr);
96 break;
97 case Expression::kFieldAccess_Kind:
98 this->writeFieldAccess(((FieldAccess&) expr));
99 break;
100 case Expression::kFloatLiteral_Kind:
101 this->writeFloatLiteral(((FloatLiteral&) expr));
102 break;
103 case Expression::kFunctionCall_Kind:
104 this->writeFunctionCall((FunctionCall&) expr);
105 break;
106 case Expression::kPrefix_Kind:
107 this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
108 break;
109 case Expression::kPostfix_Kind:
110 this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
111 break;
112 case Expression::kSwizzle_Kind:
113 this->writeSwizzle((Swizzle&) expr);
114 break;
115 case Expression::kVariableReference_Kind:
116 this->writeVariableReference((VariableReference&) expr);
117 break;
118 case Expression::kTernary_Kind:
119 this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
120 break;
121 case Expression::kIndex_Kind:
122 this->writeIndexExpression((IndexExpression&) expr);
123 break;
124 default:
125 ABORT("unsupported expression: %s", expr.description().c_str());
126 }
127}
128
ethannicholas5961bc92016-10-12 06:39:56 -0700129static bool is_abs(Expression& expr) {
130 if (expr.fKind != Expression::kFunctionCall_Kind) {
131 return false;
132 }
133 return ((FunctionCall&) expr).fFunction.fName == "abs";
134}
135
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500136// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
ethannicholas5961bc92016-10-12 06:39:56 -0700137// Tegra3 compiler bug.
138void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500139 ASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500140 SkString tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
141 SkString tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
ethannicholas5961bc92016-10-12 06:39:56 -0700142 this->fFunctionHeader += " " + absExpr.fType.name() + " " + tmpVar1 + ";\n";
143 this->fFunctionHeader += " " + otherExpr.fType.name() + " " + tmpVar2 + ";\n";
144 this->write("((" + tmpVar1 + " = ");
145 this->writeExpression(absExpr, kTopLevel_Precedence);
146 this->write(") < (" + tmpVar2 + " = ");
147 this->writeExpression(otherExpr, kAssignment_Precedence);
148 this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
149}
150
ethannicholasf789b382016-08-03 12:43:36 -0700151void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500152 if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether() && c.fFunction.fName == "min" &&
153 c.fFunction.fBuiltin) {
ethannicholas5961bc92016-10-12 06:39:56 -0700154 ASSERT(c.fArguments.size() == 2);
155 if (is_abs(*c.fArguments[0])) {
156 this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
157 return;
158 }
159 if (is_abs(*c.fArguments[1])) {
160 // note that this violates the GLSL left-to-right evaluation semantics. I doubt it will
161 // ever end up mattering, but it's worth calling out.
162 this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
163 return;
164 }
165 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500166 if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
167 c.fFunction.fName == "atan" &&
168 c.fFunction.fBuiltin && c.fArguments.size() == 2 &&
ethannicholasddb37d62016-10-20 09:54:00 -0700169 c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
ethannicholasad146f62016-10-14 06:40:02 -0700170 const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
171 if (p.fOperator == Token::MINUS) {
172 this->write("atan(");
173 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
174 this->write(", -1.0 * ");
175 this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
176 this->write(")");
177 return;
178 }
179 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500180 if (!fFoundDerivatives && (c.fFunction.fName == "dFdx" || c.fFunction.fName == "dFdy") &&
181 c.fFunction.fBuiltin && fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
182 ASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500183 fHeader.writeText("#extension ");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500184 fHeader.writeText(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500185 fHeader.writeText(" : require\n");
ethannicholasddb37d62016-10-20 09:54:00 -0700186 fFoundDerivatives = true;
187 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500188 if (c.fFunction.fName == "texture" && c.fFunction.fBuiltin) {
189 const char* dim = "";
190 bool proj = false;
191 switch (c.fArguments[0]->fType.dimensions()) {
192 case SpvDim1D:
193 dim = "1D";
194 if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
195 proj = false;
196 } else {
197 ASSERT(c.fArguments[1]->fType == *fContext.fVec2_Type);
198 proj = true;
199 }
200 break;
201 case SpvDim2D:
202 dim = "2D";
203 if (c.fArguments[1]->fType == *fContext.fVec2_Type) {
204 proj = false;
205 } else {
206 ASSERT(c.fArguments[1]->fType == *fContext.fVec3_Type);
207 proj = true;
208 }
209 break;
210 case SpvDim3D:
211 dim = "3D";
212 if (c.fArguments[1]->fType == *fContext.fVec3_Type) {
213 proj = false;
214 } else {
215 ASSERT(c.fArguments[1]->fType == *fContext.fVec4_Type);
216 proj = true;
217 }
218 break;
219 case SpvDimCube:
220 dim = "Cube";
221 proj = false;
222 break;
223 case SpvDimRect:
224 dim = "Rect";
225 proj = false;
226 break;
227 case SpvDimBuffer:
228 ASSERT(false); // doesn't exist
229 dim = "Buffer";
230 proj = false;
231 break;
232 case SpvDimSubpassData:
233 ASSERT(false); // doesn't exist
234 dim = "SubpassData";
235 proj = false;
236 break;
237 }
238 this->write("texture");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500239 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500240 this->write(dim);
241 }
242 if (proj) {
243 this->write("Proj");
244 }
245
246 } else {
247 this->write(c.fFunction.fName);
248 }
249 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700250 const char* separator = "";
251 for (const auto& arg : c.fArguments) {
252 this->write(separator);
253 separator = ", ";
254 this->writeExpression(*arg, kSequence_Precedence);
255 }
256 this->write(")");
257}
258
259void GLSLCodeGenerator::writeConstructor(const Constructor& c) {
260 this->write(c.fType.name() + "(");
261 const char* separator = "";
262 for (const auto& arg : c.fArguments) {
263 this->write(separator);
264 separator = ", ";
265 this->writeExpression(*arg, kSequence_Precedence);
266 }
267 this->write(")");
268}
269
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500270void GLSLCodeGenerator::writeFragCoord() {
271 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
272 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
273 // declaration varies in earlier GLSL specs. So it is simpler to omit it.
274 if (!fProgram.fSettings.fFlipY) {
275 this->write("gl_FragCoord");
276 } else if (const char* extension =
277 fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
278 if (!fSetupFragPositionGlobal) {
279 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
280 fHeader.writeText("#extension ");
281 fHeader.writeText(extension);
282 fHeader.writeText(" : require\n");
283 }
284 fHeader.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
285 fSetupFragPositionGlobal = true;
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000286 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500287 this->write("gl_FragCoord");
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000288 } else {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500289 if (!fSetupFragPositionGlobal) {
290 // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
291 // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
292 // depending on the surrounding code, accessing .xy with a uniform involved can
293 // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand
294 // (and only accessing .xy) seems to "fix" things.
295 const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp "
296 : "";
297 fHeader.writeText("uniform ");
298 fHeader.writeText(precision);
299 fHeader.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
300 fSetupFragPositionGlobal = true;
301 }
302 if (!fSetupFragPositionLocal) {
303 const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp "
304 : "";
305 fFunctionHeader += precision;
306 fFunctionHeader += " vec2 _sktmpCoord = gl_FragCoord.xy;\n";
307 fFunctionHeader += precision;
308 fFunctionHeader += " vec4 sk_FragCoord = vec4(_sktmpCoord.x, " SKSL_RTHEIGHT_NAME
309 " - _sktmpCoord.y, 1.0, 1.0);\n";
310 fSetupFragPositionLocal = true;
311 }
312 this->write("sk_FragCoord");
313 }
314}
315
316
317void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
318 switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
319 case SK_FRAGCOLOR_BUILTIN:
320 if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
321 this->write("sk_FragColor");
322 } else {
323 this->write("gl_FragColor");
324 }
325 break;
326 case SK_FRAGCOORD_BUILTIN:
327 this->writeFragCoord();
328 break;
Ethan Nicholasa51740c2017-02-07 14:53:32 -0500329 case SK_VERTEXID_BUILTIN:
330 this->write("gl_VertexID");
331 break;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500332 default:
333 this->write(ref.fVariable.fName);
ethannicholas5961bc92016-10-12 06:39:56 -0700334 }
ethannicholasf789b382016-08-03 12:43:36 -0700335}
336
337void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
338 this->writeExpression(*expr.fBase, kPostfix_Precedence);
339 this->write("[");
340 this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
341 this->write("]");
342}
343
344void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
345 if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
346 this->writeExpression(*f.fBase, kPostfix_Precedence);
347 this->write(".");
348 }
349 this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
350}
351
352void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
353 this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
354 this->write(".");
355 for (int c : swizzle.fComponents) {
356 this->write(&("x\0y\0z\0w\0"[c * 2]));
357 }
358}
359
360static GLSLCodeGenerator::Precedence get_binary_precedence(Token::Kind op) {
361 switch (op) {
362 case Token::STAR: // fall through
363 case Token::SLASH: // fall through
364 case Token::PERCENT: return GLSLCodeGenerator::kMultiplicative_Precedence;
365 case Token::PLUS: // fall through
366 case Token::MINUS: return GLSLCodeGenerator::kAdditive_Precedence;
367 case Token::SHL: // fall through
368 case Token::SHR: return GLSLCodeGenerator::kShift_Precedence;
369 case Token::LT: // fall through
370 case Token::GT: // fall through
371 case Token::LTEQ: // fall through
372 case Token::GTEQ: return GLSLCodeGenerator::kRelational_Precedence;
373 case Token::EQEQ: // fall through
374 case Token::NEQ: return GLSLCodeGenerator::kEquality_Precedence;
375 case Token::BITWISEAND: return GLSLCodeGenerator::kBitwiseAnd_Precedence;
376 case Token::BITWISEXOR: return GLSLCodeGenerator::kBitwiseXor_Precedence;
377 case Token::BITWISEOR: return GLSLCodeGenerator::kBitwiseOr_Precedence;
378 case Token::LOGICALAND: return GLSLCodeGenerator::kLogicalAnd_Precedence;
379 case Token::LOGICALXOR: return GLSLCodeGenerator::kLogicalXor_Precedence;
380 case Token::LOGICALOR: return GLSLCodeGenerator::kLogicalOr_Precedence;
381 case Token::EQ: // fall through
382 case Token::PLUSEQ: // fall through
383 case Token::MINUSEQ: // fall through
384 case Token::STAREQ: // fall through
385 case Token::SLASHEQ: // fall through
386 case Token::PERCENTEQ: // fall through
387 case Token::SHLEQ: // fall through
388 case Token::SHREQ: // fall through
389 case Token::LOGICALANDEQ: // fall through
390 case Token::LOGICALXOREQ: // fall through
391 case Token::LOGICALOREQ: // fall through
392 case Token::BITWISEANDEQ: // fall through
393 case Token::BITWISEXOREQ: // fall through
394 case Token::BITWISEOREQ: return GLSLCodeGenerator::kAssignment_Precedence;
395 default: ABORT("unsupported binary operator");
396 }
397}
398
399void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
400 Precedence parentPrecedence) {
401 Precedence precedence = get_binary_precedence(b.fOperator);
402 if (precedence >= parentPrecedence) {
403 this->write("(");
404 }
405 this->writeExpression(*b.fLeft, precedence);
406 this->write(" " + Token::OperatorName(b.fOperator) + " ");
407 this->writeExpression(*b.fRight, precedence);
408 if (precedence >= parentPrecedence) {
409 this->write(")");
410 }
411}
412
413void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
414 Precedence parentPrecedence) {
415 if (kTernary_Precedence >= parentPrecedence) {
416 this->write("(");
417 }
418 this->writeExpression(*t.fTest, kTernary_Precedence);
419 this->write(" ? ");
420 this->writeExpression(*t.fIfTrue, kTernary_Precedence);
421 this->write(" : ");
422 this->writeExpression(*t.fIfFalse, kTernary_Precedence);
423 if (kTernary_Precedence >= parentPrecedence) {
424 this->write(")");
425 }
426}
427
428void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
429 Precedence parentPrecedence) {
430 if (kPrefix_Precedence >= parentPrecedence) {
431 this->write("(");
432 }
433 this->write(Token::OperatorName(p.fOperator));
434 this->writeExpression(*p.fOperand, kPrefix_Precedence);
435 if (kPrefix_Precedence >= parentPrecedence) {
436 this->write(")");
437 }
438}
439
440void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
441 Precedence parentPrecedence) {
442 if (kPostfix_Precedence >= parentPrecedence) {
443 this->write("(");
444 }
445 this->writeExpression(*p.fOperand, kPostfix_Precedence);
446 this->write(Token::OperatorName(p.fOperator));
447 if (kPostfix_Precedence >= parentPrecedence) {
448 this->write(")");
449 }
450}
451
452void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
453 this->write(b.fValue ? "true" : "false");
454}
455
456void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholas5961bc92016-10-12 06:39:56 -0700457 if (i.fType == *fContext.fUInt_Type) {
458 this->write(to_string(i.fValue & 0xffffffff) + "u");
459 } else {
460 this->write(to_string((int32_t) i.fValue));
461 }
ethannicholasf789b382016-08-03 12:43:36 -0700462}
463
464void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
465 this->write(to_string(f.fValue));
466}
467
468void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
469 this->writeType(f.fDeclaration.fReturnType);
470 this->write(" " + f.fDeclaration.fName + "(");
471 const char* separator = "";
472 for (const auto& param : f.fDeclaration.fParameters) {
473 this->write(separator);
474 separator = ", ";
ethannicholas5961bc92016-10-12 06:39:56 -0700475 this->writeModifiers(param->fModifiers, false);
476 std::vector<int> sizes;
477 const Type* type = &param->fType;
478 while (type->kind() == Type::kArray_Kind) {
479 sizes.push_back(type->columns());
480 type = &type->componentType();
481 }
482 this->writeType(*type);
ethannicholasf789b382016-08-03 12:43:36 -0700483 this->write(" " + param->fName);
ethannicholas5961bc92016-10-12 06:39:56 -0700484 for (int s : sizes) {
485 if (s <= 0) {
486 this->write("[]");
487 } else {
488 this->write("[" + to_string(s) + "]");
489 }
490 }
ethannicholasf789b382016-08-03 12:43:36 -0700491 }
ethannicholas5961bc92016-10-12 06:39:56 -0700492 this->writeLine(") {");
493
494 fFunctionHeader = "";
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500495 SkWStream* oldOut = fOut;
496 SkDynamicMemoryWStream buffer;
ethannicholas5961bc92016-10-12 06:39:56 -0700497 fOut = &buffer;
498 fIndentation++;
Ethan Nicholase1d9cb82017-02-06 18:53:07 +0000499 for (const auto& s : f.fBody->fStatements) {
500 this->writeStatement(*s);
501 this->writeLine();
502 }
ethannicholas5961bc92016-10-12 06:39:56 -0700503 fIndentation--;
504 this->writeLine("}");
505
506 fOut = oldOut;
507 this->write(fFunctionHeader);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500508 sk_sp<SkData> data(buffer.detachAsData());
509 this->write(SkString((const char*) data->data(), data->size()));
ethannicholasf789b382016-08-03 12:43:36 -0700510}
511
Greg Daniel64773e62016-11-22 09:44:03 -0500512void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
ethannicholas5961bc92016-10-12 06:39:56 -0700513 bool globalContext) {
Brian Salomonf9f45122016-11-29 11:59:17 -0500514 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
515 this->write("flat ");
516 }
ethannicholas5961bc92016-10-12 06:39:56 -0700517 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
518 this->write("noperspective ");
519 }
Brian Salomonf9f45122016-11-29 11:59:17 -0500520 if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
521 this->write("readonly ");
522 }
523 if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
524 this->write("writeonly ");
525 }
526 if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
527 this->write("coherent ");
528 }
529 if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
530 this->write("volatile ");
531 }
532 if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
533 this->write("restrict ");
ethannicholas5961bc92016-10-12 06:39:56 -0700534 }
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500535 SkString layout = modifiers.fLayout.description();
536 if (layout.size()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700537 this->write(layout + " ");
538 }
Greg Daniel64773e62016-11-22 09:44:03 -0500539 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
ethannicholas5961bc92016-10-12 06:39:56 -0700540 (modifiers.fFlags & Modifiers::kOut_Flag)) {
541 this->write("inout ");
542 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500543 if (globalContext &&
544 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -0700545 this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
546 : "varying ");
547 } else {
548 this->write("in ");
549 }
550 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500551 if (globalContext &&
552 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -0700553 this->write("varying ");
554 } else {
555 this->write("out ");
556 }
557 }
558 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
559 this->write("uniform ");
560 }
561 if (modifiers.fFlags & Modifiers::kConst_Flag) {
562 this->write("const ");
563 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500564 if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700565 if (modifiers.fFlags & Modifiers::kLowp_Flag) {
566 this->write("lowp ");
567 }
568 if (modifiers.fFlags & Modifiers::kMediump_Flag) {
569 this->write("mediump ");
570 }
571 if (modifiers.fFlags & Modifiers::kHighp_Flag) {
572 this->write("highp ");
573 }
574 }
ethannicholasf789b382016-08-03 12:43:36 -0700575}
576
577void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
578 if (intf.fVariable.fName == "gl_PerVertex") {
579 return;
580 }
ethannicholas5961bc92016-10-12 06:39:56 -0700581 this->writeModifiers(intf.fVariable.fModifiers, true);
ethannicholasf789b382016-08-03 12:43:36 -0700582 this->writeLine(intf.fVariable.fType.name() + " {");
583 fIndentation++;
584 for (const auto& f : intf.fVariable.fType.fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700585 this->writeModifiers(f.fModifiers, false);
ethannicholas0730be72016-09-01 07:59:02 -0700586 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -0700587 this->writeLine(" " + f.fName + ";");
588 }
589 fIndentation--;
590 this->writeLine("};");
591}
592
ethannicholas5961bc92016-10-12 06:39:56 -0700593void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
ethannicholasf789b382016-08-03 12:43:36 -0700594 ASSERT(decl.fVars.size() > 0);
Ethan Nicholase1d9cb82017-02-06 18:53:07 +0000595 this->writeModifiers(decl.fVars[0].fVar->fModifiers, global);
ethannicholasf789b382016-08-03 12:43:36 -0700596 this->writeType(decl.fBaseType);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500597 SkString separator(" ");
ethannicholas14fe8cc2016-09-07 13:37:16 -0700598 for (const auto& var : decl.fVars) {
Ethan Nicholase1d9cb82017-02-06 18:53:07 +0000599 ASSERT(var.fVar->fModifiers == decl.fVars[0].fVar->fModifiers);
ethannicholasf789b382016-08-03 12:43:36 -0700600 this->write(separator);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500601 separator = SkString(", ");
Ethan Nicholase1d9cb82017-02-06 18:53:07 +0000602 this->write(var.fVar->fName);
603 for (const auto& size : var.fSizes) {
ethannicholasf789b382016-08-03 12:43:36 -0700604 this->write("[");
ethannicholas5961bc92016-10-12 06:39:56 -0700605 if (size) {
606 this->writeExpression(*size, kTopLevel_Precedence);
607 }
ethannicholasf789b382016-08-03 12:43:36 -0700608 this->write("]");
609 }
Ethan Nicholase1d9cb82017-02-06 18:53:07 +0000610 if (var.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -0700611 this->write(" = ");
Ethan Nicholase1d9cb82017-02-06 18:53:07 +0000612 this->writeExpression(*var.fValue, kTopLevel_Precedence);
ethannicholasf789b382016-08-03 12:43:36 -0700613 }
Ethan Nicholase1d9cb82017-02-06 18:53:07 +0000614 if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500615 if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500616 fHeader.writeText("#extension ");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500617 fHeader.writeText(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500618 fHeader.writeText(" : require\n");
Brian Salomon2a51de82016-11-16 12:06:01 -0500619 }
620 fFoundImageDecl = true;
621 }
ethannicholasf789b382016-08-03 12:43:36 -0700622 }
623 this->write(";");
624}
625
626void GLSLCodeGenerator::writeStatement(const Statement& s) {
627 switch (s.fKind) {
628 case Statement::kBlock_Kind:
629 this->writeBlock((Block&) s);
630 break;
631 case Statement::kExpression_Kind:
632 this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
633 this->write(";");
634 break;
635 case Statement::kReturn_Kind:
636 this->writeReturnStatement((ReturnStatement&) s);
637 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -0700638 case Statement::kVarDeclarations_Kind:
ethannicholas5961bc92016-10-12 06:39:56 -0700639 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
ethannicholasf789b382016-08-03 12:43:36 -0700640 break;
641 case Statement::kIf_Kind:
642 this->writeIfStatement((IfStatement&) s);
643 break;
644 case Statement::kFor_Kind:
645 this->writeForStatement((ForStatement&) s);
646 break;
647 case Statement::kWhile_Kind:
648 this->writeWhileStatement((WhileStatement&) s);
649 break;
650 case Statement::kDo_Kind:
651 this->writeDoStatement((DoStatement&) s);
652 break;
653 case Statement::kBreak_Kind:
654 this->write("break;");
655 break;
656 case Statement::kContinue_Kind:
657 this->write("continue;");
658 break;
659 case Statement::kDiscard_Kind:
660 this->write("discard;");
661 break;
662 default:
663 ABORT("unsupported statement: %s", s.description().c_str());
664 }
665}
666
667void GLSLCodeGenerator::writeBlock(const Block& b) {
668 this->writeLine("{");
669 fIndentation++;
Ethan Nicholase1d9cb82017-02-06 18:53:07 +0000670 for (const auto& s : b.fStatements) {
671 this->writeStatement(*s);
672 this->writeLine();
673 }
ethannicholasf789b382016-08-03 12:43:36 -0700674 fIndentation--;
675 this->write("}");
676}
677
678void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
679 this->write("if (");
680 this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
681 this->write(") ");
682 this->writeStatement(*stmt.fIfTrue);
683 if (stmt.fIfFalse) {
684 this->write(" else ");
685 this->writeStatement(*stmt.fIfFalse);
686 }
687}
688
689void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
690 this->write("for (");
691 if (f.fInitializer) {
692 this->writeStatement(*f.fInitializer);
693 } else {
694 this->write("; ");
695 }
696 if (f.fTest) {
697 this->writeExpression(*f.fTest, kTopLevel_Precedence);
698 }
699 this->write("; ");
700 if (f.fNext) {
701 this->writeExpression(*f.fNext, kTopLevel_Precedence);
702 }
703 this->write(") ");
704 this->writeStatement(*f.fStatement);
705}
706
707void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
708 this->write("while (");
709 this->writeExpression(*w.fTest, kTopLevel_Precedence);
710 this->write(") ");
711 this->writeStatement(*w.fStatement);
712}
713
714void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
715 this->write("do ");
716 this->writeStatement(*d.fStatement);
717 this->write(" while (");
718 this->writeExpression(*d.fTest, kTopLevel_Precedence);
719 this->write(");");
720}
721
722void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
723 this->write("return");
724 if (r.fExpression) {
725 this->write(" ");
726 this->writeExpression(*r.fExpression, kTopLevel_Precedence);
727 }
728 this->write(";");
729}
730
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500731bool GLSLCodeGenerator::generateCode() {
732 SkWStream* rawOut = fOut;
ethannicholasddb37d62016-10-20 09:54:00 -0700733 fOut = &fHeader;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500734 fProgramKind = fProgram.fKind;
735 this->write(fProgram.fSettings.fCaps->versionDeclString());
ethannicholasf789b382016-08-03 12:43:36 -0700736 this->writeLine();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500737 for (const auto& e : fProgram.fElements) {
ethannicholas5961bc92016-10-12 06:39:56 -0700738 if (e->fKind == ProgramElement::kExtension_Kind) {
739 this->writeExtension((Extension&) *e);
740 }
741 }
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500742 SkDynamicMemoryWStream body;
ethannicholasddb37d62016-10-20 09:54:00 -0700743 fOut = &body;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500744 if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700745 this->write("precision ");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500746 switch (fProgram.fDefaultPrecision) {
ethannicholas5961bc92016-10-12 06:39:56 -0700747 case Modifiers::kLowp_Flag:
748 this->write("lowp");
749 break;
750 case Modifiers::kMediump_Flag:
751 this->write("mediump");
752 break;
753 case Modifiers::kHighp_Flag:
754 this->write("highp");
755 break;
756 default:
757 ASSERT(false);
758 this->write("<error>");
759 }
760 this->writeLine(" float;");
761 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500762 for (const auto& e : fProgram.fElements) {
ethannicholasf789b382016-08-03 12:43:36 -0700763 switch (e->fKind) {
764 case ProgramElement::kExtension_Kind:
ethannicholasf789b382016-08-03 12:43:36 -0700765 break;
766 case ProgramElement::kVar_Kind: {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700767 VarDeclarations& decl = (VarDeclarations&) *e;
ethannicholas5961bc92016-10-12 06:39:56 -0700768 if (decl.fVars.size() > 0) {
Ethan Nicholase1d9cb82017-02-06 18:53:07 +0000769 int builtin = decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin;
ethannicholas5961bc92016-10-12 06:39:56 -0700770 if (builtin == -1) {
771 // normal var
772 this->writeVarDeclarations(decl, true);
773 this->writeLine();
774 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500775 fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700776 this->write("out ");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500777 if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700778 this->write("mediump ");
779 }
780 this->writeLine("vec4 sk_FragColor;");
781 }
ethannicholasf789b382016-08-03 12:43:36 -0700782 }
783 break;
784 }
785 case ProgramElement::kInterfaceBlock_Kind:
786 this->writeInterfaceBlock((InterfaceBlock&) *e);
787 break;
788 case ProgramElement::kFunction_Kind:
789 this->writeFunction((FunctionDefinition&) *e);
790 break;
ethannicholas5961bc92016-10-12 06:39:56 -0700791 case ProgramElement::kModifiers_Kind:
792 this->writeModifiers(((ModifiersDeclaration&) *e).fModifiers, true);
793 this->writeLine(";");
794 break;
ethannicholasf789b382016-08-03 12:43:36 -0700795 default:
796 printf("%s\n", e->description().c_str());
797 ABORT("unsupported program element");
798 }
799 }
800 fOut = nullptr;
ethannicholasddb37d62016-10-20 09:54:00 -0700801
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500802 write_data(*fHeader.detachAsData(), *rawOut);
803 write_data(*body.detachAsData(), *rawOut);
804 return true;
ethannicholasf789b382016-08-03 12:43:36 -0700805}
806
807}