blob: ee1f49dc6ab5289a2f03c69b19a0f14fb67fa5fb [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
7#include "OutputGLSL.h"
8#include "common/debug.h"
9
10namespace
11{
12TString getTypeName(const TType& type)
13{
14 TInfoSinkBase out;
15 if (type.isMatrix())
16 {
17 out << "mat";
18 out << type.getNominalSize();
19 }
20 else if (type.isArray())
21 {
22 UNIMPLEMENTED();
23 }
24 else if (type.isVector())
25 {
26 switch (type.getBasicType())
27 {
28 case EbtFloat: out << "vec"; break;
29 case EbtInt: out << "ivec"; break;
30 case EbtBool: out << "bvec"; break;
31 default: UNREACHABLE(); break;
32 }
33 out << type.getNominalSize();
34 }
35 else
36 {
37 if (type.getBasicType() == EbtStruct)
38 out << type.getTypeName();
39 else
40 out << type.getBasicString();
41 }
42 return TString(out.c_str());
43}
44
45TString getUnmangledFunctionName(const TString& mangledName)
46{
47 return TString(mangledName.c_str(), mangledName.find_first_of('('));
48}
49
50TString getIndentationString(int depth)
51{
52 TString indentation(depth, ' ');
53 return indentation;
54}
55} // namespace
56
57TOutputGLSL::TOutputGLSL(TParseContext &context)
58 : TIntermTraverser(true, true, true),
59 writeFullSymbol(false),
60 parseContext(context)
61{
62}
63
64void TOutputGLSL::header()
65{
66 TInfoSinkBase& out = objSink();
67
68 TSymbolTableLevel* symbols = parseContext.symbolTable.getGlobalLevel();
69 for (TSymbolTableLevel::const_iterator symbolIter = symbols->begin(); symbolIter != symbols->end(); ++symbolIter)
70 {
71 const TSymbol* symbol = symbolIter->second;
72 if (!symbol->isVariable())
73 continue;
74
75 const TVariable* variable = static_cast<const TVariable*>(symbol);
76 const TString& name = variable->getName();
77 const TType& type = variable->getType();
78 TQualifier qualifier = type.getQualifier();
79
80 //symbol->dump(parseContext.infoSink);
81 }
82}
83
84void TOutputGLSL::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
85{
86 TInfoSinkBase& out = objSink();
87 if (visit == PreVisit && preStr)
88 {
89 out << preStr;
90 }
91 else if (visit == InVisit && inStr)
92 {
93 out << inStr;
94 }
95 else if (visit == PostVisit && postStr)
96 {
97 out << postStr;
98 }
99}
100
101void TOutputGLSL::visitSymbol(TIntermSymbol* node)
102{
103 TInfoSinkBase& out = objSink();
104 if (writeFullSymbol)
105 {
106 TQualifier qualifier = node->getQualifier();
107 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
108 out << node->getQualifierString() << " ";
109
110 out << getTypeName(node->getType()) << " ";
111 }
112 out << node->getSymbol();
113}
114
115void TOutputGLSL::visitConstantUnion(TIntermConstantUnion* node)
116{
117 TInfoSinkBase& out = objSink();
118
119 TType type = node->getType();
120 int size = type.getObjectSize();
121 if (size > 1)
122 out << getTypeName(type) << "(";
123 for (int i = 0; i < size; ++i) {
124 const constUnion& data = node->getUnionArrayPointer()[i];
125 switch (data.getType())
126 {
127 case EbtFloat: out << data.getFConst(); break;
128 case EbtInt: out << data.getIConst(); break;
129 case EbtBool: out << data.getBConst(); break;
130 default: UNREACHABLE(); break;
131 }
132 if (i != size - 1)
133 out << ", ";
134 }
135 if (size > 1)
136 out << ")";
137}
138
139bool TOutputGLSL::visitBinary(Visit visit, TIntermBinary* node)
140{
141 bool visitChildren = true;
142 TInfoSinkBase& out = objSink();
143 switch (node->getOp())
144 {
145 case EOpAssign: writeTriplet(visit, NULL, " = ", NULL); break;
146 case EOpInitialize:
147 if (visit == InVisit) {
148 out << " = ";
149 writeFullSymbol= false;
150 }
151 break;
152 case EOpAddAssign: writeTriplet(visit, NULL, " += ", NULL); break;
153 case EOpSubAssign: UNIMPLEMENTED(); break;
154 case EOpMulAssign: UNIMPLEMENTED(); break;
155 case EOpVectorTimesMatrixAssign: UNIMPLEMENTED(); break;
156 case EOpVectorTimesScalarAssign: UNIMPLEMENTED(); break;
157 case EOpMatrixTimesScalarAssign: UNIMPLEMENTED(); break;
158 case EOpMatrixTimesMatrixAssign: UNIMPLEMENTED(); break;
159 case EOpDivAssign: UNIMPLEMENTED(); break;
160
161 case EOpIndexDirect: writeTriplet(visit, NULL, "[", "]"); break;
162 case EOpIndexIndirect: UNIMPLEMENTED(); break;
163 case EOpIndexDirectStruct:
164 if (visit == InVisit)
165 {
166 out << ".";
167 // TODO(alokp): ASSERT
168 out << node->getType().getFieldName();
169 visitChildren = false;
170 }
171 break;
172 case EOpVectorSwizzle:
173 if (visit == InVisit)
174 {
175 out << ".";
176 TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
177 TIntermSequence& sequence = rightChild->getSequence();
178 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
179 {
180 TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
181 ASSERT(element->getBasicType() == EbtInt);
182 ASSERT(element->getNominalSize() == 1);
183 const constUnion& data = element->getUnionArrayPointer()[0];
184 ASSERT(data.getType() == EbtInt);
185 switch (data.getIConst())
186 {
187 case 0: out << "x"; break;
188 case 1: out << "y"; break;
189 case 2: out << "z"; break;
190 case 3: out << "w"; break;
191 default: UNREACHABLE(); break;
192 }
193 }
194 visitChildren = false;
195 }
196 break;
197
198 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
199 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
200 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
201 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
202 case EOpMod: UNIMPLEMENTED(); break;
203 case EOpEqual: UNIMPLEMENTED(); break;
204 case EOpNotEqual: UNIMPLEMENTED(); break;
205 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
206 case EOpGreaterThan: writeTriplet(visit, NULL, " > ", NULL); break;
207 case EOpLessThanEqual: UNIMPLEMENTED(); break;
208 case EOpGreaterThanEqual: UNIMPLEMENTED(); break;
209
210 // Notice the fall-through.
211 case EOpVectorTimesScalar:
212 case EOpVectorTimesMatrix:
213 case EOpMatrixTimesVector:
214 case EOpMatrixTimesScalar:
215 case EOpMatrixTimesMatrix:
216 writeTriplet(visit, "(", " * ", ")");
217 break;
218
219 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
220 case EOpLogicalXor: UNIMPLEMENTED(); break;
221 case EOpLogicalAnd: UNIMPLEMENTED(); break;
222 default: UNREACHABLE(); break;
223 }
224
225 return visitChildren;
226}
227
228bool TOutputGLSL::visitUnary(Visit visit, TIntermUnary* node)
229{
230 TInfoSinkBase& out = objSink();
231
232 switch (node->getOp())
233 {
234 case EOpNegative: writeTriplet(visit, "(-", NULL, ")"); break;
235 case EOpVectorLogicalNot: UNIMPLEMENTED(); break;
236 case EOpLogicalNot: UNIMPLEMENTED(); break;
237
238 case EOpPostIncrement: UNIMPLEMENTED(); break;
239 case EOpPostDecrement: UNIMPLEMENTED(); break;
240 case EOpPreIncrement: UNIMPLEMENTED(); break;
241 case EOpPreDecrement: UNIMPLEMENTED(); break;
242
243 case EOpConvIntToBool: UNIMPLEMENTED(); break;
244 case EOpConvFloatToBool: UNIMPLEMENTED(); break;
245 case EOpConvBoolToFloat: UNIMPLEMENTED(); break;
246 case EOpConvIntToFloat: writeTriplet(visit, "float(", NULL, ")"); break;
247 case EOpConvFloatToInt: UNIMPLEMENTED(); break;
248 case EOpConvBoolToInt: UNIMPLEMENTED(); break;
249
250 case EOpRadians: UNIMPLEMENTED(); break;
251 case EOpDegrees: UNIMPLEMENTED(); break;
252 case EOpSin: writeTriplet(visit, "sin(", NULL, ")"); break;
253 case EOpCos: writeTriplet(visit, "cos(", NULL, ")"); break;
254 case EOpTan: UNIMPLEMENTED(); break;
255 case EOpAsin: UNIMPLEMENTED(); break;
256 case EOpAcos: UNIMPLEMENTED(); break;
257 case EOpAtan: UNIMPLEMENTED(); break;
258
259 case EOpExp: UNIMPLEMENTED(); break;
260 case EOpLog: UNIMPLEMENTED(); break;
261 case EOpExp2: UNIMPLEMENTED(); break;
262 case EOpLog2: UNIMPLEMENTED(); break;
263 case EOpSqrt: UNIMPLEMENTED(); break;
264 case EOpInverseSqrt: UNIMPLEMENTED(); break;
265
266 case EOpAbs: UNIMPLEMENTED(); break;
267 case EOpSign: UNIMPLEMENTED(); break;
268 case EOpFloor: writeTriplet(visit, "floor(", NULL, ")"); break;
269 case EOpCeil: UNIMPLEMENTED(); break;
270 case EOpFract: UNIMPLEMENTED(); break;
271
272 case EOpLength: UNIMPLEMENTED(); break;
273 case EOpNormalize: writeTriplet(visit, "normalize(", NULL, ")"); break;
274
275 case EOpAny: UNIMPLEMENTED(); break;
276 case EOpAll: UNIMPLEMENTED(); break;
277
278 default: UNREACHABLE(); break;
279 }
280
281 return true;
282}
283
284bool TOutputGLSL::visitSelection(Visit visit, TIntermSelection* node)
285{
286 TInfoSinkBase& out = objSink();
287
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000288 if (node->usesTernaryOperator())
alokp@chromium.org76b82082010-03-24 17:59:39 +0000289 {
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000290 out << "(";
291 node->getCondition()->traverse(this);
292 out << ") ? (";
293 node->getTrueBlock()->traverse(this);
294 out << ") : (";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000295 node->getFalseBlock()->traverse(this);
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000296 out << ")";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000297 }
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000298 else
299 {
300 out << "if (";
301 node->getCondition()->traverse(this);
302 out << ") {\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000303
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000304 incrementDepth();
305 node->getTrueBlock()->traverse(this);
306 out << getIndentationString(depth - 2) << "}";
307
308 if (node->getFalseBlock())
309 {
310 out << " else {\n";
311 node->getFalseBlock()->traverse(this);
312 out << getIndentationString(depth - 2) << "}";
313 }
314 decrementDepth();
315 out << "\n";
316 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000317 return false;
318}
319
320bool TOutputGLSL::visitAggregate(Visit visit, TIntermAggregate* node)
321{
322 TInfoSinkBase& out = objSink();
323 switch (node->getOp())
324 {
325 case EOpSequence:
326 if (visit == PreVisit)
327 {
328 out << getIndentationString(depth);
329 }
330 else if (visit == InVisit)
331 {
332 out << ";\n";
333 out << getIndentationString(depth - 1);
334 }
335 else
336 {
337 out << ";\n";
338 }
339 break;
340 case EOpComma:
341 UNIMPLEMENTED();
342 return true;
343 case EOpFunction:
344 if (visit == PreVisit)
345 {
346 TString returnType = node->getBasicString();
347 TString functionName = getUnmangledFunctionName(node->getName());
348 out << returnType << " " << functionName;
349 }
350 else if (visit == InVisit)
351 {
352 // Called after traversing function arguments (EOpParameters)
353 // but before traversing function body (EOpSequence).
354 out << "{\n";
355 }
356 else if (visit == PostVisit)
357 {
358 // Called after traversing function body (EOpSequence).
359 out << "}\n";
360 }
361 break;
362 case EOpFunctionCall:
363 if (visit == PreVisit)
364 {
365 TString functionName = getUnmangledFunctionName(node->getName());
366 out << functionName << "(";
367 }
368 else if (visit == InVisit)
369 {
370 out << ", ";
371 }
372 else
373 {
374 out << ")";
375 }
376 break;
377 case EOpParameters:
378 if (visit == PreVisit)
379 {
380 out << "(";
381 writeFullSymbol = true;
382 }
383 else if (visit == InVisit)
384 {
385 out << ", ";
386 }
387 else
388 {
389 out << ")";
390 writeFullSymbol = false;
391 }
392 break;
393 case EOpDeclaration:
394 if (visit == PreVisit)
395 {
396 writeFullSymbol = true;
397 }
398 else if (visit == InVisit)
399 {
400 out << ", ";
401 writeFullSymbol = false;
402 }
403 else
404 {
405 writeFullSymbol = false;
406 }
407 break;
408
409 case EOpConstructFloat: UNIMPLEMENTED(); break;
410 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
411 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
412 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
413 case EOpConstructBool: UNIMPLEMENTED(); break;
414 case EOpConstructBVec2: UNIMPLEMENTED(); break;
415 case EOpConstructBVec3: UNIMPLEMENTED(); break;
416 case EOpConstructBVec4: UNIMPLEMENTED(); break;
417 case EOpConstructInt: UNIMPLEMENTED(); break;
418 case EOpConstructIVec2: UNIMPLEMENTED(); break;
419 case EOpConstructIVec3: UNIMPLEMENTED(); break;
420 case EOpConstructIVec4: UNIMPLEMENTED(); break;
421 case EOpConstructMat2: UNIMPLEMENTED(); break;
422 case EOpConstructMat3: UNIMPLEMENTED(); break;
423 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
424 case EOpConstructStruct: UNIMPLEMENTED(); break;
425
426 case EOpLessThan: UNIMPLEMENTED(); break;
427 case EOpGreaterThan: UNIMPLEMENTED(); break;
428 case EOpLessThanEqual: UNIMPLEMENTED(); break;
429 case EOpGreaterThanEqual: UNIMPLEMENTED(); break;
430 case EOpVectorEqual: UNIMPLEMENTED(); break;
431 case EOpVectorNotEqual: UNIMPLEMENTED(); break;
432
433 case EOpMod: writeTriplet(visit, "mod(", ", ", ")"); break;
434 case EOpPow: writeTriplet(visit, "pow(", ", ", ")"); break;
435
436 case EOpAtan: UNIMPLEMENTED(); break;
437
438 case EOpMin: writeTriplet(visit, "min(", ", ", ")"); break;
439 case EOpMax: writeTriplet(visit, "max(", ", ", ")"); break;
440 case EOpClamp: writeTriplet(visit, "clamp(", ", ", ")"); break;
441 case EOpMix: writeTriplet(visit, "mix(", ", ", ")"); break;
442 case EOpStep: UNIMPLEMENTED(); break;
443 case EOpSmoothStep: UNIMPLEMENTED(); break;
444
445 case EOpDistance: UNIMPLEMENTED(); break;
446 case EOpDot: writeTriplet(visit, "dot(", ", ", ")"); break;
447 case EOpCross: UNIMPLEMENTED(); break;
448 case EOpFaceForward: UNIMPLEMENTED(); break;
449 case EOpReflect: writeTriplet(visit, "reflect(", ", ", ")"); break;
450 case EOpRefract: UNIMPLEMENTED(); break;
451 case EOpMul: UNIMPLEMENTED(); break;
452
453 default: UNREACHABLE(); break;
454 }
455 return true;
456}
457
458bool TOutputGLSL::visitLoop(Visit visit, TIntermLoop* node)
459{
460 UNIMPLEMENTED();
461 return true;
462}
463
464bool TOutputGLSL::visitBranch(Visit visit, TIntermBranch* node)
465{
466 TInfoSinkBase &out = objSink();
467
468 switch (node->getFlowOp())
469 {
470 case EOpKill: UNIMPLEMENTED(); break;
471 case EOpBreak: UNIMPLEMENTED(); break;
472 case EOpContinue: UNIMPLEMENTED(); break;
473 case EOpReturn:
474 if (visit == PreVisit)
475 out << "return ";
476 break;
477 default: UNREACHABLE(); break;
478 }
479
480 return true;
481}