blob: 96b997f6bbfcbd12299250493e7f1f900c14ed67 [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"
ethannicholasf008b0a2016-09-30 06:23:24 -070017#include "ir/SkSLModifiersDeclaration.h"
ethannicholasf789b382016-08-03 12:43:36 -070018#include "ir/SkSLVariableReference.h"
19
ethannicholasf008b0a2016-09-30 06:23:24 -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()) {
ethannicholasf008b0a2016-09-30 06:23:24 -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
ethannicholasf008b0a2016-09-30 06:23:24 -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) {
ethannicholasf008b0a2016-09-30 06:23:24 -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) {
ethannicholasf008b0a2016-09-30 06:23:24 -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) {
ethannicholasf008b0a2016-09-30 06:23:24 -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 = ", ";
ethannicholasf008b0a2016-09-30 06:23:24 -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);
ethannicholasf008b0a2016-09-30 06:23:24 -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 }
ethannicholasf008b0a2016-09-30 06:23:24 -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
ethannicholasf008b0a2016-09-30 06:23:24 -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::kMediump_Flag) {
411 this->write("mediump ");
412 }
413 if (modifiers.fFlags & Modifiers::kHighp_Flag) {
414 this->write("highp ");
415 }
416 }
ethannicholasf789b382016-08-03 12:43:36 -0700417}
418
419void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
420 if (intf.fVariable.fName == "gl_PerVertex") {
421 return;
422 }
ethannicholasf008b0a2016-09-30 06:23:24 -0700423 this->writeModifiers(intf.fVariable.fModifiers, true);
ethannicholasf789b382016-08-03 12:43:36 -0700424 this->writeLine(intf.fVariable.fType.name() + " {");
425 fIndentation++;
426 for (const auto& f : intf.fVariable.fType.fields()) {
ethannicholasf008b0a2016-09-30 06:23:24 -0700427 this->writeModifiers(f.fModifiers, false);
ethannicholas0730be72016-09-01 07:59:02 -0700428 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -0700429 this->writeLine(" " + f.fName + ";");
430 }
431 fIndentation--;
432 this->writeLine("};");
433}
434
ethannicholasf008b0a2016-09-30 06:23:24 -0700435void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
ethannicholasf789b382016-08-03 12:43:36 -0700436 ASSERT(decl.fVars.size() > 0);
ethannicholasf008b0a2016-09-30 06:23:24 -0700437 this->writeModifiers(decl.fVars[0].fVar->fModifiers, global);
ethannicholasf789b382016-08-03 12:43:36 -0700438 this->writeType(decl.fBaseType);
439 std::string separator = " ";
ethannicholas14fe8cc2016-09-07 13:37:16 -0700440 for (const auto& var : decl.fVars) {
441 ASSERT(var.fVar->fModifiers == decl.fVars[0].fVar->fModifiers);
ethannicholasf789b382016-08-03 12:43:36 -0700442 this->write(separator);
443 separator = ", ";
ethannicholas14fe8cc2016-09-07 13:37:16 -0700444 this->write(var.fVar->fName);
445 for (const auto& size : var.fSizes) {
ethannicholasf789b382016-08-03 12:43:36 -0700446 this->write("[");
ethannicholasf008b0a2016-09-30 06:23:24 -0700447 if (size) {
448 this->writeExpression(*size, kTopLevel_Precedence);
449 }
ethannicholasf789b382016-08-03 12:43:36 -0700450 this->write("]");
451 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700452 if (var.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -0700453 this->write(" = ");
ethannicholas14fe8cc2016-09-07 13:37:16 -0700454 this->writeExpression(*var.fValue, kTopLevel_Precedence);
ethannicholasf789b382016-08-03 12:43:36 -0700455 }
456 }
457 this->write(";");
458}
459
460void GLSLCodeGenerator::writeStatement(const Statement& s) {
461 switch (s.fKind) {
462 case Statement::kBlock_Kind:
463 this->writeBlock((Block&) s);
464 break;
465 case Statement::kExpression_Kind:
466 this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
467 this->write(";");
468 break;
469 case Statement::kReturn_Kind:
470 this->writeReturnStatement((ReturnStatement&) s);
471 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -0700472 case Statement::kVarDeclarations_Kind:
ethannicholasf008b0a2016-09-30 06:23:24 -0700473 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
ethannicholasf789b382016-08-03 12:43:36 -0700474 break;
475 case Statement::kIf_Kind:
476 this->writeIfStatement((IfStatement&) s);
477 break;
478 case Statement::kFor_Kind:
479 this->writeForStatement((ForStatement&) s);
480 break;
481 case Statement::kWhile_Kind:
482 this->writeWhileStatement((WhileStatement&) s);
483 break;
484 case Statement::kDo_Kind:
485 this->writeDoStatement((DoStatement&) s);
486 break;
487 case Statement::kBreak_Kind:
488 this->write("break;");
489 break;
490 case Statement::kContinue_Kind:
491 this->write("continue;");
492 break;
493 case Statement::kDiscard_Kind:
494 this->write("discard;");
495 break;
496 default:
497 ABORT("unsupported statement: %s", s.description().c_str());
498 }
499}
500
501void GLSLCodeGenerator::writeBlock(const Block& b) {
502 this->writeLine("{");
503 fIndentation++;
504 for (const auto& s : b.fStatements) {
505 this->writeStatement(*s);
506 this->writeLine();
507 }
508 fIndentation--;
509 this->write("}");
510}
511
512void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
513 this->write("if (");
514 this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
515 this->write(") ");
516 this->writeStatement(*stmt.fIfTrue);
517 if (stmt.fIfFalse) {
518 this->write(" else ");
519 this->writeStatement(*stmt.fIfFalse);
520 }
521}
522
523void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
524 this->write("for (");
525 if (f.fInitializer) {
526 this->writeStatement(*f.fInitializer);
527 } else {
528 this->write("; ");
529 }
530 if (f.fTest) {
531 this->writeExpression(*f.fTest, kTopLevel_Precedence);
532 }
533 this->write("; ");
534 if (f.fNext) {
535 this->writeExpression(*f.fNext, kTopLevel_Precedence);
536 }
537 this->write(") ");
538 this->writeStatement(*f.fStatement);
539}
540
541void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
542 this->write("while (");
543 this->writeExpression(*w.fTest, kTopLevel_Precedence);
544 this->write(") ");
545 this->writeStatement(*w.fStatement);
546}
547
548void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
549 this->write("do ");
550 this->writeStatement(*d.fStatement);
551 this->write(" while (");
552 this->writeExpression(*d.fTest, kTopLevel_Precedence);
553 this->write(");");
554}
555
556void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
557 this->write("return");
558 if (r.fExpression) {
559 this->write(" ");
560 this->writeExpression(*r.fExpression, kTopLevel_Precedence);
561 }
562 this->write(";");
563}
564
565void GLSLCodeGenerator::generateCode(const Program& program, std::ostream& out) {
566 ASSERT(fOut == nullptr);
567 fOut = &out;
ethannicholasf008b0a2016-09-30 06:23:24 -0700568 fProgramKind = program.fKind;
ethannicholasf789b382016-08-03 12:43:36 -0700569 this->write("#version " + to_string(fCaps.fVersion));
ethannicholasf008b0a2016-09-30 06:23:24 -0700570 if (fCaps.fStandard == GLCaps::kGLES_Standard && fCaps.fVersion >= 300) {
ethannicholasf789b382016-08-03 12:43:36 -0700571 this->write(" es");
ethannicholasf008b0a2016-09-30 06:23:24 -0700572 } else if (fCaps.fIsCoreProfile) {
573 this->write(" core");
ethannicholasf789b382016-08-03 12:43:36 -0700574 }
575 this->writeLine();
576 for (const auto& e : program.fElements) {
ethannicholasf008b0a2016-09-30 06:23:24 -0700577 if (e->fKind == ProgramElement::kExtension_Kind) {
578 this->writeExtension((Extension&) *e);
579 }
580 }
581 if (fCaps.fStandard == GLCaps::kGLES_Standard) {
582 this->write("precision ");
583 switch (program.fDefaultPrecision) {
584 case Modifiers::kLowp_Flag:
585 this->write("lowp");
586 break;
587 case Modifiers::kMediump_Flag:
588 this->write("mediump");
589 break;
590 case Modifiers::kHighp_Flag:
591 this->write("highp");
592 break;
593 default:
594 ASSERT(false);
595 this->write("<error>");
596 }
597 this->writeLine(" float;");
598 }
599 for (const auto& e : program.fElements) {
ethannicholasf789b382016-08-03 12:43:36 -0700600 switch (e->fKind) {
601 case ProgramElement::kExtension_Kind:
ethannicholasf789b382016-08-03 12:43:36 -0700602 break;
603 case ProgramElement::kVar_Kind: {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700604 VarDeclarations& decl = (VarDeclarations&) *e;
ethannicholasf008b0a2016-09-30 06:23:24 -0700605 if (decl.fVars.size() > 0) {
606 int builtin = decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin;
607 if (builtin == -1) {
608 // normal var
609 this->writeVarDeclarations(decl, true);
610 this->writeLine();
611 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
612 fCaps.fMustDeclareFragmentShaderOutput) {
613 this->write("out ");
614 if (fCaps.fUsesPrecisionModifiers) {
615 this->write("mediump ");
616 }
617 this->writeLine("vec4 sk_FragColor;");
618 }
ethannicholasf789b382016-08-03 12:43:36 -0700619 }
620 break;
621 }
622 case ProgramElement::kInterfaceBlock_Kind:
623 this->writeInterfaceBlock((InterfaceBlock&) *e);
624 break;
625 case ProgramElement::kFunction_Kind:
626 this->writeFunction((FunctionDefinition&) *e);
627 break;
ethannicholasf008b0a2016-09-30 06:23:24 -0700628 case ProgramElement::kModifiers_Kind:
629 this->writeModifiers(((ModifiersDeclaration&) *e).fModifiers, true);
630 this->writeLine(";");
631 break;
ethannicholasf789b382016-08-03 12:43:36 -0700632 default:
633 printf("%s\n", e->description().c_str());
634 ABORT("unsupported program element");
635 }
636 }
637 fOut = nullptr;
638}
639
640}