blob: dd8c0cf3123fe2ea77b0f6d721a18a4c7ef78e42 [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;
329 default:
330 this->write(ref.fVariable.fName);
ethannicholas5961bc92016-10-12 06:39:56 -0700331 }
ethannicholasf789b382016-08-03 12:43:36 -0700332}
333
334void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
335 this->writeExpression(*expr.fBase, kPostfix_Precedence);
336 this->write("[");
337 this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
338 this->write("]");
339}
340
341void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
342 if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
343 this->writeExpression(*f.fBase, kPostfix_Precedence);
344 this->write(".");
345 }
346 this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
347}
348
349void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
350 this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
351 this->write(".");
352 for (int c : swizzle.fComponents) {
353 this->write(&("x\0y\0z\0w\0"[c * 2]));
354 }
355}
356
357static GLSLCodeGenerator::Precedence get_binary_precedence(Token::Kind op) {
358 switch (op) {
359 case Token::STAR: // fall through
360 case Token::SLASH: // fall through
361 case Token::PERCENT: return GLSLCodeGenerator::kMultiplicative_Precedence;
362 case Token::PLUS: // fall through
363 case Token::MINUS: return GLSLCodeGenerator::kAdditive_Precedence;
364 case Token::SHL: // fall through
365 case Token::SHR: return GLSLCodeGenerator::kShift_Precedence;
366 case Token::LT: // fall through
367 case Token::GT: // fall through
368 case Token::LTEQ: // fall through
369 case Token::GTEQ: return GLSLCodeGenerator::kRelational_Precedence;
370 case Token::EQEQ: // fall through
371 case Token::NEQ: return GLSLCodeGenerator::kEquality_Precedence;
372 case Token::BITWISEAND: return GLSLCodeGenerator::kBitwiseAnd_Precedence;
373 case Token::BITWISEXOR: return GLSLCodeGenerator::kBitwiseXor_Precedence;
374 case Token::BITWISEOR: return GLSLCodeGenerator::kBitwiseOr_Precedence;
375 case Token::LOGICALAND: return GLSLCodeGenerator::kLogicalAnd_Precedence;
376 case Token::LOGICALXOR: return GLSLCodeGenerator::kLogicalXor_Precedence;
377 case Token::LOGICALOR: return GLSLCodeGenerator::kLogicalOr_Precedence;
378 case Token::EQ: // fall through
379 case Token::PLUSEQ: // fall through
380 case Token::MINUSEQ: // fall through
381 case Token::STAREQ: // fall through
382 case Token::SLASHEQ: // fall through
383 case Token::PERCENTEQ: // fall through
384 case Token::SHLEQ: // fall through
385 case Token::SHREQ: // fall through
386 case Token::LOGICALANDEQ: // fall through
387 case Token::LOGICALXOREQ: // fall through
388 case Token::LOGICALOREQ: // fall through
389 case Token::BITWISEANDEQ: // fall through
390 case Token::BITWISEXOREQ: // fall through
391 case Token::BITWISEOREQ: return GLSLCodeGenerator::kAssignment_Precedence;
392 default: ABORT("unsupported binary operator");
393 }
394}
395
396void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
397 Precedence parentPrecedence) {
398 Precedence precedence = get_binary_precedence(b.fOperator);
399 if (precedence >= parentPrecedence) {
400 this->write("(");
401 }
402 this->writeExpression(*b.fLeft, precedence);
403 this->write(" " + Token::OperatorName(b.fOperator) + " ");
404 this->writeExpression(*b.fRight, precedence);
405 if (precedence >= parentPrecedence) {
406 this->write(")");
407 }
408}
409
410void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
411 Precedence parentPrecedence) {
412 if (kTernary_Precedence >= parentPrecedence) {
413 this->write("(");
414 }
415 this->writeExpression(*t.fTest, kTernary_Precedence);
416 this->write(" ? ");
417 this->writeExpression(*t.fIfTrue, kTernary_Precedence);
418 this->write(" : ");
419 this->writeExpression(*t.fIfFalse, kTernary_Precedence);
420 if (kTernary_Precedence >= parentPrecedence) {
421 this->write(")");
422 }
423}
424
425void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
426 Precedence parentPrecedence) {
427 if (kPrefix_Precedence >= parentPrecedence) {
428 this->write("(");
429 }
430 this->write(Token::OperatorName(p.fOperator));
431 this->writeExpression(*p.fOperand, kPrefix_Precedence);
432 if (kPrefix_Precedence >= parentPrecedence) {
433 this->write(")");
434 }
435}
436
437void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
438 Precedence parentPrecedence) {
439 if (kPostfix_Precedence >= parentPrecedence) {
440 this->write("(");
441 }
442 this->writeExpression(*p.fOperand, kPostfix_Precedence);
443 this->write(Token::OperatorName(p.fOperator));
444 if (kPostfix_Precedence >= parentPrecedence) {
445 this->write(")");
446 }
447}
448
449void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
450 this->write(b.fValue ? "true" : "false");
451}
452
453void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholas5961bc92016-10-12 06:39:56 -0700454 if (i.fType == *fContext.fUInt_Type) {
455 this->write(to_string(i.fValue & 0xffffffff) + "u");
456 } else {
457 this->write(to_string((int32_t) i.fValue));
458 }
ethannicholasf789b382016-08-03 12:43:36 -0700459}
460
461void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
462 this->write(to_string(f.fValue));
463}
464
465void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
466 this->writeType(f.fDeclaration.fReturnType);
467 this->write(" " + f.fDeclaration.fName + "(");
468 const char* separator = "";
469 for (const auto& param : f.fDeclaration.fParameters) {
470 this->write(separator);
471 separator = ", ";
ethannicholas5961bc92016-10-12 06:39:56 -0700472 this->writeModifiers(param->fModifiers, false);
473 std::vector<int> sizes;
474 const Type* type = &param->fType;
475 while (type->kind() == Type::kArray_Kind) {
476 sizes.push_back(type->columns());
477 type = &type->componentType();
478 }
479 this->writeType(*type);
ethannicholasf789b382016-08-03 12:43:36 -0700480 this->write(" " + param->fName);
ethannicholas5961bc92016-10-12 06:39:56 -0700481 for (int s : sizes) {
482 if (s <= 0) {
483 this->write("[]");
484 } else {
485 this->write("[" + to_string(s) + "]");
486 }
487 }
ethannicholasf789b382016-08-03 12:43:36 -0700488 }
ethannicholas5961bc92016-10-12 06:39:56 -0700489 this->writeLine(") {");
490
491 fFunctionHeader = "";
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500492 SkWStream* oldOut = fOut;
493 SkDynamicMemoryWStream buffer;
ethannicholas5961bc92016-10-12 06:39:56 -0700494 fOut = &buffer;
495 fIndentation++;
496 for (const auto& s : f.fBody->fStatements) {
497 this->writeStatement(*s);
498 this->writeLine();
499 }
500 fIndentation--;
501 this->writeLine("}");
502
503 fOut = oldOut;
504 this->write(fFunctionHeader);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500505 sk_sp<SkData> data(buffer.detachAsData());
506 this->write(SkString((const char*) data->data(), data->size()));
ethannicholasf789b382016-08-03 12:43:36 -0700507}
508
Greg Daniel64773e62016-11-22 09:44:03 -0500509void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
ethannicholas5961bc92016-10-12 06:39:56 -0700510 bool globalContext) {
Brian Salomonf9f45122016-11-29 11:59:17 -0500511 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
512 this->write("flat ");
513 }
ethannicholas5961bc92016-10-12 06:39:56 -0700514 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
515 this->write("noperspective ");
516 }
Brian Salomonf9f45122016-11-29 11:59:17 -0500517 if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
518 this->write("readonly ");
519 }
520 if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
521 this->write("writeonly ");
522 }
523 if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
524 this->write("coherent ");
525 }
526 if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
527 this->write("volatile ");
528 }
529 if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
530 this->write("restrict ");
ethannicholas5961bc92016-10-12 06:39:56 -0700531 }
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500532 SkString layout = modifiers.fLayout.description();
533 if (layout.size()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700534 this->write(layout + " ");
535 }
Greg Daniel64773e62016-11-22 09:44:03 -0500536 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
ethannicholas5961bc92016-10-12 06:39:56 -0700537 (modifiers.fFlags & Modifiers::kOut_Flag)) {
538 this->write("inout ");
539 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500540 if (globalContext &&
541 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -0700542 this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
543 : "varying ");
544 } else {
545 this->write("in ");
546 }
547 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500548 if (globalContext &&
549 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -0700550 this->write("varying ");
551 } else {
552 this->write("out ");
553 }
554 }
555 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
556 this->write("uniform ");
557 }
558 if (modifiers.fFlags & Modifiers::kConst_Flag) {
559 this->write("const ");
560 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500561 if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700562 if (modifiers.fFlags & Modifiers::kLowp_Flag) {
563 this->write("lowp ");
564 }
565 if (modifiers.fFlags & Modifiers::kMediump_Flag) {
566 this->write("mediump ");
567 }
568 if (modifiers.fFlags & Modifiers::kHighp_Flag) {
569 this->write("highp ");
570 }
571 }
ethannicholasf789b382016-08-03 12:43:36 -0700572}
573
574void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
575 if (intf.fVariable.fName == "gl_PerVertex") {
576 return;
577 }
ethannicholas5961bc92016-10-12 06:39:56 -0700578 this->writeModifiers(intf.fVariable.fModifiers, true);
ethannicholasf789b382016-08-03 12:43:36 -0700579 this->writeLine(intf.fVariable.fType.name() + " {");
580 fIndentation++;
581 for (const auto& f : intf.fVariable.fType.fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700582 this->writeModifiers(f.fModifiers, false);
ethannicholas0730be72016-09-01 07:59:02 -0700583 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -0700584 this->writeLine(" " + f.fName + ";");
585 }
586 fIndentation--;
587 this->writeLine("};");
588}
589
ethannicholas5961bc92016-10-12 06:39:56 -0700590void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
ethannicholasf789b382016-08-03 12:43:36 -0700591 ASSERT(decl.fVars.size() > 0);
ethannicholas5961bc92016-10-12 06:39:56 -0700592 this->writeModifiers(decl.fVars[0].fVar->fModifiers, global);
ethannicholasf789b382016-08-03 12:43:36 -0700593 this->writeType(decl.fBaseType);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500594 SkString separator(" ");
ethannicholas14fe8cc2016-09-07 13:37:16 -0700595 for (const auto& var : decl.fVars) {
596 ASSERT(var.fVar->fModifiers == decl.fVars[0].fVar->fModifiers);
ethannicholasf789b382016-08-03 12:43:36 -0700597 this->write(separator);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500598 separator = SkString(", ");
ethannicholas14fe8cc2016-09-07 13:37:16 -0700599 this->write(var.fVar->fName);
600 for (const auto& size : var.fSizes) {
ethannicholasf789b382016-08-03 12:43:36 -0700601 this->write("[");
ethannicholas5961bc92016-10-12 06:39:56 -0700602 if (size) {
603 this->writeExpression(*size, kTopLevel_Precedence);
604 }
ethannicholasf789b382016-08-03 12:43:36 -0700605 this->write("]");
606 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700607 if (var.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -0700608 this->write(" = ");
ethannicholas14fe8cc2016-09-07 13:37:16 -0700609 this->writeExpression(*var.fValue, kTopLevel_Precedence);
ethannicholasf789b382016-08-03 12:43:36 -0700610 }
Brian Salomon2a51de82016-11-16 12:06:01 -0500611 if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500612 if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500613 fHeader.writeText("#extension ");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500614 fHeader.writeText(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500615 fHeader.writeText(" : require\n");
Brian Salomon2a51de82016-11-16 12:06:01 -0500616 }
617 fFoundImageDecl = true;
618 }
ethannicholasf789b382016-08-03 12:43:36 -0700619 }
620 this->write(";");
621}
622
623void GLSLCodeGenerator::writeStatement(const Statement& s) {
624 switch (s.fKind) {
625 case Statement::kBlock_Kind:
626 this->writeBlock((Block&) s);
627 break;
628 case Statement::kExpression_Kind:
629 this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
630 this->write(";");
631 break;
632 case Statement::kReturn_Kind:
633 this->writeReturnStatement((ReturnStatement&) s);
634 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -0700635 case Statement::kVarDeclarations_Kind:
ethannicholas5961bc92016-10-12 06:39:56 -0700636 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
ethannicholasf789b382016-08-03 12:43:36 -0700637 break;
638 case Statement::kIf_Kind:
639 this->writeIfStatement((IfStatement&) s);
640 break;
641 case Statement::kFor_Kind:
642 this->writeForStatement((ForStatement&) s);
643 break;
644 case Statement::kWhile_Kind:
645 this->writeWhileStatement((WhileStatement&) s);
646 break;
647 case Statement::kDo_Kind:
648 this->writeDoStatement((DoStatement&) s);
649 break;
650 case Statement::kBreak_Kind:
651 this->write("break;");
652 break;
653 case Statement::kContinue_Kind:
654 this->write("continue;");
655 break;
656 case Statement::kDiscard_Kind:
657 this->write("discard;");
658 break;
659 default:
660 ABORT("unsupported statement: %s", s.description().c_str());
661 }
662}
663
664void GLSLCodeGenerator::writeBlock(const Block& b) {
665 this->writeLine("{");
666 fIndentation++;
667 for (const auto& s : b.fStatements) {
668 this->writeStatement(*s);
669 this->writeLine();
670 }
671 fIndentation--;
672 this->write("}");
673}
674
675void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
676 this->write("if (");
677 this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
678 this->write(") ");
679 this->writeStatement(*stmt.fIfTrue);
680 if (stmt.fIfFalse) {
681 this->write(" else ");
682 this->writeStatement(*stmt.fIfFalse);
683 }
684}
685
686void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
687 this->write("for (");
688 if (f.fInitializer) {
689 this->writeStatement(*f.fInitializer);
690 } else {
691 this->write("; ");
692 }
693 if (f.fTest) {
694 this->writeExpression(*f.fTest, kTopLevel_Precedence);
695 }
696 this->write("; ");
697 if (f.fNext) {
698 this->writeExpression(*f.fNext, kTopLevel_Precedence);
699 }
700 this->write(") ");
701 this->writeStatement(*f.fStatement);
702}
703
704void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
705 this->write("while (");
706 this->writeExpression(*w.fTest, kTopLevel_Precedence);
707 this->write(") ");
708 this->writeStatement(*w.fStatement);
709}
710
711void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
712 this->write("do ");
713 this->writeStatement(*d.fStatement);
714 this->write(" while (");
715 this->writeExpression(*d.fTest, kTopLevel_Precedence);
716 this->write(");");
717}
718
719void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
720 this->write("return");
721 if (r.fExpression) {
722 this->write(" ");
723 this->writeExpression(*r.fExpression, kTopLevel_Precedence);
724 }
725 this->write(";");
726}
727
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500728bool GLSLCodeGenerator::generateCode() {
729 SkWStream* rawOut = fOut;
ethannicholasddb37d62016-10-20 09:54:00 -0700730 fOut = &fHeader;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500731 fProgramKind = fProgram.fKind;
732 this->write(fProgram.fSettings.fCaps->versionDeclString());
ethannicholasf789b382016-08-03 12:43:36 -0700733 this->writeLine();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500734 for (const auto& e : fProgram.fElements) {
ethannicholas5961bc92016-10-12 06:39:56 -0700735 if (e->fKind == ProgramElement::kExtension_Kind) {
736 this->writeExtension((Extension&) *e);
737 }
738 }
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500739 SkDynamicMemoryWStream body;
ethannicholasddb37d62016-10-20 09:54:00 -0700740 fOut = &body;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500741 if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700742 this->write("precision ");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500743 switch (fProgram.fDefaultPrecision) {
ethannicholas5961bc92016-10-12 06:39:56 -0700744 case Modifiers::kLowp_Flag:
745 this->write("lowp");
746 break;
747 case Modifiers::kMediump_Flag:
748 this->write("mediump");
749 break;
750 case Modifiers::kHighp_Flag:
751 this->write("highp");
752 break;
753 default:
754 ASSERT(false);
755 this->write("<error>");
756 }
757 this->writeLine(" float;");
758 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500759 for (const auto& e : fProgram.fElements) {
ethannicholasf789b382016-08-03 12:43:36 -0700760 switch (e->fKind) {
761 case ProgramElement::kExtension_Kind:
ethannicholasf789b382016-08-03 12:43:36 -0700762 break;
763 case ProgramElement::kVar_Kind: {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700764 VarDeclarations& decl = (VarDeclarations&) *e;
ethannicholas5961bc92016-10-12 06:39:56 -0700765 if (decl.fVars.size() > 0) {
766 int builtin = decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin;
767 if (builtin == -1) {
768 // normal var
769 this->writeVarDeclarations(decl, true);
770 this->writeLine();
771 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500772 fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700773 this->write("out ");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500774 if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700775 this->write("mediump ");
776 }
777 this->writeLine("vec4 sk_FragColor;");
778 }
ethannicholasf789b382016-08-03 12:43:36 -0700779 }
780 break;
781 }
782 case ProgramElement::kInterfaceBlock_Kind:
783 this->writeInterfaceBlock((InterfaceBlock&) *e);
784 break;
785 case ProgramElement::kFunction_Kind:
786 this->writeFunction((FunctionDefinition&) *e);
787 break;
ethannicholas5961bc92016-10-12 06:39:56 -0700788 case ProgramElement::kModifiers_Kind:
789 this->writeModifiers(((ModifiersDeclaration&) *e).fModifiers, true);
790 this->writeLine(";");
791 break;
ethannicholasf789b382016-08-03 12:43:36 -0700792 default:
793 printf("%s\n", e->description().c_str());
794 ABORT("unsupported program element");
795 }
796 }
797 fOut = nullptr;
ethannicholasddb37d62016-10-20 09:54:00 -0700798
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500799 write_data(*fHeader.detachAsData(), *rawOut);
800 write_data(*body.detachAsData(), *rawOut);
801 return true;
ethannicholasf789b382016-08-03 12:43:36 -0700802}
803
804}