blob: a4a766faf0b9a00a223fe9b9b39a7b13431abfc4 [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}
41
alokp@chromium.org76b82082010-03-24 17:59:39 +000042TString getIndentationString(int depth)
43{
44 TString indentation(depth, ' ');
45 return indentation;
46}
47} // namespace
48
49TOutputGLSL::TOutputGLSL(TParseContext &context)
50 : TIntermTraverser(true, true, true),
51 writeFullSymbol(false),
52 parseContext(context)
53{
54}
55
alokp@chromium.orgdd037b22010-03-30 18:47:20 +000056// Header declares user-defined structs.
alokp@chromium.org76b82082010-03-24 17:59:39 +000057void TOutputGLSL::header()
58{
59 TInfoSinkBase& out = objSink();
60
61 TSymbolTableLevel* symbols = parseContext.symbolTable.getGlobalLevel();
62 for (TSymbolTableLevel::const_iterator symbolIter = symbols->begin(); symbolIter != symbols->end(); ++symbolIter)
63 {
64 const TSymbol* symbol = symbolIter->second;
65 if (!symbol->isVariable())
66 continue;
67
68 const TVariable* variable = static_cast<const TVariable*>(symbol);
alokp@chromium.orgdd037b22010-03-30 18:47:20 +000069 if (!variable->isUserType())
70 continue;
alokp@chromium.org76b82082010-03-24 17:59:39 +000071
alokp@chromium.orgdd037b22010-03-30 18:47:20 +000072 const TType& type = variable->getType();
73 ASSERT(type.getQualifier() == EvqTemporary);
74 ASSERT(type.getBasicType() == EbtStruct);
75
76 out << "struct " << variable->getName() << "{\n";
77 const TTypeList* structure = type.getStruct();
78 ASSERT(structure != NULL);
79 incrementDepth();
80 for (size_t i = 0; i < structure->size(); ++i) {
81 const TType* fieldType = (*structure)[i].type;
82 ASSERT(fieldType != NULL);
83 out << getIndentationString(depth);
84 out << getTypeName(*fieldType) << " " << fieldType->getFieldName() << ";\n";
85 }
86 decrementDepth();
87 out << "};\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +000088 }
89}
90
91void TOutputGLSL::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
92{
93 TInfoSinkBase& out = objSink();
94 if (visit == PreVisit && preStr)
95 {
96 out << preStr;
97 }
98 else if (visit == InVisit && inStr)
99 {
100 out << inStr;
101 }
102 else if (visit == PostVisit && postStr)
103 {
104 out << postStr;
105 }
106}
107
108void TOutputGLSL::visitSymbol(TIntermSymbol* node)
109{
110 TInfoSinkBase& out = objSink();
111 if (writeFullSymbol)
112 {
113 TQualifier qualifier = node->getQualifier();
114 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
115 out << node->getQualifierString() << " ";
116
117 out << getTypeName(node->getType()) << " ";
118 }
119 out << node->getSymbol();
alokp@chromium.org3d270782010-03-30 20:33:38 +0000120 if (writeFullSymbol && node->getType().isArray())
121 {
122 out << "[" << node->getType().getArraySize() << "]";
123 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000124}
125
126void TOutputGLSL::visitConstantUnion(TIntermConstantUnion* node)
127{
128 TInfoSinkBase& out = objSink();
129
130 TType type = node->getType();
131 int size = type.getObjectSize();
132 if (size > 1)
133 out << getTypeName(type) << "(";
134 for (int i = 0; i < size; ++i) {
135 const constUnion& data = node->getUnionArrayPointer()[i];
136 switch (data.getType())
137 {
138 case EbtFloat: out << data.getFConst(); break;
139 case EbtInt: out << data.getIConst(); break;
140 case EbtBool: out << data.getBConst(); break;
141 default: UNREACHABLE(); break;
142 }
143 if (i != size - 1)
144 out << ", ";
145 }
146 if (size > 1)
147 out << ")";
148}
149
150bool TOutputGLSL::visitBinary(Visit visit, TIntermBinary* node)
151{
152 bool visitChildren = true;
153 TInfoSinkBase& out = objSink();
154 switch (node->getOp())
155 {
156 case EOpAssign: writeTriplet(visit, NULL, " = ", NULL); break;
157 case EOpInitialize:
158 if (visit == InVisit) {
159 out << " = ";
160 writeFullSymbol= false;
161 }
162 break;
163 case EOpAddAssign: writeTriplet(visit, NULL, " += ", NULL); break;
164 case EOpSubAssign: UNIMPLEMENTED(); break;
alokp@chromium.org3d270782010-03-30 20:33:38 +0000165 case EOpMulAssign: writeTriplet(visit, NULL, " *= ", NULL); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000166 case EOpVectorTimesMatrixAssign: UNIMPLEMENTED(); break;
167 case EOpVectorTimesScalarAssign: UNIMPLEMENTED(); break;
168 case EOpMatrixTimesScalarAssign: UNIMPLEMENTED(); break;
169 case EOpMatrixTimesMatrixAssign: UNIMPLEMENTED(); break;
170 case EOpDivAssign: UNIMPLEMENTED(); break;
171
172 case EOpIndexDirect: writeTriplet(visit, NULL, "[", "]"); break;
173 case EOpIndexIndirect: UNIMPLEMENTED(); break;
174 case EOpIndexDirectStruct:
175 if (visit == InVisit)
176 {
177 out << ".";
178 // TODO(alokp): ASSERT
179 out << node->getType().getFieldName();
180 visitChildren = false;
181 }
182 break;
183 case EOpVectorSwizzle:
184 if (visit == InVisit)
185 {
186 out << ".";
187 TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
188 TIntermSequence& sequence = rightChild->getSequence();
189 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
190 {
191 TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
192 ASSERT(element->getBasicType() == EbtInt);
193 ASSERT(element->getNominalSize() == 1);
194 const constUnion& data = element->getUnionArrayPointer()[0];
195 ASSERT(data.getType() == EbtInt);
196 switch (data.getIConst())
197 {
198 case 0: out << "x"; break;
199 case 1: out << "y"; break;
200 case 2: out << "z"; break;
201 case 3: out << "w"; break;
202 default: UNREACHABLE(); break;
203 }
204 }
205 visitChildren = false;
206 }
207 break;
208
209 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
210 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
211 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
212 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
213 case EOpMod: UNIMPLEMENTED(); break;
alokp@chromium.org3d270782010-03-30 20:33:38 +0000214 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000215 case EOpNotEqual: UNIMPLEMENTED(); break;
216 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
alokp@chromium.orgdd037b22010-03-30 18:47:20 +0000217 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000218 case EOpLessThanEqual: UNIMPLEMENTED(); break;
219 case EOpGreaterThanEqual: UNIMPLEMENTED(); break;
220
221 // Notice the fall-through.
222 case EOpVectorTimesScalar:
223 case EOpVectorTimesMatrix:
224 case EOpMatrixTimesVector:
225 case EOpMatrixTimesScalar:
226 case EOpMatrixTimesMatrix:
227 writeTriplet(visit, "(", " * ", ")");
228 break;
229
230 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
231 case EOpLogicalXor: UNIMPLEMENTED(); break;
232 case EOpLogicalAnd: UNIMPLEMENTED(); break;
233 default: UNREACHABLE(); break;
234 }
235
236 return visitChildren;
237}
238
239bool TOutputGLSL::visitUnary(Visit visit, TIntermUnary* node)
240{
241 TInfoSinkBase& out = objSink();
242
243 switch (node->getOp())
244 {
245 case EOpNegative: writeTriplet(visit, "(-", NULL, ")"); break;
246 case EOpVectorLogicalNot: UNIMPLEMENTED(); break;
247 case EOpLogicalNot: UNIMPLEMENTED(); break;
248
249 case EOpPostIncrement: UNIMPLEMENTED(); break;
250 case EOpPostDecrement: UNIMPLEMENTED(); break;
251 case EOpPreIncrement: UNIMPLEMENTED(); break;
252 case EOpPreDecrement: UNIMPLEMENTED(); break;
253
254 case EOpConvIntToBool: UNIMPLEMENTED(); break;
255 case EOpConvFloatToBool: UNIMPLEMENTED(); break;
256 case EOpConvBoolToFloat: UNIMPLEMENTED(); break;
257 case EOpConvIntToFloat: writeTriplet(visit, "float(", NULL, ")"); break;
alokp@chromium.org3d270782010-03-30 20:33:38 +0000258 case EOpConvFloatToInt: writeTriplet(visit, "int(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000259 case EOpConvBoolToInt: UNIMPLEMENTED(); break;
260
261 case EOpRadians: UNIMPLEMENTED(); break;
262 case EOpDegrees: UNIMPLEMENTED(); break;
263 case EOpSin: writeTriplet(visit, "sin(", NULL, ")"); break;
264 case EOpCos: writeTriplet(visit, "cos(", NULL, ")"); break;
265 case EOpTan: UNIMPLEMENTED(); break;
266 case EOpAsin: UNIMPLEMENTED(); break;
alokp@chromium.org3d270782010-03-30 20:33:38 +0000267 case EOpAcos: writeTriplet(visit, "acos(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000268 case EOpAtan: UNIMPLEMENTED(); break;
269
270 case EOpExp: UNIMPLEMENTED(); break;
271 case EOpLog: UNIMPLEMENTED(); break;
272 case EOpExp2: UNIMPLEMENTED(); break;
273 case EOpLog2: UNIMPLEMENTED(); break;
274 case EOpSqrt: UNIMPLEMENTED(); break;
275 case EOpInverseSqrt: UNIMPLEMENTED(); break;
276
alokp@chromium.org3d270782010-03-30 20:33:38 +0000277 case EOpAbs: writeTriplet(visit, "abs(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000278 case EOpSign: UNIMPLEMENTED(); break;
279 case EOpFloor: writeTriplet(visit, "floor(", NULL, ")"); break;
280 case EOpCeil: UNIMPLEMENTED(); break;
281 case EOpFract: UNIMPLEMENTED(); break;
282
283 case EOpLength: UNIMPLEMENTED(); break;
284 case EOpNormalize: writeTriplet(visit, "normalize(", NULL, ")"); break;
285
286 case EOpAny: UNIMPLEMENTED(); break;
287 case EOpAll: UNIMPLEMENTED(); break;
288
289 default: UNREACHABLE(); break;
290 }
291
292 return true;
293}
294
295bool TOutputGLSL::visitSelection(Visit visit, TIntermSelection* node)
296{
297 TInfoSinkBase& out = objSink();
298
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000299 if (node->usesTernaryOperator())
alokp@chromium.org76b82082010-03-24 17:59:39 +0000300 {
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000301 out << "(";
302 node->getCondition()->traverse(this);
303 out << ") ? (";
304 node->getTrueBlock()->traverse(this);
305 out << ") : (";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000306 node->getFalseBlock()->traverse(this);
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000307 out << ")";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000308 }
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000309 else
310 {
311 out << "if (";
312 node->getCondition()->traverse(this);
313 out << ") {\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000314
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000315 incrementDepth();
316 node->getTrueBlock()->traverse(this);
317 out << getIndentationString(depth - 2) << "}";
318
319 if (node->getFalseBlock())
320 {
321 out << " else {\n";
322 node->getFalseBlock()->traverse(this);
323 out << getIndentationString(depth - 2) << "}";
324 }
325 decrementDepth();
326 out << "\n";
327 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000328 return false;
329}
330
331bool TOutputGLSL::visitAggregate(Visit visit, TIntermAggregate* node)
332{
333 TInfoSinkBase& out = objSink();
334 switch (node->getOp())
335 {
336 case EOpSequence:
337 if (visit == PreVisit)
338 {
339 out << getIndentationString(depth);
340 }
341 else if (visit == InVisit)
342 {
343 out << ";\n";
344 out << getIndentationString(depth - 1);
345 }
346 else
347 {
348 out << ";\n";
349 }
350 break;
351 case EOpComma:
352 UNIMPLEMENTED();
353 return true;
354 case EOpFunction:
355 if (visit == PreVisit)
356 {
alokp@chromium.orgdd037b22010-03-30 18:47:20 +0000357 TString returnType = getTypeName(node->getType());
alokp@chromium.org43884872010-03-30 00:08:52 +0000358 TString functionName = TFunction::unmangleName(node->getName());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000359 out << returnType << " " << functionName;
360 }
361 else if (visit == InVisit)
362 {
363 // Called after traversing function arguments (EOpParameters)
364 // but before traversing function body (EOpSequence).
365 out << "{\n";
366 }
367 else if (visit == PostVisit)
368 {
369 // Called after traversing function body (EOpSequence).
370 out << "}\n";
371 }
372 break;
373 case EOpFunctionCall:
374 if (visit == PreVisit)
375 {
alokp@chromium.org43884872010-03-30 00:08:52 +0000376 TString functionName = TFunction::unmangleName(node->getName());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000377 out << functionName << "(";
378 }
379 else if (visit == InVisit)
380 {
381 out << ", ";
382 }
383 else
384 {
385 out << ")";
386 }
387 break;
388 case EOpParameters:
389 if (visit == PreVisit)
390 {
391 out << "(";
392 writeFullSymbol = true;
393 }
394 else if (visit == InVisit)
395 {
396 out << ", ";
397 }
398 else
399 {
400 out << ")";
401 writeFullSymbol = false;
402 }
403 break;
404 case EOpDeclaration:
405 if (visit == PreVisit)
406 {
407 writeFullSymbol = true;
408 }
409 else if (visit == InVisit)
410 {
411 out << ", ";
412 writeFullSymbol = false;
413 }
414 else
415 {
416 writeFullSymbol = false;
417 }
418 break;
419
420 case EOpConstructFloat: UNIMPLEMENTED(); break;
421 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
422 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
423 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
424 case EOpConstructBool: UNIMPLEMENTED(); break;
425 case EOpConstructBVec2: UNIMPLEMENTED(); break;
426 case EOpConstructBVec3: UNIMPLEMENTED(); break;
427 case EOpConstructBVec4: UNIMPLEMENTED(); break;
428 case EOpConstructInt: UNIMPLEMENTED(); break;
429 case EOpConstructIVec2: UNIMPLEMENTED(); break;
430 case EOpConstructIVec3: UNIMPLEMENTED(); break;
431 case EOpConstructIVec4: UNIMPLEMENTED(); break;
432 case EOpConstructMat2: UNIMPLEMENTED(); break;
433 case EOpConstructMat3: UNIMPLEMENTED(); break;
434 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
435 case EOpConstructStruct: UNIMPLEMENTED(); break;
436
437 case EOpLessThan: UNIMPLEMENTED(); break;
438 case EOpGreaterThan: UNIMPLEMENTED(); break;
439 case EOpLessThanEqual: UNIMPLEMENTED(); break;
440 case EOpGreaterThanEqual: UNIMPLEMENTED(); break;
441 case EOpVectorEqual: UNIMPLEMENTED(); break;
442 case EOpVectorNotEqual: UNIMPLEMENTED(); break;
443
444 case EOpMod: writeTriplet(visit, "mod(", ", ", ")"); break;
445 case EOpPow: writeTriplet(visit, "pow(", ", ", ")"); break;
446
447 case EOpAtan: UNIMPLEMENTED(); break;
448
449 case EOpMin: writeTriplet(visit, "min(", ", ", ")"); break;
450 case EOpMax: writeTriplet(visit, "max(", ", ", ")"); break;
451 case EOpClamp: writeTriplet(visit, "clamp(", ", ", ")"); break;
452 case EOpMix: writeTriplet(visit, "mix(", ", ", ")"); break;
453 case EOpStep: UNIMPLEMENTED(); break;
454 case EOpSmoothStep: UNIMPLEMENTED(); break;
455
456 case EOpDistance: UNIMPLEMENTED(); break;
457 case EOpDot: writeTriplet(visit, "dot(", ", ", ")"); break;
458 case EOpCross: UNIMPLEMENTED(); break;
459 case EOpFaceForward: UNIMPLEMENTED(); break;
460 case EOpReflect: writeTriplet(visit, "reflect(", ", ", ")"); break;
461 case EOpRefract: UNIMPLEMENTED(); break;
462 case EOpMul: UNIMPLEMENTED(); break;
463
464 default: UNREACHABLE(); break;
465 }
466 return true;
467}
468
469bool TOutputGLSL::visitLoop(Visit visit, TIntermLoop* node)
470{
alokp@chromium.org376e1062010-03-31 20:25:53 +0000471 TInfoSinkBase& out = objSink();
472
473 // Loop header.
474 if (node->testFirst()) // for loop
475 {
476 out << "for (";
477 if (node->getInit())
478 node->getInit()->traverse(this);
479 out << "; ";
480
481 ASSERT(node->getTest() != NULL);
482 node->getTest()->traverse(this);
483 out << "; ";
484
485 if (node->getTerminal())
486 node->getTerminal()->traverse(this);
487 out << ") {\n";
488 }
489 else // do-while loop
490 {
491 out << "do {\n";
492 }
493
494 // Loop body.
495 if (node->getBody())
496 node->getBody()->traverse(this);
497
498 // Loop footer.
499 if (node->testFirst()) // for loop
500 {
501 out << "}\n";
502 }
503 else // do-while loop
504 {
505 out << "} while (";
506 ASSERT(node->getTest() != NULL);
507 node->getTest()->traverse(this);
508 out << ");\n";
509 }
510
511 // No need to visit children. They have been already processed in
512 // this function.
513 return false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000514}
515
516bool TOutputGLSL::visitBranch(Visit visit, TIntermBranch* node)
517{
518 TInfoSinkBase &out = objSink();
519
520 switch (node->getFlowOp())
521 {
522 case EOpKill: UNIMPLEMENTED(); break;
523 case EOpBreak: UNIMPLEMENTED(); break;
524 case EOpContinue: UNIMPLEMENTED(); break;
525 case EOpReturn:
526 if (visit == PreVisit)
527 out << "return ";
528 break;
529 default: UNREACHABLE(); break;
530 }
531
532 return true;
533}