gfx/angle/src/compiler/OutputGLSLBase.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/angle/src/compiler/OutputGLSLBase.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,817 @@
     1.4 +//
     1.5 +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
     1.6 +// Use of this source code is governed by a BSD-style license that can be
     1.7 +// found in the LICENSE file.
     1.8 +//
     1.9 +
    1.10 +#include "compiler/OutputGLSLBase.h"
    1.11 +#include "compiler/compiler_debug.h"
    1.12 +
    1.13 +#include <cfloat>
    1.14 +
    1.15 +namespace
    1.16 +{
    1.17 +TString arrayBrackets(const TType& type)
    1.18 +{
    1.19 +    ASSERT(type.isArray());
    1.20 +    TInfoSinkBase out;
    1.21 +    out << "[" << type.getArraySize() << "]";
    1.22 +    return TString(out.c_str());
    1.23 +}
    1.24 +
    1.25 +bool isSingleStatement(TIntermNode* node) {
    1.26 +    if (const TIntermAggregate* aggregate = node->getAsAggregate())
    1.27 +    {
    1.28 +        return (aggregate->getOp() != EOpFunction) &&
    1.29 +               (aggregate->getOp() != EOpSequence);
    1.30 +    }
    1.31 +    else if (const TIntermSelection* selection = node->getAsSelectionNode())
    1.32 +    {
    1.33 +        // Ternary operators are usually part of an assignment operator.
    1.34 +        // This handles those rare cases in which they are all by themselves.
    1.35 +        return selection->usesTernaryOperator();
    1.36 +    }
    1.37 +    else if (node->getAsLoopNode())
    1.38 +    {
    1.39 +        return false;
    1.40 +    }
    1.41 +    return true;
    1.42 +}
    1.43 +}  // namespace
    1.44 +
    1.45 +TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink,
    1.46 +                                 ShArrayIndexClampingStrategy clampingStrategy,
    1.47 +                                 ShHashFunction64 hashFunction,
    1.48 +                                 NameMap& nameMap,
    1.49 +                                 TSymbolTable& symbolTable)
    1.50 +    : TIntermTraverser(true, true, true),
    1.51 +      mObjSink(objSink),
    1.52 +      mDeclaringVariables(false),
    1.53 +      mClampingStrategy(clampingStrategy),
    1.54 +      mHashFunction(hashFunction),
    1.55 +      mNameMap(nameMap),
    1.56 +      mSymbolTable(symbolTable)
    1.57 +{
    1.58 +}
    1.59 +
    1.60 +void TOutputGLSLBase::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
    1.61 +{
    1.62 +    TInfoSinkBase& out = objSink();
    1.63 +    if (visit == PreVisit && preStr)
    1.64 +    {
    1.65 +        out << preStr;
    1.66 +    }
    1.67 +    else if (visit == InVisit && inStr)
    1.68 +    {
    1.69 +        out << inStr;
    1.70 +    }
    1.71 +    else if (visit == PostVisit && postStr)
    1.72 +    {
    1.73 +        out << postStr;
    1.74 +    }
    1.75 +}
    1.76 +
    1.77 +void TOutputGLSLBase::writeVariableType(const TType& type)
    1.78 +{
    1.79 +    TInfoSinkBase& out = objSink();
    1.80 +    TQualifier qualifier = type.getQualifier();
    1.81 +    // TODO(alokp): Validate qualifier for variable declarations.
    1.82 +    if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
    1.83 +        out << type.getQualifierString() << " ";
    1.84 +    // Declare the struct if we have not done so already.
    1.85 +    if ((type.getBasicType() == EbtStruct) && !structDeclared(type.getStruct()))
    1.86 +    {
    1.87 +        declareStruct(type.getStruct());
    1.88 +    }
    1.89 +    else
    1.90 +    {
    1.91 +        if (writeVariablePrecision(type.getPrecision()))
    1.92 +            out << " ";
    1.93 +        out << getTypeName(type);
    1.94 +    }
    1.95 +}
    1.96 +
    1.97 +void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args)
    1.98 +{
    1.99 +    TInfoSinkBase& out = objSink();
   1.100 +    for (TIntermSequence::const_iterator iter = args.begin();
   1.101 +         iter != args.end(); ++iter)
   1.102 +    {
   1.103 +        const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
   1.104 +        ASSERT(arg != NULL);
   1.105 +
   1.106 +        const TType& type = arg->getType();
   1.107 +        writeVariableType(type);
   1.108 +
   1.109 +        const TString& name = arg->getSymbol();
   1.110 +        if (!name.empty())
   1.111 +            out << " " << hashName(name);
   1.112 +        if (type.isArray())
   1.113 +            out << arrayBrackets(type);
   1.114 +
   1.115 +        // Put a comma if this is not the last argument.
   1.116 +        if (iter != args.end() - 1)
   1.117 +            out << ", ";
   1.118 +    }
   1.119 +}
   1.120 +
   1.121 +const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
   1.122 +                                                         const ConstantUnion* pConstUnion)
   1.123 +{
   1.124 +    TInfoSinkBase& out = objSink();
   1.125 +
   1.126 +    if (type.getBasicType() == EbtStruct)
   1.127 +    {
   1.128 +        const TStructure* structure = type.getStruct();
   1.129 +        out << hashName(structure->name()) << "(";
   1.130 +
   1.131 +        const TFieldList& fields = structure->fields();
   1.132 +        for (size_t i = 0; i < fields.size(); ++i)
   1.133 +        {
   1.134 +            const TType* fieldType = fields[i]->type();
   1.135 +            ASSERT(fieldType != NULL);
   1.136 +            pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
   1.137 +            if (i != fields.size() - 1) out << ", ";
   1.138 +        }
   1.139 +        out << ")";
   1.140 +    }
   1.141 +    else
   1.142 +    {
   1.143 +        size_t size = type.getObjectSize();
   1.144 +        bool writeType = size > 1;
   1.145 +        if (writeType) out << getTypeName(type) << "(";
   1.146 +        for (size_t i = 0; i < size; ++i, ++pConstUnion)
   1.147 +        {
   1.148 +            switch (pConstUnion->getType())
   1.149 +            {
   1.150 +                case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst())); break;
   1.151 +                case EbtInt: out << pConstUnion->getIConst(); break;
   1.152 +                case EbtBool: out << pConstUnion->getBConst(); break;
   1.153 +                default: UNREACHABLE();
   1.154 +            }
   1.155 +            if (i != size - 1) out << ", ";
   1.156 +        }
   1.157 +        if (writeType) out << ")";
   1.158 +    }
   1.159 +    return pConstUnion;
   1.160 +}
   1.161 +
   1.162 +void TOutputGLSLBase::visitSymbol(TIntermSymbol* node)
   1.163 +{
   1.164 +    TInfoSinkBase& out = objSink();
   1.165 +    if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node))
   1.166 +        out << mLoopUnroll.GetLoopIndexValue(node);
   1.167 +    else
   1.168 +        out << hashVariableName(node->getSymbol());
   1.169 +
   1.170 +    if (mDeclaringVariables && node->getType().isArray())
   1.171 +        out << arrayBrackets(node->getType());
   1.172 +}
   1.173 +
   1.174 +void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
   1.175 +{
   1.176 +    writeConstantUnion(node->getType(), node->getUnionArrayPointer());
   1.177 +}
   1.178 +
   1.179 +bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
   1.180 +{
   1.181 +    bool visitChildren = true;
   1.182 +    TInfoSinkBase& out = objSink();
   1.183 +    switch (node->getOp())
   1.184 +    {
   1.185 +        case EOpInitialize:
   1.186 +            if (visit == InVisit)
   1.187 +            {
   1.188 +                out << " = ";
   1.189 +                // RHS of initialize is not being declared.
   1.190 +                mDeclaringVariables = false;
   1.191 +            }
   1.192 +            break;
   1.193 +        case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break;
   1.194 +        case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break;
   1.195 +        case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break;
   1.196 +        case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break;
   1.197 +        // Notice the fall-through.
   1.198 +        case EOpMulAssign: 
   1.199 +        case EOpVectorTimesMatrixAssign:
   1.200 +        case EOpVectorTimesScalarAssign:
   1.201 +        case EOpMatrixTimesScalarAssign:
   1.202 +        case EOpMatrixTimesMatrixAssign:
   1.203 +            writeTriplet(visit, "(", " *= ", ")");
   1.204 +            break;
   1.205 +
   1.206 +        case EOpIndexDirect:
   1.207 +            writeTriplet(visit, NULL, "[", "]");
   1.208 +            break;
   1.209 +        case EOpIndexIndirect:
   1.210 +            if (node->getAddIndexClamp())
   1.211 +            {
   1.212 +                if (visit == InVisit)
   1.213 +                {
   1.214 +                    if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) {
   1.215 +                        out << "[int(clamp(float(";
   1.216 +                    } else {
   1.217 +                        out << "[webgl_int_clamp(";
   1.218 +                    }
   1.219 +                }
   1.220 +                else if (visit == PostVisit)
   1.221 +                {
   1.222 +                    int maxSize;
   1.223 +                    TIntermTyped *left = node->getLeft();
   1.224 +                    TType leftType = left->getType();
   1.225 +
   1.226 +                    if (left->isArray())
   1.227 +                    {
   1.228 +                        // The shader will fail validation if the array length is not > 0.
   1.229 +                        maxSize = leftType.getArraySize() - 1;
   1.230 +                    }
   1.231 +                    else
   1.232 +                    {
   1.233 +                        maxSize = leftType.getNominalSize() - 1;
   1.234 +                    }
   1.235 +
   1.236 +                    if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) {
   1.237 +                        out << "), 0.0, float(" << maxSize << ")))]";
   1.238 +                    } else {
   1.239 +                        out << ", 0, " << maxSize << ")]";
   1.240 +                    }
   1.241 +                }
   1.242 +            }
   1.243 +            else
   1.244 +            {
   1.245 +                writeTriplet(visit, NULL, "[", "]");
   1.246 +            }
   1.247 +            break;
   1.248 +        case EOpIndexDirectStruct:
   1.249 +            if (visit == InVisit)
   1.250 +            {
   1.251 +                // Here we are writing out "foo.bar", where "foo" is struct
   1.252 +                // and "bar" is field. In AST, it is represented as a binary
   1.253 +                // node, where left child represents "foo" and right child "bar".
   1.254 +                // The node itself represents ".". The struct field "bar" is
   1.255 +                // actually stored as an index into TStructure::fields.
   1.256 +                out << ".";
   1.257 +                const TStructure* structure = node->getLeft()->getType().getStruct();
   1.258 +                const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
   1.259 +                const TField* field = structure->fields()[index->getIConst(0)];
   1.260 +
   1.261 +                TString fieldName = field->name();
   1.262 +                if (!mSymbolTable.findBuiltIn(structure->name()))
   1.263 +                    fieldName = hashName(fieldName);
   1.264 +
   1.265 +                out << fieldName;
   1.266 +                visitChildren = false;
   1.267 +            }
   1.268 +            break;
   1.269 +        case EOpVectorSwizzle:
   1.270 +            if (visit == InVisit)
   1.271 +            {
   1.272 +                out << ".";
   1.273 +                TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
   1.274 +                TIntermSequence& sequence = rightChild->getSequence();
   1.275 +                for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
   1.276 +                {
   1.277 +                    TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
   1.278 +                    ASSERT(element->getBasicType() == EbtInt);
   1.279 +                    ASSERT(element->getNominalSize() == 1);
   1.280 +                    const ConstantUnion& data = element->getUnionArrayPointer()[0];
   1.281 +                    ASSERT(data.getType() == EbtInt);
   1.282 +                    switch (data.getIConst())
   1.283 +                    {
   1.284 +                        case 0: out << "x"; break;
   1.285 +                        case 1: out << "y"; break;
   1.286 +                        case 2: out << "z"; break;
   1.287 +                        case 3: out << "w"; break;
   1.288 +                        default: UNREACHABLE(); break;
   1.289 +                    }
   1.290 +                }
   1.291 +                visitChildren = false;
   1.292 +            }
   1.293 +            break;
   1.294 +
   1.295 +        case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
   1.296 +        case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
   1.297 +        case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
   1.298 +        case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
   1.299 +        case EOpMod: UNIMPLEMENTED(); break;
   1.300 +        case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
   1.301 +        case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
   1.302 +        case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
   1.303 +        case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
   1.304 +        case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
   1.305 +        case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
   1.306 +
   1.307 +        // Notice the fall-through.
   1.308 +        case EOpVectorTimesScalar:
   1.309 +        case EOpVectorTimesMatrix:
   1.310 +        case EOpMatrixTimesVector:
   1.311 +        case EOpMatrixTimesScalar:
   1.312 +        case EOpMatrixTimesMatrix:
   1.313 +            writeTriplet(visit, "(", " * ", ")");
   1.314 +            break;
   1.315 +
   1.316 +        case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
   1.317 +        case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
   1.318 +        case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
   1.319 +        default: UNREACHABLE(); break;
   1.320 +    }
   1.321 +
   1.322 +    return visitChildren;
   1.323 +}
   1.324 +
   1.325 +bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
   1.326 +{
   1.327 +    TString preString;
   1.328 +    TString postString = ")";
   1.329 +
   1.330 +    switch (node->getOp())
   1.331 +    {
   1.332 +        case EOpNegative: preString = "(-"; break;
   1.333 +        case EOpVectorLogicalNot: preString = "not("; break;
   1.334 +        case EOpLogicalNot: preString = "(!"; break;
   1.335 +
   1.336 +        case EOpPostIncrement: preString = "("; postString = "++)"; break;
   1.337 +        case EOpPostDecrement: preString = "("; postString = "--)"; break;
   1.338 +        case EOpPreIncrement: preString = "(++"; break;
   1.339 +        case EOpPreDecrement: preString = "(--"; break;
   1.340 +
   1.341 +        case EOpConvIntToBool:
   1.342 +        case EOpConvFloatToBool:
   1.343 +            switch (node->getOperand()->getType().getNominalSize())
   1.344 +            {
   1.345 +                case 1: preString =  "bool(";  break;
   1.346 +                case 2: preString = "bvec2("; break;
   1.347 +                case 3: preString = "bvec3("; break;
   1.348 +                case 4: preString = "bvec4("; break;
   1.349 +                default: UNREACHABLE();
   1.350 +            }
   1.351 +            break;
   1.352 +        case EOpConvBoolToFloat:
   1.353 +        case EOpConvIntToFloat:
   1.354 +            switch (node->getOperand()->getType().getNominalSize())
   1.355 +            {
   1.356 +                case 1: preString = "float(";  break;
   1.357 +                case 2: preString = "vec2("; break;
   1.358 +                case 3: preString = "vec3("; break;
   1.359 +                case 4: preString = "vec4("; break;
   1.360 +                default: UNREACHABLE();
   1.361 +            }
   1.362 +            break;
   1.363 +        case EOpConvFloatToInt:
   1.364 +        case EOpConvBoolToInt:
   1.365 +            switch (node->getOperand()->getType().getNominalSize())
   1.366 +            {
   1.367 +                case 1: preString = "int(";  break;
   1.368 +                case 2: preString = "ivec2("; break;
   1.369 +                case 3: preString = "ivec3("; break;
   1.370 +                case 4: preString = "ivec4("; break;
   1.371 +                default: UNREACHABLE();
   1.372 +            }
   1.373 +            break;
   1.374 +
   1.375 +        case EOpRadians: preString = "radians("; break;
   1.376 +        case EOpDegrees: preString = "degrees("; break;
   1.377 +        case EOpSin: preString = "sin("; break;
   1.378 +        case EOpCos: preString = "cos("; break;
   1.379 +        case EOpTan: preString = "tan("; break;
   1.380 +        case EOpAsin: preString = "asin("; break;
   1.381 +        case EOpAcos: preString = "acos("; break;
   1.382 +        case EOpAtan: preString = "atan("; break;
   1.383 +
   1.384 +        case EOpExp: preString = "exp("; break;
   1.385 +        case EOpLog: preString = "log("; break;
   1.386 +        case EOpExp2: preString = "exp2("; break;
   1.387 +        case EOpLog2: preString = "log2("; break;
   1.388 +        case EOpSqrt: preString = "sqrt("; break;
   1.389 +        case EOpInverseSqrt: preString = "inversesqrt("; break;
   1.390 +
   1.391 +        case EOpAbs: preString = "abs("; break;
   1.392 +        case EOpSign: preString = "sign("; break;
   1.393 +        case EOpFloor: preString = "floor("; break;
   1.394 +        case EOpCeil: preString = "ceil("; break;
   1.395 +        case EOpFract: preString = "fract("; break;
   1.396 +
   1.397 +        case EOpLength: preString = "length("; break;
   1.398 +        case EOpNormalize: preString = "normalize("; break;
   1.399 +
   1.400 +        case EOpDFdx: preString = "dFdx("; break;
   1.401 +        case EOpDFdy: preString = "dFdy("; break;
   1.402 +        case EOpFwidth: preString = "fwidth("; break;
   1.403 +
   1.404 +        case EOpAny: preString = "any("; break;
   1.405 +        case EOpAll: preString = "all("; break;
   1.406 +
   1.407 +        default: UNREACHABLE(); break;
   1.408 +    }
   1.409 +
   1.410 +    if (visit == PreVisit && node->getUseEmulatedFunction())
   1.411 +        preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
   1.412 +    writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
   1.413 +
   1.414 +    return true;
   1.415 +}
   1.416 +
   1.417 +bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
   1.418 +{
   1.419 +    TInfoSinkBase& out = objSink();
   1.420 +
   1.421 +    if (node->usesTernaryOperator())
   1.422 +    {
   1.423 +        // Notice two brackets at the beginning and end. The outer ones
   1.424 +        // encapsulate the whole ternary expression. This preserves the
   1.425 +        // order of precedence when ternary expressions are used in a
   1.426 +        // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
   1.427 +        out << "((";
   1.428 +        node->getCondition()->traverse(this);
   1.429 +        out << ") ? (";
   1.430 +        node->getTrueBlock()->traverse(this);
   1.431 +        out << ") : (";
   1.432 +        node->getFalseBlock()->traverse(this);
   1.433 +        out << "))";
   1.434 +    }
   1.435 +    else
   1.436 +    {
   1.437 +        out << "if (";
   1.438 +        node->getCondition()->traverse(this);
   1.439 +        out << ")\n";
   1.440 +
   1.441 +        incrementDepth();
   1.442 +        visitCodeBlock(node->getTrueBlock());
   1.443 +
   1.444 +        if (node->getFalseBlock())
   1.445 +        {
   1.446 +            out << "else\n";
   1.447 +            visitCodeBlock(node->getFalseBlock());
   1.448 +        }
   1.449 +        decrementDepth();
   1.450 +    }
   1.451 +    return false;
   1.452 +}
   1.453 +
   1.454 +bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
   1.455 +{
   1.456 +    bool visitChildren = true;
   1.457 +    TInfoSinkBase& out = objSink();
   1.458 +    TString preString;
   1.459 +    bool delayedWrite = false;
   1.460 +    switch (node->getOp())
   1.461 +    {
   1.462 +        case EOpSequence: {
   1.463 +            // Scope the sequences except when at the global scope.
   1.464 +            if (depth > 0) out << "{\n";
   1.465 +
   1.466 +            incrementDepth();
   1.467 +            const TIntermSequence& sequence = node->getSequence();
   1.468 +            for (TIntermSequence::const_iterator iter = sequence.begin();
   1.469 +                 iter != sequence.end(); ++iter)
   1.470 +            {
   1.471 +                TIntermNode* node = *iter;
   1.472 +                ASSERT(node != NULL);
   1.473 +                node->traverse(this);
   1.474 +
   1.475 +                if (isSingleStatement(node))
   1.476 +                    out << ";\n";
   1.477 +            }
   1.478 +            decrementDepth();
   1.479 +
   1.480 +            // Scope the sequences except when at the global scope.
   1.481 +            if (depth > 0) out << "}\n";
   1.482 +            visitChildren = false;
   1.483 +            break;
   1.484 +        }
   1.485 +        case EOpPrototype: {
   1.486 +            // Function declaration.
   1.487 +            ASSERT(visit == PreVisit);
   1.488 +            writeVariableType(node->getType());
   1.489 +            out << " " << hashName(node->getName());
   1.490 +
   1.491 +            out << "(";
   1.492 +            writeFunctionParameters(node->getSequence());
   1.493 +            out << ")";
   1.494 +
   1.495 +            visitChildren = false;
   1.496 +            break;
   1.497 +        }
   1.498 +        case EOpFunction: {
   1.499 +            // Function definition.
   1.500 +            ASSERT(visit == PreVisit);
   1.501 +            writeVariableType(node->getType());
   1.502 +            out << " " << hashFunctionName(node->getName());
   1.503 +
   1.504 +            incrementDepth();
   1.505 +            // Function definition node contains one or two children nodes
   1.506 +            // representing function parameters and function body. The latter
   1.507 +            // is not present in case of empty function bodies.
   1.508 +            const TIntermSequence& sequence = node->getSequence();
   1.509 +            ASSERT((sequence.size() == 1) || (sequence.size() == 2));
   1.510 +            TIntermSequence::const_iterator seqIter = sequence.begin();
   1.511 +
   1.512 +            // Traverse function parameters.
   1.513 +            TIntermAggregate* params = (*seqIter)->getAsAggregate();
   1.514 +            ASSERT(params != NULL);
   1.515 +            ASSERT(params->getOp() == EOpParameters);
   1.516 +            params->traverse(this);
   1.517 +
   1.518 +            // Traverse function body.
   1.519 +            TIntermAggregate* body = ++seqIter != sequence.end() ?
   1.520 +                (*seqIter)->getAsAggregate() : NULL;
   1.521 +            visitCodeBlock(body);
   1.522 +            decrementDepth();
   1.523 + 
   1.524 +            // Fully processed; no need to visit children.
   1.525 +            visitChildren = false;
   1.526 +            break;
   1.527 +        }
   1.528 +        case EOpFunctionCall:
   1.529 +            // Function call.
   1.530 +            if (visit == PreVisit)
   1.531 +            {
   1.532 +                out << hashFunctionName(node->getName()) << "(";
   1.533 +            }
   1.534 +            else if (visit == InVisit)
   1.535 +            {
   1.536 +                out << ", ";
   1.537 +            }
   1.538 +            else
   1.539 +            {
   1.540 +                out << ")";
   1.541 +            }
   1.542 +            break;
   1.543 +        case EOpParameters: {
   1.544 +            // Function parameters.
   1.545 +            ASSERT(visit == PreVisit);
   1.546 +            out << "(";
   1.547 +            writeFunctionParameters(node->getSequence());
   1.548 +            out << ")";
   1.549 +            visitChildren = false;
   1.550 +            break;
   1.551 +        }
   1.552 +        case EOpDeclaration: {
   1.553 +            // Variable declaration.
   1.554 +            if (visit == PreVisit)
   1.555 +            {
   1.556 +                const TIntermSequence& sequence = node->getSequence();
   1.557 +                const TIntermTyped* variable = sequence.front()->getAsTyped();
   1.558 +                writeVariableType(variable->getType());
   1.559 +                out << " ";
   1.560 +                mDeclaringVariables = true;
   1.561 +            }
   1.562 +            else if (visit == InVisit)
   1.563 +            {
   1.564 +                out << ", ";
   1.565 +                mDeclaringVariables = true;
   1.566 +            }
   1.567 +            else
   1.568 +            {
   1.569 +                mDeclaringVariables = false;
   1.570 +            }
   1.571 +            break;
   1.572 +        }
   1.573 +        case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
   1.574 +        case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
   1.575 +        case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
   1.576 +        case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
   1.577 +        case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
   1.578 +        case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
   1.579 +        case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
   1.580 +        case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
   1.581 +        case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
   1.582 +        case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
   1.583 +        case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
   1.584 +        case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
   1.585 +        case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
   1.586 +        case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
   1.587 +        case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
   1.588 +        case EOpConstructStruct:
   1.589 +            if (visit == PreVisit)
   1.590 +            {
   1.591 +                const TType& type = node->getType();
   1.592 +                ASSERT(type.getBasicType() == EbtStruct);
   1.593 +                out << hashName(type.getStruct()->name()) << "(";
   1.594 +            }
   1.595 +            else if (visit == InVisit)
   1.596 +            {
   1.597 +                out << ", ";
   1.598 +            }
   1.599 +            else
   1.600 +            {
   1.601 +                out << ")";
   1.602 +            }
   1.603 +            break;
   1.604 +
   1.605 +        case EOpLessThan: preString = "lessThan("; delayedWrite = true; break;
   1.606 +        case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break;
   1.607 +        case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break;
   1.608 +        case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break;
   1.609 +        case EOpVectorEqual: preString = "equal("; delayedWrite = true; break;
   1.610 +        case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break;
   1.611 +        case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
   1.612 +
   1.613 +        case EOpMod: preString = "mod("; delayedWrite = true; break;
   1.614 +        case EOpPow: preString = "pow("; delayedWrite = true; break;
   1.615 +        case EOpAtan: preString = "atan("; delayedWrite = true; break;
   1.616 +        case EOpMin: preString = "min("; delayedWrite = true; break;
   1.617 +        case EOpMax: preString = "max("; delayedWrite = true; break;
   1.618 +        case EOpClamp: preString = "clamp("; delayedWrite = true; break;
   1.619 +        case EOpMix: preString = "mix("; delayedWrite = true; break;
   1.620 +        case EOpStep: preString = "step("; delayedWrite = true; break;
   1.621 +        case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break;
   1.622 +
   1.623 +        case EOpDistance: preString = "distance("; delayedWrite = true; break;
   1.624 +        case EOpDot: preString = "dot("; delayedWrite = true; break;
   1.625 +        case EOpCross: preString = "cross("; delayedWrite = true; break;
   1.626 +        case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break;
   1.627 +        case EOpReflect: preString = "reflect("; delayedWrite = true; break;
   1.628 +        case EOpRefract: preString = "refract("; delayedWrite = true; break;
   1.629 +        case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break;
   1.630 +
   1.631 +        default: UNREACHABLE(); break;
   1.632 +    }
   1.633 +    if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction())
   1.634 +        preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
   1.635 +    if (delayedWrite)
   1.636 +        writeTriplet(visit, preString.c_str(), ", ", ")");
   1.637 +    return visitChildren;
   1.638 +}
   1.639 +
   1.640 +bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
   1.641 +{
   1.642 +    TInfoSinkBase& out = objSink();
   1.643 +
   1.644 +    incrementDepth();
   1.645 +    // Loop header.
   1.646 +    TLoopType loopType = node->getType();
   1.647 +    if (loopType == ELoopFor)  // for loop
   1.648 +    {
   1.649 +        if (!node->getUnrollFlag()) {
   1.650 +            out << "for (";
   1.651 +            if (node->getInit())
   1.652 +                node->getInit()->traverse(this);
   1.653 +            out << "; ";
   1.654 +
   1.655 +            if (node->getCondition())
   1.656 +                node->getCondition()->traverse(this);
   1.657 +            out << "; ";
   1.658 +
   1.659 +            if (node->getExpression())
   1.660 +                node->getExpression()->traverse(this);
   1.661 +            out << ")\n";
   1.662 +        }
   1.663 +    }
   1.664 +    else if (loopType == ELoopWhile)  // while loop
   1.665 +    {
   1.666 +        out << "while (";
   1.667 +        ASSERT(node->getCondition() != NULL);
   1.668 +        node->getCondition()->traverse(this);
   1.669 +        out << ")\n";
   1.670 +    }
   1.671 +    else  // do-while loop
   1.672 +    {
   1.673 +        ASSERT(loopType == ELoopDoWhile);
   1.674 +        out << "do\n";
   1.675 +    }
   1.676 +
   1.677 +    // Loop body.
   1.678 +    if (node->getUnrollFlag())
   1.679 +    {
   1.680 +        TLoopIndexInfo indexInfo;
   1.681 +        mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
   1.682 +        mLoopUnroll.Push(indexInfo);
   1.683 +        while (mLoopUnroll.SatisfiesLoopCondition())
   1.684 +        {
   1.685 +            visitCodeBlock(node->getBody());
   1.686 +            mLoopUnroll.Step();
   1.687 +        }
   1.688 +        mLoopUnroll.Pop();
   1.689 +    }
   1.690 +    else
   1.691 +    {
   1.692 +        visitCodeBlock(node->getBody());
   1.693 +    }
   1.694 +
   1.695 +    // Loop footer.
   1.696 +    if (loopType == ELoopDoWhile)  // do-while loop
   1.697 +    {
   1.698 +        out << "while (";
   1.699 +        ASSERT(node->getCondition() != NULL);
   1.700 +        node->getCondition()->traverse(this);
   1.701 +        out << ");\n";
   1.702 +    }
   1.703 +    decrementDepth();
   1.704 +
   1.705 +    // No need to visit children. They have been already processed in
   1.706 +    // this function.
   1.707 +    return false;
   1.708 +}
   1.709 +
   1.710 +bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
   1.711 +{
   1.712 +    switch (node->getFlowOp())
   1.713 +    {
   1.714 +        case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
   1.715 +        case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
   1.716 +        case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
   1.717 +        case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
   1.718 +        default: UNREACHABLE(); break;
   1.719 +    }
   1.720 +
   1.721 +    return true;
   1.722 +}
   1.723 +
   1.724 +void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
   1.725 +    TInfoSinkBase &out = objSink();
   1.726 +    if (node != NULL)
   1.727 +    {
   1.728 +        node->traverse(this);
   1.729 +        // Single statements not part of a sequence need to be terminated
   1.730 +        // with semi-colon.
   1.731 +        if (isSingleStatement(node))
   1.732 +            out << ";\n";
   1.733 +    }
   1.734 +    else
   1.735 +    {
   1.736 +        out << "{\n}\n";  // Empty code block.
   1.737 +    }
   1.738 +}
   1.739 +
   1.740 +TString TOutputGLSLBase::getTypeName(const TType& type)
   1.741 +{
   1.742 +    TInfoSinkBase out;
   1.743 +    if (type.isMatrix())
   1.744 +    {
   1.745 +        out << "mat";
   1.746 +        out << type.getNominalSize();
   1.747 +    }
   1.748 +    else if (type.isVector())
   1.749 +    {
   1.750 +        switch (type.getBasicType())
   1.751 +        {
   1.752 +            case EbtFloat: out << "vec"; break;
   1.753 +            case EbtInt: out << "ivec"; break;
   1.754 +            case EbtBool: out << "bvec"; break;
   1.755 +            default: UNREACHABLE(); break;
   1.756 +        }
   1.757 +        out << type.getNominalSize();
   1.758 +    }
   1.759 +    else
   1.760 +    {
   1.761 +        if (type.getBasicType() == EbtStruct)
   1.762 +            out << hashName(type.getStruct()->name());
   1.763 +        else
   1.764 +            out << type.getBasicString();
   1.765 +    }
   1.766 +    return TString(out.c_str());
   1.767 +}
   1.768 +
   1.769 +TString TOutputGLSLBase::hashName(const TString& name)
   1.770 +{
   1.771 +    if (mHashFunction == NULL || name.empty())
   1.772 +        return name;
   1.773 +    NameMap::const_iterator it = mNameMap.find(name.c_str());
   1.774 +    if (it != mNameMap.end())
   1.775 +        return it->second.c_str();
   1.776 +    TString hashedName = TIntermTraverser::hash(name, mHashFunction);
   1.777 +    mNameMap[name.c_str()] = hashedName.c_str();
   1.778 +    return hashedName;
   1.779 +}
   1.780 +
   1.781 +TString TOutputGLSLBase::hashVariableName(const TString& name)
   1.782 +{
   1.783 +    if (mSymbolTable.findBuiltIn(name) != NULL)
   1.784 +        return name;
   1.785 +    return hashName(name);
   1.786 +}
   1.787 +
   1.788 +TString TOutputGLSLBase::hashFunctionName(const TString& mangled_name)
   1.789 +{
   1.790 +    TString name = TFunction::unmangleName(mangled_name);
   1.791 +    if (mSymbolTable.findBuiltIn(mangled_name) != NULL || name == "main")
   1.792 +        return name;
   1.793 +    return hashName(name);
   1.794 +}
   1.795 +
   1.796 +bool TOutputGLSLBase::structDeclared(const TStructure* structure) const
   1.797 +{
   1.798 +    return mDeclaredStructs.find(structure->name()) != mDeclaredStructs.end();
   1.799 +}
   1.800 +
   1.801 +void TOutputGLSLBase::declareStruct(const TStructure* structure)
   1.802 +{
   1.803 +    TInfoSinkBase& out = objSink();
   1.804 +
   1.805 +    out << "struct " << hashName(structure->name()) << "{\n";
   1.806 +    const TFieldList& fields = structure->fields();
   1.807 +    for (size_t i = 0; i < fields.size(); ++i)
   1.808 +    {
   1.809 +        const TField* field = fields[i];
   1.810 +        if (writeVariablePrecision(field->type()->getPrecision()))
   1.811 +            out << " ";
   1.812 +        out << getTypeName(*field->type()) << " " << hashName(field->name());
   1.813 +        if (field->type()->isArray())
   1.814 +            out << arrayBrackets(*field->type());
   1.815 +        out << ";\n";
   1.816 +    }
   1.817 +    out << "}";
   1.818 +
   1.819 +    mDeclaredStructs.insert(structure->name());
   1.820 +}

mercurial