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 +}