1 //
2 // Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 #include "compiler/OutputGLSLBase.h"
8 #include "compiler/debug.h"
9
10 #include <cfloat>
11
12 namespace
13 {
arrayBrackets(const TType & type)14 TString arrayBrackets(const TType& type)
15 {
16 ASSERT(type.isArray());
17 TInfoSinkBase out;
18 out << "[" << type.getArraySize() << "]";
19 return TString(out.c_str());
20 }
21
isSingleStatement(TIntermNode * node)22 bool isSingleStatement(TIntermNode* node) {
23 if (const TIntermAggregate* aggregate = node->getAsAggregate())
24 {
25 return (aggregate->getOp() != EOpFunction) &&
26 (aggregate->getOp() != EOpSequence);
27 }
28 else if (const TIntermSelection* selection = node->getAsSelectionNode())
29 {
30 // Ternary operators are usually part of an assignment operator.
31 // This handles those rare cases in which they are all by themselves.
32 return selection->usesTernaryOperator();
33 }
34 else if (node->getAsLoopNode())
35 {
36 return false;
37 }
38 return true;
39 }
40 } // namespace
41
TOutputGLSLBase(TInfoSinkBase & objSink,ShArrayIndexClampingStrategy clampingStrategy,ShHashFunction64 hashFunction,NameMap & nameMap,TSymbolTable & symbolTable)42 TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink,
43 ShArrayIndexClampingStrategy clampingStrategy,
44 ShHashFunction64 hashFunction,
45 NameMap& nameMap,
46 TSymbolTable& symbolTable)
47 : TIntermTraverser(true, true, true),
48 mObjSink(objSink),
49 mDeclaringVariables(false),
50 mClampingStrategy(clampingStrategy),
51 mHashFunction(hashFunction),
52 mNameMap(nameMap),
53 mSymbolTable(symbolTable)
54 {
55 }
56
writeTriplet(Visit visit,const char * preStr,const char * inStr,const char * postStr)57 void TOutputGLSLBase::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
58 {
59 TInfoSinkBase& out = objSink();
60 if (visit == PreVisit && preStr)
61 {
62 out << preStr;
63 }
64 else if (visit == InVisit && inStr)
65 {
66 out << inStr;
67 }
68 else if (visit == PostVisit && postStr)
69 {
70 out << postStr;
71 }
72 }
73
writeVariableType(const TType & type)74 void TOutputGLSLBase::writeVariableType(const TType& type)
75 {
76 TInfoSinkBase& out = objSink();
77 TQualifier qualifier = type.getQualifier();
78 // TODO(alokp): Validate qualifier for variable declarations.
79 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
80 out << type.getQualifierString() << " ";
81 // Declare the struct if we have not done so already.
82 if ((type.getBasicType() == EbtStruct) && !structDeclared(type.getStruct()))
83 {
84 declareStruct(type.getStruct());
85 }
86 else
87 {
88 if (writeVariablePrecision(type.getPrecision()))
89 out << " ";
90 out << getTypeName(type);
91 }
92 }
93
writeFunctionParameters(const TIntermSequence & args)94 void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args)
95 {
96 TInfoSinkBase& out = objSink();
97 for (TIntermSequence::const_iterator iter = args.begin();
98 iter != args.end(); ++iter)
99 {
100 const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
101 ASSERT(arg != NULL);
102
103 const TType& type = arg->getType();
104 writeVariableType(type);
105
106 const TString& name = arg->getSymbol();
107 if (!name.empty())
108 out << " " << hashName(name);
109 if (type.isArray())
110 out << arrayBrackets(type);
111
112 // Put a comma if this is not the last argument.
113 if (iter != args.end() - 1)
114 out << ", ";
115 }
116 }
117
writeConstantUnion(const TType & type,const ConstantUnion * pConstUnion)118 const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
119 const ConstantUnion* pConstUnion)
120 {
121 TInfoSinkBase& out = objSink();
122
123 if (type.getBasicType() == EbtStruct)
124 {
125 const TStructure* structure = type.getStruct();
126 out << hashName(structure->name()) << "(";
127
128 const TFieldList& fields = structure->fields();
129 for (size_t i = 0; i < fields.size(); ++i)
130 {
131 const TType* fieldType = fields[i]->type();
132 ASSERT(fieldType != NULL);
133 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
134 if (i != fields.size() - 1) out << ", ";
135 }
136 out << ")";
137 }
138 else
139 {
140 size_t size = type.getObjectSize();
141 bool writeType = size > 1;
142 if (writeType) out << getTypeName(type) << "(";
143 for (size_t i = 0; i < size; ++i, ++pConstUnion)
144 {
145 switch (pConstUnion->getType())
146 {
147 case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst())); break;
148 case EbtInt: out << pConstUnion->getIConst(); break;
149 case EbtBool: out << pConstUnion->getBConst(); break;
150 default: UNREACHABLE();
151 }
152 if (i != size - 1) out << ", ";
153 }
154 if (writeType) out << ")";
155 }
156 return pConstUnion;
157 }
158
visitSymbol(TIntermSymbol * node)159 void TOutputGLSLBase::visitSymbol(TIntermSymbol* node)
160 {
161 TInfoSinkBase& out = objSink();
162 if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node))
163 out << mLoopUnroll.GetLoopIndexValue(node);
164 else
165 out << hashVariableName(node->getSymbol());
166
167 if (mDeclaringVariables && node->getType().isArray())
168 out << arrayBrackets(node->getType());
169 }
170
visitConstantUnion(TIntermConstantUnion * node)171 void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
172 {
173 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
174 }
175
visitBinary(Visit visit,TIntermBinary * node)176 bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
177 {
178 bool visitChildren = true;
179 TInfoSinkBase& out = objSink();
180 switch (node->getOp())
181 {
182 case EOpInitialize:
183 if (visit == InVisit)
184 {
185 out << " = ";
186 // RHS of initialize is not being declared.
187 mDeclaringVariables = false;
188 }
189 break;
190 case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break;
191 case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break;
192 case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break;
193 case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break;
194 // Notice the fall-through.
195 case EOpMulAssign:
196 case EOpVectorTimesMatrixAssign:
197 case EOpVectorTimesScalarAssign:
198 case EOpMatrixTimesScalarAssign:
199 case EOpMatrixTimesMatrixAssign:
200 writeTriplet(visit, "(", " *= ", ")");
201 break;
202
203 case EOpIndexDirect:
204 writeTriplet(visit, NULL, "[", "]");
205 break;
206 case EOpIndexIndirect:
207 if (node->getAddIndexClamp())
208 {
209 if (visit == InVisit)
210 {
211 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) {
212 out << "[int(clamp(float(";
213 } else {
214 out << "[webgl_int_clamp(";
215 }
216 }
217 else if (visit == PostVisit)
218 {
219 int maxSize;
220 TIntermTyped *left = node->getLeft();
221 TType leftType = left->getType();
222
223 if (left->isArray())
224 {
225 // The shader will fail validation if the array length is not > 0.
226 maxSize = leftType.getArraySize() - 1;
227 }
228 else
229 {
230 maxSize = leftType.getNominalSize() - 1;
231 }
232
233 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) {
234 out << "), 0.0, float(" << maxSize << ")))]";
235 } else {
236 out << ", 0, " << maxSize << ")]";
237 }
238 }
239 }
240 else
241 {
242 writeTriplet(visit, NULL, "[", "]");
243 }
244 break;
245 case EOpIndexDirectStruct:
246 if (visit == InVisit)
247 {
248 // Here we are writing out "foo.bar", where "foo" is struct
249 // and "bar" is field. In AST, it is represented as a binary
250 // node, where left child represents "foo" and right child "bar".
251 // The node itself represents ".". The struct field "bar" is
252 // actually stored as an index into TStructure::fields.
253 out << ".";
254 const TStructure* structure = node->getLeft()->getType().getStruct();
255 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
256 const TField* field = structure->fields()[index->getIConst(0)];
257
258 TString fieldName = field->name();
259 if (!mSymbolTable.findBuiltIn(structure->name()))
260 fieldName = hashName(fieldName);
261
262 out << fieldName;
263 visitChildren = false;
264 }
265 break;
266 case EOpVectorSwizzle:
267 if (visit == InVisit)
268 {
269 out << ".";
270 TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
271 TIntermSequence& sequence = rightChild->getSequence();
272 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
273 {
274 TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
275 ASSERT(element->getBasicType() == EbtInt);
276 ASSERT(element->getNominalSize() == 1);
277 const ConstantUnion& data = element->getUnionArrayPointer()[0];
278 ASSERT(data.getType() == EbtInt);
279 switch (data.getIConst())
280 {
281 case 0: out << "x"; break;
282 case 1: out << "y"; break;
283 case 2: out << "z"; break;
284 case 3: out << "w"; break;
285 default: UNREACHABLE(); break;
286 }
287 }
288 visitChildren = false;
289 }
290 break;
291
292 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
293 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
294 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
295 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
296 case EOpMod: UNIMPLEMENTED(); break;
297 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
298 case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
299 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
300 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
301 case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
302 case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
303
304 // Notice the fall-through.
305 case EOpVectorTimesScalar:
306 case EOpVectorTimesMatrix:
307 case EOpMatrixTimesVector:
308 case EOpMatrixTimesScalar:
309 case EOpMatrixTimesMatrix:
310 writeTriplet(visit, "(", " * ", ")");
311 break;
312
313 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
314 case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
315 case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
316 default: UNREACHABLE(); break;
317 }
318
319 return visitChildren;
320 }
321
visitUnary(Visit visit,TIntermUnary * node)322 bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
323 {
324 TString preString;
325 TString postString = ")";
326
327 switch (node->getOp())
328 {
329 case EOpNegative: preString = "(-"; break;
330 case EOpVectorLogicalNot: preString = "not("; break;
331 case EOpLogicalNot: preString = "(!"; break;
332
333 case EOpPostIncrement: preString = "("; postString = "++)"; break;
334 case EOpPostDecrement: preString = "("; postString = "--)"; break;
335 case EOpPreIncrement: preString = "(++"; break;
336 case EOpPreDecrement: preString = "(--"; break;
337
338 case EOpConvIntToBool:
339 case EOpConvFloatToBool:
340 switch (node->getOperand()->getType().getNominalSize())
341 {
342 case 1: preString = "bool("; break;
343 case 2: preString = "bvec2("; break;
344 case 3: preString = "bvec3("; break;
345 case 4: preString = "bvec4("; break;
346 default: UNREACHABLE();
347 }
348 break;
349 case EOpConvBoolToFloat:
350 case EOpConvIntToFloat:
351 switch (node->getOperand()->getType().getNominalSize())
352 {
353 case 1: preString = "float("; break;
354 case 2: preString = "vec2("; break;
355 case 3: preString = "vec3("; break;
356 case 4: preString = "vec4("; break;
357 default: UNREACHABLE();
358 }
359 break;
360 case EOpConvFloatToInt:
361 case EOpConvBoolToInt:
362 switch (node->getOperand()->getType().getNominalSize())
363 {
364 case 1: preString = "int("; break;
365 case 2: preString = "ivec2("; break;
366 case 3: preString = "ivec3("; break;
367 case 4: preString = "ivec4("; break;
368 default: UNREACHABLE();
369 }
370 break;
371
372 case EOpRadians: preString = "radians("; break;
373 case EOpDegrees: preString = "degrees("; break;
374 case EOpSin: preString = "sin("; break;
375 case EOpCos: preString = "cos("; break;
376 case EOpTan: preString = "tan("; break;
377 case EOpAsin: preString = "asin("; break;
378 case EOpAcos: preString = "acos("; break;
379 case EOpAtan: preString = "atan("; break;
380
381 case EOpExp: preString = "exp("; break;
382 case EOpLog: preString = "log("; break;
383 case EOpExp2: preString = "exp2("; break;
384 case EOpLog2: preString = "log2("; break;
385 case EOpSqrt: preString = "sqrt("; break;
386 case EOpInverseSqrt: preString = "inversesqrt("; break;
387
388 case EOpAbs: preString = "abs("; break;
389 case EOpSign: preString = "sign("; break;
390 case EOpFloor: preString = "floor("; break;
391 case EOpCeil: preString = "ceil("; break;
392 case EOpFract: preString = "fract("; break;
393
394 case EOpLength: preString = "length("; break;
395 case EOpNormalize: preString = "normalize("; break;
396
397 case EOpDFdx: preString = "dFdx("; break;
398 case EOpDFdy: preString = "dFdy("; break;
399 case EOpFwidth: preString = "fwidth("; break;
400
401 case EOpAny: preString = "any("; break;
402 case EOpAll: preString = "all("; break;
403
404 default: UNREACHABLE(); break;
405 }
406
407 if (visit == PreVisit && node->getUseEmulatedFunction())
408 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
409 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
410
411 return true;
412 }
413
visitSelection(Visit visit,TIntermSelection * node)414 bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
415 {
416 TInfoSinkBase& out = objSink();
417
418 if (node->usesTernaryOperator())
419 {
420 // Notice two brackets at the beginning and end. The outer ones
421 // encapsulate the whole ternary expression. This preserves the
422 // order of precedence when ternary expressions are used in a
423 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
424 out << "((";
425 node->getCondition()->traverse(this);
426 out << ") ? (";
427 node->getTrueBlock()->traverse(this);
428 out << ") : (";
429 node->getFalseBlock()->traverse(this);
430 out << "))";
431 }
432 else
433 {
434 out << "if (";
435 node->getCondition()->traverse(this);
436 out << ")\n";
437
438 incrementDepth(node);
439 visitCodeBlock(node->getTrueBlock());
440
441 if (node->getFalseBlock())
442 {
443 out << "else\n";
444 visitCodeBlock(node->getFalseBlock());
445 }
446 decrementDepth();
447 }
448 return false;
449 }
450
visitAggregate(Visit visit,TIntermAggregate * node)451 bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
452 {
453 bool visitChildren = true;
454 TInfoSinkBase& out = objSink();
455 TString preString;
456 bool delayedWrite = false;
457 switch (node->getOp())
458 {
459 case EOpSequence: {
460 // Scope the sequences except when at the global scope.
461 if (depth > 0) out << "{\n";
462
463 incrementDepth(node);
464 const TIntermSequence& sequence = node->getSequence();
465 for (TIntermSequence::const_iterator iter = sequence.begin();
466 iter != sequence.end(); ++iter)
467 {
468 TIntermNode* node = *iter;
469 ASSERT(node != NULL);
470 node->traverse(this);
471
472 if (isSingleStatement(node))
473 out << ";\n";
474 }
475 decrementDepth();
476
477 // Scope the sequences except when at the global scope.
478 if (depth > 0) out << "}\n";
479 visitChildren = false;
480 break;
481 }
482 case EOpPrototype: {
483 // Function declaration.
484 ASSERT(visit == PreVisit);
485 writeVariableType(node->getType());
486 out << " " << hashName(node->getName());
487
488 out << "(";
489 writeFunctionParameters(node->getSequence());
490 out << ")";
491
492 visitChildren = false;
493 break;
494 }
495 case EOpFunction: {
496 // Function definition.
497 ASSERT(visit == PreVisit);
498 writeVariableType(node->getType());
499 out << " " << hashFunctionName(node->getName());
500
501 incrementDepth(node);
502 // Function definition node contains one or two children nodes
503 // representing function parameters and function body. The latter
504 // is not present in case of empty function bodies.
505 const TIntermSequence& sequence = node->getSequence();
506 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
507 TIntermSequence::const_iterator seqIter = sequence.begin();
508
509 // Traverse function parameters.
510 TIntermAggregate* params = (*seqIter)->getAsAggregate();
511 ASSERT(params != NULL);
512 ASSERT(params->getOp() == EOpParameters);
513 params->traverse(this);
514
515 // Traverse function body.
516 TIntermAggregate* body = ++seqIter != sequence.end() ?
517 (*seqIter)->getAsAggregate() : NULL;
518 visitCodeBlock(body);
519 decrementDepth();
520
521 // Fully processed; no need to visit children.
522 visitChildren = false;
523 break;
524 }
525 case EOpFunctionCall:
526 // Function call.
527 if (visit == PreVisit)
528 {
529 out << hashFunctionName(node->getName()) << "(";
530 }
531 else if (visit == InVisit)
532 {
533 out << ", ";
534 }
535 else
536 {
537 out << ")";
538 }
539 break;
540 case EOpParameters: {
541 // Function parameters.
542 ASSERT(visit == PreVisit);
543 out << "(";
544 writeFunctionParameters(node->getSequence());
545 out << ")";
546 visitChildren = false;
547 break;
548 }
549 case EOpDeclaration: {
550 // Variable declaration.
551 if (visit == PreVisit)
552 {
553 const TIntermSequence& sequence = node->getSequence();
554 const TIntermTyped* variable = sequence.front()->getAsTyped();
555 writeVariableType(variable->getType());
556 out << " ";
557 mDeclaringVariables = true;
558 }
559 else if (visit == InVisit)
560 {
561 out << ", ";
562 mDeclaringVariables = true;
563 }
564 else
565 {
566 mDeclaringVariables = false;
567 }
568 break;
569 }
570 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
571 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
572 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
573 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
574 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
575 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
576 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
577 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
578 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
579 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
580 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
581 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
582 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
583 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
584 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
585 case EOpConstructStruct:
586 if (visit == PreVisit)
587 {
588 const TType& type = node->getType();
589 ASSERT(type.getBasicType() == EbtStruct);
590 out << hashName(type.getStruct()->name()) << "(";
591 }
592 else if (visit == InVisit)
593 {
594 out << ", ";
595 }
596 else
597 {
598 out << ")";
599 }
600 break;
601
602 case EOpLessThan: preString = "lessThan("; delayedWrite = true; break;
603 case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break;
604 case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break;
605 case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break;
606 case EOpVectorEqual: preString = "equal("; delayedWrite = true; break;
607 case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break;
608 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
609
610 case EOpMod: preString = "mod("; delayedWrite = true; break;
611 case EOpPow: preString = "pow("; delayedWrite = true; break;
612 case EOpAtan: preString = "atan("; delayedWrite = true; break;
613 case EOpMin: preString = "min("; delayedWrite = true; break;
614 case EOpMax: preString = "max("; delayedWrite = true; break;
615 case EOpClamp: preString = "clamp("; delayedWrite = true; break;
616 case EOpMix: preString = "mix("; delayedWrite = true; break;
617 case EOpStep: preString = "step("; delayedWrite = true; break;
618 case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break;
619
620 case EOpDistance: preString = "distance("; delayedWrite = true; break;
621 case EOpDot: preString = "dot("; delayedWrite = true; break;
622 case EOpCross: preString = "cross("; delayedWrite = true; break;
623 case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break;
624 case EOpReflect: preString = "reflect("; delayedWrite = true; break;
625 case EOpRefract: preString = "refract("; delayedWrite = true; break;
626 case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break;
627
628 default: UNREACHABLE(); break;
629 }
630 if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction())
631 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
632 if (delayedWrite)
633 writeTriplet(visit, preString.c_str(), ", ", ")");
634 return visitChildren;
635 }
636
visitLoop(Visit visit,TIntermLoop * node)637 bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
638 {
639 TInfoSinkBase& out = objSink();
640
641 incrementDepth(node);
642 // Loop header.
643 TLoopType loopType = node->getType();
644 if (loopType == ELoopFor) // for loop
645 {
646 if (!node->getUnrollFlag()) {
647 out << "for (";
648 if (node->getInit())
649 node->getInit()->traverse(this);
650 out << "; ";
651
652 if (node->getCondition())
653 node->getCondition()->traverse(this);
654 out << "; ";
655
656 if (node->getExpression())
657 node->getExpression()->traverse(this);
658 out << ")\n";
659 }
660 }
661 else if (loopType == ELoopWhile) // while loop
662 {
663 out << "while (";
664 ASSERT(node->getCondition() != NULL);
665 node->getCondition()->traverse(this);
666 out << ")\n";
667 }
668 else // do-while loop
669 {
670 ASSERT(loopType == ELoopDoWhile);
671 out << "do\n";
672 }
673
674 // Loop body.
675 if (node->getUnrollFlag())
676 {
677 TLoopIndexInfo indexInfo;
678 mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
679 mLoopUnroll.Push(indexInfo);
680 while (mLoopUnroll.SatisfiesLoopCondition())
681 {
682 visitCodeBlock(node->getBody());
683 mLoopUnroll.Step();
684 }
685 mLoopUnroll.Pop();
686 }
687 else
688 {
689 visitCodeBlock(node->getBody());
690 }
691
692 // Loop footer.
693 if (loopType == ELoopDoWhile) // do-while loop
694 {
695 out << "while (";
696 ASSERT(node->getCondition() != NULL);
697 node->getCondition()->traverse(this);
698 out << ");\n";
699 }
700 decrementDepth();
701
702 // No need to visit children. They have been already processed in
703 // this function.
704 return false;
705 }
706
visitBranch(Visit visit,TIntermBranch * node)707 bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
708 {
709 switch (node->getFlowOp())
710 {
711 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
712 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
713 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
714 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
715 default: UNREACHABLE(); break;
716 }
717
718 return true;
719 }
720
visitCodeBlock(TIntermNode * node)721 void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
722 TInfoSinkBase &out = objSink();
723 if (node != NULL)
724 {
725 node->traverse(this);
726 // Single statements not part of a sequence need to be terminated
727 // with semi-colon.
728 if (isSingleStatement(node))
729 out << ";\n";
730 }
731 else
732 {
733 out << "{\n}\n"; // Empty code block.
734 }
735 }
736
getTypeName(const TType & type)737 TString TOutputGLSLBase::getTypeName(const TType& type)
738 {
739 TInfoSinkBase out;
740 if (type.isMatrix())
741 {
742 out << "mat";
743 out << type.getNominalSize();
744 }
745 else if (type.isVector())
746 {
747 switch (type.getBasicType())
748 {
749 case EbtFloat: out << "vec"; break;
750 case EbtInt: out << "ivec"; break;
751 case EbtBool: out << "bvec"; break;
752 default: UNREACHABLE(); break;
753 }
754 out << type.getNominalSize();
755 }
756 else
757 {
758 if (type.getBasicType() == EbtStruct)
759 out << hashName(type.getStruct()->name());
760 else
761 out << type.getBasicString();
762 }
763 return TString(out.c_str());
764 }
765
hashName(const TString & name)766 TString TOutputGLSLBase::hashName(const TString& name)
767 {
768 if (mHashFunction == NULL || name.empty())
769 return name;
770 NameMap::const_iterator it = mNameMap.find(name.c_str());
771 if (it != mNameMap.end())
772 return it->second.c_str();
773 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
774 mNameMap[name.c_str()] = hashedName.c_str();
775 return hashedName;
776 }
777
hashVariableName(const TString & name)778 TString TOutputGLSLBase::hashVariableName(const TString& name)
779 {
780 if (mSymbolTable.findBuiltIn(name) != NULL)
781 return name;
782 return hashName(name);
783 }
784
hashFunctionName(const TString & mangled_name)785 TString TOutputGLSLBase::hashFunctionName(const TString& mangled_name)
786 {
787 TString name = TFunction::unmangleName(mangled_name);
788 if (mSymbolTable.findBuiltIn(mangled_name) != NULL || name == "main")
789 return name;
790 return hashName(name);
791 }
792
structDeclared(const TStructure * structure) const793 bool TOutputGLSLBase::structDeclared(const TStructure* structure) const
794 {
795 return mDeclaredStructs.find(structure->name()) != mDeclaredStructs.end();
796 }
797
declareStruct(const TStructure * structure)798 void TOutputGLSLBase::declareStruct(const TStructure* structure)
799 {
800 TInfoSinkBase& out = objSink();
801
802 out << "struct " << hashName(structure->name()) << "{\n";
803 const TFieldList& fields = structure->fields();
804 for (size_t i = 0; i < fields.size(); ++i)
805 {
806 const TField* field = fields[i];
807 if (writeVariablePrecision(field->type()->getPrecision()))
808 out << " ";
809 out << getTypeName(*field->type()) << " " << hashName(field->name());
810 if (field->type()->isArray())
811 out << arrayBrackets(*field->type());
812 out << ";\n";
813 }
814 out << "}";
815
816 mDeclaredStructs.insert(structure->name());
817 }
818