blob: 47bb3cd623550f80894c1f8f377a21d19b4701d3 [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 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400155 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000156 bool writeType = size > 1;
157 if (writeType) out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400158 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000159 {
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.com97b16d12013-02-01 03:20:42 +0000265 TString fieldName = node->getType().getFieldName();
266
267 const TType& structType = node->getLeft()->getType();
268 if (!mSymbolTable.findBuiltIn(structType.getTypeName()))
269 fieldName = hashName(fieldName);
270
271 out << fieldName;
zmo@google.com5601ea02011-06-10 18:23:25 +0000272 visitChildren = false;
273 }
274 break;
275 case EOpVectorSwizzle:
276 if (visit == InVisit)
277 {
278 out << ".";
279 TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
280 TIntermSequence& sequence = rightChild->getSequence();
281 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
282 {
283 TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
284 ASSERT(element->getBasicType() == EbtInt);
285 ASSERT(element->getNominalSize() == 1);
286 const ConstantUnion& data = element->getUnionArrayPointer()[0];
287 ASSERT(data.getType() == EbtInt);
288 switch (data.getIConst())
289 {
290 case 0: out << "x"; break;
291 case 1: out << "y"; break;
292 case 2: out << "z"; break;
293 case 3: out << "w"; break;
294 default: UNREACHABLE(); break;
295 }
296 }
297 visitChildren = false;
298 }
299 break;
300
301 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
302 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
303 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
304 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
305 case EOpMod: UNIMPLEMENTED(); break;
306 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
307 case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
308 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
309 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
310 case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
311 case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
312
313 // Notice the fall-through.
314 case EOpVectorTimesScalar:
315 case EOpVectorTimesMatrix:
316 case EOpMatrixTimesVector:
317 case EOpMatrixTimesScalar:
318 case EOpMatrixTimesMatrix:
319 writeTriplet(visit, "(", " * ", ")");
320 break;
321
322 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
323 case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
324 case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
325 default: UNREACHABLE(); break;
326 }
327
328 return visitChildren;
329}
330
331bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
332{
zmo@google.com32e97312011-08-24 01:03:11 +0000333 TString preString;
334 TString postString = ")";
335
zmo@google.com5601ea02011-06-10 18:23:25 +0000336 switch (node->getOp())
337 {
zmo@google.com32e97312011-08-24 01:03:11 +0000338 case EOpNegative: preString = "(-"; break;
339 case EOpVectorLogicalNot: preString = "not("; break;
340 case EOpLogicalNot: preString = "(!"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000341
zmo@google.com32e97312011-08-24 01:03:11 +0000342 case EOpPostIncrement: preString = "("; postString = "++)"; break;
343 case EOpPostDecrement: preString = "("; postString = "--)"; break;
344 case EOpPreIncrement: preString = "(++"; break;
345 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000346
347 case EOpConvIntToBool:
348 case EOpConvFloatToBool:
349 switch (node->getOperand()->getType().getNominalSize())
350 {
zmo@google.com32e97312011-08-24 01:03:11 +0000351 case 1: preString = "bool("; break;
352 case 2: preString = "bvec2("; break;
353 case 3: preString = "bvec3("; break;
354 case 4: preString = "bvec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000355 default: UNREACHABLE();
356 }
357 break;
358 case EOpConvBoolToFloat:
359 case EOpConvIntToFloat:
360 switch (node->getOperand()->getType().getNominalSize())
361 {
zmo@google.com32e97312011-08-24 01:03:11 +0000362 case 1: preString = "float("; break;
363 case 2: preString = "vec2("; break;
364 case 3: preString = "vec3("; break;
365 case 4: preString = "vec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000366 default: UNREACHABLE();
367 }
368 break;
369 case EOpConvFloatToInt:
370 case EOpConvBoolToInt:
371 switch (node->getOperand()->getType().getNominalSize())
372 {
zmo@google.com32e97312011-08-24 01:03:11 +0000373 case 1: preString = "int("; break;
374 case 2: preString = "ivec2("; break;
375 case 3: preString = "ivec3("; break;
376 case 4: preString = "ivec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000377 default: UNREACHABLE();
378 }
379 break;
380
zmo@google.com32e97312011-08-24 01:03:11 +0000381 case EOpRadians: preString = "radians("; break;
382 case EOpDegrees: preString = "degrees("; break;
383 case EOpSin: preString = "sin("; break;
384 case EOpCos: preString = "cos("; break;
385 case EOpTan: preString = "tan("; break;
386 case EOpAsin: preString = "asin("; break;
387 case EOpAcos: preString = "acos("; break;
388 case EOpAtan: preString = "atan("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000389
zmo@google.com32e97312011-08-24 01:03:11 +0000390 case EOpExp: preString = "exp("; break;
391 case EOpLog: preString = "log("; break;
392 case EOpExp2: preString = "exp2("; break;
393 case EOpLog2: preString = "log2("; break;
394 case EOpSqrt: preString = "sqrt("; break;
395 case EOpInverseSqrt: preString = "inversesqrt("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000396
zmo@google.com32e97312011-08-24 01:03:11 +0000397 case EOpAbs: preString = "abs("; break;
398 case EOpSign: preString = "sign("; break;
399 case EOpFloor: preString = "floor("; break;
400 case EOpCeil: preString = "ceil("; break;
401 case EOpFract: preString = "fract("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000402
zmo@google.com32e97312011-08-24 01:03:11 +0000403 case EOpLength: preString = "length("; break;
404 case EOpNormalize: preString = "normalize("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000405
zmo@google.com32e97312011-08-24 01:03:11 +0000406 case EOpDFdx: preString = "dFdx("; break;
407 case EOpDFdy: preString = "dFdy("; break;
408 case EOpFwidth: preString = "fwidth("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000409
zmo@google.com32e97312011-08-24 01:03:11 +0000410 case EOpAny: preString = "any("; break;
411 case EOpAll: preString = "all("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000412
413 default: UNREACHABLE(); break;
414 }
415
zmo@google.com32e97312011-08-24 01:03:11 +0000416 if (visit == PreVisit && node->getUseEmulatedFunction())
417 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
418 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
419
zmo@google.com5601ea02011-06-10 18:23:25 +0000420 return true;
421}
422
423bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
424{
425 TInfoSinkBase& out = objSink();
426
427 if (node->usesTernaryOperator())
428 {
429 // Notice two brackets at the beginning and end. The outer ones
430 // encapsulate the whole ternary expression. This preserves the
431 // order of precedence when ternary expressions are used in a
432 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
433 out << "((";
434 node->getCondition()->traverse(this);
435 out << ") ? (";
436 node->getTrueBlock()->traverse(this);
437 out << ") : (";
438 node->getFalseBlock()->traverse(this);
439 out << "))";
440 }
441 else
442 {
443 out << "if (";
444 node->getCondition()->traverse(this);
445 out << ")\n";
446
447 incrementDepth();
448 visitCodeBlock(node->getTrueBlock());
449
450 if (node->getFalseBlock())
451 {
452 out << "else\n";
453 visitCodeBlock(node->getFalseBlock());
454 }
455 decrementDepth();
456 }
457 return false;
458}
459
460bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
461{
462 bool visitChildren = true;
463 TInfoSinkBase& out = objSink();
zmo@google.comf420c422011-09-12 18:27:59 +0000464 TString preString;
465 bool delayedWrite = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000466 switch (node->getOp())
467 {
468 case EOpSequence: {
469 // Scope the sequences except when at the global scope.
470 if (depth > 0) out << "{\n";
471
472 incrementDepth();
473 const TIntermSequence& sequence = node->getSequence();
474 for (TIntermSequence::const_iterator iter = sequence.begin();
475 iter != sequence.end(); ++iter)
476 {
477 TIntermNode* node = *iter;
478 ASSERT(node != NULL);
479 node->traverse(this);
480
481 if (isSingleStatement(node))
482 out << ";\n";
483 }
484 decrementDepth();
485
486 // Scope the sequences except when at the global scope.
487 if (depth > 0) out << "}\n";
488 visitChildren = false;
489 break;
490 }
491 case EOpPrototype: {
492 // Function declaration.
493 ASSERT(visit == PreVisit);
kbr@chromium.org57f7ce02011-08-15 23:13:05 +0000494 writeVariableType(node->getType());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000495 out << " " << hashName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000496
497 out << "(";
498 writeFunctionParameters(node->getSequence());
499 out << ")";
500
501 visitChildren = false;
502 break;
503 }
504 case EOpFunction: {
505 // Function definition.
506 ASSERT(visit == PreVisit);
zmo@google.com189be2f2011-06-16 18:28:53 +0000507 writeVariableType(node->getType());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000508 out << " " << hashFunctionName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000509
510 incrementDepth();
511 // Function definition node contains one or two children nodes
512 // representing function parameters and function body. The latter
513 // is not present in case of empty function bodies.
514 const TIntermSequence& sequence = node->getSequence();
515 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
516 TIntermSequence::const_iterator seqIter = sequence.begin();
517
518 // Traverse function parameters.
519 TIntermAggregate* params = (*seqIter)->getAsAggregate();
520 ASSERT(params != NULL);
521 ASSERT(params->getOp() == EOpParameters);
522 params->traverse(this);
523
524 // Traverse function body.
525 TIntermAggregate* body = ++seqIter != sequence.end() ?
526 (*seqIter)->getAsAggregate() : NULL;
527 visitCodeBlock(body);
528 decrementDepth();
529
530 // Fully processed; no need to visit children.
531 visitChildren = false;
532 break;
533 }
534 case EOpFunctionCall:
535 // Function call.
536 if (visit == PreVisit)
537 {
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000538 out << hashFunctionName(node->getName()) << "(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000539 }
540 else if (visit == InVisit)
541 {
542 out << ", ";
543 }
544 else
545 {
546 out << ")";
547 }
548 break;
549 case EOpParameters: {
550 // Function parameters.
551 ASSERT(visit == PreVisit);
552 out << "(";
553 writeFunctionParameters(node->getSequence());
554 out << ")";
555 visitChildren = false;
556 break;
557 }
558 case EOpDeclaration: {
559 // Variable declaration.
560 if (visit == PreVisit)
561 {
562 const TIntermSequence& sequence = node->getSequence();
563 const TIntermTyped* variable = sequence.front()->getAsTyped();
564 writeVariableType(variable->getType());
565 out << " ";
566 mDeclaringVariables = true;
567 }
568 else if (visit == InVisit)
569 {
570 out << ", ";
571 mDeclaringVariables = true;
572 }
573 else
574 {
575 mDeclaringVariables = false;
576 }
577 break;
578 }
579 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
580 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
581 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
582 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
583 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
584 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
585 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
586 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
587 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
588 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
589 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
590 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
591 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
592 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
593 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
594 case EOpConstructStruct:
595 if (visit == PreVisit)
596 {
597 const TType& type = node->getType();
598 ASSERT(type.getBasicType() == EbtStruct);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000599 out << hashName(type.getTypeName()) << "(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000600 }
601 else if (visit == InVisit)
602 {
603 out << ", ";
604 }
605 else
606 {
607 out << ")";
608 }
609 break;
610
zmo@google.comf420c422011-09-12 18:27:59 +0000611 case EOpLessThan: preString = "lessThan("; delayedWrite = true; break;
612 case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break;
613 case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break;
614 case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break;
615 case EOpVectorEqual: preString = "equal("; delayedWrite = true; break;
616 case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000617 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
618
zmo@google.comf420c422011-09-12 18:27:59 +0000619 case EOpMod: preString = "mod("; delayedWrite = true; break;
620 case EOpPow: preString = "pow("; delayedWrite = true; break;
621 case EOpAtan: preString = "atan("; delayedWrite = true; break;
622 case EOpMin: preString = "min("; delayedWrite = true; break;
623 case EOpMax: preString = "max("; delayedWrite = true; break;
624 case EOpClamp: preString = "clamp("; delayedWrite = true; break;
625 case EOpMix: preString = "mix("; delayedWrite = true; break;
626 case EOpStep: preString = "step("; delayedWrite = true; break;
627 case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000628
zmo@google.comf420c422011-09-12 18:27:59 +0000629 case EOpDistance: preString = "distance("; delayedWrite = true; break;
630 case EOpDot: preString = "dot("; delayedWrite = true; break;
631 case EOpCross: preString = "cross("; delayedWrite = true; break;
632 case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break;
633 case EOpReflect: preString = "reflect("; delayedWrite = true; break;
634 case EOpRefract: preString = "refract("; delayedWrite = true; break;
635 case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000636
637 default: UNREACHABLE(); break;
638 }
zmo@google.comf420c422011-09-12 18:27:59 +0000639 if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction())
640 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
641 if (delayedWrite)
642 writeTriplet(visit, preString.c_str(), ", ", ")");
zmo@google.com5601ea02011-06-10 18:23:25 +0000643 return visitChildren;
644}
645
646bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
647{
648 TInfoSinkBase& out = objSink();
649
650 incrementDepth();
651 // Loop header.
652 TLoopType loopType = node->getType();
653 if (loopType == ELoopFor) // for loop
654 {
655 if (!node->getUnrollFlag()) {
656 out << "for (";
657 if (node->getInit())
658 node->getInit()->traverse(this);
659 out << "; ";
660
661 if (node->getCondition())
662 node->getCondition()->traverse(this);
663 out << "; ";
664
665 if (node->getExpression())
666 node->getExpression()->traverse(this);
667 out << ")\n";
668 }
669 }
670 else if (loopType == ELoopWhile) // while loop
671 {
672 out << "while (";
673 ASSERT(node->getCondition() != NULL);
674 node->getCondition()->traverse(this);
675 out << ")\n";
676 }
677 else // do-while loop
678 {
679 ASSERT(loopType == ELoopDoWhile);
680 out << "do\n";
681 }
682
683 // Loop body.
684 if (node->getUnrollFlag())
685 {
686 TLoopIndexInfo indexInfo;
687 mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
688 mLoopUnroll.Push(indexInfo);
689 while (mLoopUnroll.SatisfiesLoopCondition())
690 {
691 visitCodeBlock(node->getBody());
692 mLoopUnroll.Step();
693 }
694 mLoopUnroll.Pop();
695 }
696 else
697 {
698 visitCodeBlock(node->getBody());
699 }
700
701 // Loop footer.
702 if (loopType == ELoopDoWhile) // do-while loop
703 {
704 out << "while (";
705 ASSERT(node->getCondition() != NULL);
706 node->getCondition()->traverse(this);
707 out << ");\n";
708 }
709 decrementDepth();
710
711 // No need to visit children. They have been already processed in
712 // this function.
713 return false;
714}
715
716bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
717{
718 switch (node->getFlowOp())
719 {
720 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
721 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
722 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
723 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
724 default: UNREACHABLE(); break;
725 }
726
727 return true;
728}
729
730void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
731 TInfoSinkBase &out = objSink();
732 if (node != NULL)
733 {
734 node->traverse(this);
735 // Single statements not part of a sequence need to be terminated
736 // with semi-colon.
737 if (isSingleStatement(node))
738 out << ";\n";
739 }
740 else
741 {
742 out << "{\n}\n"; // Empty code block.
743 }
744}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000745
746TString TOutputGLSLBase::getTypeName(const TType& type)
747{
748 TInfoSinkBase out;
749 if (type.isMatrix())
750 {
751 out << "mat";
752 out << type.getNominalSize();
753 }
754 else if (type.isVector())
755 {
756 switch (type.getBasicType())
757 {
758 case EbtFloat: out << "vec"; break;
759 case EbtInt: out << "ivec"; break;
760 case EbtBool: out << "bvec"; break;
761 default: UNREACHABLE(); break;
762 }
763 out << type.getNominalSize();
764 }
765 else
766 {
767 if (type.getBasicType() == EbtStruct)
768 out << hashName(type.getTypeName());
769 else
770 out << type.getBasicString();
771 }
772 return TString(out.c_str());
773}
774
775TString TOutputGLSLBase::hashName(const TString& name)
776{
777 if (mHashFunction == NULL || name.empty())
778 return name;
779 NameMap::const_iterator it = mNameMap.find(name.c_str());
780 if (it != mNameMap.end())
781 return it->second.c_str();
782 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
783 mNameMap[name.c_str()] = hashedName.c_str();
784 return hashedName;
785}
786
787TString TOutputGLSLBase::hashVariableName(const TString& name)
788{
789 if (mSymbolTable.findBuiltIn(name) != NULL)
790 return name;
791 return hashName(name);
792}
793
794TString TOutputGLSLBase::hashFunctionName(const TString& mangled_name)
795{
796 TString name = TFunction::unmangleName(mangled_name);
797 if (mSymbolTable.findBuiltIn(mangled_name) != NULL || name == "main")
798 return name;
799 return hashName(name);
800}