2
// Copyright (c) 2002-2011 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.
7
#include "compiler/OutputGLSLBase.h"
8
#include "compiler/debug.h"
12
TString getTypeName(const TType& type)
18
out << type.getNominalSize();
20
else if (type.isVector())
22
switch (type.getBasicType())
24
case EbtFloat: out << "vec"; break;
25
case EbtInt: out << "ivec"; break;
26
case EbtBool: out << "bvec"; break;
27
default: UNREACHABLE(); break;
29
out << type.getNominalSize();
33
if (type.getBasicType() == EbtStruct)
34
out << type.getTypeName();
36
out << type.getBasicString();
38
return TString(out.c_str());
41
TString arrayBrackets(const TType& type)
43
ASSERT(type.isArray());
45
out << "[" << type.getArraySize() << "]";
46
return TString(out.c_str());
49
bool isSingleStatement(TIntermNode* node) {
50
if (const TIntermAggregate* aggregate = node->getAsAggregate())
52
return (aggregate->getOp() != EOpFunction) &&
53
(aggregate->getOp() != EOpSequence);
55
else if (const TIntermSelection* selection = node->getAsSelectionNode())
57
// Ternary operators are usually part of an assignment operator.
58
// This handles those rare cases in which they are all by themselves.
59
return selection->usesTernaryOperator();
61
else if (node->getAsLoopNode())
69
TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink)
70
: TIntermTraverser(true, true, true),
72
mDeclaringVariables(false)
76
void TOutputGLSLBase::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
78
TInfoSinkBase& out = objSink();
79
if (visit == PreVisit && preStr)
83
else if (visit == InVisit && inStr)
87
else if (visit == PostVisit && postStr)
93
void TOutputGLSLBase::writeVariableType(const TType& type)
95
TInfoSinkBase& out = objSink();
96
TQualifier qualifier = type.getQualifier();
97
// TODO(alokp): Validate qualifier for variable declarations.
98
if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
99
out << type.getQualifierString() << " ";
100
// Declare the struct if we have not done so already.
101
if ((type.getBasicType() == EbtStruct) &&
102
(mDeclaredStructs.find(type.getTypeName()) == mDeclaredStructs.end()))
104
out << "struct " << type.getTypeName() << "{\n";
105
const TTypeList* structure = type.getStruct();
106
ASSERT(structure != NULL);
107
for (size_t i = 0; i < structure->size(); ++i)
109
const TType* fieldType = (*structure)[i].type;
110
ASSERT(fieldType != NULL);
111
if (writeVariablePrecision(fieldType->getPrecision()))
113
out << getTypeName(*fieldType) << " " << fieldType->getFieldName();
114
if (fieldType->isArray())
115
out << arrayBrackets(*fieldType);
119
mDeclaredStructs.insert(type.getTypeName());
123
if (writeVariablePrecision(type.getPrecision()))
125
out << getTypeName(type);
129
void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args)
131
TInfoSinkBase& out = objSink();
132
for (TIntermSequence::const_iterator iter = args.begin();
133
iter != args.end(); ++iter)
135
const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
138
const TType& type = arg->getType();
139
writeVariableType(type);
141
const TString& name = arg->getSymbol();
145
out << arrayBrackets(type);
147
// Put a comma if this is not the last argument.
148
if (iter != args.end() - 1)
153
const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
154
const ConstantUnion* pConstUnion)
156
TInfoSinkBase& out = objSink();
158
if (type.getBasicType() == EbtStruct)
160
out << type.getTypeName() << "(";
161
const TTypeList* structure = type.getStruct();
162
ASSERT(structure != NULL);
163
for (size_t i = 0; i < structure->size(); ++i)
165
const TType* fieldType = (*structure)[i].type;
166
ASSERT(fieldType != NULL);
167
pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
168
if (i != structure->size() - 1) out << ", ";
174
int size = type.getObjectSize();
175
bool writeType = size > 1;
176
if (writeType) out << getTypeName(type) << "(";
177
for (int i = 0; i < size; ++i, ++pConstUnion)
179
switch (pConstUnion->getType())
181
case EbtFloat: out << pConstUnion->getFConst(); break;
182
case EbtInt: out << pConstUnion->getIConst(); break;
183
case EbtBool: out << pConstUnion->getBConst(); break;
184
default: UNREACHABLE();
186
if (i != size - 1) out << ", ";
188
if (writeType) out << ")";
193
void TOutputGLSLBase::visitSymbol(TIntermSymbol* node)
195
TInfoSinkBase& out = objSink();
196
if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node))
197
out << mLoopUnroll.GetLoopIndexValue(node);
199
out << node->getSymbol();
201
if (mDeclaringVariables && node->getType().isArray())
202
out << arrayBrackets(node->getType());
205
void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
207
writeConstantUnion(node->getType(), node->getUnionArrayPointer());
210
bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
212
bool visitChildren = true;
213
TInfoSinkBase& out = objSink();
214
switch (node->getOp())
217
if (visit == InVisit)
220
// RHS of initialize is not being declared.
221
mDeclaringVariables = false;
224
case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break;
225
case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break;
226
case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break;
227
case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break;
228
// Notice the fall-through.
230
case EOpVectorTimesMatrixAssign:
231
case EOpVectorTimesScalarAssign:
232
case EOpMatrixTimesScalarAssign:
233
case EOpMatrixTimesMatrixAssign:
234
writeTriplet(visit, "(", " *= ", ")");
238
case EOpIndexIndirect:
239
writeTriplet(visit, NULL, "[", "]");
241
case EOpIndexDirectStruct:
242
if (visit == InVisit)
245
// TODO(alokp): ASSERT
246
out << node->getType().getFieldName();
247
visitChildren = false;
250
case EOpVectorSwizzle:
251
if (visit == InVisit)
254
TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
255
TIntermSequence& sequence = rightChild->getSequence();
256
for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
258
TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
259
ASSERT(element->getBasicType() == EbtInt);
260
ASSERT(element->getNominalSize() == 1);
261
const ConstantUnion& data = element->getUnionArrayPointer()[0];
262
ASSERT(data.getType() == EbtInt);
263
switch (data.getIConst())
265
case 0: out << "x"; break;
266
case 1: out << "y"; break;
267
case 2: out << "z"; break;
268
case 3: out << "w"; break;
269
default: UNREACHABLE(); break;
272
visitChildren = false;
276
case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
277
case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
278
case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
279
case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
280
case EOpMod: UNIMPLEMENTED(); break;
281
case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
282
case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
283
case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
284
case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
285
case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
286
case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
288
// Notice the fall-through.
289
case EOpVectorTimesScalar:
290
case EOpVectorTimesMatrix:
291
case EOpMatrixTimesVector:
292
case EOpMatrixTimesScalar:
293
case EOpMatrixTimesMatrix:
294
writeTriplet(visit, "(", " * ", ")");
297
case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
298
case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
299
case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
300
default: UNREACHABLE(); break;
303
return visitChildren;
306
bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
309
TString postString = ")";
311
switch (node->getOp())
313
case EOpNegative: preString = "(-"; break;
314
case EOpVectorLogicalNot: preString = "not("; break;
315
case EOpLogicalNot: preString = "(!"; break;
317
case EOpPostIncrement: preString = "("; postString = "++)"; break;
318
case EOpPostDecrement: preString = "("; postString = "--)"; break;
319
case EOpPreIncrement: preString = "(++"; break;
320
case EOpPreDecrement: preString = "(--"; break;
322
case EOpConvIntToBool:
323
case EOpConvFloatToBool:
324
switch (node->getOperand()->getType().getNominalSize())
326
case 1: preString = "bool("; break;
327
case 2: preString = "bvec2("; break;
328
case 3: preString = "bvec3("; break;
329
case 4: preString = "bvec4("; break;
330
default: UNREACHABLE();
333
case EOpConvBoolToFloat:
334
case EOpConvIntToFloat:
335
switch (node->getOperand()->getType().getNominalSize())
337
case 1: preString = "float("; break;
338
case 2: preString = "vec2("; break;
339
case 3: preString = "vec3("; break;
340
case 4: preString = "vec4("; break;
341
default: UNREACHABLE();
344
case EOpConvFloatToInt:
345
case EOpConvBoolToInt:
346
switch (node->getOperand()->getType().getNominalSize())
348
case 1: preString = "int("; break;
349
case 2: preString = "ivec2("; break;
350
case 3: preString = "ivec3("; break;
351
case 4: preString = "ivec4("; break;
352
default: UNREACHABLE();
356
case EOpRadians: preString = "radians("; break;
357
case EOpDegrees: preString = "degrees("; break;
358
case EOpSin: preString = "sin("; break;
359
case EOpCos: preString = "cos("; break;
360
case EOpTan: preString = "tan("; break;
361
case EOpAsin: preString = "asin("; break;
362
case EOpAcos: preString = "acos("; break;
363
case EOpAtan: preString = "atan("; break;
365
case EOpExp: preString = "exp("; break;
366
case EOpLog: preString = "log("; break;
367
case EOpExp2: preString = "exp2("; break;
368
case EOpLog2: preString = "log2("; break;
369
case EOpSqrt: preString = "sqrt("; break;
370
case EOpInverseSqrt: preString = "inversesqrt("; break;
372
case EOpAbs: preString = "abs("; break;
373
case EOpSign: preString = "sign("; break;
374
case EOpFloor: preString = "floor("; break;
375
case EOpCeil: preString = "ceil("; break;
376
case EOpFract: preString = "fract("; break;
378
case EOpLength: preString = "length("; break;
379
case EOpNormalize: preString = "normalize("; break;
381
case EOpDFdx: preString = "dFdx("; break;
382
case EOpDFdy: preString = "dFdy("; break;
383
case EOpFwidth: preString = "fwidth("; break;
385
case EOpAny: preString = "any("; break;
386
case EOpAll: preString = "all("; break;
388
default: UNREACHABLE(); break;
391
if (visit == PreVisit && node->getUseEmulatedFunction())
392
preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
393
writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
398
bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
400
TInfoSinkBase& out = objSink();
402
if (node->usesTernaryOperator())
404
// Notice two brackets at the beginning and end. The outer ones
405
// encapsulate the whole ternary expression. This preserves the
406
// order of precedence when ternary expressions are used in a
407
// compound expression, i.e., c = 2 * (a < b ? 1 : 2).
409
node->getCondition()->traverse(this);
411
node->getTrueBlock()->traverse(this);
413
node->getFalseBlock()->traverse(this);
419
node->getCondition()->traverse(this);
423
visitCodeBlock(node->getTrueBlock());
425
if (node->getFalseBlock())
428
visitCodeBlock(node->getFalseBlock());
435
bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
437
bool visitChildren = true;
438
TInfoSinkBase& out = objSink();
440
bool delayedWrite = false;
441
switch (node->getOp())
444
// Scope the sequences except when at the global scope.
445
if (depth > 0) out << "{\n";
448
const TIntermSequence& sequence = node->getSequence();
449
for (TIntermSequence::const_iterator iter = sequence.begin();
450
iter != sequence.end(); ++iter)
452
TIntermNode* node = *iter;
453
ASSERT(node != NULL);
454
node->traverse(this);
456
if (isSingleStatement(node))
461
// Scope the sequences except when at the global scope.
462
if (depth > 0) out << "}\n";
463
visitChildren = false;
467
// Function declaration.
468
ASSERT(visit == PreVisit);
469
writeVariableType(node->getType());
470
out << " " << node->getName();
473
writeFunctionParameters(node->getSequence());
476
visitChildren = false;
480
// Function definition.
481
ASSERT(visit == PreVisit);
482
writeVariableType(node->getType());
483
out << " " << TFunction::unmangleName(node->getName());
486
// Function definition node contains one or two children nodes
487
// representing function parameters and function body. The latter
488
// is not present in case of empty function bodies.
489
const TIntermSequence& sequence = node->getSequence();
490
ASSERT((sequence.size() == 1) || (sequence.size() == 2));
491
TIntermSequence::const_iterator seqIter = sequence.begin();
493
// Traverse function parameters.
494
TIntermAggregate* params = (*seqIter)->getAsAggregate();
495
ASSERT(params != NULL);
496
ASSERT(params->getOp() == EOpParameters);
497
params->traverse(this);
499
// Traverse function body.
500
TIntermAggregate* body = ++seqIter != sequence.end() ?
501
(*seqIter)->getAsAggregate() : NULL;
502
visitCodeBlock(body);
505
// Fully processed; no need to visit children.
506
visitChildren = false;
509
case EOpFunctionCall:
511
if (visit == PreVisit)
513
TString functionName = TFunction::unmangleName(node->getName());
514
out << functionName << "(";
516
else if (visit == InVisit)
525
case EOpParameters: {
526
// Function parameters.
527
ASSERT(visit == PreVisit);
529
writeFunctionParameters(node->getSequence());
531
visitChildren = false;
534
case EOpDeclaration: {
535
// Variable declaration.
536
if (visit == PreVisit)
538
const TIntermSequence& sequence = node->getSequence();
539
const TIntermTyped* variable = sequence.front()->getAsTyped();
540
writeVariableType(variable->getType());
542
mDeclaringVariables = true;
544
else if (visit == InVisit)
547
mDeclaringVariables = true;
551
mDeclaringVariables = false;
555
case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
556
case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
557
case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
558
case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
559
case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
560
case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
561
case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
562
case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
563
case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
564
case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
565
case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
566
case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
567
case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
568
case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
569
case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
570
case EOpConstructStruct:
571
if (visit == PreVisit)
573
const TType& type = node->getType();
574
ASSERT(type.getBasicType() == EbtStruct);
575
out << type.getTypeName() << "(";
577
else if (visit == InVisit)
587
case EOpLessThan: preString = "lessThan("; delayedWrite = true; break;
588
case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break;
589
case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break;
590
case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break;
591
case EOpVectorEqual: preString = "equal("; delayedWrite = true; break;
592
case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break;
593
case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
595
case EOpMod: preString = "mod("; delayedWrite = true; break;
596
case EOpPow: preString = "pow("; delayedWrite = true; break;
597
case EOpAtan: preString = "atan("; delayedWrite = true; break;
598
case EOpMin: preString = "min("; delayedWrite = true; break;
599
case EOpMax: preString = "max("; delayedWrite = true; break;
600
case EOpClamp: preString = "clamp("; delayedWrite = true; break;
601
case EOpMix: preString = "mix("; delayedWrite = true; break;
602
case EOpStep: preString = "step("; delayedWrite = true; break;
603
case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break;
605
case EOpDistance: preString = "distance("; delayedWrite = true; break;
606
case EOpDot: preString = "dot("; delayedWrite = true; break;
607
case EOpCross: preString = "cross("; delayedWrite = true; break;
608
case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break;
609
case EOpReflect: preString = "reflect("; delayedWrite = true; break;
610
case EOpRefract: preString = "refract("; delayedWrite = true; break;
611
case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break;
613
default: UNREACHABLE(); break;
615
if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction())
616
preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
618
writeTriplet(visit, preString.c_str(), ", ", ")");
619
return visitChildren;
622
bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
624
TInfoSinkBase& out = objSink();
628
TLoopType loopType = node->getType();
629
if (loopType == ELoopFor) // for loop
631
if (!node->getUnrollFlag()) {
634
node->getInit()->traverse(this);
637
if (node->getCondition())
638
node->getCondition()->traverse(this);
641
if (node->getExpression())
642
node->getExpression()->traverse(this);
646
else if (loopType == ELoopWhile) // while loop
649
ASSERT(node->getCondition() != NULL);
650
node->getCondition()->traverse(this);
653
else // do-while loop
655
ASSERT(loopType == ELoopDoWhile);
660
if (node->getUnrollFlag())
662
TLoopIndexInfo indexInfo;
663
mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
664
mLoopUnroll.Push(indexInfo);
665
while (mLoopUnroll.SatisfiesLoopCondition())
667
visitCodeBlock(node->getBody());
674
visitCodeBlock(node->getBody());
678
if (loopType == ELoopDoWhile) // do-while loop
681
ASSERT(node->getCondition() != NULL);
682
node->getCondition()->traverse(this);
687
// No need to visit children. They have been already processed in
692
bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
694
switch (node->getFlowOp())
696
case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
697
case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
698
case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
699
case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
700
default: UNREACHABLE(); break;
706
void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
707
TInfoSinkBase &out = objSink();
710
node->traverse(this);
711
// Single statements not part of a sequence need to be terminated
713
if (isSingleStatement(node))
718
out << "{\n}\n"; // Empty code block.