From 2a43c86c2428dd427bb5c8dc62e57774d87952a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Fri, 22 May 2020 20:59:38 -0700 Subject: [PATCH] Updated glslang. --- 3rdparty/glslang/SPIRV/GlslangToSpv.cpp | 2 +- 3rdparty/glslang/glslang/Include/Types.h | 4 + 3rdparty/glslang/glslang/Include/revision.h | 2 +- .../MachineIndependent/Intermediate.cpp | 8 +- .../MachineIndependent/ParseHelper.cpp | 20 ++++- .../glslang/MachineIndependent/iomapper.cpp | 42 ++++----- .../glslang/MachineIndependent/iomapper.h | 1 + .../MachineIndependent/linkValidate.cpp | 6 +- .../MachineIndependent/localintermediate.h | 4 + .../glslang/MachineIndependent/reflection.cpp | 4 +- 3rdparty/glslang/glslang/Public/ShaderLang.h | 2 +- 3rdparty/glslang/hlsl/hlslParseHelper.cpp | 87 +++++++++++++++---- 3rdparty/glslang/hlsl/hlslParseHelper.h | 2 +- 13 files changed, 128 insertions(+), 56 deletions(-) diff --git a/3rdparty/glslang/SPIRV/GlslangToSpv.cpp b/3rdparty/glslang/SPIRV/GlslangToSpv.cpp index 3bed67835..e41bb5de6 100644 --- a/3rdparty/glslang/SPIRV/GlslangToSpv.cpp +++ b/3rdparty/glslang/SPIRV/GlslangToSpv.cpp @@ -1448,7 +1448,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb); } - if (sourceExtensions.find("GL_EXT_ray_flags_primitive_culling") != sourceExtensions.end()) { + if (glslangIntermediate->getLayoutPrimitiveCulling()) { builder.addCapability(spv::CapabilityRayTraversalPrimitiveCullingProvisionalKHR); } diff --git a/3rdparty/glslang/glslang/Include/Types.h b/3rdparty/glslang/glslang/Include/Types.h index b2c416d10..235ea3f1d 100644 --- a/3rdparty/glslang/glslang/Include/Types.h +++ b/3rdparty/glslang/glslang/Include/Types.h @@ -1235,6 +1235,7 @@ struct TShaderQualifiers { bool layoutDerivativeGroupQuads; // true if layout derivative_group_quadsNV set bool layoutDerivativeGroupLinear; // true if layout derivative_group_linearNV set int primitives; // mesh shader "max_primitives"DerivativeGroupLinear; // true if layout derivative_group_linearNV set + bool layoutPrimitiveCulling; // true if layout primitive_culling set TLayoutDepth getDepth() const { return layoutDepth; } #else TLayoutDepth getDepth() const { return EldNone; } @@ -1268,6 +1269,7 @@ struct TShaderQualifiers { layoutOverrideCoverage = false; layoutDerivativeGroupQuads = false; layoutDerivativeGroupLinear = false; + layoutPrimitiveCulling = false; primitives = TQualifier::layoutNotSet; interlockOrdering = EioNone; #endif @@ -1331,6 +1333,8 @@ struct TShaderQualifiers { primitives = src.primitives; if (src.interlockOrdering != EioNone) interlockOrdering = src.interlockOrdering; + if (src.layoutPrimitiveCulling) + layoutPrimitiveCulling = src.layoutPrimitiveCulling; #endif } }; diff --git a/3rdparty/glslang/glslang/Include/revision.h b/3rdparty/glslang/glslang/Include/revision.h index 76c2971dd..693557bec 100644 --- a/3rdparty/glslang/glslang/Include/revision.h +++ b/3rdparty/glslang/glslang/Include/revision.h @@ -1,3 +1,3 @@ // This header is generated by the make-revision script. -#define GLSLANG_PATCH_LEVEL 3763 +#define GLSLANG_PATCH_LEVEL 3766 diff --git a/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp b/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp index d7049d8d5..52ec6115f 100755 --- a/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp +++ b/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp @@ -1733,12 +1733,14 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat case EbtUint64: case EbtFloat: case EbtDouble: - return true; + return version >= 400 || extensionRequested(E_GL_ARB_gpu_shader_fp64); case EbtInt16: case EbtUint16: - return extensionRequested(E_GL_AMD_gpu_shader_int16); + return (version >= 400 || extensionRequested(E_GL_ARB_gpu_shader_fp64)) && + extensionRequested(E_GL_AMD_gpu_shader_int16); case EbtFloat16: - return extensionRequested(E_GL_AMD_gpu_shader_half_float); + return (version >= 400 || extensionRequested(E_GL_ARB_gpu_shader_fp64)) && + extensionRequested(E_GL_AMD_gpu_shader_half_float); default: return false; } diff --git a/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp b/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp index b678a3653..a35d41a05 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp +++ b/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp @@ -5173,6 +5173,12 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi } } } + + if (id == "primitive_culling") { + requireExtensions(loc, 1, &E_GL_EXT_ray_flags_primitive_culling, "primitive culling"); + publicType.shaderQualifiers.layoutPrimitiveCulling = true; + return; + } #endif error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), ""); @@ -6104,6 +6110,8 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua error(loc, message, "num_views", ""); if (shaderQualifiers.interlockOrdering != EioNone) error(loc, message, TQualifier::getInterlockOrderingString(shaderQualifiers.interlockOrdering), ""); + if (shaderQualifiers.layoutPrimitiveCulling) + error(loc, "can only be applied as standalone", "primitive_culling", ""); #endif } @@ -8368,6 +8376,16 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con { checkIoArraysConsistency(loc); } + + if (publicType.shaderQualifiers.layoutPrimitiveCulling) { + if (publicType.qualifier.storage != EvqTemporary) + error(loc, "layout qualifier can not have storage qualifiers", "primitive_culling","", ""); + else { + intermediate.setLayoutPrimitiveCulling(); + } + // Exit early as further checks are not valid + return; + } #endif const TQualifier& qualifier = publicType.qualifier; @@ -8527,7 +8545,7 @@ const TTypeList* TParseContext::recordStructCopy(TStructRecord& record, const TT size_t memberCount = tmpType->getStruct()->size(); size_t originHash = 0, tmpHash = 0; std::hash hasher; - for (uint32_t i = 0; i < memberCount; i++) { + for (size_t i = 0; i < memberCount; i++) { size_t originMemberHash = hasher(originType->getStruct()->at(i).type->getQualifier().layoutPacking + originType->getStruct()->at(i).type->getQualifier().layoutMatrix); size_t tmpMemberHash = hasher(tmpType->getStruct()->at(i).type->getQualifier().layoutPacking + diff --git a/3rdparty/glslang/glslang/MachineIndependent/iomapper.cpp b/3rdparty/glslang/glslang/MachineIndependent/iomapper.cpp index 9dc1da2c9..4e409e06a 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/iomapper.cpp +++ b/3rdparty/glslang/glslang/MachineIndependent/iomapper.cpp @@ -579,10 +579,7 @@ TDefaultGlslIoResolver::TDefaultGlslIoResolver(const TIntermediate& intermediate int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) { const TType& type = ent.symbol->getType(); - const TString& name = IsAnonymous(ent.symbol->getName()) ? - ent.symbol->getType().getTypeName() - : - ent.symbol->getName(); + const TString& name = getAccessName(ent.symbol); if (currentStage != stage) { preStage = currentStage; currentStage = stage; @@ -630,7 +627,7 @@ int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInf TVarSlotMap::iterator iter = storageSlotMap[resourceKey].find(name); if (iter != storageSlotMap[resourceKey].end()) { // If interface resource be found, set it has location and this symbol's new location - // equal the symbol's explicit location declarated in pre or next stage. + // equal the symbol's explicit location declaration in pre or next stage. // // vs: out vec4 a; // fs: layout(..., location = 3,...) in vec4 a; @@ -666,10 +663,7 @@ int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInf int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) { const TType& type = ent.symbol->getType(); - const TString& name = IsAnonymous(ent.symbol->getName()) ? - ent.symbol->getType().getTypeName() - : - ent.symbol->getName(); + const TString& name = getAccessName(ent.symbol); // kick out of not doing this if (! doAutoLocationMapping()) { return ent.newLocation = -1; @@ -712,7 +706,7 @@ int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEn TVarSlotMap::iterator iter = slotMap.find(name); if (iter != slotMap.end()) { // If uniform resource be found, set it has location and this symbol's new location - // equal the uniform's explicit location declarated in other stage. + // equal the uniform's explicit location declaration in other stage. // // vs: uniform vec4 a; // fs: layout(..., location = 3,...) uniform vec4 a; @@ -720,7 +714,7 @@ int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEn location = iter->second; } if (! hasLocation) { - // No explicit location declaraten in other stage. + // No explicit location declaration in other stage. // So we should find a new slot for this uniform. // // vs: uniform vec4 a; @@ -729,7 +723,7 @@ int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEn storageSlotMap[resourceKey][name] = location; } } else { - // the first uniform declarated in a program. + // the first uniform declaration in a program. TVarSlotMap varSlotMap; location = getFreeSlot(resourceKey, 0, size); varSlotMap[name] = location; @@ -740,11 +734,8 @@ int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEn int TDefaultGlslIoResolver::resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent) { const TType& type = ent.symbol->getType(); - const TString& name = IsAnonymous(ent.symbol->getName()) ? - ent.symbol->getType().getTypeName() - : - ent.symbol->getName(); - // On OpenGL arrays of opaque types take a seperate binding for each element + const TString& name = getAccessName(ent.symbol); + // On OpenGL arrays of opaque types take a separate binding for each element int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1; TResourceType resource = getResourceType(type); // don't need to handle uniform symbol, it will be handled in resolveUniformLocation @@ -818,10 +809,7 @@ void TDefaultGlslIoResolver::endCollect(EShLanguage /*stage*/) { void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) { const TType& type = ent.symbol->getType(); - const TString& name = IsAnonymous(ent.symbol->getName()) ? - ent.symbol->getType().getTypeName() - : - ent.symbol->getName(); + const TString& name = getAccessName(ent.symbol); TStorageQualifier storage = type.getQualifier().storage; EShLanguage stage(EShLangCount); switch (storage) { @@ -881,10 +869,7 @@ void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) { const TType& type = ent.symbol->getType(); - const TString& name = IsAnonymous(ent.symbol->getName()) ? - ent.symbol->getType().getTypeName() - : - ent.symbol->getName(); + const TString& name = getAccessName(ent.symbol); int resource = getResourceType(type); if (type.getQualifier().hasBinding()) { TVarSlotMap& varSlotMap = resourceSlotMap[resource]; @@ -907,6 +892,13 @@ void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& } } +const TString& TDefaultGlslIoResolver::getAccessName(const TIntermSymbol* symbol) +{ + return symbol->getBasicType() == EbtBlock ? + symbol->getType().getTypeName() : + symbol->getName(); +} + //TDefaultGlslIoResolver end /* diff --git a/3rdparty/glslang/glslang/MachineIndependent/iomapper.h b/3rdparty/glslang/glslang/MachineIndependent/iomapper.h index a6f2480ca..7ca18b8a5 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/iomapper.h +++ b/3rdparty/glslang/glslang/MachineIndependent/iomapper.h @@ -203,6 +203,7 @@ public: void endCollect(EShLanguage) override; void reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) override; void reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) override; + const TString& getAccessName(const TIntermSymbol*); // in/out symbol and uniform symbol are stored in the same resourceSlotMap, the storage key is used to identify each type of symbol. // We use stage and storage qualifier to construct a storage key. it can help us identify the same storage resource used in different stage. // if a resource is a program resource and we don't need know it usage stage, we can use same stage to build storage key. diff --git a/3rdparty/glslang/glslang/MachineIndependent/linkValidate.cpp b/3rdparty/glslang/glslang/MachineIndependent/linkValidate.cpp index dcb1cc8cb..045d45e3c 100755 --- a/3rdparty/glslang/glslang/MachineIndependent/linkValidate.cpp +++ b/3rdparty/glslang/glslang/MachineIndependent/linkValidate.cpp @@ -153,7 +153,7 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit) if (vertices == TQualifier::layoutNotSet) vertices = unit.vertices; - else if (vertices != unit.vertices) { + else if (unit.vertices != TQualifier::layoutNotSet && vertices != unit.vertices) { if (language == EShLangGeometry || language == EShLangMeshNV) error(infoSink, "Contradictory layout max_vertices values"); else if (language == EShLangTessControl) @@ -172,12 +172,12 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit) if (inputPrimitive == ElgNone) inputPrimitive = unit.inputPrimitive; - else if (inputPrimitive != unit.inputPrimitive) + else if (unit.inputPrimitive != ElgNone && inputPrimitive != unit.inputPrimitive) error(infoSink, "Contradictory input layout primitives"); if (outputPrimitive == ElgNone) outputPrimitive = unit.outputPrimitive; - else if (outputPrimitive != unit.outputPrimitive) + else if (unit.outputPrimitive != ElgNone && outputPrimitive != unit.outputPrimitive) error(infoSink, "Contradictory output layout primitives"); if (originUpperLeft != unit.originUpperLeft || pixelCenterInteger != unit.pixelCenterInteger) diff --git a/3rdparty/glslang/glslang/MachineIndependent/localintermediate.h b/3rdparty/glslang/glslang/MachineIndependent/localintermediate.h index 996e347fb..b6a445fd5 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/localintermediate.h +++ b/3rdparty/glslang/glslang/MachineIndependent/localintermediate.h @@ -265,6 +265,7 @@ public: computeDerivativeMode(LayoutDerivativeNone), primitives(TQualifier::layoutNotSet), numTaskNVBlocks(0), + layoutPrimitiveCulling(false), autoMapBindings(false), autoMapLocations(false), flattenUniformArrays(false), @@ -742,6 +743,8 @@ public: void setLayoutDerivativeMode(ComputeDerivativeMode mode) { computeDerivativeMode = mode; } bool hasLayoutDerivativeModeNone() const { return computeDerivativeMode != LayoutDerivativeNone; } ComputeDerivativeMode getLayoutDerivativeModeNone() const { return computeDerivativeMode; } + void setLayoutPrimitiveCulling() { layoutPrimitiveCulling = true; } + bool getLayoutPrimitiveCulling() const { return layoutPrimitiveCulling; } bool setPrimitives(int m) { if (primitives != TQualifier::layoutNotSet) @@ -974,6 +977,7 @@ protected: ComputeDerivativeMode computeDerivativeMode; int primitives; int numTaskNVBlocks; + bool layoutPrimitiveCulling; // Base shift values std::array shiftBinding; diff --git a/3rdparty/glslang/glslang/MachineIndependent/reflection.cpp b/3rdparty/glslang/glslang/MachineIndependent/reflection.cpp index 769466083..55caa1f44 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/reflection.cpp +++ b/3rdparty/glslang/glslang/MachineIndependent/reflection.cpp @@ -92,8 +92,8 @@ public: if (processedDerefs.find(&base) == processedDerefs.end()) { processedDerefs.insert(&base); - uint32_t blockIndex = -1; - uint32_t offset = -1; + int blockIndex = -1; + int offset = -1; TList derefs; TString baseName = base.getName(); diff --git a/3rdparty/glslang/glslang/Public/ShaderLang.h b/3rdparty/glslang/glslang/Public/ShaderLang.h index 8ce654167..ee23556d9 100644 --- a/3rdparty/glslang/glslang/Public/ShaderLang.h +++ b/3rdparty/glslang/glslang/Public/ShaderLang.h @@ -68,7 +68,7 @@ // This should always increase, as some paths to do not consume // a more major number. // It should increment by one when new functionality is added. -#define GLSLANG_MINOR_VERSION 13 +#define GLSLANG_MINOR_VERSION 14 // // Call before doing any other compiler/linker operations. diff --git a/3rdparty/glslang/hlsl/hlslParseHelper.cpp b/3rdparty/glslang/hlsl/hlslParseHelper.cpp index 2dc173fca..61ca8244d 100755 --- a/3rdparty/glslang/hlsl/hlslParseHelper.cpp +++ b/3rdparty/glslang/hlsl/hlslParseHelper.cpp @@ -1169,7 +1169,7 @@ bool HlslParseContext::shouldFlatten(const TType& type, TStorageQualifier qualif } // Top level variable flattening: construct data -void HlslParseContext::flatten(const TVariable& variable, bool linkage) +void HlslParseContext::flatten(const TVariable& variable, bool linkage, bool arrayed) { const TType& type = variable.getType(); @@ -1181,8 +1181,15 @@ void HlslParseContext::flatten(const TVariable& variable, bool linkage) TFlattenData(type.getQualifier().layoutBinding, type.getQualifier().layoutLocation))); - // the item is a map pair, so first->second is the TFlattenData itself. - flatten(variable, type, entry.first->second, variable.getName(), linkage, type.getQualifier(), nullptr); + // if flattening arrayed io struct, array each member of dereferenced type + if (arrayed) { + const TType dereferencedType(type, 0); + flatten(variable, dereferencedType, entry.first->second, variable.getName(), linkage, + type.getQualifier(), type.getArraySizes()); + } else { + flatten(variable, type, entry.first->second, variable.getName(), linkage, + type.getQualifier(), nullptr); + } } // Recursively flatten the given variable at the provided type, building the flattenData as we go. @@ -1256,6 +1263,10 @@ int HlslParseContext::addFlattenedMember(const TVariable& variable, const TType& } } + // Only propagate arraysizes here for arrayed io + if (variable.getType().getQualifier().isArrayedIo(language) && builtInArraySizes != nullptr) + memberVariable->getWritableType().copyArraySizes(*builtInArraySizes); + flattenData.offsets.push_back(static_cast(flattenData.members.size())); flattenData.members.push_back(memberVariable); @@ -2068,11 +2079,8 @@ TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunct // Further this return/in/out transform by flattening, splitting, and assigning locations const auto makeVariableInOut = [&](TVariable& variable) { if (variable.getType().isStruct()) { - if (variable.getType().getQualifier().isArrayedIo(language)) { - if (variable.getType().containsBuiltIn()) - split(variable); - } else if (shouldFlatten(variable.getType(), EvqVaryingIn /* not assigned yet, but close enough */, true)) - flatten(variable, false /* don't track linkage here, it will be tracked in assignToInterface() */); + bool arrayed = variable.getType().getQualifier().isArrayedIo(language); + flatten(variable, false /* don't track linkage here, it will be tracked in assignToInterface() */, arrayed); } // TODO: flatten arrays too // TODO: flatten everything in I/O @@ -2733,17 +2741,33 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op wasSplit(binaryNode->getLeft()); }; + // Return symbol if node is symbol or index ref + const auto getSymbol = [](const TIntermTyped* node) -> const TIntermSymbol* { + const TIntermSymbol* symbolNode = node->getAsSymbolNode(); + if (symbolNode != nullptr) + return symbolNode; + + const TIntermBinary* binaryNode = node->getAsBinaryNode(); + if (binaryNode != nullptr && (binaryNode->getOp() == EOpIndexDirect || binaryNode->getOp() == EOpIndexIndirect)) + return binaryNode->getLeft()->getAsSymbolNode(); + + return nullptr; + }; + // Return true if this stage assigns clip position with potentially inverted Y const auto assignsClipPos = [this](const TIntermTyped* node) -> bool { return node->getType().getQualifier().builtIn == EbvPosition && (language == EShLangVertex || language == EShLangGeometry || language == EShLangTessEvaluation); }; + const TIntermSymbol* leftSymbol = getSymbol(left); + const TIntermSymbol* rightSymbol = getSymbol(right); + const bool isSplitLeft = wasSplit(left) || indexesSplit(left); const bool isSplitRight = wasSplit(right) || indexesSplit(right); - const bool isFlattenLeft = wasFlattened(left); - const bool isFlattenRight = wasFlattened(right); + const bool isFlattenLeft = wasFlattened(leftSymbol); + const bool isFlattenRight = wasFlattened(rightSymbol); // OK to do a single assign if neither side is split or flattened. Otherwise, // fall through to a member-wise copy. @@ -2791,10 +2815,10 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op memberCount = left->getType().getCumulativeArraySize(); if (isFlattenLeft) - leftVariables = &flattenMap.find(left->getAsSymbolNode()->getId())->second.members; + leftVariables = &flattenMap.find(leftSymbol->getId())->second.members; if (isFlattenRight) { - rightVariables = &flattenMap.find(right->getAsSymbolNode()->getId())->second.members; + rightVariables = &flattenMap.find(rightSymbol->getId())->second.members; } else { // The RHS is not flattened. There are several cases: // 1. 1 item to copy: Use the RHS directly. @@ -2828,8 +2852,10 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op TStorageQualifier leftStorage = left->getType().getQualifier().storage; TStorageQualifier rightStorage = right->getType().getQualifier().storage; - int leftOffset = findSubtreeOffset(*left); - int rightOffset = findSubtreeOffset(*right); + int leftOffsetStart = findSubtreeOffset(*left); + int rightOffsetStart = findSubtreeOffset(*right); + int leftOffset = leftOffsetStart; + int rightOffset = rightOffsetStart; const auto getMember = [&](bool isLeft, const TType& type, int member, TIntermTyped* splitNode, int splitMember, bool flattened) @@ -2869,10 +2895,35 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op } } } else if (flattened && !shouldFlatten(derefType, isLeft ? leftStorage : rightStorage, false)) { - if (isLeft) + if (isLeft) { + // offset will cycle through variables for arrayed io + if (leftOffset >= static_cast(leftVariables->size())) + leftOffset = leftOffsetStart; subTree = intermediate.addSymbol(*(*leftVariables)[leftOffset++]); - else + } else { + // offset will cycle through variables for arrayed io + if (rightOffset >= static_cast(rightVariables->size())) + rightOffset = rightOffsetStart; subTree = intermediate.addSymbol(*(*rightVariables)[rightOffset++]); + } + + // arrayed io + if (subTree->getType().isArray()) { + if (!arrayElement.empty()) { + const TType derefType(subTree->getType(), arrayElement.front()); + subTree = intermediate.addIndex(EOpIndexDirect, subTree, + intermediate.addConstantUnion(arrayElement.front(), loc), loc); + subTree->setType(derefType); + } else { + // There's an index operation we should transfer to the output builtin. + assert(splitNode->getAsOperator() != nullptr && + splitNode->getAsOperator()->getOp() == EOpIndexIndirect); + const TType splitDerefType(subTree->getType(), 0); + subTree = intermediate.addIndex(splitNode->getAsOperator()->getOp(), subTree, + splitNode->getAsBinaryNode()->getRight(), loc); + subTree->setType(splitDerefType); + } + } } else { // Index operator if it's an aggregate, else EOpNull const TOperator accessOp = type.isArray() ? EOpIndexDirect @@ -9911,8 +9962,8 @@ void HlslParseContext::addPatchConstantInvocation() TVariable* pcfOutput = makeInternalVariable("@patchConstantOutput", outType); pcfOutput->getWritableType().getQualifier().storage = EvqVaryingOut; - if (pcfOutput->getType().containsBuiltIn()) - split(*pcfOutput); + if (pcfOutput->getType().isStruct()) + flatten(*pcfOutput, false); assignToInterface(*pcfOutput); diff --git a/3rdparty/glslang/hlsl/hlslParseHelper.h b/3rdparty/glslang/hlsl/hlslParseHelper.h index 6f4166103..3ca21c6c9 100644 --- a/3rdparty/glslang/hlsl/hlslParseHelper.h +++ b/3rdparty/glslang/hlsl/hlslParseHelper.h @@ -276,7 +276,7 @@ protected: void fixBuiltInIoType(TType&); - void flatten(const TVariable& variable, bool linkage); + void flatten(const TVariable& variable, bool linkage, bool arrayed = false); int flatten(const TVariable& variable, const TType&, TFlattenData&, TString name, bool linkage, const TQualifier& outerQualifier, const TArraySizes* builtInArraySizes); int flattenStruct(const TVariable& variable, const TType&, TFlattenData&, TString name, bool linkage,