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