summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/compiler/translator/OutputGLSLBase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/compiler/translator/OutputGLSLBase.cpp')
-rwxr-xr-xgfx/angle/src/compiler/translator/OutputGLSLBase.cpp891
1 files changed, 390 insertions, 501 deletions
diff --git a/gfx/angle/src/compiler/translator/OutputGLSLBase.cpp b/gfx/angle/src/compiler/translator/OutputGLSLBase.cpp
index 2c32b2ea5..296eef7d1 100755
--- a/gfx/angle/src/compiler/translator/OutputGLSLBase.cpp
+++ b/gfx/angle/src/compiler/translator/OutputGLSLBase.cpp
@@ -10,9 +10,6 @@
#include <cfloat>
-namespace sh
-{
-
namespace
{
TString arrayBrackets(const TType &type)
@@ -25,17 +22,16 @@ TString arrayBrackets(const TType &type)
bool isSingleStatement(TIntermNode *node)
{
- if (node->getAsFunctionDefinition())
- {
- return false;
- }
- else if (node->getAsBlock())
+ if (const TIntermAggregate *aggregate = node->getAsAggregate())
{
- return false;
+ return (aggregate->getOp() != EOpFunction) &&
+ (aggregate->getOp() != EOpSequence);
}
- else if (node->getAsIfElseNode())
+ else if (const TIntermSelection *selection = node->getAsSelectionNode())
{
- return false;
+ // Ternary operators are usually part of an assignment operator.
+ // This handles those rare cases in which they are all by themselves.
+ return selection->usesTernaryOperator();
}
else if (node->getAsLoopNode())
{
@@ -52,32 +48,6 @@ bool isSingleStatement(TIntermNode *node)
return true;
}
-// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
-// variables with specified layout qualifiers are copied. Additional checks are needed against the
-// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
-// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
-// NeedsToWriteLayoutQualifier.
-bool NeedsToWriteLayoutQualifier(const TType &type)
-{
- if (type.getBasicType() == EbtInterfaceBlock)
- {
- return false;
- }
-
- const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
-
- if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
- layoutQualifier.location >= 0)
- {
- return true;
- }
- if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
- {
- return true;
- }
- return false;
-}
-
} // namespace
TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
@@ -85,10 +55,8 @@ TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
ShHashFunction64 hashFunction,
NameMap &nameMap,
TSymbolTable &symbolTable,
- sh::GLenum shaderType,
int shaderVersion,
- ShShaderOutput output,
- ShCompileOptions compileOptions)
+ ShShaderOutput output)
: TIntermTraverser(true, true, true),
mObjSink(objSink),
mDeclaringVariables(false),
@@ -96,20 +64,9 @@ TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
mHashFunction(hashFunction),
mNameMap(nameMap),
mSymbolTable(symbolTable),
- mShaderType(shaderType),
mShaderVersion(shaderVersion),
- mOutput(output),
- mCompileOptions(compileOptions)
-{
-}
-
-void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
+ mOutput(output)
{
- if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
- {
- TInfoSinkBase &out = objSink();
- out << "invariant ";
- }
}
void TOutputGLSLBase::writeTriplet(
@@ -134,121 +91,55 @@ void TOutputGLSLBase::writeBuiltInFunctionTriplet(
void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
{
- if (!NeedsToWriteLayoutQualifier(type))
- {
- return;
- }
-
- TInfoSinkBase &out = objSink();
- const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
- out << "layout(";
-
if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
{
+ const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
if (layoutQualifier.location >= 0)
{
- out << "location = " << layoutQualifier.location;
+ TInfoSinkBase &out = objSink();
+ out << "layout(location = " << layoutQualifier.location << ") ";
}
}
-
- if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
- {
- ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
- out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
- }
-
- out << ") ";
-}
-
-const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
-{
- if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
- (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
- {
- switch (qualifier)
- {
- // The return string is consistent with sh::getQualifierString() from
- // BaseTypes.h minus the "centroid" keyword.
- case EvqCentroid:
- return "";
- case EvqCentroidIn:
- return "smooth in";
- case EvqCentroidOut:
- return "smooth out";
- default:
- break;
- }
- }
- if (sh::IsGLSL130OrNewer(mOutput))
- {
- switch (qualifier)
- {
- case EvqAttribute:
- return "in";
- case EvqVaryingIn:
- return "in";
- case EvqVaryingOut:
- return "out";
- default:
- break;
- }
- }
- return sh::getQualifierString(qualifier);
}
void TOutputGLSLBase::writeVariableType(const TType &type)
{
- TQualifier qualifier = type.getQualifier();
TInfoSinkBase &out = objSink();
if (type.isInvariant())
{
- writeInvariantQualifier(type);
+ out << "invariant ";
}
if (type.getBasicType() == EbtInterfaceBlock)
{
TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
declareInterfaceBlockLayout(interfaceBlock);
}
+ TQualifier qualifier = type.getQualifier();
if (qualifier != EvqTemporary && qualifier != EvqGlobal)
{
- const char *qualifierString = mapQualifierToString(qualifier);
- if (qualifierString && qualifierString[0] != '\0')
+ if (IsGLSL130OrNewer(mOutput))
{
- out << qualifierString << " ";
+ switch (qualifier)
+ {
+ case EvqAttribute:
+ out << "in ";
+ break;
+ case EvqVaryingIn:
+ out << "in ";
+ break;
+ case EvqVaryingOut:
+ out << "out ";
+ break;
+ default:
+ out << type.getQualifierString() << " ";
+ break;
+ }
+ }
+ else
+ {
+ out << type.getQualifierString() << " ";
}
}
-
- const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
- if (memoryQualifier.readonly)
- {
- ASSERT(IsImage(type.getBasicType()));
- out << "readonly ";
- }
-
- if (memoryQualifier.writeonly)
- {
- ASSERT(IsImage(type.getBasicType()));
- out << "writeonly ";
- }
-
- if (memoryQualifier.coherent)
- {
- ASSERT(IsImage(type.getBasicType()));
- out << "coherent ";
- }
-
- if (memoryQualifier.restrictQualifier)
- {
- ASSERT(IsImage(type.getBasicType()));
- out << "restrict ";
- }
-
- if (memoryQualifier.volatileQualifier)
- {
- ASSERT(IsImage(type.getBasicType()));
- out << "volatile ";
- }
-
// Declare the struct if we have not done so already.
if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
{
@@ -286,8 +177,9 @@ void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
const TType &type = arg->getType();
writeVariableType(type);
- if (!arg->getName().getString().empty())
- out << " " << hashName(arg->getName());
+ const TString &name = arg->getSymbol();
+ if (!name.empty())
+ out << " " << hashName(name);
if (type.isArray())
out << arrayBrackets(type);
@@ -305,7 +197,7 @@ const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
if (type.getBasicType() == EbtStruct)
{
const TStructure *structure = type.getStruct();
- out << hashName(TName(structure->name())) << "(";
+ out << hashName(structure->name()) << "(";
const TFieldList &fields = structure->fields();
for (size_t i = 0; i < fields.size(); ++i)
@@ -379,7 +271,7 @@ void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
out << mLoopUnrollStack.getLoopIndexValue(node);
else
- out << hashVariableName(node->getName());
+ out << hashVariableName(node->getSymbol());
if (mDeclaringVariables && node->getType().isArray())
out << arrayBrackets(node->getType());
@@ -390,222 +282,241 @@ void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
writeConstantUnion(node->getType(), node->getUnionArrayPointer());
}
-bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
-{
- TInfoSinkBase &out = objSink();
- if (visit == PostVisit)
- {
- out << ".";
- node->writeOffsetsAsXYZW(&out);
- }
- return true;
-}
-
bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
{
bool visitChildren = true;
TInfoSinkBase &out = objSink();
switch (node->getOp())
{
- case EOpComma:
- writeTriplet(visit, "(", ", ", ")");
- break;
- case EOpInitialize:
+ case EOpInitialize:
+ if (visit == InVisit)
+ {
+ out << " = ";
+ // RHS of initialize is not being declared.
+ mDeclaringVariables = false;
+ }
+ break;
+ case EOpAssign:
+ writeTriplet(visit, "(", " = ", ")");
+ break;
+ case EOpAddAssign:
+ writeTriplet(visit, "(", " += ", ")");
+ break;
+ case EOpSubAssign:
+ writeTriplet(visit, "(", " -= ", ")");
+ break;
+ case EOpDivAssign:
+ writeTriplet(visit, "(", " /= ", ")");
+ break;
+ case EOpIModAssign:
+ writeTriplet(visit, "(", " %= ", ")");
+ break;
+ // Notice the fall-through.
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ writeTriplet(visit, "(", " *= ", ")");
+ break;
+ case EOpBitShiftLeftAssign:
+ writeTriplet(visit, "(", " <<= ", ")");
+ break;
+ case EOpBitShiftRightAssign:
+ writeTriplet(visit, "(", " >>= ", ")");
+ break;
+ case EOpBitwiseAndAssign:
+ writeTriplet(visit, "(", " &= ", ")");
+ break;
+ case EOpBitwiseXorAssign:
+ writeTriplet(visit, "(", " ^= ", ")");
+ break;
+ case EOpBitwiseOrAssign:
+ writeTriplet(visit, "(", " |= ", ")");
+ break;
+
+ case EOpIndexDirect:
+ writeTriplet(visit, NULL, "[", "]");
+ break;
+ case EOpIndexIndirect:
+ if (node->getAddIndexClamp())
+ {
if (visit == InVisit)
{
- out << " = ";
- // RHS of initialize is not being declared.
- mDeclaringVariables = false;
+ if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
+ out << "[int(clamp(float(";
+ else
+ out << "[webgl_int_clamp(";
}
- break;
- case EOpAssign:
- writeTriplet(visit, "(", " = ", ")");
- break;
- case EOpAddAssign:
- writeTriplet(visit, "(", " += ", ")");
- break;
- case EOpSubAssign:
- writeTriplet(visit, "(", " -= ", ")");
- break;
- case EOpDivAssign:
- writeTriplet(visit, "(", " /= ", ")");
- break;
- case EOpIModAssign:
- writeTriplet(visit, "(", " %= ", ")");
- break;
- // Notice the fall-through.
- case EOpMulAssign:
- case EOpVectorTimesMatrixAssign:
- case EOpVectorTimesScalarAssign:
- case EOpMatrixTimesScalarAssign:
- case EOpMatrixTimesMatrixAssign:
- writeTriplet(visit, "(", " *= ", ")");
- break;
- case EOpBitShiftLeftAssign:
- writeTriplet(visit, "(", " <<= ", ")");
- break;
- case EOpBitShiftRightAssign:
- writeTriplet(visit, "(", " >>= ", ")");
- break;
- case EOpBitwiseAndAssign:
- writeTriplet(visit, "(", " &= ", ")");
- break;
- case EOpBitwiseXorAssign:
- writeTriplet(visit, "(", " ^= ", ")");
- break;
- case EOpBitwiseOrAssign:
- writeTriplet(visit, "(", " |= ", ")");
- break;
-
- case EOpIndexDirect:
- writeTriplet(visit, NULL, "[", "]");
- break;
- case EOpIndexIndirect:
- if (node->getAddIndexClamp())
+ else if (visit == PostVisit)
{
- if (visit == InVisit)
+ int maxSize;
+ TIntermTyped *left = node->getLeft();
+ TType leftType = left->getType();
+
+ if (left->isArray())
{
- if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
- out << "[int(clamp(float(";
- else
- out << "[webgl_int_clamp(";
+ // The shader will fail validation if the array length is not > 0.
+ maxSize = static_cast<int>(leftType.getArraySize()) - 1;
}
- else if (visit == PostVisit)
+ else
{
- int maxSize;
- TIntermTyped *left = node->getLeft();
- TType leftType = left->getType();
-
- if (left->isArray())
- {
- // The shader will fail validation if the array length is not > 0.
- maxSize = static_cast<int>(leftType.getArraySize()) - 1;
- }
- else
- {
- maxSize = leftType.getNominalSize() - 1;
- }
-
- if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
- out << "), 0.0, float(" << maxSize << ")))]";
- else
- out << ", 0, " << maxSize << ")]";
+ maxSize = leftType.getNominalSize() - 1;
}
+
+ if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
+ out << "), 0.0, float(" << maxSize << ")))]";
+ else
+ out << ", 0, " << maxSize << ")]";
}
- else
- {
- writeTriplet(visit, NULL, "[", "]");
- }
- break;
- case EOpIndexDirectStruct:
- if (visit == InVisit)
- {
- // Here we are writing out "foo.bar", where "foo" is struct
- // and "bar" is field. In AST, it is represented as a binary
- // node, where left child represents "foo" and right child "bar".
- // The node itself represents ".". The struct field "bar" is
- // actually stored as an index into TStructure::fields.
- out << ".";
- const TStructure *structure = node->getLeft()->getType().getStruct();
- const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
- const TField *field = structure->fields()[index->getIConst(0)];
-
- TString fieldName = field->name();
- if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
- fieldName = hashName(TName(fieldName));
-
- out << fieldName;
- visitChildren = false;
- }
- break;
- case EOpIndexDirectInterfaceBlock:
- if (visit == InVisit)
+ }
+ else
+ {
+ writeTriplet(visit, NULL, "[", "]");
+ }
+ break;
+ case EOpIndexDirectStruct:
+ if (visit == InVisit)
+ {
+ // Here we are writing out "foo.bar", where "foo" is struct
+ // and "bar" is field. In AST, it is represented as a binary
+ // node, where left child represents "foo" and right child "bar".
+ // The node itself represents ".". The struct field "bar" is
+ // actually stored as an index into TStructure::fields.
+ out << ".";
+ const TStructure *structure = node->getLeft()->getType().getStruct();
+ const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
+ const TField *field = structure->fields()[index->getIConst(0)];
+
+ TString fieldName = field->name();
+ if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
+ fieldName = hashName(fieldName);
+
+ out << fieldName;
+ visitChildren = false;
+ }
+ break;
+ case EOpIndexDirectInterfaceBlock:
+ if (visit == InVisit)
+ {
+ out << ".";
+ const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
+ const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
+ const TField *field = interfaceBlock->fields()[index->getIConst(0)];
+
+ TString fieldName = field->name();
+ ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
+ fieldName = hashName(fieldName);
+
+ out << fieldName;
+ visitChildren = false;
+ }
+ break;
+ case EOpVectorSwizzle:
+ if (visit == InVisit)
+ {
+ out << ".";
+ TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
+ TIntermSequence *sequence = rightChild->getSequence();
+ for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
{
- out << ".";
- const TInterfaceBlock *interfaceBlock =
- node->getLeft()->getType().getInterfaceBlock();
- const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
- const TField *field = interfaceBlock->fields()[index->getIConst(0)];
-
- TString fieldName = field->name();
- ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
- fieldName = hashName(TName(fieldName));
-
- out << fieldName;
- visitChildren = false;
+ TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
+ ASSERT(element->getBasicType() == EbtInt);
+ ASSERT(element->getNominalSize() == 1);
+ const TConstantUnion& data = element->getUnionArrayPointer()[0];
+ ASSERT(data.getType() == EbtInt);
+ switch (data.getIConst())
+ {
+ case 0:
+ out << "x";
+ break;
+ case 1:
+ out << "y";
+ break;
+ case 2:
+ out << "z";
+ break;
+ case 3:
+ out << "w";
+ break;
+ default:
+ UNREACHABLE();
+ }
}
- break;
+ visitChildren = false;
+ }
+ break;
- case EOpAdd:
- writeTriplet(visit, "(", " + ", ")");
- break;
- case EOpSub:
- writeTriplet(visit, "(", " - ", ")");
- break;
- case EOpMul:
- writeTriplet(visit, "(", " * ", ")");
- break;
- case EOpDiv:
- writeTriplet(visit, "(", " / ", ")");
- break;
- case EOpIMod:
- writeTriplet(visit, "(", " % ", ")");
- break;
- case EOpBitShiftLeft:
- writeTriplet(visit, "(", " << ", ")");
- break;
- case EOpBitShiftRight:
- writeTriplet(visit, "(", " >> ", ")");
- break;
- case EOpBitwiseAnd:
- writeTriplet(visit, "(", " & ", ")");
- break;
- case EOpBitwiseXor:
- writeTriplet(visit, "(", " ^ ", ")");
- break;
- case EOpBitwiseOr:
- writeTriplet(visit, "(", " | ", ")");
- break;
+ case EOpAdd:
+ writeTriplet(visit, "(", " + ", ")");
+ break;
+ case EOpSub:
+ writeTriplet(visit, "(", " - ", ")");
+ break;
+ case EOpMul:
+ writeTriplet(visit, "(", " * ", ")");
+ break;
+ case EOpDiv:
+ writeTriplet(visit, "(", " / ", ")");
+ break;
+ case EOpIMod:
+ writeTriplet(visit, "(", " % ", ")");
+ break;
+ case EOpBitShiftLeft:
+ writeTriplet(visit, "(", " << ", ")");
+ break;
+ case EOpBitShiftRight:
+ writeTriplet(visit, "(", " >> ", ")");
+ break;
+ case EOpBitwiseAnd:
+ writeTriplet(visit, "(", " & ", ")");
+ break;
+ case EOpBitwiseXor:
+ writeTriplet(visit, "(", " ^ ", ")");
+ break;
+ case EOpBitwiseOr:
+ writeTriplet(visit, "(", " | ", ")");
+ break;
- case EOpEqual:
- writeTriplet(visit, "(", " == ", ")");
- break;
- case EOpNotEqual:
- writeTriplet(visit, "(", " != ", ")");
- break;
- case EOpLessThan:
- writeTriplet(visit, "(", " < ", ")");
- break;
- case EOpGreaterThan:
- writeTriplet(visit, "(", " > ", ")");
- break;
- case EOpLessThanEqual:
- writeTriplet(visit, "(", " <= ", ")");
- break;
- case EOpGreaterThanEqual:
- writeTriplet(visit, "(", " >= ", ")");
- break;
+ case EOpEqual:
+ writeTriplet(visit, "(", " == ", ")");
+ break;
+ case EOpNotEqual:
+ writeTriplet(visit, "(", " != ", ")");
+ break;
+ case EOpLessThan:
+ writeTriplet(visit, "(", " < ", ")");
+ break;
+ case EOpGreaterThan:
+ writeTriplet(visit, "(", " > ", ")");
+ break;
+ case EOpLessThanEqual:
+ writeTriplet(visit, "(", " <= ", ")");
+ break;
+ case EOpGreaterThanEqual:
+ writeTriplet(visit, "(", " >= ", ")");
+ break;
- // Notice the fall-through.
- case EOpVectorTimesScalar:
- case EOpVectorTimesMatrix:
- case EOpMatrixTimesVector:
- case EOpMatrixTimesScalar:
- case EOpMatrixTimesMatrix:
- writeTriplet(visit, "(", " * ", ")");
- break;
+ // Notice the fall-through.
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesMatrix:
+ writeTriplet(visit, "(", " * ", ")");
+ break;
- case EOpLogicalOr:
- writeTriplet(visit, "(", " || ", ")");
- break;
- case EOpLogicalXor:
- writeTriplet(visit, "(", " ^^ ", ")");
- break;
- case EOpLogicalAnd:
- writeTriplet(visit, "(", " && ", ")");
- break;
- default:
- UNREACHABLE();
+ case EOpLogicalOr:
+ writeTriplet(visit, "(", " || ", ")");
+ break;
+ case EOpLogicalXor:
+ writeTriplet(visit, "(", " ^^ ", ")");
+ break;
+ case EOpLogicalAnd:
+ writeTriplet(visit, "(", " && ", ")");
+ break;
+ default:
+ UNREACHABLE();
}
return visitChildren;
@@ -800,40 +711,40 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
return true;
}
-bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
+bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
{
TInfoSinkBase &out = objSink();
- // Notice two brackets at the beginning and end. The outer ones
- // encapsulate the whole ternary expression. This preserves the
- // order of precedence when ternary expressions are used in a
- // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
- out << "((";
- node->getCondition()->traverse(this);
- out << ") ? (";
- node->getTrueExpression()->traverse(this);
- out << ") : (";
- node->getFalseExpression()->traverse(this);
- out << "))";
- return false;
-}
-bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
-{
- TInfoSinkBase &out = objSink();
-
- out << "if (";
- node->getCondition()->traverse(this);
- out << ")\n";
+ if (node->usesTernaryOperator())
+ {
+ // Notice two brackets at the beginning and end. The outer ones
+ // encapsulate the whole ternary expression. This preserves the
+ // order of precedence when ternary expressions are used in a
+ // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
+ out << "((";
+ node->getCondition()->traverse(this);
+ out << ") ? (";
+ node->getTrueBlock()->traverse(this);
+ out << ") : (";
+ node->getFalseBlock()->traverse(this);
+ out << "))";
+ }
+ else
+ {
+ out << "if (";
+ node->getCondition()->traverse(this);
+ out << ")\n";
- incrementDepth(node);
- visitCodeBlock(node->getTrueBlock());
+ incrementDepth(node);
+ visitCodeBlock(node->getTrueBlock());
- if (node->getFalseBlock())
- {
- out << "else\n";
- visitCodeBlock(node->getFalseBlock());
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
+ visitCodeBlock(node->getFalseBlock());
+ }
+ decrementDepth();
}
- decrementDepth();
return false;
}
@@ -867,65 +778,6 @@ bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
}
}
-bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
-{
- TInfoSinkBase &out = objSink();
- // Scope the blocks except when at the global scope.
- if (mDepth > 0)
- {
- out << "{\n";
- }
-
- incrementDepth(node);
- for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
- iter != node->getSequence()->end(); ++iter)
- {
- TIntermNode *curNode = *iter;
- ASSERT(curNode != nullptr);
- curNode->traverse(this);
-
- if (isSingleStatement(curNode))
- out << ";\n";
- }
- decrementDepth();
-
- // Scope the blocks except when at the global scope.
- if (mDepth > 0)
- {
- out << "}\n";
- }
- return false;
-}
-
-bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
-{
- TInfoSinkBase &out = objSink();
-
- ASSERT(visit == PreVisit);
- {
- const TType &type = node->getType();
- writeVariableType(type);
- if (type.isArray())
- out << arrayBrackets(type);
- }
-
- out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
-
- incrementDepth(node);
-
- // Traverse function parameters.
- TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
- ASSERT(params->getOp() == EOpParameters);
- params->traverse(this);
-
- // Traverse function body.
- visitCodeBlock(node->getBody());
- decrementDepth();
-
- // Fully processed; no need to visit children.
- return false;
-}
-
bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
{
bool visitChildren = true;
@@ -933,6 +785,33 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
switch (node->getOp())
{
+ case EOpSequence:
+ // Scope the sequences except when at the global scope.
+ if (mDepth > 0)
+ {
+ out << "{\n";
+ }
+
+ incrementDepth(node);
+ for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
+ iter != node->getSequence()->end(); ++iter)
+ {
+ TIntermNode *curNode = *iter;
+ ASSERT(curNode != NULL);
+ curNode->traverse(this);
+
+ if (isSingleStatement(curNode))
+ out << ";\n";
+ }
+ decrementDepth();
+
+ // Scope the sequences except when at the global scope.
+ if (mDepth > 0)
+ {
+ out << "}\n";
+ }
+ visitChildren = false;
+ break;
case EOpPrototype:
// Function declaration.
ASSERT(visit == PreVisit);
@@ -943,7 +822,7 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
out << arrayBrackets(type);
}
- out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
+ out << " " << hashFunctionNameIfNeeded(node->getNameObj());
out << "(";
writeFunctionParameters(*(node->getSequence()));
@@ -951,10 +830,46 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
visitChildren = false;
break;
+ case EOpFunction: {
+ // Function definition.
+ ASSERT(visit == PreVisit);
+ {
+ const TType &type = node->getType();
+ writeVariableType(type);
+ if (type.isArray())
+ out << arrayBrackets(type);
+ }
+
+ out << " " << hashFunctionNameIfNeeded(node->getNameObj());
+
+ incrementDepth(node);
+ // Function definition node contains one or two children nodes
+ // representing function parameters and function body. The latter
+ // is not present in case of empty function bodies.
+ const TIntermSequence &sequence = *(node->getSequence());
+ ASSERT((sequence.size() == 1) || (sequence.size() == 2));
+ TIntermSequence::const_iterator seqIter = sequence.begin();
+
+ // Traverse function parameters.
+ TIntermAggregate *params = (*seqIter)->getAsAggregate();
+ ASSERT(params != NULL);
+ ASSERT(params->getOp() == EOpParameters);
+ params->traverse(this);
+
+ // Traverse function body.
+ TIntermAggregate *body = ++seqIter != sequence.end() ?
+ (*seqIter)->getAsAggregate() : NULL;
+ visitCodeBlock(body);
+ decrementDepth();
+
+ // Fully processed; no need to visit children.
+ visitChildren = false;
+ break;
+ }
case EOpFunctionCall:
// Function call.
if (visit == PreVisit)
- out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
+ out << hashFunctionNameIfNeeded(node->getNameObj()) << "(";
else if (visit == InVisit)
out << ", ";
else
@@ -968,6 +883,27 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
out << ")";
visitChildren = false;
break;
+ case EOpDeclaration:
+ // Variable declaration.
+ if (visit == PreVisit)
+ {
+ const TIntermSequence &sequence = *(node->getSequence());
+ const TIntermTyped *variable = sequence.front()->getAsTyped();
+ writeLayoutQualifier(variable->getType());
+ writeVariableType(variable->getType());
+ out << " ";
+ mDeclaringVariables = true;
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ mDeclaringVariables = true;
+ }
+ else
+ {
+ mDeclaringVariables = false;
+ }
+ break;
case EOpInvariantDeclaration:
// Invariant declaration.
ASSERT(visit == PreVisit);
@@ -976,7 +912,7 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
ASSERT(sequence && sequence->size() == 1);
const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
ASSERT(symbol);
- out << "invariant " << hashVariableName(symbol->getName());
+ out << "invariant " << hashVariableName(symbol->getSymbol());
}
visitChildren = false;
break;
@@ -1031,6 +967,9 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpVectorNotEqual:
writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
break;
+ case EOpComma:
+ writeTriplet(visit, "(", ", ", ")");
+ break;
case EOpMod:
writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
@@ -1090,32 +1029,6 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
return visitChildren;
}
-bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
-{
- TInfoSinkBase &out = objSink();
-
- // Variable declaration.
- if (visit == PreVisit)
- {
- const TIntermSequence &sequence = *(node->getSequence());
- const TIntermTyped *variable = sequence.front()->getAsTyped();
- writeLayoutQualifier(variable->getType());
- writeVariableType(variable->getType());
- out << " ";
- mDeclaringVariables = true;
- }
- else if (visit == InVisit)
- {
- out << ", ";
- mDeclaringVariables = true;
- }
- else
- {
- mDeclaringVariables = false;
- }
- return true;
-}
-
bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
{
TInfoSinkBase &out = objSink();
@@ -1149,10 +1062,11 @@ bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
else
{
// Need to put a one-iteration loop here to handle break.
- TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
+ TIntermSequence *declSeq =
+ node->getInit()->getAsAggregate()->getSequence();
TIntermSymbol *indexSymbol =
(*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
- TString name = hashVariableName(indexSymbol->getName());
+ TString name = hashVariableName(indexSymbol->getSymbol());
out << "for (int " << name << " = 0; "
<< name << " < 1; "
<< "++" << name << ")\n";
@@ -1220,7 +1134,7 @@ bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
return true;
}
-void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
+void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
{
TInfoSinkBase &out = objSink();
if (node != NULL)
@@ -1240,43 +1154,27 @@ void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
TString TOutputGLSLBase::getTypeName(const TType &type)
{
if (type.getBasicType() == EbtStruct)
- return hashName(TName(type.getStruct()->name()));
+ return hashName(type.getStruct()->name());
else
return type.getBuiltInTypeNameString();
}
-TString TOutputGLSLBase::hashName(const TName &name)
+TString TOutputGLSLBase::hashName(const TString &name)
{
- if (name.getString().empty())
- {
- ASSERT(!name.isInternal());
- return name.getString();
- }
- if (name.isInternal())
- {
- // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
- // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
- // as well.
- // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
- // names don't conflict with user-defined names from WebGL.
- return "webgl_angle_" + name.getString();
- }
- if (mHashFunction == nullptr)
- {
- return name.getString();
- }
- NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
+ if (mHashFunction == NULL || name.empty())
+ return name;
+ NameMap::const_iterator it = mNameMap.find(name.c_str());
if (it != mNameMap.end())
return it->second.c_str();
- TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
- mNameMap[name.getString().c_str()] = hashedName.c_str();
+ TString hashedName = TIntermTraverser::hash(name, mHashFunction);
+ mNameMap[name.c_str()] = hashedName.c_str();
return hashedName;
}
-TString TOutputGLSLBase::hashVariableName(const TName &name)
+TString TOutputGLSLBase::hashVariableName(const TString &name)
{
- if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
- return name.getString();
+ if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
+ return name;
return hashName(name);
}
@@ -1287,16 +1185,9 @@ TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
return translateTextureFunction(name);
if (mangledName.isInternal())
- {
- // Internal function names are outputted as-is - they may refer to functions manually added
- // to the output shader source that are not included in the AST at all.
return name;
- }
else
- {
- TName nameObj(name);
- return hashName(nameObj);
- }
+ return hashName(name);
}
bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
@@ -1314,14 +1205,14 @@ void TOutputGLSLBase::declareStruct(const TStructure *structure)
{
TInfoSinkBase &out = objSink();
- out << "struct " << hashName(TName(structure->name())) << "{\n";
+ out << "struct " << hashName(structure->name()) << "{\n";
const TFieldList &fields = structure->fields();
for (size_t i = 0; i < fields.size(); ++i)
{
const TField *field = fields[i];
if (writeVariablePrecision(field->type()->getPrecision()))
out << " ";
- out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
+ out << getTypeName(*field->type()) << " " << hashName(field->name());
if (field->type()->isArray())
out << arrayBrackets(*field->type());
out << ";\n";
@@ -1382,19 +1273,17 @@ void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBloc
{
TInfoSinkBase &out = objSink();
- out << hashName(TName(interfaceBlock->name())) << "{\n";
+ out << hashName(interfaceBlock->name()) << "{\n";
const TFieldList &fields = interfaceBlock->fields();
for (size_t i = 0; i < fields.size(); ++i)
{
const TField *field = fields[i];
if (writeVariablePrecision(field->type()->getPrecision()))
out << " ";
- out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
+ out << getTypeName(*field->type()) << " " << hashName(field->name());
if (field->type()->isArray())
out << arrayBrackets(*field->type());
out << ";\n";
}
out << "}";
}
-
-} // namespace sh