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