gfx/angle/src/compiler/OutputGLSLBase.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 //
michael@0 2 // Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
michael@0 3 // Use of this source code is governed by a BSD-style license that can be
michael@0 4 // found in the LICENSE file.
michael@0 5 //
michael@0 6
michael@0 7 #include "compiler/OutputGLSLBase.h"
michael@0 8 #include "compiler/compiler_debug.h"
michael@0 9
michael@0 10 #include <cfloat>
michael@0 11
michael@0 12 namespace
michael@0 13 {
michael@0 14 TString arrayBrackets(const TType& type)
michael@0 15 {
michael@0 16 ASSERT(type.isArray());
michael@0 17 TInfoSinkBase out;
michael@0 18 out << "[" << type.getArraySize() << "]";
michael@0 19 return TString(out.c_str());
michael@0 20 }
michael@0 21
michael@0 22 bool isSingleStatement(TIntermNode* node) {
michael@0 23 if (const TIntermAggregate* aggregate = node->getAsAggregate())
michael@0 24 {
michael@0 25 return (aggregate->getOp() != EOpFunction) &&
michael@0 26 (aggregate->getOp() != EOpSequence);
michael@0 27 }
michael@0 28 else if (const TIntermSelection* selection = node->getAsSelectionNode())
michael@0 29 {
michael@0 30 // Ternary operators are usually part of an assignment operator.
michael@0 31 // This handles those rare cases in which they are all by themselves.
michael@0 32 return selection->usesTernaryOperator();
michael@0 33 }
michael@0 34 else if (node->getAsLoopNode())
michael@0 35 {
michael@0 36 return false;
michael@0 37 }
michael@0 38 return true;
michael@0 39 }
michael@0 40 } // namespace
michael@0 41
michael@0 42 TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink,
michael@0 43 ShArrayIndexClampingStrategy clampingStrategy,
michael@0 44 ShHashFunction64 hashFunction,
michael@0 45 NameMap& nameMap,
michael@0 46 TSymbolTable& symbolTable)
michael@0 47 : TIntermTraverser(true, true, true),
michael@0 48 mObjSink(objSink),
michael@0 49 mDeclaringVariables(false),
michael@0 50 mClampingStrategy(clampingStrategy),
michael@0 51 mHashFunction(hashFunction),
michael@0 52 mNameMap(nameMap),
michael@0 53 mSymbolTable(symbolTable)
michael@0 54 {
michael@0 55 }
michael@0 56
michael@0 57 void TOutputGLSLBase::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
michael@0 58 {
michael@0 59 TInfoSinkBase& out = objSink();
michael@0 60 if (visit == PreVisit && preStr)
michael@0 61 {
michael@0 62 out << preStr;
michael@0 63 }
michael@0 64 else if (visit == InVisit && inStr)
michael@0 65 {
michael@0 66 out << inStr;
michael@0 67 }
michael@0 68 else if (visit == PostVisit && postStr)
michael@0 69 {
michael@0 70 out << postStr;
michael@0 71 }
michael@0 72 }
michael@0 73
michael@0 74 void TOutputGLSLBase::writeVariableType(const TType& type)
michael@0 75 {
michael@0 76 TInfoSinkBase& out = objSink();
michael@0 77 TQualifier qualifier = type.getQualifier();
michael@0 78 // TODO(alokp): Validate qualifier for variable declarations.
michael@0 79 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
michael@0 80 out << type.getQualifierString() << " ";
michael@0 81 // Declare the struct if we have not done so already.
michael@0 82 if ((type.getBasicType() == EbtStruct) && !structDeclared(type.getStruct()))
michael@0 83 {
michael@0 84 declareStruct(type.getStruct());
michael@0 85 }
michael@0 86 else
michael@0 87 {
michael@0 88 if (writeVariablePrecision(type.getPrecision()))
michael@0 89 out << " ";
michael@0 90 out << getTypeName(type);
michael@0 91 }
michael@0 92 }
michael@0 93
michael@0 94 void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args)
michael@0 95 {
michael@0 96 TInfoSinkBase& out = objSink();
michael@0 97 for (TIntermSequence::const_iterator iter = args.begin();
michael@0 98 iter != args.end(); ++iter)
michael@0 99 {
michael@0 100 const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
michael@0 101 ASSERT(arg != NULL);
michael@0 102
michael@0 103 const TType& type = arg->getType();
michael@0 104 writeVariableType(type);
michael@0 105
michael@0 106 const TString& name = arg->getSymbol();
michael@0 107 if (!name.empty())
michael@0 108 out << " " << hashName(name);
michael@0 109 if (type.isArray())
michael@0 110 out << arrayBrackets(type);
michael@0 111
michael@0 112 // Put a comma if this is not the last argument.
michael@0 113 if (iter != args.end() - 1)
michael@0 114 out << ", ";
michael@0 115 }
michael@0 116 }
michael@0 117
michael@0 118 const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
michael@0 119 const ConstantUnion* pConstUnion)
michael@0 120 {
michael@0 121 TInfoSinkBase& out = objSink();
michael@0 122
michael@0 123 if (type.getBasicType() == EbtStruct)
michael@0 124 {
michael@0 125 const TStructure* structure = type.getStruct();
michael@0 126 out << hashName(structure->name()) << "(";
michael@0 127
michael@0 128 const TFieldList& fields = structure->fields();
michael@0 129 for (size_t i = 0; i < fields.size(); ++i)
michael@0 130 {
michael@0 131 const TType* fieldType = fields[i]->type();
michael@0 132 ASSERT(fieldType != NULL);
michael@0 133 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
michael@0 134 if (i != fields.size() - 1) out << ", ";
michael@0 135 }
michael@0 136 out << ")";
michael@0 137 }
michael@0 138 else
michael@0 139 {
michael@0 140 size_t size = type.getObjectSize();
michael@0 141 bool writeType = size > 1;
michael@0 142 if (writeType) out << getTypeName(type) << "(";
michael@0 143 for (size_t i = 0; i < size; ++i, ++pConstUnion)
michael@0 144 {
michael@0 145 switch (pConstUnion->getType())
michael@0 146 {
michael@0 147 case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst())); break;
michael@0 148 case EbtInt: out << pConstUnion->getIConst(); break;
michael@0 149 case EbtBool: out << pConstUnion->getBConst(); break;
michael@0 150 default: UNREACHABLE();
michael@0 151 }
michael@0 152 if (i != size - 1) out << ", ";
michael@0 153 }
michael@0 154 if (writeType) out << ")";
michael@0 155 }
michael@0 156 return pConstUnion;
michael@0 157 }
michael@0 158
michael@0 159 void TOutputGLSLBase::visitSymbol(TIntermSymbol* node)
michael@0 160 {
michael@0 161 TInfoSinkBase& out = objSink();
michael@0 162 if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node))
michael@0 163 out << mLoopUnroll.GetLoopIndexValue(node);
michael@0 164 else
michael@0 165 out << hashVariableName(node->getSymbol());
michael@0 166
michael@0 167 if (mDeclaringVariables && node->getType().isArray())
michael@0 168 out << arrayBrackets(node->getType());
michael@0 169 }
michael@0 170
michael@0 171 void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
michael@0 172 {
michael@0 173 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
michael@0 174 }
michael@0 175
michael@0 176 bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
michael@0 177 {
michael@0 178 bool visitChildren = true;
michael@0 179 TInfoSinkBase& out = objSink();
michael@0 180 switch (node->getOp())
michael@0 181 {
michael@0 182 case EOpInitialize:
michael@0 183 if (visit == InVisit)
michael@0 184 {
michael@0 185 out << " = ";
michael@0 186 // RHS of initialize is not being declared.
michael@0 187 mDeclaringVariables = false;
michael@0 188 }
michael@0 189 break;
michael@0 190 case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break;
michael@0 191 case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break;
michael@0 192 case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break;
michael@0 193 case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break;
michael@0 194 // Notice the fall-through.
michael@0 195 case EOpMulAssign:
michael@0 196 case EOpVectorTimesMatrixAssign:
michael@0 197 case EOpVectorTimesScalarAssign:
michael@0 198 case EOpMatrixTimesScalarAssign:
michael@0 199 case EOpMatrixTimesMatrixAssign:
michael@0 200 writeTriplet(visit, "(", " *= ", ")");
michael@0 201 break;
michael@0 202
michael@0 203 case EOpIndexDirect:
michael@0 204 writeTriplet(visit, NULL, "[", "]");
michael@0 205 break;
michael@0 206 case EOpIndexIndirect:
michael@0 207 if (node->getAddIndexClamp())
michael@0 208 {
michael@0 209 if (visit == InVisit)
michael@0 210 {
michael@0 211 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) {
michael@0 212 out << "[int(clamp(float(";
michael@0 213 } else {
michael@0 214 out << "[webgl_int_clamp(";
michael@0 215 }
michael@0 216 }
michael@0 217 else if (visit == PostVisit)
michael@0 218 {
michael@0 219 int maxSize;
michael@0 220 TIntermTyped *left = node->getLeft();
michael@0 221 TType leftType = left->getType();
michael@0 222
michael@0 223 if (left->isArray())
michael@0 224 {
michael@0 225 // The shader will fail validation if the array length is not > 0.
michael@0 226 maxSize = leftType.getArraySize() - 1;
michael@0 227 }
michael@0 228 else
michael@0 229 {
michael@0 230 maxSize = leftType.getNominalSize() - 1;
michael@0 231 }
michael@0 232
michael@0 233 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) {
michael@0 234 out << "), 0.0, float(" << maxSize << ")))]";
michael@0 235 } else {
michael@0 236 out << ", 0, " << maxSize << ")]";
michael@0 237 }
michael@0 238 }
michael@0 239 }
michael@0 240 else
michael@0 241 {
michael@0 242 writeTriplet(visit, NULL, "[", "]");
michael@0 243 }
michael@0 244 break;
michael@0 245 case EOpIndexDirectStruct:
michael@0 246 if (visit == InVisit)
michael@0 247 {
michael@0 248 // Here we are writing out "foo.bar", where "foo" is struct
michael@0 249 // and "bar" is field. In AST, it is represented as a binary
michael@0 250 // node, where left child represents "foo" and right child "bar".
michael@0 251 // The node itself represents ".". The struct field "bar" is
michael@0 252 // actually stored as an index into TStructure::fields.
michael@0 253 out << ".";
michael@0 254 const TStructure* structure = node->getLeft()->getType().getStruct();
michael@0 255 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
michael@0 256 const TField* field = structure->fields()[index->getIConst(0)];
michael@0 257
michael@0 258 TString fieldName = field->name();
michael@0 259 if (!mSymbolTable.findBuiltIn(structure->name()))
michael@0 260 fieldName = hashName(fieldName);
michael@0 261
michael@0 262 out << fieldName;
michael@0 263 visitChildren = false;
michael@0 264 }
michael@0 265 break;
michael@0 266 case EOpVectorSwizzle:
michael@0 267 if (visit == InVisit)
michael@0 268 {
michael@0 269 out << ".";
michael@0 270 TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
michael@0 271 TIntermSequence& sequence = rightChild->getSequence();
michael@0 272 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
michael@0 273 {
michael@0 274 TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
michael@0 275 ASSERT(element->getBasicType() == EbtInt);
michael@0 276 ASSERT(element->getNominalSize() == 1);
michael@0 277 const ConstantUnion& data = element->getUnionArrayPointer()[0];
michael@0 278 ASSERT(data.getType() == EbtInt);
michael@0 279 switch (data.getIConst())
michael@0 280 {
michael@0 281 case 0: out << "x"; break;
michael@0 282 case 1: out << "y"; break;
michael@0 283 case 2: out << "z"; break;
michael@0 284 case 3: out << "w"; break;
michael@0 285 default: UNREACHABLE(); break;
michael@0 286 }
michael@0 287 }
michael@0 288 visitChildren = false;
michael@0 289 }
michael@0 290 break;
michael@0 291
michael@0 292 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
michael@0 293 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
michael@0 294 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
michael@0 295 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
michael@0 296 case EOpMod: UNIMPLEMENTED(); break;
michael@0 297 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
michael@0 298 case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
michael@0 299 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
michael@0 300 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
michael@0 301 case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
michael@0 302 case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
michael@0 303
michael@0 304 // Notice the fall-through.
michael@0 305 case EOpVectorTimesScalar:
michael@0 306 case EOpVectorTimesMatrix:
michael@0 307 case EOpMatrixTimesVector:
michael@0 308 case EOpMatrixTimesScalar:
michael@0 309 case EOpMatrixTimesMatrix:
michael@0 310 writeTriplet(visit, "(", " * ", ")");
michael@0 311 break;
michael@0 312
michael@0 313 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
michael@0 314 case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
michael@0 315 case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
michael@0 316 default: UNREACHABLE(); break;
michael@0 317 }
michael@0 318
michael@0 319 return visitChildren;
michael@0 320 }
michael@0 321
michael@0 322 bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
michael@0 323 {
michael@0 324 TString preString;
michael@0 325 TString postString = ")";
michael@0 326
michael@0 327 switch (node->getOp())
michael@0 328 {
michael@0 329 case EOpNegative: preString = "(-"; break;
michael@0 330 case EOpVectorLogicalNot: preString = "not("; break;
michael@0 331 case EOpLogicalNot: preString = "(!"; break;
michael@0 332
michael@0 333 case EOpPostIncrement: preString = "("; postString = "++)"; break;
michael@0 334 case EOpPostDecrement: preString = "("; postString = "--)"; break;
michael@0 335 case EOpPreIncrement: preString = "(++"; break;
michael@0 336 case EOpPreDecrement: preString = "(--"; break;
michael@0 337
michael@0 338 case EOpConvIntToBool:
michael@0 339 case EOpConvFloatToBool:
michael@0 340 switch (node->getOperand()->getType().getNominalSize())
michael@0 341 {
michael@0 342 case 1: preString = "bool("; break;
michael@0 343 case 2: preString = "bvec2("; break;
michael@0 344 case 3: preString = "bvec3("; break;
michael@0 345 case 4: preString = "bvec4("; break;
michael@0 346 default: UNREACHABLE();
michael@0 347 }
michael@0 348 break;
michael@0 349 case EOpConvBoolToFloat:
michael@0 350 case EOpConvIntToFloat:
michael@0 351 switch (node->getOperand()->getType().getNominalSize())
michael@0 352 {
michael@0 353 case 1: preString = "float("; break;
michael@0 354 case 2: preString = "vec2("; break;
michael@0 355 case 3: preString = "vec3("; break;
michael@0 356 case 4: preString = "vec4("; break;
michael@0 357 default: UNREACHABLE();
michael@0 358 }
michael@0 359 break;
michael@0 360 case EOpConvFloatToInt:
michael@0 361 case EOpConvBoolToInt:
michael@0 362 switch (node->getOperand()->getType().getNominalSize())
michael@0 363 {
michael@0 364 case 1: preString = "int("; break;
michael@0 365 case 2: preString = "ivec2("; break;
michael@0 366 case 3: preString = "ivec3("; break;
michael@0 367 case 4: preString = "ivec4("; break;
michael@0 368 default: UNREACHABLE();
michael@0 369 }
michael@0 370 break;
michael@0 371
michael@0 372 case EOpRadians: preString = "radians("; break;
michael@0 373 case EOpDegrees: preString = "degrees("; break;
michael@0 374 case EOpSin: preString = "sin("; break;
michael@0 375 case EOpCos: preString = "cos("; break;
michael@0 376 case EOpTan: preString = "tan("; break;
michael@0 377 case EOpAsin: preString = "asin("; break;
michael@0 378 case EOpAcos: preString = "acos("; break;
michael@0 379 case EOpAtan: preString = "atan("; break;
michael@0 380
michael@0 381 case EOpExp: preString = "exp("; break;
michael@0 382 case EOpLog: preString = "log("; break;
michael@0 383 case EOpExp2: preString = "exp2("; break;
michael@0 384 case EOpLog2: preString = "log2("; break;
michael@0 385 case EOpSqrt: preString = "sqrt("; break;
michael@0 386 case EOpInverseSqrt: preString = "inversesqrt("; break;
michael@0 387
michael@0 388 case EOpAbs: preString = "abs("; break;
michael@0 389 case EOpSign: preString = "sign("; break;
michael@0 390 case EOpFloor: preString = "floor("; break;
michael@0 391 case EOpCeil: preString = "ceil("; break;
michael@0 392 case EOpFract: preString = "fract("; break;
michael@0 393
michael@0 394 case EOpLength: preString = "length("; break;
michael@0 395 case EOpNormalize: preString = "normalize("; break;
michael@0 396
michael@0 397 case EOpDFdx: preString = "dFdx("; break;
michael@0 398 case EOpDFdy: preString = "dFdy("; break;
michael@0 399 case EOpFwidth: preString = "fwidth("; break;
michael@0 400
michael@0 401 case EOpAny: preString = "any("; break;
michael@0 402 case EOpAll: preString = "all("; break;
michael@0 403
michael@0 404 default: UNREACHABLE(); break;
michael@0 405 }
michael@0 406
michael@0 407 if (visit == PreVisit && node->getUseEmulatedFunction())
michael@0 408 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
michael@0 409 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
michael@0 410
michael@0 411 return true;
michael@0 412 }
michael@0 413
michael@0 414 bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
michael@0 415 {
michael@0 416 TInfoSinkBase& out = objSink();
michael@0 417
michael@0 418 if (node->usesTernaryOperator())
michael@0 419 {
michael@0 420 // Notice two brackets at the beginning and end. The outer ones
michael@0 421 // encapsulate the whole ternary expression. This preserves the
michael@0 422 // order of precedence when ternary expressions are used in a
michael@0 423 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
michael@0 424 out << "((";
michael@0 425 node->getCondition()->traverse(this);
michael@0 426 out << ") ? (";
michael@0 427 node->getTrueBlock()->traverse(this);
michael@0 428 out << ") : (";
michael@0 429 node->getFalseBlock()->traverse(this);
michael@0 430 out << "))";
michael@0 431 }
michael@0 432 else
michael@0 433 {
michael@0 434 out << "if (";
michael@0 435 node->getCondition()->traverse(this);
michael@0 436 out << ")\n";
michael@0 437
michael@0 438 incrementDepth();
michael@0 439 visitCodeBlock(node->getTrueBlock());
michael@0 440
michael@0 441 if (node->getFalseBlock())
michael@0 442 {
michael@0 443 out << "else\n";
michael@0 444 visitCodeBlock(node->getFalseBlock());
michael@0 445 }
michael@0 446 decrementDepth();
michael@0 447 }
michael@0 448 return false;
michael@0 449 }
michael@0 450
michael@0 451 bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
michael@0 452 {
michael@0 453 bool visitChildren = true;
michael@0 454 TInfoSinkBase& out = objSink();
michael@0 455 TString preString;
michael@0 456 bool delayedWrite = false;
michael@0 457 switch (node->getOp())
michael@0 458 {
michael@0 459 case EOpSequence: {
michael@0 460 // Scope the sequences except when at the global scope.
michael@0 461 if (depth > 0) out << "{\n";
michael@0 462
michael@0 463 incrementDepth();
michael@0 464 const TIntermSequence& sequence = node->getSequence();
michael@0 465 for (TIntermSequence::const_iterator iter = sequence.begin();
michael@0 466 iter != sequence.end(); ++iter)
michael@0 467 {
michael@0 468 TIntermNode* node = *iter;
michael@0 469 ASSERT(node != NULL);
michael@0 470 node->traverse(this);
michael@0 471
michael@0 472 if (isSingleStatement(node))
michael@0 473 out << ";\n";
michael@0 474 }
michael@0 475 decrementDepth();
michael@0 476
michael@0 477 // Scope the sequences except when at the global scope.
michael@0 478 if (depth > 0) out << "}\n";
michael@0 479 visitChildren = false;
michael@0 480 break;
michael@0 481 }
michael@0 482 case EOpPrototype: {
michael@0 483 // Function declaration.
michael@0 484 ASSERT(visit == PreVisit);
michael@0 485 writeVariableType(node->getType());
michael@0 486 out << " " << hashName(node->getName());
michael@0 487
michael@0 488 out << "(";
michael@0 489 writeFunctionParameters(node->getSequence());
michael@0 490 out << ")";
michael@0 491
michael@0 492 visitChildren = false;
michael@0 493 break;
michael@0 494 }
michael@0 495 case EOpFunction: {
michael@0 496 // Function definition.
michael@0 497 ASSERT(visit == PreVisit);
michael@0 498 writeVariableType(node->getType());
michael@0 499 out << " " << hashFunctionName(node->getName());
michael@0 500
michael@0 501 incrementDepth();
michael@0 502 // Function definition node contains one or two children nodes
michael@0 503 // representing function parameters and function body. The latter
michael@0 504 // is not present in case of empty function bodies.
michael@0 505 const TIntermSequence& sequence = node->getSequence();
michael@0 506 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
michael@0 507 TIntermSequence::const_iterator seqIter = sequence.begin();
michael@0 508
michael@0 509 // Traverse function parameters.
michael@0 510 TIntermAggregate* params = (*seqIter)->getAsAggregate();
michael@0 511 ASSERT(params != NULL);
michael@0 512 ASSERT(params->getOp() == EOpParameters);
michael@0 513 params->traverse(this);
michael@0 514
michael@0 515 // Traverse function body.
michael@0 516 TIntermAggregate* body = ++seqIter != sequence.end() ?
michael@0 517 (*seqIter)->getAsAggregate() : NULL;
michael@0 518 visitCodeBlock(body);
michael@0 519 decrementDepth();
michael@0 520
michael@0 521 // Fully processed; no need to visit children.
michael@0 522 visitChildren = false;
michael@0 523 break;
michael@0 524 }
michael@0 525 case EOpFunctionCall:
michael@0 526 // Function call.
michael@0 527 if (visit == PreVisit)
michael@0 528 {
michael@0 529 out << hashFunctionName(node->getName()) << "(";
michael@0 530 }
michael@0 531 else if (visit == InVisit)
michael@0 532 {
michael@0 533 out << ", ";
michael@0 534 }
michael@0 535 else
michael@0 536 {
michael@0 537 out << ")";
michael@0 538 }
michael@0 539 break;
michael@0 540 case EOpParameters: {
michael@0 541 // Function parameters.
michael@0 542 ASSERT(visit == PreVisit);
michael@0 543 out << "(";
michael@0 544 writeFunctionParameters(node->getSequence());
michael@0 545 out << ")";
michael@0 546 visitChildren = false;
michael@0 547 break;
michael@0 548 }
michael@0 549 case EOpDeclaration: {
michael@0 550 // Variable declaration.
michael@0 551 if (visit == PreVisit)
michael@0 552 {
michael@0 553 const TIntermSequence& sequence = node->getSequence();
michael@0 554 const TIntermTyped* variable = sequence.front()->getAsTyped();
michael@0 555 writeVariableType(variable->getType());
michael@0 556 out << " ";
michael@0 557 mDeclaringVariables = true;
michael@0 558 }
michael@0 559 else if (visit == InVisit)
michael@0 560 {
michael@0 561 out << ", ";
michael@0 562 mDeclaringVariables = true;
michael@0 563 }
michael@0 564 else
michael@0 565 {
michael@0 566 mDeclaringVariables = false;
michael@0 567 }
michael@0 568 break;
michael@0 569 }
michael@0 570 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
michael@0 571 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
michael@0 572 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
michael@0 573 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
michael@0 574 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
michael@0 575 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
michael@0 576 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
michael@0 577 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
michael@0 578 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
michael@0 579 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
michael@0 580 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
michael@0 581 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
michael@0 582 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
michael@0 583 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
michael@0 584 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
michael@0 585 case EOpConstructStruct:
michael@0 586 if (visit == PreVisit)
michael@0 587 {
michael@0 588 const TType& type = node->getType();
michael@0 589 ASSERT(type.getBasicType() == EbtStruct);
michael@0 590 out << hashName(type.getStruct()->name()) << "(";
michael@0 591 }
michael@0 592 else if (visit == InVisit)
michael@0 593 {
michael@0 594 out << ", ";
michael@0 595 }
michael@0 596 else
michael@0 597 {
michael@0 598 out << ")";
michael@0 599 }
michael@0 600 break;
michael@0 601
michael@0 602 case EOpLessThan: preString = "lessThan("; delayedWrite = true; break;
michael@0 603 case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break;
michael@0 604 case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break;
michael@0 605 case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break;
michael@0 606 case EOpVectorEqual: preString = "equal("; delayedWrite = true; break;
michael@0 607 case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break;
michael@0 608 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
michael@0 609
michael@0 610 case EOpMod: preString = "mod("; delayedWrite = true; break;
michael@0 611 case EOpPow: preString = "pow("; delayedWrite = true; break;
michael@0 612 case EOpAtan: preString = "atan("; delayedWrite = true; break;
michael@0 613 case EOpMin: preString = "min("; delayedWrite = true; break;
michael@0 614 case EOpMax: preString = "max("; delayedWrite = true; break;
michael@0 615 case EOpClamp: preString = "clamp("; delayedWrite = true; break;
michael@0 616 case EOpMix: preString = "mix("; delayedWrite = true; break;
michael@0 617 case EOpStep: preString = "step("; delayedWrite = true; break;
michael@0 618 case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break;
michael@0 619
michael@0 620 case EOpDistance: preString = "distance("; delayedWrite = true; break;
michael@0 621 case EOpDot: preString = "dot("; delayedWrite = true; break;
michael@0 622 case EOpCross: preString = "cross("; delayedWrite = true; break;
michael@0 623 case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break;
michael@0 624 case EOpReflect: preString = "reflect("; delayedWrite = true; break;
michael@0 625 case EOpRefract: preString = "refract("; delayedWrite = true; break;
michael@0 626 case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break;
michael@0 627
michael@0 628 default: UNREACHABLE(); break;
michael@0 629 }
michael@0 630 if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction())
michael@0 631 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
michael@0 632 if (delayedWrite)
michael@0 633 writeTriplet(visit, preString.c_str(), ", ", ")");
michael@0 634 return visitChildren;
michael@0 635 }
michael@0 636
michael@0 637 bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
michael@0 638 {
michael@0 639 TInfoSinkBase& out = objSink();
michael@0 640
michael@0 641 incrementDepth();
michael@0 642 // Loop header.
michael@0 643 TLoopType loopType = node->getType();
michael@0 644 if (loopType == ELoopFor) // for loop
michael@0 645 {
michael@0 646 if (!node->getUnrollFlag()) {
michael@0 647 out << "for (";
michael@0 648 if (node->getInit())
michael@0 649 node->getInit()->traverse(this);
michael@0 650 out << "; ";
michael@0 651
michael@0 652 if (node->getCondition())
michael@0 653 node->getCondition()->traverse(this);
michael@0 654 out << "; ";
michael@0 655
michael@0 656 if (node->getExpression())
michael@0 657 node->getExpression()->traverse(this);
michael@0 658 out << ")\n";
michael@0 659 }
michael@0 660 }
michael@0 661 else if (loopType == ELoopWhile) // while loop
michael@0 662 {
michael@0 663 out << "while (";
michael@0 664 ASSERT(node->getCondition() != NULL);
michael@0 665 node->getCondition()->traverse(this);
michael@0 666 out << ")\n";
michael@0 667 }
michael@0 668 else // do-while loop
michael@0 669 {
michael@0 670 ASSERT(loopType == ELoopDoWhile);
michael@0 671 out << "do\n";
michael@0 672 }
michael@0 673
michael@0 674 // Loop body.
michael@0 675 if (node->getUnrollFlag())
michael@0 676 {
michael@0 677 TLoopIndexInfo indexInfo;
michael@0 678 mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
michael@0 679 mLoopUnroll.Push(indexInfo);
michael@0 680 while (mLoopUnroll.SatisfiesLoopCondition())
michael@0 681 {
michael@0 682 visitCodeBlock(node->getBody());
michael@0 683 mLoopUnroll.Step();
michael@0 684 }
michael@0 685 mLoopUnroll.Pop();
michael@0 686 }
michael@0 687 else
michael@0 688 {
michael@0 689 visitCodeBlock(node->getBody());
michael@0 690 }
michael@0 691
michael@0 692 // Loop footer.
michael@0 693 if (loopType == ELoopDoWhile) // do-while loop
michael@0 694 {
michael@0 695 out << "while (";
michael@0 696 ASSERT(node->getCondition() != NULL);
michael@0 697 node->getCondition()->traverse(this);
michael@0 698 out << ");\n";
michael@0 699 }
michael@0 700 decrementDepth();
michael@0 701
michael@0 702 // No need to visit children. They have been already processed in
michael@0 703 // this function.
michael@0 704 return false;
michael@0 705 }
michael@0 706
michael@0 707 bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
michael@0 708 {
michael@0 709 switch (node->getFlowOp())
michael@0 710 {
michael@0 711 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
michael@0 712 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
michael@0 713 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
michael@0 714 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
michael@0 715 default: UNREACHABLE(); break;
michael@0 716 }
michael@0 717
michael@0 718 return true;
michael@0 719 }
michael@0 720
michael@0 721 void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
michael@0 722 TInfoSinkBase &out = objSink();
michael@0 723 if (node != NULL)
michael@0 724 {
michael@0 725 node->traverse(this);
michael@0 726 // Single statements not part of a sequence need to be terminated
michael@0 727 // with semi-colon.
michael@0 728 if (isSingleStatement(node))
michael@0 729 out << ";\n";
michael@0 730 }
michael@0 731 else
michael@0 732 {
michael@0 733 out << "{\n}\n"; // Empty code block.
michael@0 734 }
michael@0 735 }
michael@0 736
michael@0 737 TString TOutputGLSLBase::getTypeName(const TType& type)
michael@0 738 {
michael@0 739 TInfoSinkBase out;
michael@0 740 if (type.isMatrix())
michael@0 741 {
michael@0 742 out << "mat";
michael@0 743 out << type.getNominalSize();
michael@0 744 }
michael@0 745 else if (type.isVector())
michael@0 746 {
michael@0 747 switch (type.getBasicType())
michael@0 748 {
michael@0 749 case EbtFloat: out << "vec"; break;
michael@0 750 case EbtInt: out << "ivec"; break;
michael@0 751 case EbtBool: out << "bvec"; break;
michael@0 752 default: UNREACHABLE(); break;
michael@0 753 }
michael@0 754 out << type.getNominalSize();
michael@0 755 }
michael@0 756 else
michael@0 757 {
michael@0 758 if (type.getBasicType() == EbtStruct)
michael@0 759 out << hashName(type.getStruct()->name());
michael@0 760 else
michael@0 761 out << type.getBasicString();
michael@0 762 }
michael@0 763 return TString(out.c_str());
michael@0 764 }
michael@0 765
michael@0 766 TString TOutputGLSLBase::hashName(const TString& name)
michael@0 767 {
michael@0 768 if (mHashFunction == NULL || name.empty())
michael@0 769 return name;
michael@0 770 NameMap::const_iterator it = mNameMap.find(name.c_str());
michael@0 771 if (it != mNameMap.end())
michael@0 772 return it->second.c_str();
michael@0 773 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
michael@0 774 mNameMap[name.c_str()] = hashedName.c_str();
michael@0 775 return hashedName;
michael@0 776 }
michael@0 777
michael@0 778 TString TOutputGLSLBase::hashVariableName(const TString& name)
michael@0 779 {
michael@0 780 if (mSymbolTable.findBuiltIn(name) != NULL)
michael@0 781 return name;
michael@0 782 return hashName(name);
michael@0 783 }
michael@0 784
michael@0 785 TString TOutputGLSLBase::hashFunctionName(const TString& mangled_name)
michael@0 786 {
michael@0 787 TString name = TFunction::unmangleName(mangled_name);
michael@0 788 if (mSymbolTable.findBuiltIn(mangled_name) != NULL || name == "main")
michael@0 789 return name;
michael@0 790 return hashName(name);
michael@0 791 }
michael@0 792
michael@0 793 bool TOutputGLSLBase::structDeclared(const TStructure* structure) const
michael@0 794 {
michael@0 795 return mDeclaredStructs.find(structure->name()) != mDeclaredStructs.end();
michael@0 796 }
michael@0 797
michael@0 798 void TOutputGLSLBase::declareStruct(const TStructure* structure)
michael@0 799 {
michael@0 800 TInfoSinkBase& out = objSink();
michael@0 801
michael@0 802 out << "struct " << hashName(structure->name()) << "{\n";
michael@0 803 const TFieldList& fields = structure->fields();
michael@0 804 for (size_t i = 0; i < fields.size(); ++i)
michael@0 805 {
michael@0 806 const TField* field = fields[i];
michael@0 807 if (writeVariablePrecision(field->type()->getPrecision()))
michael@0 808 out << " ";
michael@0 809 out << getTypeName(*field->type()) << " " << hashName(field->name());
michael@0 810 if (field->type()->isArray())
michael@0 811 out << arrayBrackets(*field->type());
michael@0 812 out << ";\n";
michael@0 813 }
michael@0 814 out << "}";
michael@0 815
michael@0 816 mDeclaredStructs.insert(structure->name());
michael@0 817 }

mercurial