blob: 936d1bbe77af216a2cb88a921f8542e29cdb8a69 [file] [log] [blame]
alokp@chromium.org76b82082010-03-24 17:59:39 +00001//
2// Copyright (c) 2002-2010 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
daniel@transgaming.combbf56f72010-04-20 18:52:13 +00007#include "compiler/OutputGLSL.h"
8
alokp@chromium.org76b82082010-03-24 17:59:39 +00009#include "common/debug.h"
10
11namespace
12{
13TString getTypeName(const TType& type)
14{
15 TInfoSinkBase out;
16 if (type.isMatrix())
17 {
18 out << "mat";
19 out << type.getNominalSize();
20 }
alokp@chromium.org76b82082010-03-24 17:59:39 +000021 else if (type.isVector())
22 {
23 switch (type.getBasicType())
24 {
25 case EbtFloat: out << "vec"; break;
26 case EbtInt: out << "ivec"; break;
27 case EbtBool: out << "bvec"; break;
28 default: UNREACHABLE(); break;
29 }
30 out << type.getNominalSize();
31 }
32 else
33 {
34 if (type.getBasicType() == EbtStruct)
35 out << type.getTypeName();
36 else
37 out << type.getBasicString();
38 }
39 return TString(out.c_str());
40}
alokp@chromium.org194522f2010-05-06 19:09:26 +000041
42TString arrayBrackets(const TType& type)
43{
44 ASSERT(type.isArray());
45 TInfoSinkBase out;
46 out << "[" << type.getArraySize() << "]";
47 return TString(out.c_str());
48}
alokp@chromium.org76b82082010-03-24 17:59:39 +000049} // namespace
50
alokp@chromium.orga499cfc2010-05-03 23:14:49 +000051TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink)
alokp@chromium.org76b82082010-03-24 17:59:39 +000052 : TIntermTraverser(true, true, true),
alokp@chromium.orga499cfc2010-05-03 23:14:49 +000053 mObjSink(objSink),
alokp@chromium.org194522f2010-05-06 19:09:26 +000054 mScopeSequences(false),
55 mDeclaringVariables(false)
alokp@chromium.org76b82082010-03-24 17:59:39 +000056{
57}
58
alokp@chromium.org76b82082010-03-24 17:59:39 +000059void TOutputGLSL::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
60{
61 TInfoSinkBase& out = objSink();
62 if (visit == PreVisit && preStr)
63 {
64 out << preStr;
65 }
66 else if (visit == InVisit && inStr)
67 {
68 out << inStr;
69 }
70 else if (visit == PostVisit && postStr)
71 {
72 out << postStr;
73 }
74}
75
alokp@chromium.org194522f2010-05-06 19:09:26 +000076void TOutputGLSL::writeVariableType(const TType& type)
77{
78 TInfoSinkBase& out = objSink();
79 TQualifier qualifier = type.getQualifier();
80 // TODO(alokp): Validate qualifier for variable declarations.
81 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
82 out << type.getQualifierString() << " ";
83
84 // Declare the struct if we have not done so already.
85 if ((type.getBasicType() == EbtStruct) &&
86 (mDeclaredStructs.find(type.getTypeName()) == mDeclaredStructs.end()))
87 {
88 out << "struct " << type.getTypeName() << "{\n";
89 const TTypeList* structure = type.getStruct();
90 ASSERT(structure != NULL);
91 for (size_t i = 0; i < structure->size(); ++i)
92 {
93 const TType* fieldType = (*structure)[i].type;
94 ASSERT(fieldType != NULL);
95 out << getTypeName(*fieldType) << " " << fieldType->getFieldName();
96 if (fieldType->isArray())
97 out << arrayBrackets(*fieldType);
98 out << ";\n";
99 }
100 out << "}";
101 mDeclaredStructs.insert(type.getTypeName());
102 }
103 else
104 {
105 out << getTypeName(type);
106 }
107}
108
109void TOutputGLSL::writeFunctionParameters(const TIntermSequence& args)
110{
111 TInfoSinkBase& out = objSink();
112 for (TIntermSequence::const_iterator iter = args.begin();
113 iter != args.end(); ++iter)
114 {
115 const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
116 ASSERT(arg != NULL);
117
118 const TType& type = arg->getType();
119 TQualifier qualifier = type.getQualifier();
120 // TODO(alokp): Validate qualifier for function arguments.
121 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
122 out << type.getQualifierString() << " ";
123
124 out << getTypeName(type);
125
126 const TString& name = arg->getSymbol();
127 if (!name.empty())
128 out << " " << name;
129 if (type.isArray())
130 out << arrayBrackets(type);
131
132 // Put a comma if this is not the last argument.
133 if (iter != --args.end())
134 out << ", ";
135 }
136}
137
138const ConstantUnion* TOutputGLSL::writeConstantUnion(const TType& type,
139 const ConstantUnion* pConstUnion)
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000140{
141 TInfoSinkBase& out = objSink();
142
143 if (type.getBasicType() == EbtStruct)
144 {
145 out << type.getTypeName() << "(";
146 const TTypeList* structure = type.getStruct();
147 ASSERT(structure != NULL);
148 for (size_t i = 0; i < structure->size(); ++i)
149 {
150 const TType* fieldType = (*structure)[i].type;
151 ASSERT(fieldType != NULL);
152 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
153 if (i != structure->size() - 1) out << ", ";
154 }
155 out << ")";
156 }
157 else
158 {
159 int size = type.getObjectSize();
160 bool writeType = size > 1;
161 if (writeType) out << getTypeName(type) << "(";
162 for (int i = 0; i < size; ++i, ++pConstUnion)
163 {
164 switch (pConstUnion->getType())
165 {
166 case EbtFloat: out << pConstUnion->getFConst(); break;
167 case EbtInt: out << pConstUnion->getIConst(); break;
168 case EbtBool:
169 if (pConstUnion->getBConst())
170 out << "true";
171 else
172 out << "false";
173 break;
174 default: UNREACHABLE();
175 }
176 if (i != size - 1) out << ", ";
177 }
178 if (writeType) out << ")";
179 }
180 return pConstUnion;
181}
182
alokp@chromium.org76b82082010-03-24 17:59:39 +0000183void TOutputGLSL::visitSymbol(TIntermSymbol* node)
184{
185 TInfoSinkBase& out = objSink();
alokp@chromium.org76b82082010-03-24 17:59:39 +0000186 out << node->getSymbol();
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000187
alokp@chromium.org194522f2010-05-06 19:09:26 +0000188 if (mDeclaringVariables && node->getType().isArray())
189 out << arrayBrackets(node->getType());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000190}
191
192void TOutputGLSL::visitConstantUnion(TIntermConstantUnion* node)
193{
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000194 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000195}
196
197bool TOutputGLSL::visitBinary(Visit visit, TIntermBinary* node)
198{
199 bool visitChildren = true;
200 TInfoSinkBase& out = objSink();
201 switch (node->getOp())
202 {
alokp@chromium.org76b82082010-03-24 17:59:39 +0000203 case EOpInitialize:
alokp@chromium.org194522f2010-05-06 19:09:26 +0000204 if (visit == InVisit)
205 {
alokp@chromium.org76b82082010-03-24 17:59:39 +0000206 out << " = ";
alokp@chromium.org194522f2010-05-06 19:09:26 +0000207 // RHS of initialize is not being declared.
208 mDeclaringVariables = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000209 }
210 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000211 case EOpAssign: writeTriplet(visit, NULL, " = ", NULL); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000212 case EOpAddAssign: writeTriplet(visit, NULL, " += ", NULL); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000213 case EOpSubAssign: writeTriplet(visit, NULL, " -= ", NULL); break;
214 case EOpDivAssign: writeTriplet(visit, NULL, " /= ", NULL); break;
215 case EOpMulAssign:
216 case EOpVectorTimesMatrixAssign:
217 case EOpVectorTimesScalarAssign:
218 case EOpMatrixTimesScalarAssign:
219 case EOpMatrixTimesMatrixAssign:
220 writeTriplet(visit, NULL, " *= ", NULL);
221 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000222
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000223 case EOpIndexDirect:
224 case EOpIndexIndirect:
225 writeTriplet(visit, NULL, "[", "]");
226 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000227 case EOpIndexDirectStruct:
228 if (visit == InVisit)
229 {
230 out << ".";
231 // TODO(alokp): ASSERT
232 out << node->getType().getFieldName();
233 visitChildren = false;
234 }
235 break;
236 case EOpVectorSwizzle:
237 if (visit == InVisit)
238 {
239 out << ".";
240 TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
241 TIntermSequence& sequence = rightChild->getSequence();
242 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
243 {
244 TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
245 ASSERT(element->getBasicType() == EbtInt);
246 ASSERT(element->getNominalSize() == 1);
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +0000247 const ConstantUnion& data = element->getUnionArrayPointer()[0];
alokp@chromium.org76b82082010-03-24 17:59:39 +0000248 ASSERT(data.getType() == EbtInt);
249 switch (data.getIConst())
250 {
251 case 0: out << "x"; break;
252 case 1: out << "y"; break;
253 case 2: out << "z"; break;
254 case 3: out << "w"; break;
255 default: UNREACHABLE(); break;
256 }
257 }
258 visitChildren = false;
259 }
260 break;
261
262 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
263 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
264 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
265 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
266 case EOpMod: UNIMPLEMENTED(); break;
alokp@chromium.org3d270782010-03-30 20:33:38 +0000267 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000268 case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000269 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
alokp@chromium.orgdd037b22010-03-30 18:47:20 +0000270 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000271 case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
272 case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000273
274 // Notice the fall-through.
275 case EOpVectorTimesScalar:
276 case EOpVectorTimesMatrix:
277 case EOpMatrixTimesVector:
278 case EOpMatrixTimesScalar:
279 case EOpMatrixTimesMatrix:
280 writeTriplet(visit, "(", " * ", ")");
281 break;
282
283 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000284 case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
285 case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000286 default: UNREACHABLE(); break;
287 }
288
289 return visitChildren;
290}
291
292bool TOutputGLSL::visitUnary(Visit visit, TIntermUnary* node)
293{
294 TInfoSinkBase& out = objSink();
295
296 switch (node->getOp())
297 {
298 case EOpNegative: writeTriplet(visit, "(-", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000299 case EOpVectorLogicalNot: writeTriplet(visit, "(!", NULL, ")"); break;
300 case EOpLogicalNot: writeTriplet(visit, "(!", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000301
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000302 case EOpPostIncrement: writeTriplet(visit, "(", NULL, "++)"); break;
303 case EOpPostDecrement: writeTriplet(visit, "(", NULL, "--)"); break;
304 case EOpPreIncrement: writeTriplet(visit, "(++", NULL, ")"); break;
305 case EOpPreDecrement: writeTriplet(visit, "(--", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000306
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000307 case EOpConvIntToBool:
308 case EOpConvFloatToBool:
309 switch (node->getOperand()->getType().getNominalSize())
310 {
311 case 1: writeTriplet(visit, "bool(", NULL, ")"); break;
312 case 2: writeTriplet(visit, "bvec2(", NULL, ")"); break;
313 case 3: writeTriplet(visit, "bvec3(", NULL, ")"); break;
314 case 4: writeTriplet(visit, "bvec4(", NULL, ")"); break;
315 default: UNREACHABLE();
316 }
317 break;
318 case EOpConvBoolToFloat:
319 case EOpConvIntToFloat:
320 switch (node->getOperand()->getType().getNominalSize())
321 {
322 case 1: writeTriplet(visit, "float(", NULL, ")"); break;
323 case 2: writeTriplet(visit, "vec2(", NULL, ")"); break;
324 case 3: writeTriplet(visit, "vec3(", NULL, ")"); break;
325 case 4: writeTriplet(visit, "vec4(", NULL, ")"); break;
326 default: UNREACHABLE();
327 }
328 break;
329 case EOpConvFloatToInt:
330 case EOpConvBoolToInt:
331 switch (node->getOperand()->getType().getNominalSize())
332 {
333 case 1: writeTriplet(visit, "int(", NULL, ")"); break;
334 case 2: writeTriplet(visit, "ivec2(", NULL, ")"); break;
335 case 3: writeTriplet(visit, "ivec3(", NULL, ")"); break;
336 case 4: writeTriplet(visit, "ivec4(", NULL, ")"); break;
337 default: UNREACHABLE();
338 }
339 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000340
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000341 case EOpRadians: writeTriplet(visit, "radians(", NULL, ")"); break;
342 case EOpDegrees: writeTriplet(visit, "degrees(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000343 case EOpSin: writeTriplet(visit, "sin(", NULL, ")"); break;
344 case EOpCos: writeTriplet(visit, "cos(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000345 case EOpTan: writeTriplet(visit, "tan(", NULL, ")"); break;
346 case EOpAsin: writeTriplet(visit, "asin(", NULL, ")"); break;
alokp@chromium.org3d270782010-03-30 20:33:38 +0000347 case EOpAcos: writeTriplet(visit, "acos(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000348 case EOpAtan: writeTriplet(visit, "atan(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000349
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000350 case EOpExp: writeTriplet(visit, "exp(", NULL, ")"); break;
351 case EOpLog: writeTriplet(visit, "log(", NULL, ")"); break;
352 case EOpExp2: writeTriplet(visit, "exp2(", NULL, ")"); break;
353 case EOpLog2: writeTriplet(visit, "log2(", NULL, ")"); break;
354 case EOpSqrt: writeTriplet(visit, "sqrt(", NULL, ")"); break;
355 case EOpInverseSqrt: writeTriplet(visit, "inversesqrt(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000356
alokp@chromium.org3d270782010-03-30 20:33:38 +0000357 case EOpAbs: writeTriplet(visit, "abs(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000358 case EOpSign: writeTriplet(visit, "sign(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000359 case EOpFloor: writeTriplet(visit, "floor(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000360 case EOpCeil: writeTriplet(visit, "ceil(", NULL, ")"); break;
361 case EOpFract: writeTriplet(visit, "fract(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000362
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000363 case EOpLength: writeTriplet(visit, "length(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000364 case EOpNormalize: writeTriplet(visit, "normalize(", NULL, ")"); break;
365
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000366 case EOpAny: writeTriplet(visit, "any(", NULL, ")"); break;
367 case EOpAll: writeTriplet(visit, "all(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000368
369 default: UNREACHABLE(); break;
370 }
371
372 return true;
373}
374
375bool TOutputGLSL::visitSelection(Visit visit, TIntermSelection* node)
376{
377 TInfoSinkBase& out = objSink();
378
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000379 if (node->usesTernaryOperator())
alokp@chromium.org76b82082010-03-24 17:59:39 +0000380 {
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000381 out << "(";
382 node->getCondition()->traverse(this);
383 out << ") ? (";
384 node->getTrueBlock()->traverse(this);
385 out << ") : (";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000386 node->getFalseBlock()->traverse(this);
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000387 out << ")";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000388 }
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000389 else
390 {
391 out << "if (";
392 node->getCondition()->traverse(this);
393 out << ") {\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000394
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000395 incrementDepth();
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000396 if (node->getTrueBlock())
397 {
398 node->getTrueBlock()->traverse(this);
399 }
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000400 out << ";\n}";
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000401
402 if (node->getFalseBlock())
403 {
404 out << " else {\n";
405 node->getFalseBlock()->traverse(this);
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000406 out << ";\n}";
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000407 }
408 decrementDepth();
409 out << "\n";
410 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000411 return false;
412}
413
414bool TOutputGLSL::visitAggregate(Visit visit, TIntermAggregate* node)
415{
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000416 bool visitChildren = true;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000417 TInfoSinkBase& out = objSink();
418 switch (node->getOp())
419 {
420 case EOpSequence:
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000421 if (visit == PreVisit)
422 {
423 if (mScopeSequences)
424 out << "{\n";
425 }
426 else if (visit == InVisit)
427 {
428 out << ";\n";
429 }
430 else if (visit == PostVisit)
431 {
432 out << ";\n";
433 if (mScopeSequences)
434 out << "}\n";
435 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000436 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000437 case EOpPrototype: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000438 // Function declaration.
alokp@chromium.org194522f2010-05-06 19:09:26 +0000439 ASSERT(visit == PreVisit);
440 TString returnType = getTypeName(node->getType());
441 out << returnType << " " << node->getName();
442
443 out << "(";
444 writeFunctionParameters(node->getSequence());
445 out << ")";
446
447 visitChildren = false;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000448 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000449 }
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000450 case EOpFunction: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000451 // Function definition.
alokp@chromium.org194522f2010-05-06 19:09:26 +0000452 ASSERT(visit == PreVisit);
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000453 TString returnType = getTypeName(node->getType());
454 TString functionName = TFunction::unmangleName(node->getName());
455 out << returnType << " " << functionName;
456
457 // Function definition node contains one or two children nodes
458 // representing function parameters and function body. The latter
459 // is not present in case of empty function bodies.
460 const TIntermSequence& sequence = node->getSequence();
461 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
462 TIntermSequence::const_iterator seqIter = sequence.begin();
463
464 // Traverse function parameters.
465 TIntermAggregate* params = (*seqIter)->getAsAggregate();
466 ASSERT(params != NULL);
467 ASSERT(params->getOp() == EOpParameters);
468 params->traverse(this);
469
470 // Traverse function body.
471 TIntermAggregate* body = ++seqIter != sequence.end() ?
472 (*seqIter)->getAsAggregate() : NULL;
473 if (body != NULL)
alokp@chromium.org76b82082010-03-24 17:59:39 +0000474 {
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000475 ASSERT(body->getOp() == EOpSequence);
476 // Sequences are scoped with {} inside function body so that
477 // variables are declared in the correct scope.
478 mScopeSequences = true;
479 body->traverse(this);
480 mScopeSequences = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000481 }
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000482 else
alokp@chromium.org76b82082010-03-24 17:59:39 +0000483 {
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000484 // Empty function body.
485 out << "{}\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000486 }
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000487
488 // Fully processed; no need to visit children.
489 visitChildren = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000490 break;
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000491 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000492 case EOpFunctionCall:
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000493 // Function call.
alokp@chromium.org76b82082010-03-24 17:59:39 +0000494 if (visit == PreVisit)
495 {
alokp@chromium.org43884872010-03-30 00:08:52 +0000496 TString functionName = TFunction::unmangleName(node->getName());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000497 out << functionName << "(";
498 }
499 else if (visit == InVisit)
500 {
501 out << ", ";
502 }
503 else
504 {
505 out << ")";
506 }
507 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000508 case EOpParameters: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000509 // Function parameters.
alokp@chromium.org194522f2010-05-06 19:09:26 +0000510 ASSERT(visit == PreVisit);
511 out << "(";
512 writeFunctionParameters(node->getSequence());
513 out << ")";
514 visitChildren = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000515 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000516 }
517 case EOpDeclaration: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000518 // Variable declaration.
alokp@chromium.org76b82082010-03-24 17:59:39 +0000519 if (visit == PreVisit)
520 {
alokp@chromium.org194522f2010-05-06 19:09:26 +0000521 const TIntermSequence& sequence = node->getSequence();
522 const TIntermTyped* variable = sequence.front()->getAsTyped();
523 writeVariableType(variable->getType());
524 out << " ";
525 mDeclaringVariables = true;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000526 }
527 else if (visit == InVisit)
528 {
529 out << ", ";
alokp@chromium.org194522f2010-05-06 19:09:26 +0000530 mDeclaringVariables = true;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000531 }
532 else
533 {
alokp@chromium.org194522f2010-05-06 19:09:26 +0000534 mDeclaringVariables = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000535 }
536 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000537 }
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000538 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
539 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
540 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
541 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
542 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
543 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
544 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
545 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
546 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
547 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
548 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
549 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
550 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
551 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
552 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000553 case EOpConstructStruct:
554 if (visit == PreVisit)
555 {
556 const TType& type = node->getType();
557 ASSERT(type.getBasicType() == EbtStruct);
558 out << type.getTypeName() << "(";
559 }
560 else if (visit == InVisit)
561 {
562 out << ", ";
563 }
564 else
565 {
566 out << ")";
567 }
568 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000569
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000570 case EOpLessThan: writeTriplet(visit, "lessThan(", ", ", ")"); break;
571 case EOpGreaterThan: writeTriplet(visit, "greaterThan(", ", ", ")"); break;
572 case EOpLessThanEqual: writeTriplet(visit, "lessThanEqual(", ", ", ")"); break;
573 case EOpGreaterThanEqual: writeTriplet(visit, "greaterThanEqual(", ", ", ")"); break;
574 case EOpVectorEqual: writeTriplet(visit, "equal(", ", ", ")"); break;
575 case EOpVectorNotEqual: writeTriplet(visit, "notEqual(", ", ", ")"); break;
576 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000577
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000578 case EOpMod: writeTriplet(visit, "mod(", ", ", ")"); break;
579 case EOpPow: writeTriplet(visit, "pow(", ", ", ")"); break;
580 case EOpAtan: writeTriplet(visit, "atan(", ", ", ")"); break;
581 case EOpMin: writeTriplet(visit, "min(", ", ", ")"); break;
582 case EOpMax: writeTriplet(visit, "max(", ", ", ")"); break;
583 case EOpClamp: writeTriplet(visit, "clamp(", ", ", ")"); break;
584 case EOpMix: writeTriplet(visit, "mix(", ", ", ")"); break;
585 case EOpStep: writeTriplet(visit, "step(", ", ", ")"); break;
586 case EOpSmoothStep: writeTriplet(visit, "smoothstep(", ", ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000587
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000588 case EOpDistance: writeTriplet(visit, "distance(", ", ", ")"); break;
589 case EOpDot: writeTriplet(visit, "dot(", ", ", ")"); break;
590 case EOpCross: writeTriplet(visit, "cross(", ", ", ")"); break;
591 case EOpFaceForward: writeTriplet(visit, "faceforward(", ", ", ")"); break;
592 case EOpReflect: writeTriplet(visit, "reflect(", ", ", ")"); break;
593 case EOpRefract: writeTriplet(visit, "refract(", ", ", ")"); break;
594 case EOpMul: writeTriplet(visit, "matrixCompMult(", ", ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000595
596 default: UNREACHABLE(); break;
597 }
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000598 return visitChildren;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000599}
600
601bool TOutputGLSL::visitLoop(Visit visit, TIntermLoop* node)
602{
alokp@chromium.org376e1062010-03-31 20:25:53 +0000603 TInfoSinkBase& out = objSink();
604
605 // Loop header.
606 if (node->testFirst()) // for loop
607 {
608 out << "for (";
609 if (node->getInit())
610 node->getInit()->traverse(this);
611 out << "; ";
612
613 ASSERT(node->getTest() != NULL);
614 node->getTest()->traverse(this);
615 out << "; ";
616
617 if (node->getTerminal())
618 node->getTerminal()->traverse(this);
619 out << ") {\n";
620 }
621 else // do-while loop
622 {
623 out << "do {\n";
624 }
625
626 // Loop body.
627 if (node->getBody())
628 node->getBody()->traverse(this);
629
630 // Loop footer.
631 if (node->testFirst()) // for loop
632 {
633 out << "}\n";
634 }
635 else // do-while loop
636 {
637 out << "} while (";
638 ASSERT(node->getTest() != NULL);
639 node->getTest()->traverse(this);
640 out << ");\n";
641 }
642
643 // No need to visit children. They have been already processed in
644 // this function.
645 return false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000646}
647
648bool TOutputGLSL::visitBranch(Visit visit, TIntermBranch* node)
649{
650 TInfoSinkBase &out = objSink();
651
652 switch (node->getFlowOp())
653 {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000654 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
655 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
656 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000657 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000658 default: UNREACHABLE(); break;
659 }
660
661 return true;
662}