blob: ed86c686d21eff3bc8cba5bd5e5bbd549bfe60c7 [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:
215 case EOpIndexIndirect:
216 writeTriplet(visit, NULL, "[", "]");
217 break;
218 case EOpIndexDirectStruct:
219 if (visit == InVisit)
220 {
221 out << ".";
222 // TODO(alokp): ASSERT
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000223 out << hashName(node->getType().getFieldName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000224 visitChildren = false;
225 }
226 break;
227 case EOpVectorSwizzle:
228 if (visit == InVisit)
229 {
230 out << ".";
231 TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
232 TIntermSequence& sequence = rightChild->getSequence();
233 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
234 {
235 TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
236 ASSERT(element->getBasicType() == EbtInt);
237 ASSERT(element->getNominalSize() == 1);
238 const ConstantUnion& data = element->getUnionArrayPointer()[0];
239 ASSERT(data.getType() == EbtInt);
240 switch (data.getIConst())
241 {
242 case 0: out << "x"; break;
243 case 1: out << "y"; break;
244 case 2: out << "z"; break;
245 case 3: out << "w"; break;
246 default: UNREACHABLE(); break;
247 }
248 }
249 visitChildren = false;
250 }
251 break;
252
253 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
254 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
255 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
256 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
257 case EOpMod: UNIMPLEMENTED(); break;
258 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
259 case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
260 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
261 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
262 case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
263 case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
264
265 // Notice the fall-through.
266 case EOpVectorTimesScalar:
267 case EOpVectorTimesMatrix:
268 case EOpMatrixTimesVector:
269 case EOpMatrixTimesScalar:
270 case EOpMatrixTimesMatrix:
271 writeTriplet(visit, "(", " * ", ")");
272 break;
273
274 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
275 case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
276 case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
277 default: UNREACHABLE(); break;
278 }
279
280 return visitChildren;
281}
282
283bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
284{
zmo@google.com32e97312011-08-24 01:03:11 +0000285 TString preString;
286 TString postString = ")";
287
zmo@google.com5601ea02011-06-10 18:23:25 +0000288 switch (node->getOp())
289 {
zmo@google.com32e97312011-08-24 01:03:11 +0000290 case EOpNegative: preString = "(-"; break;
291 case EOpVectorLogicalNot: preString = "not("; break;
292 case EOpLogicalNot: preString = "(!"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000293
zmo@google.com32e97312011-08-24 01:03:11 +0000294 case EOpPostIncrement: preString = "("; postString = "++)"; break;
295 case EOpPostDecrement: preString = "("; postString = "--)"; break;
296 case EOpPreIncrement: preString = "(++"; break;
297 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000298
299 case EOpConvIntToBool:
300 case EOpConvFloatToBool:
301 switch (node->getOperand()->getType().getNominalSize())
302 {
zmo@google.com32e97312011-08-24 01:03:11 +0000303 case 1: preString = "bool("; break;
304 case 2: preString = "bvec2("; break;
305 case 3: preString = "bvec3("; break;
306 case 4: preString = "bvec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000307 default: UNREACHABLE();
308 }
309 break;
310 case EOpConvBoolToFloat:
311 case EOpConvIntToFloat:
312 switch (node->getOperand()->getType().getNominalSize())
313 {
zmo@google.com32e97312011-08-24 01:03:11 +0000314 case 1: preString = "float("; break;
315 case 2: preString = "vec2("; break;
316 case 3: preString = "vec3("; break;
317 case 4: preString = "vec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000318 default: UNREACHABLE();
319 }
320 break;
321 case EOpConvFloatToInt:
322 case EOpConvBoolToInt:
323 switch (node->getOperand()->getType().getNominalSize())
324 {
zmo@google.com32e97312011-08-24 01:03:11 +0000325 case 1: preString = "int("; break;
326 case 2: preString = "ivec2("; break;
327 case 3: preString = "ivec3("; break;
328 case 4: preString = "ivec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000329 default: UNREACHABLE();
330 }
331 break;
332
zmo@google.com32e97312011-08-24 01:03:11 +0000333 case EOpRadians: preString = "radians("; break;
334 case EOpDegrees: preString = "degrees("; break;
335 case EOpSin: preString = "sin("; break;
336 case EOpCos: preString = "cos("; break;
337 case EOpTan: preString = "tan("; break;
338 case EOpAsin: preString = "asin("; break;
339 case EOpAcos: preString = "acos("; break;
340 case EOpAtan: preString = "atan("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000341
zmo@google.com32e97312011-08-24 01:03:11 +0000342 case EOpExp: preString = "exp("; break;
343 case EOpLog: preString = "log("; break;
344 case EOpExp2: preString = "exp2("; break;
345 case EOpLog2: preString = "log2("; break;
346 case EOpSqrt: preString = "sqrt("; break;
347 case EOpInverseSqrt: preString = "inversesqrt("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000348
zmo@google.com32e97312011-08-24 01:03:11 +0000349 case EOpAbs: preString = "abs("; break;
350 case EOpSign: preString = "sign("; break;
351 case EOpFloor: preString = "floor("; break;
352 case EOpCeil: preString = "ceil("; break;
353 case EOpFract: preString = "fract("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000354
zmo@google.com32e97312011-08-24 01:03:11 +0000355 case EOpLength: preString = "length("; break;
356 case EOpNormalize: preString = "normalize("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000357
zmo@google.com32e97312011-08-24 01:03:11 +0000358 case EOpDFdx: preString = "dFdx("; break;
359 case EOpDFdy: preString = "dFdy("; break;
360 case EOpFwidth: preString = "fwidth("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000361
zmo@google.com32e97312011-08-24 01:03:11 +0000362 case EOpAny: preString = "any("; break;
363 case EOpAll: preString = "all("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000364
365 default: UNREACHABLE(); break;
366 }
367
zmo@google.com32e97312011-08-24 01:03:11 +0000368 if (visit == PreVisit && node->getUseEmulatedFunction())
369 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
370 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
371
zmo@google.com5601ea02011-06-10 18:23:25 +0000372 return true;
373}
374
375bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
376{
377 TInfoSinkBase& out = objSink();
378
379 if (node->usesTernaryOperator())
380 {
381 // Notice two brackets at the beginning and end. The outer ones
382 // encapsulate the whole ternary expression. This preserves the
383 // order of precedence when ternary expressions are used in a
384 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
385 out << "((";
386 node->getCondition()->traverse(this);
387 out << ") ? (";
388 node->getTrueBlock()->traverse(this);
389 out << ") : (";
390 node->getFalseBlock()->traverse(this);
391 out << "))";
392 }
393 else
394 {
395 out << "if (";
396 node->getCondition()->traverse(this);
397 out << ")\n";
398
399 incrementDepth();
400 visitCodeBlock(node->getTrueBlock());
401
402 if (node->getFalseBlock())
403 {
404 out << "else\n";
405 visitCodeBlock(node->getFalseBlock());
406 }
407 decrementDepth();
408 }
409 return false;
410}
411
412bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
413{
414 bool visitChildren = true;
415 TInfoSinkBase& out = objSink();
zmo@google.comf420c422011-09-12 18:27:59 +0000416 TString preString;
417 bool delayedWrite = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000418 switch (node->getOp())
419 {
420 case EOpSequence: {
421 // Scope the sequences except when at the global scope.
422 if (depth > 0) out << "{\n";
423
424 incrementDepth();
425 const TIntermSequence& sequence = node->getSequence();
426 for (TIntermSequence::const_iterator iter = sequence.begin();
427 iter != sequence.end(); ++iter)
428 {
429 TIntermNode* node = *iter;
430 ASSERT(node != NULL);
431 node->traverse(this);
432
433 if (isSingleStatement(node))
434 out << ";\n";
435 }
436 decrementDepth();
437
438 // Scope the sequences except when at the global scope.
439 if (depth > 0) out << "}\n";
440 visitChildren = false;
441 break;
442 }
443 case EOpPrototype: {
444 // Function declaration.
445 ASSERT(visit == PreVisit);
kbr@chromium.org57f7ce02011-08-15 23:13:05 +0000446 writeVariableType(node->getType());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000447 out << " " << hashName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000448
449 out << "(";
450 writeFunctionParameters(node->getSequence());
451 out << ")";
452
453 visitChildren = false;
454 break;
455 }
456 case EOpFunction: {
457 // Function definition.
458 ASSERT(visit == PreVisit);
zmo@google.com189be2f2011-06-16 18:28:53 +0000459 writeVariableType(node->getType());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000460 out << " " << hashFunctionName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000461
462 incrementDepth();
463 // Function definition node contains one or two children nodes
464 // representing function parameters and function body. The latter
465 // is not present in case of empty function bodies.
466 const TIntermSequence& sequence = node->getSequence();
467 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
468 TIntermSequence::const_iterator seqIter = sequence.begin();
469
470 // Traverse function parameters.
471 TIntermAggregate* params = (*seqIter)->getAsAggregate();
472 ASSERT(params != NULL);
473 ASSERT(params->getOp() == EOpParameters);
474 params->traverse(this);
475
476 // Traverse function body.
477 TIntermAggregate* body = ++seqIter != sequence.end() ?
478 (*seqIter)->getAsAggregate() : NULL;
479 visitCodeBlock(body);
480 decrementDepth();
481
482 // Fully processed; no need to visit children.
483 visitChildren = false;
484 break;
485 }
486 case EOpFunctionCall:
487 // Function call.
488 if (visit == PreVisit)
489 {
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000490 out << hashFunctionName(node->getName()) << "(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000491 }
492 else if (visit == InVisit)
493 {
494 out << ", ";
495 }
496 else
497 {
498 out << ")";
499 }
500 break;
501 case EOpParameters: {
502 // Function parameters.
503 ASSERT(visit == PreVisit);
504 out << "(";
505 writeFunctionParameters(node->getSequence());
506 out << ")";
507 visitChildren = false;
508 break;
509 }
510 case EOpDeclaration: {
511 // Variable declaration.
512 if (visit == PreVisit)
513 {
514 const TIntermSequence& sequence = node->getSequence();
515 const TIntermTyped* variable = sequence.front()->getAsTyped();
516 writeVariableType(variable->getType());
517 out << " ";
518 mDeclaringVariables = true;
519 }
520 else if (visit == InVisit)
521 {
522 out << ", ";
523 mDeclaringVariables = true;
524 }
525 else
526 {
527 mDeclaringVariables = false;
528 }
529 break;
530 }
531 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
532 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
533 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
534 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
535 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
536 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
537 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
538 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
539 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
540 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
541 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
542 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
543 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
544 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
545 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
546 case EOpConstructStruct:
547 if (visit == PreVisit)
548 {
549 const TType& type = node->getType();
550 ASSERT(type.getBasicType() == EbtStruct);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000551 out << hashName(type.getTypeName()) << "(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000552 }
553 else if (visit == InVisit)
554 {
555 out << ", ";
556 }
557 else
558 {
559 out << ")";
560 }
561 break;
562
zmo@google.comf420c422011-09-12 18:27:59 +0000563 case EOpLessThan: preString = "lessThan("; delayedWrite = true; break;
564 case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break;
565 case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break;
566 case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break;
567 case EOpVectorEqual: preString = "equal("; delayedWrite = true; break;
568 case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000569 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
570
zmo@google.comf420c422011-09-12 18:27:59 +0000571 case EOpMod: preString = "mod("; delayedWrite = true; break;
572 case EOpPow: preString = "pow("; delayedWrite = true; break;
573 case EOpAtan: preString = "atan("; delayedWrite = true; break;
574 case EOpMin: preString = "min("; delayedWrite = true; break;
575 case EOpMax: preString = "max("; delayedWrite = true; break;
576 case EOpClamp: preString = "clamp("; delayedWrite = true; break;
577 case EOpMix: preString = "mix("; delayedWrite = true; break;
578 case EOpStep: preString = "step("; delayedWrite = true; break;
579 case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000580
zmo@google.comf420c422011-09-12 18:27:59 +0000581 case EOpDistance: preString = "distance("; delayedWrite = true; break;
582 case EOpDot: preString = "dot("; delayedWrite = true; break;
583 case EOpCross: preString = "cross("; delayedWrite = true; break;
584 case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break;
585 case EOpReflect: preString = "reflect("; delayedWrite = true; break;
586 case EOpRefract: preString = "refract("; delayedWrite = true; break;
587 case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000588
589 default: UNREACHABLE(); break;
590 }
zmo@google.comf420c422011-09-12 18:27:59 +0000591 if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction())
592 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
593 if (delayedWrite)
594 writeTriplet(visit, preString.c_str(), ", ", ")");
zmo@google.com5601ea02011-06-10 18:23:25 +0000595 return visitChildren;
596}
597
598bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
599{
600 TInfoSinkBase& out = objSink();
601
602 incrementDepth();
603 // Loop header.
604 TLoopType loopType = node->getType();
605 if (loopType == ELoopFor) // for loop
606 {
607 if (!node->getUnrollFlag()) {
608 out << "for (";
609 if (node->getInit())
610 node->getInit()->traverse(this);
611 out << "; ";
612
613 if (node->getCondition())
614 node->getCondition()->traverse(this);
615 out << "; ";
616
617 if (node->getExpression())
618 node->getExpression()->traverse(this);
619 out << ")\n";
620 }
621 }
622 else if (loopType == ELoopWhile) // while loop
623 {
624 out << "while (";
625 ASSERT(node->getCondition() != NULL);
626 node->getCondition()->traverse(this);
627 out << ")\n";
628 }
629 else // do-while loop
630 {
631 ASSERT(loopType == ELoopDoWhile);
632 out << "do\n";
633 }
634
635 // Loop body.
636 if (node->getUnrollFlag())
637 {
638 TLoopIndexInfo indexInfo;
639 mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
640 mLoopUnroll.Push(indexInfo);
641 while (mLoopUnroll.SatisfiesLoopCondition())
642 {
643 visitCodeBlock(node->getBody());
644 mLoopUnroll.Step();
645 }
646 mLoopUnroll.Pop();
647 }
648 else
649 {
650 visitCodeBlock(node->getBody());
651 }
652
653 // Loop footer.
654 if (loopType == ELoopDoWhile) // do-while loop
655 {
656 out << "while (";
657 ASSERT(node->getCondition() != NULL);
658 node->getCondition()->traverse(this);
659 out << ");\n";
660 }
661 decrementDepth();
662
663 // No need to visit children. They have been already processed in
664 // this function.
665 return false;
666}
667
668bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
669{
670 switch (node->getFlowOp())
671 {
672 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
673 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
674 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
675 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
676 default: UNREACHABLE(); break;
677 }
678
679 return true;
680}
681
682void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
683 TInfoSinkBase &out = objSink();
684 if (node != NULL)
685 {
686 node->traverse(this);
687 // Single statements not part of a sequence need to be terminated
688 // with semi-colon.
689 if (isSingleStatement(node))
690 out << ";\n";
691 }
692 else
693 {
694 out << "{\n}\n"; // Empty code block.
695 }
696}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000697
698TString TOutputGLSLBase::getTypeName(const TType& type)
699{
700 TInfoSinkBase out;
701 if (type.isMatrix())
702 {
703 out << "mat";
704 out << type.getNominalSize();
705 }
706 else if (type.isVector())
707 {
708 switch (type.getBasicType())
709 {
710 case EbtFloat: out << "vec"; break;
711 case EbtInt: out << "ivec"; break;
712 case EbtBool: out << "bvec"; break;
713 default: UNREACHABLE(); break;
714 }
715 out << type.getNominalSize();
716 }
717 else
718 {
719 if (type.getBasicType() == EbtStruct)
720 out << hashName(type.getTypeName());
721 else
722 out << type.getBasicString();
723 }
724 return TString(out.c_str());
725}
726
727TString TOutputGLSLBase::hashName(const TString& name)
728{
729 if (mHashFunction == NULL || name.empty())
730 return name;
731 NameMap::const_iterator it = mNameMap.find(name.c_str());
732 if (it != mNameMap.end())
733 return it->second.c_str();
734 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
735 mNameMap[name.c_str()] = hashedName.c_str();
736 return hashedName;
737}
738
739TString TOutputGLSLBase::hashVariableName(const TString& name)
740{
741 if (mSymbolTable.findBuiltIn(name) != NULL)
742 return name;
743 return hashName(name);
744}
745
746TString TOutputGLSLBase::hashFunctionName(const TString& mangled_name)
747{
748 TString name = TFunction::unmangleName(mangled_name);
749 if (mSymbolTable.findBuiltIn(mangled_name) != NULL || name == "main")
750 return name;
751 return hashName(name);
752}