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