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