~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to src/3rdparty/angle/src/compiler/OutputGLSLBase.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
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.
 
5
//
 
6
 
 
7
#include "compiler/OutputGLSLBase.h"
 
8
#include "compiler/debug.h"
 
9
 
 
10
namespace
 
11
{
 
12
TString 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.isVector())
 
21
    {
 
22
        switch (type.getBasicType())
 
23
        {
 
24
            case EbtFloat: out << "vec"; break;
 
25
            case EbtInt: out << "ivec"; break;
 
26
            case EbtBool: out << "bvec"; break;
 
27
            default: UNREACHABLE(); break;
 
28
        }
 
29
        out << type.getNominalSize();
 
30
    }
 
31
    else
 
32
    {
 
33
        if (type.getBasicType() == EbtStruct)
 
34
            out << type.getTypeName();
 
35
        else
 
36
            out << type.getBasicString();
 
37
    }
 
38
    return TString(out.c_str());
 
39
}
 
40
 
 
41
TString arrayBrackets(const TType& type)
 
42
{
 
43
    ASSERT(type.isArray());
 
44
    TInfoSinkBase out;
 
45
    out << "[" << type.getArraySize() << "]";
 
46
    return TString(out.c_str());
 
47
}
 
48
 
 
49
bool isSingleStatement(TIntermNode* node) {
 
50
    if (const TIntermAggregate* aggregate = node->getAsAggregate())
 
51
    {
 
52
        return (aggregate->getOp() != EOpFunction) &&
 
53
               (aggregate->getOp() != EOpSequence);
 
54
    }
 
55
    else if (const TIntermSelection* selection = node->getAsSelectionNode())
 
56
    {
 
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();
 
60
    }
 
61
    else if (node->getAsLoopNode())
 
62
    {
 
63
        return false;
 
64
    }
 
65
    return true;
 
66
}
 
67
}  // namespace
 
68
 
 
69
TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink)
 
70
    : TIntermTraverser(true, true, true),
 
71
      mObjSink(objSink),
 
72
      mDeclaringVariables(false)
 
73
{
 
74
}
 
75
 
 
76
void TOutputGLSLBase::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
 
77
{
 
78
    TInfoSinkBase& out = objSink();
 
79
    if (visit == PreVisit && preStr)
 
80
    {
 
81
        out << preStr;
 
82
    }
 
83
    else if (visit == InVisit && inStr)
 
84
    {
 
85
        out << inStr;
 
86
    }
 
87
    else if (visit == PostVisit && postStr)
 
88
    {
 
89
        out << postStr;
 
90
    }
 
91
}
 
92
 
 
93
void TOutputGLSLBase::writeVariableType(const TType& type)
 
94
{
 
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()))
 
103
    {
 
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)
 
108
        {
 
109
            const TType* fieldType = (*structure)[i].type;
 
110
            ASSERT(fieldType != NULL);
 
111
            if (writeVariablePrecision(fieldType->getPrecision()))
 
112
                out << " ";
 
113
            out << getTypeName(*fieldType) << " " << fieldType->getFieldName();
 
114
            if (fieldType->isArray())
 
115
                out << arrayBrackets(*fieldType);
 
116
            out << ";\n";
 
117
        }
 
118
        out << "}";
 
119
        mDeclaredStructs.insert(type.getTypeName());
 
120
    }
 
121
    else
 
122
    {
 
123
        if (writeVariablePrecision(type.getPrecision()))
 
124
            out << " ";
 
125
        out << getTypeName(type);
 
126
    }
 
127
}
 
128
 
 
129
void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args)
 
130
{
 
131
    TInfoSinkBase& out = objSink();
 
132
    for (TIntermSequence::const_iterator iter = args.begin();
 
133
         iter != args.end(); ++iter)
 
134
    {
 
135
        const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
 
136
        ASSERT(arg != NULL);
 
137
 
 
138
        const TType& type = arg->getType();
 
139
        writeVariableType(type);
 
140
 
 
141
        const TString& name = arg->getSymbol();
 
142
        if (!name.empty())
 
143
            out << " " << name;
 
144
        if (type.isArray())
 
145
            out << arrayBrackets(type);
 
146
 
 
147
        // Put a comma if this is not the last argument.
 
148
        if (iter != args.end() - 1)
 
149
            out << ", ";
 
150
    }
 
151
}
 
152
 
 
153
const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
 
154
                                                         const ConstantUnion* pConstUnion)
 
155
{
 
156
    TInfoSinkBase& out = objSink();
 
157
 
 
158
    if (type.getBasicType() == EbtStruct)
 
159
    {
 
160
        out << type.getTypeName() << "(";
 
161
        const TTypeList* structure = type.getStruct();
 
162
        ASSERT(structure != NULL);
 
163
        for (size_t i = 0; i < structure->size(); ++i)
 
164
        {
 
165
            const TType* fieldType = (*structure)[i].type;
 
166
            ASSERT(fieldType != NULL);
 
167
            pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
 
168
            if (i != structure->size() - 1) out << ", ";
 
169
        }
 
170
        out << ")";
 
171
    }
 
172
    else
 
173
    {
 
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)
 
178
        {
 
179
            switch (pConstUnion->getType())
 
180
            {
 
181
                case EbtFloat: out << pConstUnion->getFConst(); break;
 
182
                case EbtInt: out << pConstUnion->getIConst(); break;
 
183
                case EbtBool: out << pConstUnion->getBConst(); break;
 
184
                default: UNREACHABLE();
 
185
            }
 
186
            if (i != size - 1) out << ", ";
 
187
        }
 
188
        if (writeType) out << ")";
 
189
    }
 
190
    return pConstUnion;
 
191
}
 
192
 
 
193
void TOutputGLSLBase::visitSymbol(TIntermSymbol* node)
 
194
{
 
195
    TInfoSinkBase& out = objSink();
 
196
    if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node))
 
197
        out << mLoopUnroll.GetLoopIndexValue(node);
 
198
    else
 
199
        out << node->getSymbol();
 
200
 
 
201
    if (mDeclaringVariables && node->getType().isArray())
 
202
        out << arrayBrackets(node->getType());
 
203
}
 
204
 
 
205
void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
 
206
{
 
207
    writeConstantUnion(node->getType(), node->getUnionArrayPointer());
 
208
}
 
209
 
 
210
bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
 
211
{
 
212
    bool visitChildren = true;
 
213
    TInfoSinkBase& out = objSink();
 
214
    switch (node->getOp())
 
215
    {
 
216
        case EOpInitialize:
 
217
            if (visit == InVisit)
 
218
            {
 
219
                out << " = ";
 
220
                // RHS of initialize is not being declared.
 
221
                mDeclaringVariables = false;
 
222
            }
 
223
            break;
 
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.
 
229
        case EOpMulAssign: 
 
230
        case EOpVectorTimesMatrixAssign:
 
231
        case EOpVectorTimesScalarAssign:
 
232
        case EOpMatrixTimesScalarAssign:
 
233
        case EOpMatrixTimesMatrixAssign:
 
234
            writeTriplet(visit, "(", " *= ", ")");
 
235
            break;
 
236
 
 
237
        case EOpIndexDirect:
 
238
        case EOpIndexIndirect:
 
239
            writeTriplet(visit, NULL, "[", "]");
 
240
            break;
 
241
        case EOpIndexDirectStruct:
 
242
            if (visit == InVisit)
 
243
            {
 
244
                out << ".";
 
245
                // TODO(alokp): ASSERT
 
246
                out << node->getType().getFieldName();
 
247
                visitChildren = false;
 
248
            }
 
249
            break;
 
250
        case EOpVectorSwizzle:
 
251
            if (visit == InVisit)
 
252
            {
 
253
                out << ".";
 
254
                TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
 
255
                TIntermSequence& sequence = rightChild->getSequence();
 
256
                for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
 
257
                {
 
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())
 
264
                    {
 
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;
 
270
                    }
 
271
                }
 
272
                visitChildren = false;
 
273
            }
 
274
            break;
 
275
 
 
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;
 
287
 
 
288
        // Notice the fall-through.
 
289
        case EOpVectorTimesScalar:
 
290
        case EOpVectorTimesMatrix:
 
291
        case EOpMatrixTimesVector:
 
292
        case EOpMatrixTimesScalar:
 
293
        case EOpMatrixTimesMatrix:
 
294
            writeTriplet(visit, "(", " * ", ")");
 
295
            break;
 
296
 
 
297
        case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
 
298
        case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
 
299
        case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
 
300
        default: UNREACHABLE(); break;
 
301
    }
 
302
 
 
303
    return visitChildren;
 
304
}
 
305
 
 
306
bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
 
307
{
 
308
    TString preString;
 
309
    TString postString = ")";
 
310
 
 
311
    switch (node->getOp())
 
312
    {
 
313
        case EOpNegative: preString = "(-"; break;
 
314
        case EOpVectorLogicalNot: preString = "not("; break;
 
315
        case EOpLogicalNot: preString = "(!"; break;
 
316
 
 
317
        case EOpPostIncrement: preString = "("; postString = "++)"; break;
 
318
        case EOpPostDecrement: preString = "("; postString = "--)"; break;
 
319
        case EOpPreIncrement: preString = "(++"; break;
 
320
        case EOpPreDecrement: preString = "(--"; break;
 
321
 
 
322
        case EOpConvIntToBool:
 
323
        case EOpConvFloatToBool:
 
324
            switch (node->getOperand()->getType().getNominalSize())
 
325
            {
 
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();
 
331
            }
 
332
            break;
 
333
        case EOpConvBoolToFloat:
 
334
        case EOpConvIntToFloat:
 
335
            switch (node->getOperand()->getType().getNominalSize())
 
336
            {
 
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();
 
342
            }
 
343
            break;
 
344
        case EOpConvFloatToInt:
 
345
        case EOpConvBoolToInt:
 
346
            switch (node->getOperand()->getType().getNominalSize())
 
347
            {
 
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();
 
353
            }
 
354
            break;
 
355
 
 
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;
 
364
 
 
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;
 
371
 
 
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;
 
377
 
 
378
        case EOpLength: preString = "length("; break;
 
379
        case EOpNormalize: preString = "normalize("; break;
 
380
 
 
381
        case EOpDFdx: preString = "dFdx("; break;
 
382
        case EOpDFdy: preString = "dFdy("; break;
 
383
        case EOpFwidth: preString = "fwidth("; break;
 
384
 
 
385
        case EOpAny: preString = "any("; break;
 
386
        case EOpAll: preString = "all("; break;
 
387
 
 
388
        default: UNREACHABLE(); break;
 
389
    }
 
390
 
 
391
    if (visit == PreVisit && node->getUseEmulatedFunction())
 
392
        preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
 
393
    writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
 
394
 
 
395
    return true;
 
396
}
 
397
 
 
398
bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
 
399
{
 
400
    TInfoSinkBase& out = objSink();
 
401
 
 
402
    if (node->usesTernaryOperator())
 
403
    {
 
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).
 
408
        out << "((";
 
409
        node->getCondition()->traverse(this);
 
410
        out << ") ? (";
 
411
        node->getTrueBlock()->traverse(this);
 
412
        out << ") : (";
 
413
        node->getFalseBlock()->traverse(this);
 
414
        out << "))";
 
415
    }
 
416
    else
 
417
    {
 
418
        out << "if (";
 
419
        node->getCondition()->traverse(this);
 
420
        out << ")\n";
 
421
 
 
422
        incrementDepth();
 
423
        visitCodeBlock(node->getTrueBlock());
 
424
 
 
425
        if (node->getFalseBlock())
 
426
        {
 
427
            out << "else\n";
 
428
            visitCodeBlock(node->getFalseBlock());
 
429
        }
 
430
        decrementDepth();
 
431
    }
 
432
    return false;
 
433
}
 
434
 
 
435
bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
 
436
{
 
437
    bool visitChildren = true;
 
438
    TInfoSinkBase& out = objSink();
 
439
    TString preString;
 
440
    bool delayedWrite = false;
 
441
    switch (node->getOp())
 
442
    {
 
443
        case EOpSequence: {
 
444
            // Scope the sequences except when at the global scope.
 
445
            if (depth > 0) out << "{\n";
 
446
 
 
447
            incrementDepth();
 
448
            const TIntermSequence& sequence = node->getSequence();
 
449
            for (TIntermSequence::const_iterator iter = sequence.begin();
 
450
                 iter != sequence.end(); ++iter)
 
451
            {
 
452
                TIntermNode* node = *iter;
 
453
                ASSERT(node != NULL);
 
454
                node->traverse(this);
 
455
 
 
456
                if (isSingleStatement(node))
 
457
                    out << ";\n";
 
458
            }
 
459
            decrementDepth();
 
460
 
 
461
            // Scope the sequences except when at the global scope.
 
462
            if (depth > 0) out << "}\n";
 
463
            visitChildren = false;
 
464
            break;
 
465
        }
 
466
        case EOpPrototype: {
 
467
            // Function declaration.
 
468
            ASSERT(visit == PreVisit);
 
469
            writeVariableType(node->getType());
 
470
            out << " " << node->getName();
 
471
 
 
472
            out << "(";
 
473
            writeFunctionParameters(node->getSequence());
 
474
            out << ")";
 
475
 
 
476
            visitChildren = false;
 
477
            break;
 
478
        }
 
479
        case EOpFunction: {
 
480
            // Function definition.
 
481
            ASSERT(visit == PreVisit);
 
482
            writeVariableType(node->getType());
 
483
            out << " " << TFunction::unmangleName(node->getName());
 
484
 
 
485
            incrementDepth();
 
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();
 
492
 
 
493
            // Traverse function parameters.
 
494
            TIntermAggregate* params = (*seqIter)->getAsAggregate();
 
495
            ASSERT(params != NULL);
 
496
            ASSERT(params->getOp() == EOpParameters);
 
497
            params->traverse(this);
 
498
 
 
499
            // Traverse function body.
 
500
            TIntermAggregate* body = ++seqIter != sequence.end() ?
 
501
                (*seqIter)->getAsAggregate() : NULL;
 
502
            visitCodeBlock(body);
 
503
            decrementDepth();
 
504
 
 
505
            // Fully processed; no need to visit children.
 
506
            visitChildren = false;
 
507
            break;
 
508
        }
 
509
        case EOpFunctionCall:
 
510
            // Function call.
 
511
            if (visit == PreVisit)
 
512
            {
 
513
                TString functionName = TFunction::unmangleName(node->getName());
 
514
                out << functionName << "(";
 
515
            }
 
516
            else if (visit == InVisit)
 
517
            {
 
518
                out << ", ";
 
519
            }
 
520
            else
 
521
            {
 
522
                out << ")";
 
523
            }
 
524
            break;
 
525
        case EOpParameters: {
 
526
            // Function parameters.
 
527
            ASSERT(visit == PreVisit);
 
528
            out << "(";
 
529
            writeFunctionParameters(node->getSequence());
 
530
            out << ")";
 
531
            visitChildren = false;
 
532
            break;
 
533
        }
 
534
        case EOpDeclaration: {
 
535
            // Variable declaration.
 
536
            if (visit == PreVisit)
 
537
            {
 
538
                const TIntermSequence& sequence = node->getSequence();
 
539
                const TIntermTyped* variable = sequence.front()->getAsTyped();
 
540
                writeVariableType(variable->getType());
 
541
                out << " ";
 
542
                mDeclaringVariables = true;
 
543
            }
 
544
            else if (visit == InVisit)
 
545
            {
 
546
                out << ", ";
 
547
                mDeclaringVariables = true;
 
548
            }
 
549
            else
 
550
            {
 
551
                mDeclaringVariables = false;
 
552
            }
 
553
            break;
 
554
        }
 
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)
 
572
            {
 
573
                const TType& type = node->getType();
 
574
                ASSERT(type.getBasicType() == EbtStruct);
 
575
                out << type.getTypeName() << "(";
 
576
            }
 
577
            else if (visit == InVisit)
 
578
            {
 
579
                out << ", ";
 
580
            }
 
581
            else
 
582
            {
 
583
                out << ")";
 
584
            }
 
585
            break;
 
586
 
 
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;
 
594
 
 
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;
 
604
 
 
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;
 
612
 
 
613
        default: UNREACHABLE(); break;
 
614
    }
 
615
    if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction())
 
616
        preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
 
617
    if (delayedWrite)
 
618
        writeTriplet(visit, preString.c_str(), ", ", ")");
 
619
    return visitChildren;
 
620
}
 
621
 
 
622
bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
 
623
{
 
624
    TInfoSinkBase& out = objSink();
 
625
 
 
626
    incrementDepth();
 
627
    // Loop header.
 
628
    TLoopType loopType = node->getType();
 
629
    if (loopType == ELoopFor)  // for loop
 
630
    {
 
631
        if (!node->getUnrollFlag()) {
 
632
            out << "for (";
 
633
            if (node->getInit())
 
634
                node->getInit()->traverse(this);
 
635
            out << "; ";
 
636
 
 
637
            if (node->getCondition())
 
638
                node->getCondition()->traverse(this);
 
639
            out << "; ";
 
640
 
 
641
            if (node->getExpression())
 
642
                node->getExpression()->traverse(this);
 
643
            out << ")\n";
 
644
        }
 
645
    }
 
646
    else if (loopType == ELoopWhile)  // while loop
 
647
    {
 
648
        out << "while (";
 
649
        ASSERT(node->getCondition() != NULL);
 
650
        node->getCondition()->traverse(this);
 
651
        out << ")\n";
 
652
    }
 
653
    else  // do-while loop
 
654
    {
 
655
        ASSERT(loopType == ELoopDoWhile);
 
656
        out << "do\n";
 
657
    }
 
658
 
 
659
    // Loop body.
 
660
    if (node->getUnrollFlag())
 
661
    {
 
662
        TLoopIndexInfo indexInfo;
 
663
        mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
 
664
        mLoopUnroll.Push(indexInfo);
 
665
        while (mLoopUnroll.SatisfiesLoopCondition())
 
666
        {
 
667
            visitCodeBlock(node->getBody());
 
668
            mLoopUnroll.Step();
 
669
        }
 
670
        mLoopUnroll.Pop();
 
671
    }
 
672
    else
 
673
    {
 
674
        visitCodeBlock(node->getBody());
 
675
    }
 
676
 
 
677
    // Loop footer.
 
678
    if (loopType == ELoopDoWhile)  // do-while loop
 
679
    {
 
680
        out << "while (";
 
681
        ASSERT(node->getCondition() != NULL);
 
682
        node->getCondition()->traverse(this);
 
683
        out << ");\n";
 
684
    }
 
685
    decrementDepth();
 
686
 
 
687
    // No need to visit children. They have been already processed in
 
688
    // this function.
 
689
    return false;
 
690
}
 
691
 
 
692
bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
 
693
{
 
694
    switch (node->getFlowOp())
 
695
    {
 
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;
 
701
    }
 
702
 
 
703
    return true;
 
704
}
 
705
 
 
706
void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
 
707
    TInfoSinkBase &out = objSink();
 
708
    if (node != NULL)
 
709
    {
 
710
        node->traverse(this);
 
711
        // Single statements not part of a sequence need to be terminated
 
712
        // with semi-colon.
 
713
        if (isSingleStatement(node))
 
714
            out << ";\n";
 
715
    }
 
716
    else
 
717
    {
 
718
        out << "{\n}\n";  // Empty code block.
 
719
    }
 
720
}