blob: 6a82cf2477fc583e351d92d1c07608ef17fedd34 [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 */
7
8#include "SkSLGLSLCodeGenerator.h"
9
10#include "string.h"
11
12#include "GLSL.std.450.h"
13
14#include "ir/SkSLExpressionStatement.h"
15#include "ir/SkSLExtension.h"
16#include "ir/SkSLIndexExpression.h"
ethannicholasb12b3c62016-09-26 11:58:52 -070017#include "ir/SkSLModifiersDeclaration.h"
ethannicholasf789b382016-08-03 12:43:36 -070018#include "ir/SkSLVariableReference.h"
19
ethannicholasb12b3c62016-09-26 11:58:52 -070020#define SK_FRAGCOLOR_BUILTIN 10001
21
ethannicholasf789b382016-08-03 12:43:36 -070022namespace SkSL {
23
24void GLSLCodeGenerator::write(const char* s) {
25 if (s[0] == 0) {
26 return;
27 }
28 if (fAtLineStart) {
29 for (int i = 0; i < fIndentation; i++) {
30 *fOut << " ";
31 }
32 }
33 *fOut << s;
34 fAtLineStart = false;
35}
36
37void GLSLCodeGenerator::writeLine(const char* s) {
38 this->write(s);
39 *fOut << "\n";
40 fAtLineStart = true;
41}
42
43void GLSLCodeGenerator::write(const std::string& s) {
44 this->write(s.c_str());
45}
46
47void GLSLCodeGenerator::writeLine(const std::string& s) {
48 this->writeLine(s.c_str());
49}
50
51void GLSLCodeGenerator::writeLine() {
52 this->writeLine("");
53}
54
55void GLSLCodeGenerator::writeExtension(const Extension& ext) {
56 this->writeLine("#extension " + ext.fName + " : enable");
57}
58
59void GLSLCodeGenerator::writeType(const Type& type) {
60 if (type.kind() == Type::kStruct_Kind) {
61 for (const Type* search : fWrittenStructs) {
62 if (*search == type) {
63 // already written
64 this->write(type.name());
65 return;
66 }
67 }
68 fWrittenStructs.push_back(&type);
69 this->writeLine("struct " + type.name() + " {");
70 fIndentation++;
71 for (const auto& f : type.fields()) {
ethannicholasb12b3c62016-09-26 11:58:52 -070072 this->writeModifiers(f.fModifiers, false);
ethannicholasf789b382016-08-03 12:43:36 -070073 // sizes (which must be static in structs) are part of the type name here
ethannicholas0730be72016-09-01 07:59:02 -070074 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -070075 this->writeLine(" " + f.fName + ";");
76 }
77 fIndentation--;
78 this->writeLine("}");
79 } else {
80 this->write(type.name());
81 }
82}
83
84void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
85 switch (expr.fKind) {
86 case Expression::kBinary_Kind:
87 this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
88 break;
89 case Expression::kBoolLiteral_Kind:
90 this->writeBoolLiteral((BoolLiteral&) expr);
91 break;
92 case Expression::kConstructor_Kind:
93 this->writeConstructor((Constructor&) expr);
94 break;
95 case Expression::kIntLiteral_Kind:
96 this->writeIntLiteral((IntLiteral&) expr);
97 break;
98 case Expression::kFieldAccess_Kind:
99 this->writeFieldAccess(((FieldAccess&) expr));
100 break;
101 case Expression::kFloatLiteral_Kind:
102 this->writeFloatLiteral(((FloatLiteral&) expr));
103 break;
104 case Expression::kFunctionCall_Kind:
105 this->writeFunctionCall((FunctionCall&) expr);
106 break;
107 case Expression::kPrefix_Kind:
108 this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
109 break;
110 case Expression::kPostfix_Kind:
111 this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
112 break;
113 case Expression::kSwizzle_Kind:
114 this->writeSwizzle((Swizzle&) expr);
115 break;
116 case Expression::kVariableReference_Kind:
117 this->writeVariableReference((VariableReference&) expr);
118 break;
119 case Expression::kTernary_Kind:
120 this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
121 break;
122 case Expression::kIndex_Kind:
123 this->writeIndexExpression((IndexExpression&) expr);
124 break;
125 default:
126 ABORT("unsupported expression: %s", expr.description().c_str());
127 }
128}
129
ethannicholasb12b3c62016-09-26 11:58:52 -0700130static bool is_abs(Expression& expr) {
131 if (expr.fKind != Expression::kFunctionCall_Kind) {
132 return false;
133 }
134 return ((FunctionCall&) expr).fFunction.fName == "abs";
135}
136
137// turns min(abs(x), y) into (abs(x) > (tmpVar = y) ? tmpVar : abs(x)) to avoid a Tegra3 compiler
138// bug.
139void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
140 ASSERT(!fCaps.fCanUseMinAndAbsTogether);
141 std::string varName = "minAbsHackVar" + to_string(fVarCount++);
142 this->fFunctionHeader += " " + otherExpr.fType.name() + " " + varName + ";\n";
143 this->write("(");
144 this->writeExpression(absExpr, kTopLevel_Precedence);
145 this->write(" > (" + varName + " = ");
146 this->writeExpression(otherExpr, kRelational_Precedence);
147 this->write(") ? " + varName + " : ");
148 this->writeExpression(absExpr, kTernary_Precedence);
149 this->write(")");
150}
151
ethannicholasf789b382016-08-03 12:43:36 -0700152void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
ethannicholasb12b3c62016-09-26 11:58:52 -0700153 if (!fCaps.fCanUseMinAndAbsTogether && c.fFunction.fName == "min") {
154 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 this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
161 return;
162 }
163 }
ethannicholasf789b382016-08-03 12:43:36 -0700164 this->write(c.fFunction.fName + "(");
165 const char* separator = "";
166 for (const auto& arg : c.fArguments) {
167 this->write(separator);
168 separator = ", ";
169 this->writeExpression(*arg, kSequence_Precedence);
170 }
171 this->write(")");
172}
173
174void GLSLCodeGenerator::writeConstructor(const Constructor& c) {
175 this->write(c.fType.name() + "(");
176 const char* separator = "";
177 for (const auto& arg : c.fArguments) {
178 this->write(separator);
179 separator = ", ";
180 this->writeExpression(*arg, kSequence_Precedence);
181 }
182 this->write(")");
183}
184
185void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
ethannicholasb12b3c62016-09-26 11:58:52 -0700186 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN) {
187 if (fCaps.fMustDeclareFragmentShaderOutput) {
188 this->write("sk_FragColor");
189 } else {
190 this->write("gl_FragColor");
191 }
192 } else {
193 this->write(ref.fVariable.fName);
194 }
ethannicholasf789b382016-08-03 12:43:36 -0700195}
196
197void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
198 this->writeExpression(*expr.fBase, kPostfix_Precedence);
199 this->write("[");
200 this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
201 this->write("]");
202}
203
204void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
205 if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
206 this->writeExpression(*f.fBase, kPostfix_Precedence);
207 this->write(".");
208 }
209 this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
210}
211
212void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
213 this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
214 this->write(".");
215 for (int c : swizzle.fComponents) {
216 this->write(&("x\0y\0z\0w\0"[c * 2]));
217 }
218}
219
220static GLSLCodeGenerator::Precedence get_binary_precedence(Token::Kind op) {
221 switch (op) {
222 case Token::STAR: // fall through
223 case Token::SLASH: // fall through
224 case Token::PERCENT: return GLSLCodeGenerator::kMultiplicative_Precedence;
225 case Token::PLUS: // fall through
226 case Token::MINUS: return GLSLCodeGenerator::kAdditive_Precedence;
227 case Token::SHL: // fall through
228 case Token::SHR: return GLSLCodeGenerator::kShift_Precedence;
229 case Token::LT: // fall through
230 case Token::GT: // fall through
231 case Token::LTEQ: // fall through
232 case Token::GTEQ: return GLSLCodeGenerator::kRelational_Precedence;
233 case Token::EQEQ: // fall through
234 case Token::NEQ: return GLSLCodeGenerator::kEquality_Precedence;
235 case Token::BITWISEAND: return GLSLCodeGenerator::kBitwiseAnd_Precedence;
236 case Token::BITWISEXOR: return GLSLCodeGenerator::kBitwiseXor_Precedence;
237 case Token::BITWISEOR: return GLSLCodeGenerator::kBitwiseOr_Precedence;
238 case Token::LOGICALAND: return GLSLCodeGenerator::kLogicalAnd_Precedence;
239 case Token::LOGICALXOR: return GLSLCodeGenerator::kLogicalXor_Precedence;
240 case Token::LOGICALOR: return GLSLCodeGenerator::kLogicalOr_Precedence;
241 case Token::EQ: // fall through
242 case Token::PLUSEQ: // fall through
243 case Token::MINUSEQ: // fall through
244 case Token::STAREQ: // fall through
245 case Token::SLASHEQ: // fall through
246 case Token::PERCENTEQ: // fall through
247 case Token::SHLEQ: // fall through
248 case Token::SHREQ: // fall through
249 case Token::LOGICALANDEQ: // fall through
250 case Token::LOGICALXOREQ: // fall through
251 case Token::LOGICALOREQ: // fall through
252 case Token::BITWISEANDEQ: // fall through
253 case Token::BITWISEXOREQ: // fall through
254 case Token::BITWISEOREQ: return GLSLCodeGenerator::kAssignment_Precedence;
255 default: ABORT("unsupported binary operator");
256 }
257}
258
259void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
260 Precedence parentPrecedence) {
261 Precedence precedence = get_binary_precedence(b.fOperator);
262 if (precedence >= parentPrecedence) {
263 this->write("(");
264 }
265 this->writeExpression(*b.fLeft, precedence);
266 this->write(" " + Token::OperatorName(b.fOperator) + " ");
267 this->writeExpression(*b.fRight, precedence);
268 if (precedence >= parentPrecedence) {
269 this->write(")");
270 }
271}
272
273void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
274 Precedence parentPrecedence) {
275 if (kTernary_Precedence >= parentPrecedence) {
276 this->write("(");
277 }
278 this->writeExpression(*t.fTest, kTernary_Precedence);
279 this->write(" ? ");
280 this->writeExpression(*t.fIfTrue, kTernary_Precedence);
281 this->write(" : ");
282 this->writeExpression(*t.fIfFalse, kTernary_Precedence);
283 if (kTernary_Precedence >= parentPrecedence) {
284 this->write(")");
285 }
286}
287
288void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
289 Precedence parentPrecedence) {
290 if (kPrefix_Precedence >= parentPrecedence) {
291 this->write("(");
292 }
293 this->write(Token::OperatorName(p.fOperator));
294 this->writeExpression(*p.fOperand, kPrefix_Precedence);
295 if (kPrefix_Precedence >= parentPrecedence) {
296 this->write(")");
297 }
298}
299
300void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
301 Precedence parentPrecedence) {
302 if (kPostfix_Precedence >= parentPrecedence) {
303 this->write("(");
304 }
305 this->writeExpression(*p.fOperand, kPostfix_Precedence);
306 this->write(Token::OperatorName(p.fOperator));
307 if (kPostfix_Precedence >= parentPrecedence) {
308 this->write(")");
309 }
310}
311
312void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
313 this->write(b.fValue ? "true" : "false");
314}
315
316void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholasb12b3c62016-09-26 11:58:52 -0700317 if (i.fType == *fContext.fUInt_Type) {
318 this->write(to_string(i.fValue & 0xffffffff) + "u");
319 } else {
320 this->write(to_string(i.fValue));
321 }
ethannicholasf789b382016-08-03 12:43:36 -0700322}
323
324void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
325 this->write(to_string(f.fValue));
326}
327
328void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
329 this->writeType(f.fDeclaration.fReturnType);
330 this->write(" " + f.fDeclaration.fName + "(");
331 const char* separator = "";
332 for (const auto& param : f.fDeclaration.fParameters) {
333 this->write(separator);
334 separator = ", ";
ethannicholasb12b3c62016-09-26 11:58:52 -0700335 this->writeModifiers(param->fModifiers, false);
336 std::vector<int> sizes;
337 const Type* type = &param->fType;
338 while (type->kind() == Type::kArray_Kind) {
339 sizes.push_back(type->columns());
340 type = &type->componentType();
341 }
342 this->writeType(*type);
ethannicholasf789b382016-08-03 12:43:36 -0700343 this->write(" " + param->fName);
ethannicholasb12b3c62016-09-26 11:58:52 -0700344 for (int s : sizes) {
345 if (s <= 0) {
346 this->write("[]");
347 } else {
348 this->write("[" + to_string(s) + "]");
349 }
350 }
ethannicholasf789b382016-08-03 12:43:36 -0700351 }
ethannicholasb12b3c62016-09-26 11:58:52 -0700352 this->writeLine(") {");
353
354 fFunctionHeader = "";
355 std::ostream* oldOut = fOut;
356 std::stringstream buffer;
357 fOut = &buffer;
358 fIndentation++;
359 for (const auto& s : f.fBody->fStatements) {
360 this->writeStatement(*s);
361 this->writeLine();
362 }
363 fIndentation--;
364 this->writeLine("}");
365
366 fOut = oldOut;
367 this->write(fFunctionHeader);
368 this->write(buffer.str());
ethannicholasf789b382016-08-03 12:43:36 -0700369}
370
ethannicholasb12b3c62016-09-26 11:58:52 -0700371void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
372 bool globalContext) {
373 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
374 this->write("noperspective ");
375 }
376 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
377 this->write("flat ");
378 }
379 std::string layout = modifiers.fLayout.description();
380 if (layout.length()) {
381 this->write(layout + " ");
382 }
383 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
384 (modifiers.fFlags & Modifiers::kOut_Flag)) {
385 this->write("inout ");
386 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
387 if (globalContext && fCaps.fVersion < 130) {
388 this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
389 : "varying ");
390 } else {
391 this->write("in ");
392 }
393 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
394 if (globalContext && fCaps.fVersion < 130) {
395 this->write("varying ");
396 } else {
397 this->write("out ");
398 }
399 }
400 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
401 this->write("uniform ");
402 }
403 if (modifiers.fFlags & Modifiers::kConst_Flag) {
404 this->write("const ");
405 }
406 if (fCaps.fUsesPrecisionModifiers) {
407 if (modifiers.fFlags & Modifiers::kLowp_Flag) {
408 this->write("lowp ");
409 }
410 if (modifiers.fFlags & Modifiers::kHighp_Flag) {
411 this->write("highp ");
412 }
413 }
ethannicholasf789b382016-08-03 12:43:36 -0700414}
415
416void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
417 if (intf.fVariable.fName == "gl_PerVertex") {
418 return;
419 }
ethannicholasb12b3c62016-09-26 11:58:52 -0700420 this->writeModifiers(intf.fVariable.fModifiers, true);
ethannicholasf789b382016-08-03 12:43:36 -0700421 this->writeLine(intf.fVariable.fType.name() + " {");
422 fIndentation++;
423 for (const auto& f : intf.fVariable.fType.fields()) {
ethannicholasb12b3c62016-09-26 11:58:52 -0700424 this->writeModifiers(f.fModifiers, false);
ethannicholas0730be72016-09-01 07:59:02 -0700425 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -0700426 this->writeLine(" " + f.fName + ";");
427 }
428 fIndentation--;
429 this->writeLine("};");
430}
431
ethannicholasb12b3c62016-09-26 11:58:52 -0700432void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
ethannicholasf789b382016-08-03 12:43:36 -0700433 ASSERT(decl.fVars.size() > 0);
ethannicholasb12b3c62016-09-26 11:58:52 -0700434 this->writeModifiers(decl.fVars[0].fVar->fModifiers, global);
ethannicholasf789b382016-08-03 12:43:36 -0700435 this->writeType(decl.fBaseType);
436 std::string separator = " ";
ethannicholas14fe8cc2016-09-07 13:37:16 -0700437 for (const auto& var : decl.fVars) {
438 ASSERT(var.fVar->fModifiers == decl.fVars[0].fVar->fModifiers);
ethannicholasf789b382016-08-03 12:43:36 -0700439 this->write(separator);
440 separator = ", ";
ethannicholas14fe8cc2016-09-07 13:37:16 -0700441 this->write(var.fVar->fName);
442 for (const auto& size : var.fSizes) {
ethannicholasf789b382016-08-03 12:43:36 -0700443 this->write("[");
ethannicholasb12b3c62016-09-26 11:58:52 -0700444 if (size) {
445 this->writeExpression(*size, kTopLevel_Precedence);
446 }
ethannicholasf789b382016-08-03 12:43:36 -0700447 this->write("]");
448 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700449 if (var.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -0700450 this->write(" = ");
ethannicholas14fe8cc2016-09-07 13:37:16 -0700451 this->writeExpression(*var.fValue, kTopLevel_Precedence);
ethannicholasf789b382016-08-03 12:43:36 -0700452 }
453 }
454 this->write(";");
455}
456
457void GLSLCodeGenerator::writeStatement(const Statement& s) {
458 switch (s.fKind) {
459 case Statement::kBlock_Kind:
460 this->writeBlock((Block&) s);
461 break;
462 case Statement::kExpression_Kind:
463 this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
464 this->write(";");
465 break;
466 case Statement::kReturn_Kind:
467 this->writeReturnStatement((ReturnStatement&) s);
468 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -0700469 case Statement::kVarDeclarations_Kind:
ethannicholasb12b3c62016-09-26 11:58:52 -0700470 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
ethannicholasf789b382016-08-03 12:43:36 -0700471 break;
472 case Statement::kIf_Kind:
473 this->writeIfStatement((IfStatement&) s);
474 break;
475 case Statement::kFor_Kind:
476 this->writeForStatement((ForStatement&) s);
477 break;
478 case Statement::kWhile_Kind:
479 this->writeWhileStatement((WhileStatement&) s);
480 break;
481 case Statement::kDo_Kind:
482 this->writeDoStatement((DoStatement&) s);
483 break;
484 case Statement::kBreak_Kind:
485 this->write("break;");
486 break;
487 case Statement::kContinue_Kind:
488 this->write("continue;");
489 break;
490 case Statement::kDiscard_Kind:
491 this->write("discard;");
492 break;
493 default:
494 ABORT("unsupported statement: %s", s.description().c_str());
495 }
496}
497
498void GLSLCodeGenerator::writeBlock(const Block& b) {
499 this->writeLine("{");
500 fIndentation++;
501 for (const auto& s : b.fStatements) {
502 this->writeStatement(*s);
503 this->writeLine();
504 }
505 fIndentation--;
506 this->write("}");
507}
508
509void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
510 this->write("if (");
511 this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
512 this->write(") ");
513 this->writeStatement(*stmt.fIfTrue);
514 if (stmt.fIfFalse) {
515 this->write(" else ");
516 this->writeStatement(*stmt.fIfFalse);
517 }
518}
519
520void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
521 this->write("for (");
522 if (f.fInitializer) {
523 this->writeStatement(*f.fInitializer);
524 } else {
525 this->write("; ");
526 }
527 if (f.fTest) {
528 this->writeExpression(*f.fTest, kTopLevel_Precedence);
529 }
530 this->write("; ");
531 if (f.fNext) {
532 this->writeExpression(*f.fNext, kTopLevel_Precedence);
533 }
534 this->write(") ");
535 this->writeStatement(*f.fStatement);
536}
537
538void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
539 this->write("while (");
540 this->writeExpression(*w.fTest, kTopLevel_Precedence);
541 this->write(") ");
542 this->writeStatement(*w.fStatement);
543}
544
545void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
546 this->write("do ");
547 this->writeStatement(*d.fStatement);
548 this->write(" while (");
549 this->writeExpression(*d.fTest, kTopLevel_Precedence);
550 this->write(");");
551}
552
553void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
554 this->write("return");
555 if (r.fExpression) {
556 this->write(" ");
557 this->writeExpression(*r.fExpression, kTopLevel_Precedence);
558 }
559 this->write(";");
560}
561
562void GLSLCodeGenerator::generateCode(const Program& program, std::ostream& out) {
563 ASSERT(fOut == nullptr);
564 fOut = &out;
ethannicholasb12b3c62016-09-26 11:58:52 -0700565 fProgramKind = program.fKind;
ethannicholasf789b382016-08-03 12:43:36 -0700566 this->write("#version " + to_string(fCaps.fVersion));
ethannicholasb12b3c62016-09-26 11:58:52 -0700567 if (fCaps.fStandard == GLCaps::kGLES_Standard && fCaps.fVersion >= 300) {
ethannicholasf789b382016-08-03 12:43:36 -0700568 this->write(" es");
ethannicholasb12b3c62016-09-26 11:58:52 -0700569 } else if (fCaps.fIsCoreProfile) {
570 this->write(" core");
ethannicholasf789b382016-08-03 12:43:36 -0700571 }
572 this->writeLine();
573 for (const auto& e : program.fElements) {
ethannicholasb12b3c62016-09-26 11:58:52 -0700574 if (e->fKind == ProgramElement::kExtension_Kind) {
575 this->writeExtension((Extension&) *e);
576 }
577 }
578 if (fCaps.fStandard == GLCaps::kGLES_Standard) {
579 this->writeLine("precision mediump float;");
580 }
581 for (const auto& e : program.fElements) {
ethannicholasf789b382016-08-03 12:43:36 -0700582 switch (e->fKind) {
583 case ProgramElement::kExtension_Kind:
ethannicholasf789b382016-08-03 12:43:36 -0700584 break;
585 case ProgramElement::kVar_Kind: {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700586 VarDeclarations& decl = (VarDeclarations&) *e;
ethannicholasb12b3c62016-09-26 11:58:52 -0700587 if (decl.fVars.size() > 0) {
588 int builtin = decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin;
589 if (builtin == -1) {
590 // normal var
591 this->writeVarDeclarations(decl, true);
592 this->writeLine();
593 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
594 fCaps.fMustDeclareFragmentShaderOutput) {
595 this->write("out ");
596 if (fCaps.fUsesPrecisionModifiers) {
597 this->write("mediump ");
598 }
599 this->writeLine("vec4 sk_FragColor;");
600 }
ethannicholasf789b382016-08-03 12:43:36 -0700601 }
602 break;
603 }
604 case ProgramElement::kInterfaceBlock_Kind:
605 this->writeInterfaceBlock((InterfaceBlock&) *e);
606 break;
607 case ProgramElement::kFunction_Kind:
608 this->writeFunction((FunctionDefinition&) *e);
609 break;
ethannicholasb12b3c62016-09-26 11:58:52 -0700610 case ProgramElement::kModifiers_Kind:
611 this->writeModifiers(((ModifiersDeclaration&) *e).fModifiers, true);
612 this->writeLine(";");
613 break;
ethannicholasf789b382016-08-03 12:43:36 -0700614 default:
615 printf("%s\n", e->description().c_str());
616 ABORT("unsupported program element");
617 }
618 }
619 fOut = nullptr;
620}
621
622}