blob: 45fabedc48bb190822116883139b08d6315c8555 [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,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000043 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000044 ShHashFunction64 hashFunction,
45 NameMap& nameMap,
46 TSymbolTable& symbolTable)
zmo@google.com5601ea02011-06-10 18:23:25 +000047 : TIntermTraverser(true, true, true),
48 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000049 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000050 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000051 mHashFunction(hashFunction),
52 mNameMap(nameMap),
53 mSymbolTable(symbolTable)
zmo@google.com5601ea02011-06-10 18:23:25 +000054{
55}
56
57void 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
74void 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) &&
83 (mDeclaredStructs.find(type.getTypeName()) == mDeclaredStructs.end()))
84 {
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000085 out << "struct " << hashName(type.getTypeName()) << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +000086 const TTypeList* structure = type.getStruct();
87 ASSERT(structure != NULL);
88 for (size_t i = 0; i < structure->size(); ++i)
89 {
90 const TType* fieldType = (*structure)[i].type;
91 ASSERT(fieldType != NULL);
92 if (writeVariablePrecision(fieldType->getPrecision()))
93 out << " ";
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000094 out << getTypeName(*fieldType) << " " << hashName(fieldType->getFieldName());
zmo@google.com5601ea02011-06-10 18:23:25 +000095 if (fieldType->isArray())
96 out << arrayBrackets(*fieldType);
97 out << ";\n";
98 }
99 out << "}";
100 mDeclaredStructs.insert(type.getTypeName());
101 }
102 else
103 {
104 if (writeVariablePrecision(type.getPrecision()))
105 out << " ";
106 out << getTypeName(type);
107 }
108}
109
110void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args)
111{
112 TInfoSinkBase& out = objSink();
113 for (TIntermSequence::const_iterator iter = args.begin();
114 iter != args.end(); ++iter)
115 {
116 const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
117 ASSERT(arg != NULL);
118
119 const TType& type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000120 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000121
122 const TString& name = arg->getSymbol();
123 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000124 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000125 if (type.isArray())
126 out << arrayBrackets(type);
127
128 // Put a comma if this is not the last argument.
129 if (iter != args.end() - 1)
130 out << ", ";
131 }
132}
133
134const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
135 const ConstantUnion* pConstUnion)
136{
137 TInfoSinkBase& out = objSink();
138
139 if (type.getBasicType() == EbtStruct)
140 {
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000141 out << hashName(type.getTypeName()) << "(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000142 const TTypeList* structure = type.getStruct();
143 ASSERT(structure != NULL);
144 for (size_t i = 0; i < structure->size(); ++i)
145 {
146 const TType* fieldType = (*structure)[i].type;
147 ASSERT(fieldType != NULL);
148 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
149 if (i != structure->size() - 1) out << ", ";
150 }
151 out << ")";
152 }
153 else
154 {
155 int size = type.getObjectSize();
156 bool writeType = size > 1;
157 if (writeType) out << getTypeName(type) << "(";
158 for (int i = 0; i < size; ++i, ++pConstUnion)
159 {
160 switch (pConstUnion->getType())
161 {
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +0000162 case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst())); break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000163 case EbtInt: out << pConstUnion->getIConst(); break;
164 case EbtBool: out << pConstUnion->getBConst(); break;
165 default: UNREACHABLE();
166 }
167 if (i != size - 1) out << ", ";
168 }
169 if (writeType) out << ")";
170 }
171 return pConstUnion;
172}
173
174void TOutputGLSLBase::visitSymbol(TIntermSymbol* node)
175{
176 TInfoSinkBase& out = objSink();
177 if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node))
178 out << mLoopUnroll.GetLoopIndexValue(node);
179 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000180 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000181
182 if (mDeclaringVariables && node->getType().isArray())
183 out << arrayBrackets(node->getType());
184}
185
186void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
187{
188 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
189}
190
191bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
192{
193 bool visitChildren = true;
194 TInfoSinkBase& out = objSink();
195 switch (node->getOp())
196 {
197 case EOpInitialize:
198 if (visit == InVisit)
199 {
200 out << " = ";
201 // RHS of initialize is not being declared.
202 mDeclaringVariables = false;
203 }
204 break;
205 case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break;
206 case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break;
207 case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break;
208 case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break;
209 // Notice the fall-through.
210 case EOpMulAssign:
211 case EOpVectorTimesMatrixAssign:
212 case EOpVectorTimesScalarAssign:
213 case EOpMatrixTimesScalarAssign:
214 case EOpMatrixTimesMatrixAssign:
215 writeTriplet(visit, "(", " *= ", ")");
216 break;
217
218 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000219 writeTriplet(visit, NULL, "[", "]");
220 break;
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000221 case EOpIndexIndirect:
222 if (node->getAddIndexClamp())
223 {
224 if (visit == InVisit)
225 {
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000226 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) {
227 out << "[int(clamp(float(";
228 } else {
229 out << "[webgl_int_clamp(";
230 }
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000231 }
232 else if (visit == PostVisit)
233 {
234 int maxSize;
235 TIntermTyped *left = node->getLeft();
236 TType leftType = left->getType();
237
238 if (left->isArray())
239 {
240 // The shader will fail validation if the array length is not > 0.
241 maxSize = leftType.getArraySize() - 1;
242 }
243 else
244 {
245 maxSize = leftType.getNominalSize() - 1;
246 }
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000247
248 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) {
249 out << "), 0.0, float(" << maxSize << ")))]";
250 } else {
251 out << ", 0, " << maxSize << ")]";
252 }
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000253 }
254 }
255 else
256 {
257 writeTriplet(visit, NULL, "[", "]");
258 }
259 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000260 case EOpIndexDirectStruct:
261 if (visit == InVisit)
262 {
263 out << ".";
264 // TODO(alokp): ASSERT
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000265 out << hashName(node->getType().getFieldName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000266 visitChildren = false;
267 }
268 break;
269 case EOpVectorSwizzle:
270 if (visit == InVisit)
271 {
272 out << ".";
273 TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
274 TIntermSequence& sequence = rightChild->getSequence();
275 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
276 {
277 TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
278 ASSERT(element->getBasicType() == EbtInt);
279 ASSERT(element->getNominalSize() == 1);
280 const ConstantUnion& data = element->getUnionArrayPointer()[0];
281 ASSERT(data.getType() == EbtInt);
282 switch (data.getIConst())
283 {
284 case 0: out << "x"; break;
285 case 1: out << "y"; break;
286 case 2: out << "z"; break;
287 case 3: out << "w"; break;
288 default: UNREACHABLE(); break;
289 }
290 }
291 visitChildren = false;
292 }
293 break;
294
295 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
296 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
297 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
298 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
299 case EOpMod: UNIMPLEMENTED(); break;
300 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
301 case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
302 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
303 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
304 case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
305 case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
306
307 // Notice the fall-through.
308 case EOpVectorTimesScalar:
309 case EOpVectorTimesMatrix:
310 case EOpMatrixTimesVector:
311 case EOpMatrixTimesScalar:
312 case EOpMatrixTimesMatrix:
313 writeTriplet(visit, "(", " * ", ")");
314 break;
315
316 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
317 case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
318 case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
319 default: UNREACHABLE(); break;
320 }
321
322 return visitChildren;
323}
324
325bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
326{
zmo@google.com32e97312011-08-24 01:03:11 +0000327 TString preString;
328 TString postString = ")";
329
zmo@google.com5601ea02011-06-10 18:23:25 +0000330 switch (node->getOp())
331 {
zmo@google.com32e97312011-08-24 01:03:11 +0000332 case EOpNegative: preString = "(-"; break;
333 case EOpVectorLogicalNot: preString = "not("; break;
334 case EOpLogicalNot: preString = "(!"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000335
zmo@google.com32e97312011-08-24 01:03:11 +0000336 case EOpPostIncrement: preString = "("; postString = "++)"; break;
337 case EOpPostDecrement: preString = "("; postString = "--)"; break;
338 case EOpPreIncrement: preString = "(++"; break;
339 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000340
341 case EOpConvIntToBool:
342 case EOpConvFloatToBool:
343 switch (node->getOperand()->getType().getNominalSize())
344 {
zmo@google.com32e97312011-08-24 01:03:11 +0000345 case 1: preString = "bool("; break;
346 case 2: preString = "bvec2("; break;
347 case 3: preString = "bvec3("; break;
348 case 4: preString = "bvec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000349 default: UNREACHABLE();
350 }
351 break;
352 case EOpConvBoolToFloat:
353 case EOpConvIntToFloat:
354 switch (node->getOperand()->getType().getNominalSize())
355 {
zmo@google.com32e97312011-08-24 01:03:11 +0000356 case 1: preString = "float("; break;
357 case 2: preString = "vec2("; break;
358 case 3: preString = "vec3("; break;
359 case 4: preString = "vec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000360 default: UNREACHABLE();
361 }
362 break;
363 case EOpConvFloatToInt:
364 case EOpConvBoolToInt:
365 switch (node->getOperand()->getType().getNominalSize())
366 {
zmo@google.com32e97312011-08-24 01:03:11 +0000367 case 1: preString = "int("; break;
368 case 2: preString = "ivec2("; break;
369 case 3: preString = "ivec3("; break;
370 case 4: preString = "ivec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000371 default: UNREACHABLE();
372 }
373 break;
374
zmo@google.com32e97312011-08-24 01:03:11 +0000375 case EOpRadians: preString = "radians("; break;
376 case EOpDegrees: preString = "degrees("; break;
377 case EOpSin: preString = "sin("; break;
378 case EOpCos: preString = "cos("; break;
379 case EOpTan: preString = "tan("; break;
380 case EOpAsin: preString = "asin("; break;
381 case EOpAcos: preString = "acos("; break;
382 case EOpAtan: preString = "atan("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000383
zmo@google.com32e97312011-08-24 01:03:11 +0000384 case EOpExp: preString = "exp("; break;
385 case EOpLog: preString = "log("; break;
386 case EOpExp2: preString = "exp2("; break;
387 case EOpLog2: preString = "log2("; break;
388 case EOpSqrt: preString = "sqrt("; break;
389 case EOpInverseSqrt: preString = "inversesqrt("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000390
zmo@google.com32e97312011-08-24 01:03:11 +0000391 case EOpAbs: preString = "abs("; break;
392 case EOpSign: preString = "sign("; break;
393 case EOpFloor: preString = "floor("; break;
394 case EOpCeil: preString = "ceil("; break;
395 case EOpFract: preString = "fract("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000396
zmo@google.com32e97312011-08-24 01:03:11 +0000397 case EOpLength: preString = "length("; break;
398 case EOpNormalize: preString = "normalize("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000399
zmo@google.com32e97312011-08-24 01:03:11 +0000400 case EOpDFdx: preString = "dFdx("; break;
401 case EOpDFdy: preString = "dFdy("; break;
402 case EOpFwidth: preString = "fwidth("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000403
zmo@google.com32e97312011-08-24 01:03:11 +0000404 case EOpAny: preString = "any("; break;
405 case EOpAll: preString = "all("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000406
407 default: UNREACHABLE(); break;
408 }
409
zmo@google.com32e97312011-08-24 01:03:11 +0000410 if (visit == PreVisit && node->getUseEmulatedFunction())
411 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
412 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
413
zmo@google.com5601ea02011-06-10 18:23:25 +0000414 return true;
415}
416
417bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
418{
419 TInfoSinkBase& out = objSink();
420
421 if (node->usesTernaryOperator())
422 {
423 // Notice two brackets at the beginning and end. The outer ones
424 // encapsulate the whole ternary expression. This preserves the
425 // order of precedence when ternary expressions are used in a
426 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
427 out << "((";
428 node->getCondition()->traverse(this);
429 out << ") ? (";
430 node->getTrueBlock()->traverse(this);
431 out << ") : (";
432 node->getFalseBlock()->traverse(this);
433 out << "))";
434 }
435 else
436 {
437 out << "if (";
438 node->getCondition()->traverse(this);
439 out << ")\n";
440
441 incrementDepth();
442 visitCodeBlock(node->getTrueBlock());
443
444 if (node->getFalseBlock())
445 {
446 out << "else\n";
447 visitCodeBlock(node->getFalseBlock());
448 }
449 decrementDepth();
450 }
451 return false;
452}
453
454bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
455{
456 bool visitChildren = true;
457 TInfoSinkBase& out = objSink();
zmo@google.comf420c422011-09-12 18:27:59 +0000458 TString preString;
459 bool delayedWrite = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000460 switch (node->getOp())
461 {
462 case EOpSequence: {
463 // Scope the sequences except when at the global scope.
464 if (depth > 0) out << "{\n";
465
466 incrementDepth();
467 const TIntermSequence& sequence = node->getSequence();
468 for (TIntermSequence::const_iterator iter = sequence.begin();
469 iter != sequence.end(); ++iter)
470 {
471 TIntermNode* node = *iter;
472 ASSERT(node != NULL);
473 node->traverse(this);
474
475 if (isSingleStatement(node))
476 out << ";\n";
477 }
478 decrementDepth();
479
480 // Scope the sequences except when at the global scope.
481 if (depth > 0) out << "}\n";
482 visitChildren = false;
483 break;
484 }
485 case EOpPrototype: {
486 // Function declaration.
487 ASSERT(visit == PreVisit);
kbr@chromium.org57f7ce02011-08-15 23:13:05 +0000488 writeVariableType(node->getType());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000489 out << " " << hashName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000490
491 out << "(";
492 writeFunctionParameters(node->getSequence());
493 out << ")";
494
495 visitChildren = false;
496 break;
497 }
498 case EOpFunction: {
499 // Function definition.
500 ASSERT(visit == PreVisit);
zmo@google.com189be2f2011-06-16 18:28:53 +0000501 writeVariableType(node->getType());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000502 out << " " << hashFunctionName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000503
504 incrementDepth();
505 // Function definition node contains one or two children nodes
506 // representing function parameters and function body. The latter
507 // is not present in case of empty function bodies.
508 const TIntermSequence& sequence = node->getSequence();
509 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
510 TIntermSequence::const_iterator seqIter = sequence.begin();
511
512 // Traverse function parameters.
513 TIntermAggregate* params = (*seqIter)->getAsAggregate();
514 ASSERT(params != NULL);
515 ASSERT(params->getOp() == EOpParameters);
516 params->traverse(this);
517
518 // Traverse function body.
519 TIntermAggregate* body = ++seqIter != sequence.end() ?
520 (*seqIter)->getAsAggregate() : NULL;
521 visitCodeBlock(body);
522 decrementDepth();
523
524 // Fully processed; no need to visit children.
525 visitChildren = false;
526 break;
527 }
528 case EOpFunctionCall:
529 // Function call.
530 if (visit == PreVisit)
531 {
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000532 out << hashFunctionName(node->getName()) << "(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000533 }
534 else if (visit == InVisit)
535 {
536 out << ", ";
537 }
538 else
539 {
540 out << ")";
541 }
542 break;
543 case EOpParameters: {
544 // Function parameters.
545 ASSERT(visit == PreVisit);
546 out << "(";
547 writeFunctionParameters(node->getSequence());
548 out << ")";
549 visitChildren = false;
550 break;
551 }
552 case EOpDeclaration: {
553 // Variable declaration.
554 if (visit == PreVisit)
555 {
556 const TIntermSequence& sequence = node->getSequence();
557 const TIntermTyped* variable = sequence.front()->getAsTyped();
558 writeVariableType(variable->getType());
559 out << " ";
560 mDeclaringVariables = true;
561 }
562 else if (visit == InVisit)
563 {
564 out << ", ";
565 mDeclaringVariables = true;
566 }
567 else
568 {
569 mDeclaringVariables = false;
570 }
571 break;
572 }
573 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
574 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
575 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
576 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
577 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
578 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
579 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
580 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
581 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
582 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
583 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
584 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
585 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
586 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
587 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
588 case EOpConstructStruct:
589 if (visit == PreVisit)
590 {
591 const TType& type = node->getType();
592 ASSERT(type.getBasicType() == EbtStruct);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000593 out << hashName(type.getTypeName()) << "(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000594 }
595 else if (visit == InVisit)
596 {
597 out << ", ";
598 }
599 else
600 {
601 out << ")";
602 }
603 break;
604
zmo@google.comf420c422011-09-12 18:27:59 +0000605 case EOpLessThan: preString = "lessThan("; delayedWrite = true; break;
606 case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break;
607 case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break;
608 case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break;
609 case EOpVectorEqual: preString = "equal("; delayedWrite = true; break;
610 case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000611 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
612
zmo@google.comf420c422011-09-12 18:27:59 +0000613 case EOpMod: preString = "mod("; delayedWrite = true; break;
614 case EOpPow: preString = "pow("; delayedWrite = true; break;
615 case EOpAtan: preString = "atan("; delayedWrite = true; break;
616 case EOpMin: preString = "min("; delayedWrite = true; break;
617 case EOpMax: preString = "max("; delayedWrite = true; break;
618 case EOpClamp: preString = "clamp("; delayedWrite = true; break;
619 case EOpMix: preString = "mix("; delayedWrite = true; break;
620 case EOpStep: preString = "step("; delayedWrite = true; break;
621 case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000622
zmo@google.comf420c422011-09-12 18:27:59 +0000623 case EOpDistance: preString = "distance("; delayedWrite = true; break;
624 case EOpDot: preString = "dot("; delayedWrite = true; break;
625 case EOpCross: preString = "cross("; delayedWrite = true; break;
626 case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break;
627 case EOpReflect: preString = "reflect("; delayedWrite = true; break;
628 case EOpRefract: preString = "refract("; delayedWrite = true; break;
629 case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000630
631 default: UNREACHABLE(); break;
632 }
zmo@google.comf420c422011-09-12 18:27:59 +0000633 if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction())
634 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
635 if (delayedWrite)
636 writeTriplet(visit, preString.c_str(), ", ", ")");
zmo@google.com5601ea02011-06-10 18:23:25 +0000637 return visitChildren;
638}
639
640bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
641{
642 TInfoSinkBase& out = objSink();
643
644 incrementDepth();
645 // Loop header.
646 TLoopType loopType = node->getType();
647 if (loopType == ELoopFor) // for loop
648 {
649 if (!node->getUnrollFlag()) {
650 out << "for (";
651 if (node->getInit())
652 node->getInit()->traverse(this);
653 out << "; ";
654
655 if (node->getCondition())
656 node->getCondition()->traverse(this);
657 out << "; ";
658
659 if (node->getExpression())
660 node->getExpression()->traverse(this);
661 out << ")\n";
662 }
663 }
664 else if (loopType == ELoopWhile) // while loop
665 {
666 out << "while (";
667 ASSERT(node->getCondition() != NULL);
668 node->getCondition()->traverse(this);
669 out << ")\n";
670 }
671 else // do-while loop
672 {
673 ASSERT(loopType == ELoopDoWhile);
674 out << "do\n";
675 }
676
677 // Loop body.
678 if (node->getUnrollFlag())
679 {
680 TLoopIndexInfo indexInfo;
681 mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
682 mLoopUnroll.Push(indexInfo);
683 while (mLoopUnroll.SatisfiesLoopCondition())
684 {
685 visitCodeBlock(node->getBody());
686 mLoopUnroll.Step();
687 }
688 mLoopUnroll.Pop();
689 }
690 else
691 {
692 visitCodeBlock(node->getBody());
693 }
694
695 // Loop footer.
696 if (loopType == ELoopDoWhile) // do-while loop
697 {
698 out << "while (";
699 ASSERT(node->getCondition() != NULL);
700 node->getCondition()->traverse(this);
701 out << ");\n";
702 }
703 decrementDepth();
704
705 // No need to visit children. They have been already processed in
706 // this function.
707 return false;
708}
709
710bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
711{
712 switch (node->getFlowOp())
713 {
714 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
715 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
716 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
717 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
718 default: UNREACHABLE(); break;
719 }
720
721 return true;
722}
723
724void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
725 TInfoSinkBase &out = objSink();
726 if (node != NULL)
727 {
728 node->traverse(this);
729 // Single statements not part of a sequence need to be terminated
730 // with semi-colon.
731 if (isSingleStatement(node))
732 out << ";\n";
733 }
734 else
735 {
736 out << "{\n}\n"; // Empty code block.
737 }
738}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000739
740TString TOutputGLSLBase::getTypeName(const TType& type)
741{
742 TInfoSinkBase out;
743 if (type.isMatrix())
744 {
745 out << "mat";
746 out << type.getNominalSize();
747 }
748 else if (type.isVector())
749 {
750 switch (type.getBasicType())
751 {
752 case EbtFloat: out << "vec"; break;
753 case EbtInt: out << "ivec"; break;
754 case EbtBool: out << "bvec"; break;
755 default: UNREACHABLE(); break;
756 }
757 out << type.getNominalSize();
758 }
759 else
760 {
761 if (type.getBasicType() == EbtStruct)
762 out << hashName(type.getTypeName());
763 else
764 out << type.getBasicString();
765 }
766 return TString(out.c_str());
767}
768
769TString TOutputGLSLBase::hashName(const TString& name)
770{
771 if (mHashFunction == NULL || name.empty())
772 return name;
773 NameMap::const_iterator it = mNameMap.find(name.c_str());
774 if (it != mNameMap.end())
775 return it->second.c_str();
776 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
777 mNameMap[name.c_str()] = hashedName.c_str();
778 return hashedName;
779}
780
781TString TOutputGLSLBase::hashVariableName(const TString& name)
782{
783 if (mSymbolTable.findBuiltIn(name) != NULL)
784 return name;
785 return hashName(name);
786}
787
788TString TOutputGLSLBase::hashFunctionName(const TString& mangled_name)
789{
790 TString name = TFunction::unmangleName(mangled_name);
791 if (mSymbolTable.findBuiltIn(mangled_name) != NULL || name == "main")
792 return name;
793 return hashName(name);
794}