summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp')
-rw-r--r--src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp1846
1 files changed, 912 insertions, 934 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp
index f048b050b7..edaf2ebebf 100644
--- a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp
@@ -6,32 +6,33 @@
#include "compiler/translator/OutputGLSLBase.h"
+#include "angle_gl.h"
#include "common/debug.h"
+#include "common/mathutil.h"
+#include "compiler/translator/Compiler.h"
+#include "compiler/translator/util.h"
#include <cfloat>
-namespace
+namespace sh
{
-TString arrayBrackets(const TType &type)
+
+namespace
{
- ASSERT(type.isArray());
- TInfoSinkBase out;
- out << "[" << type.getArraySize() << "]";
- return TString(out.c_str());
-}
bool isSingleStatement(TIntermNode *node)
{
- if (const TIntermAggregate *aggregate = node->getAsAggregate())
+ if (node->getAsFunctionDefinition())
+ {
+ return false;
+ }
+ else if (node->getAsBlock())
{
- return (aggregate->getOp() != EOpFunction) &&
- (aggregate->getOp() != EOpSequence);
+ return false;
}
- else if (const TIntermSelection *selection = node->getAsSelectionNode())
+ else if (node->getAsIfElseNode())
{
- // Ternary operators are usually part of an assignment operator.
- // This handles those rare cases in which they are all by themselves.
- return selection->usesTernaryOperator();
+ return false;
}
else if (node->getAsLoopNode())
{
@@ -48,29 +49,79 @@ bool isSingleStatement(TIntermNode *node)
return true;
}
+class CommaSeparatedListItemPrefixGenerator
+{
+ public:
+ CommaSeparatedListItemPrefixGenerator() : mFirst(true) {}
+ private:
+ bool mFirst;
+
+ friend TInfoSinkBase &operator<<(TInfoSinkBase &out,
+ CommaSeparatedListItemPrefixGenerator &gen);
+};
+
+TInfoSinkBase &operator<<(TInfoSinkBase &out, CommaSeparatedListItemPrefixGenerator &gen)
+{
+ if (gen.mFirst)
+ {
+ gen.mFirst = false;
+ }
+ else
+ {
+ out << ", ";
+ }
+ return out;
+}
+
} // namespace
TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
ShArrayIndexClampingStrategy clampingStrategy,
ShHashFunction64 hashFunction,
NameMap &nameMap,
- TSymbolTable &symbolTable,
+ TSymbolTable *symbolTable,
+ sh::GLenum shaderType,
int shaderVersion,
- ShShaderOutput output)
- : TIntermTraverser(true, true, true),
+ ShShaderOutput output,
+ ShCompileOptions compileOptions)
+ : TIntermTraverser(true, true, true, symbolTable),
mObjSink(objSink),
- mDeclaringVariables(false),
+ mDeclaringVariable(false),
mClampingStrategy(clampingStrategy),
mHashFunction(hashFunction),
mNameMap(nameMap),
- mSymbolTable(symbolTable),
+ mShaderType(shaderType),
mShaderVersion(shaderVersion),
- mOutput(output)
+ mOutput(output),
+ mCompileOptions(compileOptions)
+{
+}
+
+void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
{
+ if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
+ {
+ TInfoSinkBase &out = objSink();
+ out << "invariant ";
+ }
}
-void TOutputGLSLBase::writeTriplet(
- Visit visit, const char *preStr, const char *inStr, const char *postStr)
+void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f)
+{
+ if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300)
+ {
+ out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)";
+ }
+ else
+ {
+ out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
+ }
+}
+
+void TOutputGLSLBase::writeTriplet(Visit visit,
+ const char *preStr,
+ const char *inStr,
+ const char *postStr)
{
TInfoSinkBase &out = objSink();
if (visit == PreVisit && preStr)
@@ -81,69 +132,181 @@ void TOutputGLSLBase::writeTriplet(
out << postStr;
}
-void TOutputGLSLBase::writeBuiltInFunctionTriplet(
- Visit visit, const char *preStr, bool useEmulatedFunction)
+void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit,
+ TOperator op,
+ bool useEmulatedFunction)
{
- TString preString = useEmulatedFunction ?
- BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
- writeTriplet(visit, preString.c_str(), ", ", ")");
+ TInfoSinkBase &out = objSink();
+ if (visit == PreVisit)
+ {
+ const char *opStr(GetOperatorString(op));
+ if (useEmulatedFunction)
+ {
+ BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
+ }
+ else
+ {
+ out << opStr;
+ }
+ out << "(";
+ }
+ else
+ {
+ writeTriplet(visit, nullptr, ", ", ")");
+ }
}
-void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
+void TOutputGLSLBase::writeLayoutQualifier(TIntermTyped *variable)
{
- if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
+ const TType &type = variable->getType();
+
+ if (!NeedsToWriteLayoutQualifier(type))
+ {
+ return;
+ }
+
+ TInfoSinkBase &out = objSink();
+ const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
+ out << "layout(";
+
+ CommaSeparatedListItemPrefixGenerator listItemPrefix;
+
+ if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
+ IsVarying(type.getQualifier()))
{
- const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
if (layoutQualifier.location >= 0)
{
- TInfoSinkBase &out = objSink();
- out << "layout(location = " << layoutQualifier.location << ") ";
+ out << listItemPrefix << "location = " << layoutQualifier.location;
+ }
+ }
+
+ if (type.getQualifier() == EvqFragmentOut)
+ {
+ if (layoutQualifier.yuv == true)
+ {
+ out << listItemPrefix << "yuv";
+ }
+ }
+
+ if (IsOpaqueType(type.getBasicType()))
+ {
+ if (layoutQualifier.binding >= 0)
+ {
+ out << listItemPrefix << "binding = " << layoutQualifier.binding;
+ }
+ }
+
+ if (IsImage(type.getBasicType()))
+ {
+ if (layoutQualifier.imageInternalFormat != EiifUnspecified)
+ {
+ ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
+ out << listItemPrefix
+ << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
}
}
+
+ if (IsAtomicCounter(type.getBasicType()))
+ {
+ out << listItemPrefix << "offset = " << layoutQualifier.offset;
+ }
+
+ 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)
{
- TInfoSinkBase &out = objSink();
+ TQualifier qualifier = type.getQualifier();
+ TInfoSinkBase &out = objSink();
if (type.isInvariant())
{
- out << "invariant ";
+ writeInvariantQualifier(type);
}
if (type.getBasicType() == EbtInterfaceBlock)
{
TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
declareInterfaceBlockLayout(interfaceBlock);
}
- TQualifier qualifier = type.getQualifier();
if (qualifier != EvqTemporary && qualifier != EvqGlobal)
{
- if (IsGLSL130OrNewer(mOutput))
+ const char *qualifierString = mapQualifierToString(qualifier);
+ if (qualifierString && qualifierString[0] != '\0')
{
- 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() << " ";
+ out << qualifierString << " ";
}
}
+
+ 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()))
{
- TStructure *structure = type.getStruct();
+ const TStructure *structure = type.getStruct();
declareStruct(structure);
@@ -168,20 +331,18 @@ void TOutputGLSLBase::writeVariableType(const TType &type)
void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
{
TInfoSinkBase &out = objSink();
- for (TIntermSequence::const_iterator iter = args.begin();
- iter != args.end(); ++iter)
+ for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter)
{
const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
- ASSERT(arg != NULL);
+ ASSERT(arg != nullptr);
const TType &type = arg->getType();
writeVariableType(type);
- const TString &name = arg->getSymbol();
- if (!name.empty())
- out << " " << hashName(name);
+ if (!arg->getName().getString().empty())
+ out << " " << hashName(arg->getName());
if (type.isArray())
- out << arrayBrackets(type);
+ out << ArrayString(type);
// Put a comma if this is not the last argument.
if (iter != args.end() - 1)
@@ -189,21 +350,21 @@ void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
}
}
-const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
- const TType &type, const TConstantUnion *pConstUnion)
+const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
+ const TConstantUnion *pConstUnion)
{
TInfoSinkBase &out = objSink();
if (type.getBasicType() == EbtStruct)
{
const TStructure *structure = type.getStruct();
- out << hashName(structure->name()) << "(";
+ out << hashName(TName(structure->name())) << "(";
const TFieldList &fields = structure->fields();
for (size_t i = 0; i < fields.size(); ++i)
{
const TType *fieldType = fields[i]->type();
- ASSERT(fieldType != NULL);
+ ASSERT(fieldType != nullptr);
pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
if (i != fields.size() - 1)
out << ", ";
@@ -212,7 +373,7 @@ const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
}
else
{
- size_t size = type.getObjectSize();
+ size_t size = type.getObjectSize();
bool writeType = size > 1;
if (writeType)
out << getTypeName(type) << "(";
@@ -220,19 +381,23 @@ const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
{
switch (pConstUnion->getType())
{
- case EbtFloat:
- out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
- break;
- case EbtInt:
- out << pConstUnion->getIConst();
- break;
- case EbtUInt:
- out << pConstUnion->getUConst() << "u";
- break;
- case EbtBool:
- out << pConstUnion->getBConst();
- break;
- default: UNREACHABLE();
+ case EbtFloat:
+ writeFloat(out, pConstUnion->getFConst());
+ break;
+ case EbtInt:
+ out << pConstUnion->getIConst();
+ break;
+ case EbtUInt:
+ out << pConstUnion->getUConst() << "u";
+ break;
+ case EbtBool:
+ out << pConstUnion->getBConst();
+ break;
+ case EbtYuvCscStandardEXT:
+ out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst());
+ break;
+ default:
+ UNREACHABLE();
}
if (i != size - 1)
out << ", ";
@@ -243,20 +408,20 @@ const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
return pConstUnion;
}
-void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type, const char *constructorBaseType)
+void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
{
TInfoSinkBase &out = objSink();
if (visit == PreVisit)
{
if (type.isArray())
{
- out << constructorBaseType;
- out << arrayBrackets(type);
+ out << getTypeName(type);
+ out << ArrayString(type);
out << "(";
}
else
{
- out << constructorBaseType << "(";
+ out << getTypeName(type) << "(";
}
}
else
@@ -268,13 +433,10 @@ void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type, co
void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
{
TInfoSinkBase &out = objSink();
- if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
- out << mLoopUnrollStack.getLoopIndexValue(node);
- else
- out << hashVariableName(node->getSymbol());
+ out << hashVariableName(node->getName());
- if (mDeclaringVariables && node->getType().isArray())
- out << arrayBrackets(node->getType());
+ if (mDeclaringVariable && node->getType().isArray())
+ out << ArrayString(node->getType());
}
void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
@@ -282,241 +444,246 @@ 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 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())
- {
+ case EOpComma:
+ writeTriplet(visit, "(", ", ", ")");
+ break;
+ case EOpInitialize:
if (visit == InVisit)
{
- if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
- out << "[int(clamp(float(";
- else
- out << "[webgl_int_clamp(";
+ out << " = ";
+ // RHS of initialize is not being declared.
+ mDeclaringVariable = false;
}
- else if (visit == PostVisit)
- {
- int maxSize;
- TIntermTyped *left = node->getLeft();
- TType leftType = left->getType();
+ 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;
- if (left->isArray())
+ case EOpIndexDirect:
+ writeTriplet(visit, nullptr, "[", "]");
+ break;
+ case EOpIndexIndirect:
+ if (node->getAddIndexClamp())
+ {
+ if (visit == InVisit)
{
- // The shader will fail validation if the array length is not > 0.
- maxSize = leftType.getArraySize() - 1;
+ if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
+ out << "[int(clamp(float(";
+ else
+ out << "[webgl_int_clamp(";
}
- else
+ else if (visit == PostVisit)
{
- maxSize = leftType.getNominalSize() - 1;
+ TIntermTyped *left = node->getLeft();
+ TType leftType = left->getType();
+
+ if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
+ out << "), 0.0, float(";
+ else
+ out << ", 0, ";
+
+ if (leftType.isUnsizedArray())
+ {
+ // For runtime-sized arrays in ESSL 3.10 we need to call the length method
+ // to get the length to clamp against. See ESSL 3.10 section 4.1.9. Note
+ // that a runtime-sized array expression is guaranteed not to have side
+ // effects, so it's fine to add the expression to the output twice.
+ ASSERT(mShaderVersion >= 310);
+ ASSERT(!left->hasSideEffects());
+ left->traverse(this);
+ out << ".length() - 1";
+ }
+ else
+ {
+ int maxSize;
+ if (leftType.isArray())
+ {
+ maxSize = static_cast<int>(leftType.getOutermostArraySize()) - 1;
+ }
+ else
+ {
+ maxSize = leftType.getNominalSize() - 1;
+ }
+ out << maxSize;
+ }
+ if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
+ out << ")))]";
+ else
+ out << ")]";
}
-
- 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(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)
+ else
+ {
+ writeTriplet(visit, nullptr, "[", "]");
+ }
+ break;
+ case EOpIndexDirectStruct:
+ if (visit == InVisit)
{
- 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())
+ // 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)
+ {
+ 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();
+ if (!mSymbolTable->findBuiltIn(interfaceBlock->name(), mShaderVersion))
{
- case 0:
- out << "x";
- break;
- case 1:
- out << "y";
- break;
- case 2:
- out << "z";
- break;
- case 3:
- out << "w";
- break;
- default:
- UNREACHABLE();
+ fieldName = hashName(TName(fieldName));
}
+ else
+ {
+ ASSERT(interfaceBlock->name() == "gl_PerVertex");
+ }
+
+ out << fieldName;
+ visitChildren = false;
}
- 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 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;
-
- case EOpLogicalOr:
- writeTriplet(visit, "(", " || ", ")");
- break;
- case EOpLogicalXor:
- writeTriplet(visit, "(", " ^^ ", ")");
- break;
- case EOpLogicalAnd:
- writeTriplet(visit, "(", " && ", ")");
- break;
- default:
- UNREACHABLE();
+ 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;
+
+ // 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();
}
return visitChildren;
@@ -529,237 +696,148 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
switch (node->getOp())
{
- case EOpNegative: preString = "(-"; break;
- case EOpPositive: preString = "(+"; break;
- case EOpVectorLogicalNot: preString = "not("; break;
- case EOpLogicalNot: preString = "(!"; break;
- case EOpBitwiseNot: preString = "(~"; break;
-
- case EOpPostIncrement: preString = "("; postString = "++)"; break;
- case EOpPostDecrement: preString = "("; postString = "--)"; break;
- case EOpPreIncrement: preString = "(++"; break;
- case EOpPreDecrement: preString = "(--"; break;
-
- case EOpRadians:
- preString = "radians(";
- break;
- case EOpDegrees:
- preString = "degrees(";
- break;
- case EOpSin:
- preString = "sin(";
- break;
- case EOpCos:
- preString = "cos(";
- break;
- case EOpTan:
- preString = "tan(";
- break;
- case EOpAsin:
- preString = "asin(";
- break;
- case EOpAcos:
- preString = "acos(";
- break;
- case EOpAtan:
- preString = "atan(";
- break;
-
- case EOpSinh:
- preString = "sinh(";
- break;
- case EOpCosh:
- preString = "cosh(";
- break;
- case EOpTanh:
- preString = "tanh(";
- break;
- case EOpAsinh:
- preString = "asinh(";
- break;
- case EOpAcosh:
- preString = "acosh(";
- break;
- case EOpAtanh:
- preString = "atanh(";
- break;
-
- case EOpExp:
- preString = "exp(";
- break;
- case EOpLog:
- preString = "log(";
- break;
- case EOpExp2:
- preString = "exp2(";
- break;
- case EOpLog2:
- preString = "log2(";
- break;
- case EOpSqrt:
- preString = "sqrt(";
- break;
- case EOpInverseSqrt:
- preString = "inversesqrt(";
- break;
-
- case EOpAbs:
- preString = "abs(";
- break;
- case EOpSign:
- preString = "sign(";
- break;
- case EOpFloor:
- preString = "floor(";
- break;
- case EOpTrunc:
- preString = "trunc(";
- break;
- case EOpRound:
- preString = "round(";
- break;
- case EOpRoundEven:
- preString = "roundEven(";
- break;
- case EOpCeil:
- preString = "ceil(";
- break;
- case EOpFract:
- preString = "fract(";
- break;
- case EOpIsNan:
- preString = "isnan(";
- break;
- case EOpIsInf:
- preString = "isinf(";
- break;
-
- case EOpFloatBitsToInt:
- preString = "floatBitsToInt(";
- break;
- case EOpFloatBitsToUint:
- preString = "floatBitsToUint(";
- break;
- case EOpIntBitsToFloat:
- preString = "intBitsToFloat(";
- break;
- case EOpUintBitsToFloat:
- preString = "uintBitsToFloat(";
- break;
-
- case EOpPackSnorm2x16:
- preString = "packSnorm2x16(";
- break;
- case EOpPackUnorm2x16:
- preString = "packUnorm2x16(";
- break;
- case EOpPackHalf2x16:
- preString = "packHalf2x16(";
- break;
- case EOpUnpackSnorm2x16:
- preString = "unpackSnorm2x16(";
- break;
- case EOpUnpackUnorm2x16:
- preString = "unpackUnorm2x16(";
- break;
- case EOpUnpackHalf2x16:
- preString = "unpackHalf2x16(";
- break;
-
- case EOpLength:
- preString = "length(";
- break;
- case EOpNormalize:
- preString = "normalize(";
- break;
-
- case EOpDFdx:
- preString = "dFdx(";
- break;
- case EOpDFdy:
- preString = "dFdy(";
- break;
- case EOpFwidth:
- preString = "fwidth(";
- break;
-
- case EOpTranspose:
- preString = "transpose(";
- break;
- case EOpDeterminant:
- preString = "determinant(";
- break;
- case EOpInverse:
- preString = "inverse(";
- break;
-
- case EOpAny:
- preString = "any(";
- break;
- case EOpAll:
- preString = "all(";
- break;
-
- default:
- UNREACHABLE();
+ case EOpNegative:
+ preString = "(-";
+ break;
+ case EOpPositive:
+ preString = "(+";
+ break;
+ case EOpLogicalNot:
+ preString = "(!";
+ break;
+ case EOpBitwiseNot:
+ preString = "(~";
+ break;
+
+ case EOpPostIncrement:
+ preString = "(";
+ postString = "++)";
+ break;
+ case EOpPostDecrement:
+ preString = "(";
+ postString = "--)";
+ break;
+ case EOpPreIncrement:
+ preString = "(++";
+ break;
+ case EOpPreDecrement:
+ preString = "(--";
+ break;
+ case EOpArrayLength:
+ preString = "((";
+ postString = ").length())";
+ break;
+
+ case EOpRadians:
+ case EOpDegrees:
+ case EOpSin:
+ case EOpCos:
+ case EOpTan:
+ case EOpAsin:
+ case EOpAcos:
+ case EOpAtan:
+ case EOpSinh:
+ case EOpCosh:
+ case EOpTanh:
+ case EOpAsinh:
+ case EOpAcosh:
+ case EOpAtanh:
+ case EOpExp:
+ case EOpLog:
+ case EOpExp2:
+ case EOpLog2:
+ case EOpSqrt:
+ case EOpInverseSqrt:
+ case EOpAbs:
+ case EOpSign:
+ case EOpFloor:
+ case EOpTrunc:
+ case EOpRound:
+ case EOpRoundEven:
+ case EOpCeil:
+ case EOpFract:
+ case EOpIsNan:
+ case EOpIsInf:
+ case EOpFloatBitsToInt:
+ case EOpFloatBitsToUint:
+ case EOpIntBitsToFloat:
+ case EOpUintBitsToFloat:
+ case EOpPackSnorm2x16:
+ case EOpPackUnorm2x16:
+ case EOpPackHalf2x16:
+ case EOpUnpackSnorm2x16:
+ case EOpUnpackUnorm2x16:
+ case EOpUnpackHalf2x16:
+ case EOpPackUnorm4x8:
+ case EOpPackSnorm4x8:
+ case EOpUnpackUnorm4x8:
+ case EOpUnpackSnorm4x8:
+ case EOpLength:
+ case EOpNormalize:
+ case EOpDFdx:
+ case EOpDFdy:
+ case EOpFwidth:
+ case EOpTranspose:
+ case EOpDeterminant:
+ case EOpInverse:
+ case EOpAny:
+ case EOpAll:
+ case EOpLogicalNotComponentWise:
+ case EOpBitfieldReverse:
+ case EOpBitCount:
+ case EOpFindLSB:
+ case EOpFindMSB:
+ writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
+ return true;
+ default:
+ UNREACHABLE();
}
- if (visit == PreVisit && node->getUseEmulatedFunction())
- preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
- writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
+ writeTriplet(visit, preString.c_str(), nullptr, postString.c_str());
return true;
}
-bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
+bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *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;
+}
- 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";
+bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
+{
+ TInfoSinkBase &out = objSink();
- incrementDepth(node);
- visitCodeBlock(node->getTrueBlock());
+ out << "if (";
+ node->getCondition()->traverse(this);
+ out << ")\n";
- if (node->getFalseBlock())
- {
- out << "else\n";
- visitCodeBlock(node->getFalseBlock());
- }
- decrementDepth();
+ visitCodeBlock(node->getTrueBlock());
+
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
+ visitCodeBlock(node->getFalseBlock());
}
return false;
}
bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
{
- if (node->getStatementList())
- {
- writeTriplet(visit, "switch (", ") ", nullptr);
- // The curly braces get written when visiting the statementList aggregate
- }
- else
- {
- // No statementList, so it won't output curly braces
- writeTriplet(visit, "switch (", ") {", "}\n");
- }
+ ASSERT(node->getStatementList());
+ writeTriplet(visit, "switch (", ") ", nullptr);
+ // The curly braces get written when visiting the statementList aggregate
return true;
}
@@ -778,369 +856,208 @@ bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
}
}
-bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
+bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
{
- bool visitChildren = true;
TInfoSinkBase &out = objSink();
- bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
- switch (node->getOp())
+ // Scope the blocks except when at the global scope.
+ if (mDepth > 0)
{
- case EOpSequence:
- // Scope the sequences except when at the global scope.
- if (mDepth > 0)
- {
- out << "{\n";
- }
+ 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);
+ 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();
+ if (isSingleStatement(curNode))
+ out << ";\n";
+ }
- // Scope the sequences except when at the global scope.
- if (mDepth > 0)
- {
- out << "}\n";
- }
- visitChildren = false;
- break;
- case EOpPrototype:
- // Function declaration.
- ASSERT(visit == PreVisit);
- {
- const TType &type = node->getType();
- writeVariableType(type);
- if (type.isArray())
- out << arrayBrackets(type);
- }
+ // Scope the blocks except when at the global scope.
+ if (mDepth > 0)
+ {
+ out << "}\n";
+ }
+ return false;
+}
- out << " " << hashFunctionNameIfNeeded(node->getNameObj());
+bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+{
+ TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
+ prototype->traverse(this);
+ visitCodeBlock(node->getBody());
- out << "(";
- writeFunctionParameters(*(node->getSequence()));
- out << ")";
+ // Fully processed; no need to visit children.
+ return false;
+}
- visitChildren = false;
- break;
- case EOpFunction: {
- // Function definition.
- ASSERT(visit == PreVisit);
- {
- const TType &type = node->getType();
- writeVariableType(type);
- if (type.isArray())
- out << arrayBrackets(type);
- }
+bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
+{
+ TInfoSinkBase &out = objSink();
+ ASSERT(visit == PreVisit);
+ const TIntermSymbol *symbol = node->getSymbol();
+ out << "invariant " << hashVariableName(symbol->getName());
+ return false;
+}
+
+bool TOutputGLSLBase::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
+{
+ TInfoSinkBase &out = objSink();
+ ASSERT(visit == PreVisit);
- out << " " << hashFunctionNameIfNeeded(node->getNameObj());
+ const TType &type = node->getType();
+ writeVariableType(type);
+ if (type.isArray())
+ out << ArrayString(type);
+
+ out << " " << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
+
+ out << "(";
+ writeFunctionParameters(*(node->getSequence()));
+ out << ")";
+
+ return false;
+}
+
+bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ bool visitChildren = true;
+ TInfoSinkBase &out = objSink();
+ switch (node->getOp())
+ {
+ case EOpCallFunctionInAST:
+ case EOpCallInternalRawFunction:
+ case EOpCallBuiltInFunction:
+ // Function call.
+ if (visit == PreVisit)
+ {
+ if (node->getOp() == EOpCallBuiltInFunction)
+ {
+ out << translateTextureFunction(node->getFunctionSymbolInfo()->getName());
+ }
+ else
+ {
+ out << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
+ }
+ out << "(";
+ }
+ else if (visit == InVisit)
+ out << ", ";
+ else
+ out << ")";
+ break;
+ case EOpConstruct:
+ writeConstructorTriplet(visit, node->getType());
+ break;
- 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.
+ case EOpEqualComponentWise:
+ case EOpNotEqualComponentWise:
+ case EOpLessThanComponentWise:
+ case EOpGreaterThanComponentWise:
+ case EOpLessThanEqualComponentWise:
+ case EOpGreaterThanEqualComponentWise:
+ case EOpMod:
+ case EOpModf:
+ case EOpPow:
+ case EOpAtan:
+ case EOpMin:
+ case EOpMax:
+ case EOpClamp:
+ case EOpMix:
+ case EOpStep:
+ case EOpSmoothStep:
+ case EOpFrexp:
+ case EOpLdexp:
+ case EOpDistance:
+ case EOpDot:
+ case EOpCross:
+ case EOpFaceforward:
+ case EOpReflect:
+ case EOpRefract:
+ case EOpMulMatrixComponentWise:
+ case EOpOuterProduct:
+ case EOpBitfieldExtract:
+ case EOpBitfieldInsert:
+ case EOpUaddCarry:
+ case EOpUsubBorrow:
+ case EOpUmulExtended:
+ case EOpImulExtended:
+ case EOpBarrier:
+ case EOpMemoryBarrier:
+ case EOpMemoryBarrierAtomicCounter:
+ case EOpMemoryBarrierBuffer:
+ case EOpMemoryBarrierImage:
+ case EOpMemoryBarrierShared:
+ case EOpGroupMemoryBarrier:
+ case EOpEmitVertex:
+ case EOpEndPrimitive:
+ writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
+ break;
+ default:
+ UNREACHABLE();
+ }
+ return visitChildren;
+}
+
+bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+ TInfoSinkBase &out = objSink();
+
+ // Variable declaration.
+ if (visit == PreVisit)
+ {
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->getNameObj()) << "(";
- else if (visit == InVisit)
- out << ", ";
- else
- out << ")";
- break;
- case EOpParameters:
- // Function parameters.
- ASSERT(visit == PreVisit);
- out << "(";
- writeFunctionParameters(*(node->getSequence()));
- out << ")";
- visitChildren = false;
- break;
- case EOpDeclaration:
- // Variable declaration.
- if (visit == PreVisit)
+ TIntermTyped *variable = sequence.front()->getAsTyped();
+ writeLayoutQualifier(variable);
+ writeVariableType(variable->getType());
+ if (variable->getAsSymbolNode() == nullptr ||
+ !variable->getAsSymbolNode()->getSymbol().empty())
{
- 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);
- {
- const TIntermSequence *sequence = node->getSequence();
- ASSERT(sequence && sequence->size() == 1);
- const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
- ASSERT(symbol);
- out << "invariant " << hashVariableName(symbol->getSymbol());
- }
- visitChildren = false;
- break;
- case EOpConstructFloat:
- writeConstructorTriplet(visit, node->getType(), "float");
- break;
- case EOpConstructVec2:
- writeConstructorTriplet(visit, node->getType(), "vec2");
- break;
- case EOpConstructVec3:
- writeConstructorTriplet(visit, node->getType(), "vec3");
- break;
- case EOpConstructVec4:
- writeConstructorTriplet(visit, node->getType(), "vec4");
- break;
- case EOpConstructBool:
- writeConstructorTriplet(visit, node->getType(), "bool");
- break;
- case EOpConstructBVec2:
- writeConstructorTriplet(visit, node->getType(), "bvec2");
- break;
- case EOpConstructBVec3:
- writeConstructorTriplet(visit, node->getType(), "bvec3");
- break;
- case EOpConstructBVec4:
- writeConstructorTriplet(visit, node->getType(), "bvec4");
- break;
- case EOpConstructInt:
- writeConstructorTriplet(visit, node->getType(), "int");
- break;
- case EOpConstructIVec2:
- writeConstructorTriplet(visit, node->getType(), "ivec2");
- break;
- case EOpConstructIVec3:
- writeConstructorTriplet(visit, node->getType(), "ivec3");
- break;
- case EOpConstructIVec4:
- writeConstructorTriplet(visit, node->getType(), "ivec4");
- break;
- case EOpConstructUInt:
- writeConstructorTriplet(visit, node->getType(), "uint");
- break;
- case EOpConstructUVec2:
- writeConstructorTriplet(visit, node->getType(), "uvec2");
- break;
- case EOpConstructUVec3:
- writeConstructorTriplet(visit, node->getType(), "uvec3");
- break;
- case EOpConstructUVec4:
- writeConstructorTriplet(visit, node->getType(), "uvec4");
- break;
- case EOpConstructMat2:
- writeConstructorTriplet(visit, node->getType(), "mat2");
- break;
- case EOpConstructMat2x3:
- writeConstructorTriplet(visit, node->getType(), "mat2x3");
- break;
- case EOpConstructMat2x4:
- writeConstructorTriplet(visit, node->getType(), "mat2x4");
- break;
- case EOpConstructMat3x2:
- writeConstructorTriplet(visit, node->getType(), "mat3x2");
- break;
- case EOpConstructMat3:
- writeConstructorTriplet(visit, node->getType(), "mat3");
- break;
- case EOpConstructMat3x4:
- writeConstructorTriplet(visit, node->getType(), "mat3x4");
- break;
- case EOpConstructMat4x2:
- writeConstructorTriplet(visit, node->getType(), "mat4x2");
- break;
- case EOpConstructMat4x3:
- writeConstructorTriplet(visit, node->getType(), "mat4x3");
- break;
- case EOpConstructMat4:
- writeConstructorTriplet(visit, node->getType(), "mat4");
- break;
- case EOpConstructStruct:
- {
- const TType &type = node->getType();
- ASSERT(type.getBasicType() == EbtStruct);
- TString constructorName = hashName(type.getStruct()->name());
- writeConstructorTriplet(visit, node->getType(), constructorName.c_str());
- break;
}
-
- case EOpOuterProduct:
- writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
- break;
-
- case EOpLessThan:
- writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
- break;
- case EOpGreaterThan:
- writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
- break;
- case EOpLessThanEqual:
- writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
- break;
- case EOpGreaterThanEqual:
- writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
- break;
- case EOpVectorEqual:
- writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
- break;
- case EOpVectorNotEqual:
- writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
- break;
- case EOpComma:
- writeTriplet(visit, "(", ", ", ")");
- break;
-
- case EOpMod:
- writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
- break;
- case EOpModf:
- writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
- break;
- case EOpPow:
- writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
- break;
- case EOpAtan:
- writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
- break;
- case EOpMin:
- writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
- break;
- case EOpMax:
- writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
- break;
- case EOpClamp:
- writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
- break;
- case EOpMix:
- writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
- break;
- case EOpStep:
- writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
- break;
- case EOpSmoothStep:
- writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
- break;
- case EOpDistance:
- writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
- break;
- case EOpDot:
- writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
- break;
- case EOpCross:
- writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
- break;
- case EOpFaceForward:
- writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
- break;
- case EOpReflect:
- writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
- break;
- case EOpRefract:
- writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
- break;
- case EOpMul:
- writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
- break;
-
- default:
+ mDeclaringVariable = true;
+ }
+ else if (visit == InVisit)
+ {
UNREACHABLE();
}
- return visitChildren;
+ else
+ {
+ mDeclaringVariable = false;
+ }
+ return true;
}
bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
{
TInfoSinkBase &out = objSink();
- incrementDepth(node);
-
TLoopType loopType = node->getType();
- // Only for loops can be unrolled
- ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
-
if (loopType == ELoopFor) // for loop
{
- if (!node->getUnrollFlag())
- {
- out << "for (";
- if (node->getInit())
- node->getInit()->traverse(this);
- out << "; ";
+ out << "for (";
+ if (node->getInit())
+ node->getInit()->traverse(this);
+ out << "; ";
- if (node->getCondition())
- node->getCondition()->traverse(this);
- out << "; ";
+ if (node->getCondition())
+ node->getCondition()->traverse(this);
+ out << "; ";
- if (node->getExpression())
- node->getExpression()->traverse(this);
- out << ")\n";
+ if (node->getExpression())
+ node->getExpression()->traverse(this);
+ out << ")\n";
- visitCodeBlock(node->getBody());
- }
- else
- {
- // Need to put a one-iteration loop here to handle break.
- TIntermSequence *declSeq =
- node->getInit()->getAsAggregate()->getSequence();
- TIntermSymbol *indexSymbol =
- (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
- TString name = hashVariableName(indexSymbol->getSymbol());
- out << "for (int " << name << " = 0; "
- << name << " < 1; "
- << "++" << name << ")\n";
-
- out << "{\n";
- mLoopUnrollStack.push(node);
- while (mLoopUnrollStack.satisfiesLoopCondition())
- {
- visitCodeBlock(node->getBody());
- mLoopUnrollStack.step();
- }
- mLoopUnrollStack.pop();
- out << "}\n";
- }
+ visitCodeBlock(node->getBody());
}
else if (loopType == ELoopWhile) // while loop
{
out << "while (";
- ASSERT(node->getCondition() != NULL);
+ ASSERT(node->getCondition() != nullptr);
node->getCondition()->traverse(this);
out << ")\n";
@@ -1154,13 +1071,11 @@ bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
visitCodeBlock(node->getBody());
out << "while (";
- ASSERT(node->getCondition() != NULL);
+ ASSERT(node->getCondition() != nullptr);
node->getCondition()->traverse(this);
out << ");\n";
}
- decrementDepth();
-
// No need to visit children. They have been already processed in
// this function.
return false;
@@ -1170,29 +1085,29 @@ bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
{
switch (node->getFlowOp())
{
- case EOpKill:
- writeTriplet(visit, "discard", NULL, NULL);
- break;
- case EOpBreak:
- writeTriplet(visit, "break", NULL, NULL);
- break;
- case EOpContinue:
- writeTriplet(visit, "continue", NULL, NULL);
- break;
- case EOpReturn:
- writeTriplet(visit, "return ", NULL, NULL);
- break;
- default:
- UNREACHABLE();
+ case EOpKill:
+ writeTriplet(visit, "discard", nullptr, nullptr);
+ break;
+ case EOpBreak:
+ writeTriplet(visit, "break", nullptr, nullptr);
+ break;
+ case EOpContinue:
+ writeTriplet(visit, "continue", nullptr, nullptr);
+ break;
+ case EOpReturn:
+ writeTriplet(visit, "return ", nullptr, nullptr);
+ break;
+ default:
+ UNREACHABLE();
}
return true;
}
-void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
+void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
{
TInfoSinkBase &out = objSink();
- if (node != NULL)
+ if (node != nullptr)
{
node->traverse(this);
// Single statements not part of a sequence need to be terminated
@@ -1208,76 +1123,41 @@ void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
TString TOutputGLSLBase::getTypeName(const TType &type)
{
- TInfoSinkBase out;
- if (type.isMatrix())
- {
- out << "mat";
- out << type.getNominalSize();
- if (type.getSecondarySize() != type.getNominalSize())
- {
- out << "x" << type.getSecondarySize();
- }
- }
- else if (type.isVector())
- {
- switch (type.getBasicType())
- {
- case EbtFloat:
- out << "vec";
- break;
- case EbtInt:
- out << "ivec";
- break;
- case EbtBool:
- out << "bvec";
- break;
- case EbtUInt:
- out << "uvec";
- break;
- default:
- UNREACHABLE();
- }
- out << type.getNominalSize();
- }
- else
- {
- if (type.getBasicType() == EbtStruct)
- out << hashName(type.getStruct()->name());
- else
- out << type.getBasicString();
- }
- return TString(out.c_str());
+ return GetTypeName(type, mHashFunction, &mNameMap);
}
-TString TOutputGLSLBase::hashName(const TString &name)
+TString TOutputGLSLBase::hashName(const TName &name)
{
- 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, mHashFunction);
- mNameMap[name.c_str()] = hashedName.c_str();
- return hashedName;
+ return HashName(name, mHashFunction, &mNameMap);
}
-TString TOutputGLSLBase::hashVariableName(const TString &name)
+TString TOutputGLSLBase::hashVariableName(const TName &name)
{
- if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
- return name;
+ if (mSymbolTable->findBuiltIn(name.getString(), mShaderVersion) != nullptr ||
+ name.getString().substr(0, 3) == "gl_")
+ {
+ if (mCompileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM &&
+ name.getString() == "gl_ViewID_OVR")
+ {
+ TName uniformName(TString("ViewID_OVR"));
+ uniformName.setInternal(true);
+ return hashName(uniformName);
+ }
+ return name.getString();
+ }
return hashName(name);
}
-TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
+TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunctionSymbolInfo &info)
{
- TString mangledStr = mangledName.getString();
- TString name = TFunction::unmangleName(mangledStr);
- if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
- return translateTextureFunction(name);
- if (mangledName.isInternal())
- return name;
+ if (info.isMain())
+ {
+ return info.getName();
+ }
else
- return hashName(name);
+ {
+ return hashName(info.getNameObj());
+ }
}
bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
@@ -1295,16 +1175,16 @@ void TOutputGLSLBase::declareStruct(const TStructure *structure)
{
TInfoSinkBase &out = objSink();
- out << "struct " << hashName(structure->name()) << "{\n";
+ out << "struct " << hashName(TName(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(field->name());
+ out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
if (field->type()->isArray())
- out << arrayBrackets(*field->type());
+ out << ArrayString(*field->type());
out << ";\n";
}
out << "}";
@@ -1332,6 +1212,10 @@ void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfa
out << "std140";
break;
+ case EbsStd430:
+ out << "std430";
+ break;
+
default:
UNREACHABLE();
break;
@@ -1339,6 +1223,12 @@ void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfa
out << ", ";
+ if (interfaceBlock->blockBinding() > 0)
+ {
+ out << "binding = " << interfaceBlock->blockBinding();
+ out << ", ";
+ }
+
switch (interfaceBlock->matrixPacking())
{
case EmpUnspecified:
@@ -1363,17 +1253,105 @@ void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBloc
{
TInfoSinkBase &out = objSink();
- out << hashName(interfaceBlock->name()) << "{\n";
+ out << hashName(TName(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(field->name());
+ out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
if (field->type()->isArray())
- out << arrayBrackets(*field->type());
+ out << ArrayString(*field->type());
out << ";\n";
}
out << "}";
}
+
+void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
+ sh::TLayoutPrimitiveType inputPrimitive,
+ int invocations,
+ sh::TLayoutPrimitiveType outputPrimitive,
+ int maxVertices)
+{
+ // Omit 'invocations = 1'
+ if (inputPrimitive != EptUndefined || invocations > 1)
+ {
+ out << "layout (";
+
+ if (inputPrimitive != EptUndefined)
+ {
+ out << getGeometryShaderPrimitiveTypeString(inputPrimitive);
+ }
+
+ if (invocations > 1)
+ {
+ if (inputPrimitive != EptUndefined)
+ {
+ out << ", ";
+ }
+ out << "invocations = " << invocations;
+ }
+ out << ") in;\n";
+ }
+
+ if (outputPrimitive != EptUndefined || maxVertices != -1)
+ {
+ out << "layout (";
+
+ if (outputPrimitive != EptUndefined)
+ {
+ out << getGeometryShaderPrimitiveTypeString(outputPrimitive);
+ }
+
+ if (maxVertices != -1)
+ {
+ if (outputPrimitive != EptUndefined)
+ {
+ out << ", ";
+ }
+ out << "max_vertices = " << maxVertices;
+ }
+ out << ") out;\n";
+ }
+}
+
+// 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 ||
+ IsVarying(type.getQualifier())) &&
+ layoutQualifier.location >= 0)
+ {
+ return true;
+ }
+
+ if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
+ {
+ return true;
+ }
+
+ if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
+ {
+ return true;
+ }
+
+ if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
+ {
+ return true;
+ }
+ return false;
+}
+
+} // namespace sh