blob: de29b54034b0c17095a119935f82153baa177257 [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
288 out << "if (";
289 node->getCondition()->traverse(this);
290 out << ") {\n";
291
292 incrementDepth();
293 node->getTrueBlock()->traverse(this);
294 out << getIndentationString(depth - 2) << "}";
295
296 if (node->getFalseBlock())
297 {
298 out << " else {\n";
299 node->getFalseBlock()->traverse(this);
300 out << getIndentationString(depth - 2) << "}";
301 }
302 decrementDepth();
303
304 out << "\n";
305 return false;
306}
307
308bool TOutputGLSL::visitAggregate(Visit visit, TIntermAggregate* node)
309{
310 TInfoSinkBase& out = objSink();
311 switch (node->getOp())
312 {
313 case EOpSequence:
314 if (visit == PreVisit)
315 {
316 out << getIndentationString(depth);
317 }
318 else if (visit == InVisit)
319 {
320 out << ";\n";
321 out << getIndentationString(depth - 1);
322 }
323 else
324 {
325 out << ";\n";
326 }
327 break;
328 case EOpComma:
329 UNIMPLEMENTED();
330 return true;
331 case EOpFunction:
332 if (visit == PreVisit)
333 {
334 TString returnType = node->getBasicString();
335 TString functionName = getUnmangledFunctionName(node->getName());
336 out << returnType << " " << functionName;
337 }
338 else if (visit == InVisit)
339 {
340 // Called after traversing function arguments (EOpParameters)
341 // but before traversing function body (EOpSequence).
342 out << "{\n";
343 }
344 else if (visit == PostVisit)
345 {
346 // Called after traversing function body (EOpSequence).
347 out << "}\n";
348 }
349 break;
350 case EOpFunctionCall:
351 if (visit == PreVisit)
352 {
353 TString functionName = getUnmangledFunctionName(node->getName());
354 out << functionName << "(";
355 }
356 else if (visit == InVisit)
357 {
358 out << ", ";
359 }
360 else
361 {
362 out << ")";
363 }
364 break;
365 case EOpParameters:
366 if (visit == PreVisit)
367 {
368 out << "(";
369 writeFullSymbol = true;
370 }
371 else if (visit == InVisit)
372 {
373 out << ", ";
374 }
375 else
376 {
377 out << ")";
378 writeFullSymbol = false;
379 }
380 break;
381 case EOpDeclaration:
382 if (visit == PreVisit)
383 {
384 writeFullSymbol = true;
385 }
386 else if (visit == InVisit)
387 {
388 out << ", ";
389 writeFullSymbol = false;
390 }
391 else
392 {
393 writeFullSymbol = false;
394 }
395 break;
396
397 case EOpConstructFloat: UNIMPLEMENTED(); break;
398 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
399 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
400 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
401 case EOpConstructBool: UNIMPLEMENTED(); break;
402 case EOpConstructBVec2: UNIMPLEMENTED(); break;
403 case EOpConstructBVec3: UNIMPLEMENTED(); break;
404 case EOpConstructBVec4: UNIMPLEMENTED(); break;
405 case EOpConstructInt: UNIMPLEMENTED(); break;
406 case EOpConstructIVec2: UNIMPLEMENTED(); break;
407 case EOpConstructIVec3: UNIMPLEMENTED(); break;
408 case EOpConstructIVec4: UNIMPLEMENTED(); break;
409 case EOpConstructMat2: UNIMPLEMENTED(); break;
410 case EOpConstructMat3: UNIMPLEMENTED(); break;
411 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
412 case EOpConstructStruct: UNIMPLEMENTED(); break;
413
414 case EOpLessThan: UNIMPLEMENTED(); break;
415 case EOpGreaterThan: UNIMPLEMENTED(); break;
416 case EOpLessThanEqual: UNIMPLEMENTED(); break;
417 case EOpGreaterThanEqual: UNIMPLEMENTED(); break;
418 case EOpVectorEqual: UNIMPLEMENTED(); break;
419 case EOpVectorNotEqual: UNIMPLEMENTED(); break;
420
421 case EOpMod: writeTriplet(visit, "mod(", ", ", ")"); break;
422 case EOpPow: writeTriplet(visit, "pow(", ", ", ")"); break;
423
424 case EOpAtan: UNIMPLEMENTED(); break;
425
426 case EOpMin: writeTriplet(visit, "min(", ", ", ")"); break;
427 case EOpMax: writeTriplet(visit, "max(", ", ", ")"); break;
428 case EOpClamp: writeTriplet(visit, "clamp(", ", ", ")"); break;
429 case EOpMix: writeTriplet(visit, "mix(", ", ", ")"); break;
430 case EOpStep: UNIMPLEMENTED(); break;
431 case EOpSmoothStep: UNIMPLEMENTED(); break;
432
433 case EOpDistance: UNIMPLEMENTED(); break;
434 case EOpDot: writeTriplet(visit, "dot(", ", ", ")"); break;
435 case EOpCross: UNIMPLEMENTED(); break;
436 case EOpFaceForward: UNIMPLEMENTED(); break;
437 case EOpReflect: writeTriplet(visit, "reflect(", ", ", ")"); break;
438 case EOpRefract: UNIMPLEMENTED(); break;
439 case EOpMul: UNIMPLEMENTED(); break;
440
441 default: UNREACHABLE(); break;
442 }
443 return true;
444}
445
446bool TOutputGLSL::visitLoop(Visit visit, TIntermLoop* node)
447{
448 UNIMPLEMENTED();
449 return true;
450}
451
452bool TOutputGLSL::visitBranch(Visit visit, TIntermBranch* node)
453{
454 TInfoSinkBase &out = objSink();
455
456 switch (node->getFlowOp())
457 {
458 case EOpKill: UNIMPLEMENTED(); break;
459 case EOpBreak: UNIMPLEMENTED(); break;
460 case EOpContinue: UNIMPLEMENTED(); break;
461 case EOpReturn:
462 if (visit == PreVisit)
463 out << "return ";
464 break;
465 default: UNREACHABLE(); break;
466 }
467
468 return true;
469}