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