diff options
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp')
-rw-r--r-- | src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp | 1846 |
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 |