diff --git a/3rdparty/glslang/SPIRV/GlslangToSpv.cpp b/3rdparty/glslang/SPIRV/GlslangToSpv.cpp index d0bebaea4..c8a73a6b2 100644 --- a/3rdparty/glslang/SPIRV/GlslangToSpv.cpp +++ b/3rdparty/glslang/SPIRV/GlslangToSpv.cpp @@ -4400,7 +4400,6 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, { // Name and decorate the non-hidden members int offset = -1; - int locationOffset = 0; // for use within the members of this struct bool memberLocationInvalid = type.isArrayOfArrays() || (type.isArray() && (type.getQualifier().isArrayedIo(glslangIntermediate->getStage()) == false)); for (int i = 0; i < (int)glslangMembers->size(); i++) { @@ -4458,10 +4457,6 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, if (!memberLocationInvalid && memberQualifier.hasLocation()) builder.addMemberDecoration(spvType, member, spv::DecorationLocation, memberQualifier.layoutLocation); - if (qualifier.hasLocation()) // track for upcoming inheritance - locationOffset += glslangIntermediate->computeTypeLocationSize( - glslangMember, glslangIntermediate->getStage()); - // component, XFB, others if (glslangMember.getQualifier().hasComponent()) builder.addMemberDecoration(spvType, member, spv::DecorationComponent, @@ -5322,7 +5317,10 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO int components = node->getType().getVectorSize(); - if (node->getOp() == glslang::EOpTextureFetch) { + if (node->getOp() == glslang::EOpImageLoad || + node->getOp() == glslang::EOpImageLoadLod || + node->getOp() == glslang::EOpTextureFetch || + node->getOp() == glslang::EOpTextureFetchOffset) { // These must produce 4 components, per SPIR-V spec. We'll add a conversion constructor if needed. // This will only happen through the HLSL path for operator[], so we do not have to handle e.g. // the EOpTexture/Proj/Lod/etc family. It would be harmless to do so, but would need more logic diff --git a/3rdparty/glslang/SPIRV/SpvBuilder.cpp b/3rdparty/glslang/SPIRV/SpvBuilder.cpp index 0482c5a9a..6751dec21 100644 --- a/3rdparty/glslang/SPIRV/SpvBuilder.cpp +++ b/3rdparty/glslang/SPIRV/SpvBuilder.cpp @@ -743,6 +743,26 @@ Id Builder::getContainedTypeId(Id typeId, int member) const } } +// Figure out the final resulting type of the access chain. +Id Builder::getResultingAccessChainType() const +{ + assert(accessChain.base != NoResult); + Id typeId = getTypeId(accessChain.base); + + assert(isPointerType(typeId)); + typeId = getContainedTypeId(typeId); + + for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) { + if (isStructType(typeId)) { + assert(isConstantScalar(accessChain.indexChain[i])); + typeId = getContainedTypeId(typeId, getConstantScalar(accessChain.indexChain[i])); + } else + typeId = getContainedTypeId(typeId, accessChain.indexChain[i]); + } + + return typeId; +} + // Return the immediately contained type of a given composite type. Id Builder::getContainedTypeId(Id typeId) const { @@ -1585,16 +1605,7 @@ Id Builder::createLoad(Id lValue, spv::Decoration precision, spv::MemoryAccessMa Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector& offsets) { // Figure out the final resulting type. - spv::Id typeId = getTypeId(base); - assert(isPointerType(typeId) && offsets.size() > 0); - typeId = getContainedTypeId(typeId); - for (int i = 0; i < (int)offsets.size(); ++i) { - if (isStructType(typeId)) { - assert(isConstantScalar(offsets[i])); - typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i])); - } else - typeId = getContainedTypeId(typeId, offsets[i]); - } + Id typeId = getResultingAccessChainType(); typeId = makePointer(storageClass, typeId); // Make the instruction @@ -2794,28 +2805,58 @@ void Builder::accessChainStore(Id rvalue, Decoration nonUniform, spv::MemoryAcce assert(accessChain.isRValue == false); transferAccessChainSwizzle(true); - Id base = collapseAccessChain(); - addDecoration(base, nonUniform); - Id source = rvalue; + // If a swizzle exists and is not full and is not dynamic, then the swizzle will be broken into individual stores. + if (accessChain.swizzle.size() > 0 && + getNumTypeComponents(getResultingAccessChainType()) != (int)accessChain.swizzle.size() && + accessChain.component == NoResult) { + for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) { + accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle[i])); - // dynamic component should be gone - assert(accessChain.component == NoResult); + Id base = collapseAccessChain(); + addDecoration(base, nonUniform); - // If swizzle still exists, it is out-of-order or not full, we must load the target vector, - // extract and insert elements to perform writeMask and/or swizzle. - if (accessChain.swizzle.size() > 0) { - Id tempBaseId = createLoad(base, spv::NoPrecision); - source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle); + accessChain.indexChain.pop_back(); + accessChain.instr = NoResult; + + // dynamic component should be gone + assert(accessChain.component == NoResult); + + Id source = createCompositeExtract(rvalue, getContainedTypeId(getTypeId(rvalue)), i); + + // take LSB of alignment + alignment = alignment & ~(alignment & (alignment-1)); + if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) { + memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask); + } + + createStore(source, base, memoryAccess, scope, alignment); + } } + else { + Id base = collapseAccessChain(); + addDecoration(base, nonUniform); - // take LSB of alignment - alignment = alignment & ~(alignment & (alignment-1)); - if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) { - memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask); + Id source = rvalue; + + // dynamic component should be gone + assert(accessChain.component == NoResult); + + // If swizzle still exists, it may be out-of-order, we must load the target vector, + // extract and insert elements to perform writeMask and/or swizzle. + if (accessChain.swizzle.size() > 0) { + Id tempBaseId = createLoad(base, spv::NoPrecision); + source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle); + } + + // take LSB of alignment + alignment = alignment & ~(alignment & (alignment-1)); + if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) { + memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask); + } + + createStore(source, base, memoryAccess, scope, alignment); } - - createStore(source, base, memoryAccess, scope, alignment); } // Comments in header diff --git a/3rdparty/glslang/SPIRV/SpvBuilder.h b/3rdparty/glslang/SPIRV/SpvBuilder.h index 73847e1d1..251b9ee82 100644 --- a/3rdparty/glslang/SPIRV/SpvBuilder.h +++ b/3rdparty/glslang/SPIRV/SpvBuilder.h @@ -202,6 +202,7 @@ public: StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); } ImageFormat getImageTypeFormat(Id typeId) const { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); } + Id getResultingAccessChainType() const; bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); } bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); } diff --git a/3rdparty/glslang/StandAlone/StandAlone.cpp b/3rdparty/glslang/StandAlone/StandAlone.cpp index c6dc59743..e62f92f71 100644 --- a/3rdparty/glslang/StandAlone/StandAlone.cpp +++ b/3rdparty/glslang/StandAlone/StandAlone.cpp @@ -347,13 +347,13 @@ void ProcessBindingBase(int& argc, char**& argv, glslang::TResourceType res) lang = FindLanguage(argv[arg++], false); } - if ((argc - arg) > 2 && isdigit(argv[arg+0][0]) && isdigit(argv[arg+1][0])) { + if ((argc - arg) >= 2 && isdigit(argv[arg+0][0]) && isdigit(argv[arg+1][0])) { // Parse a per-set binding base - while ((argc - arg) > 2 && isdigit(argv[arg+0][0]) && isdigit(argv[arg+1][0])) { + do { const int baseNum = atoi(argv[arg++]); const int setNum = atoi(argv[arg++]); perSetBase[setNum] = baseNum; - } + } while ((argc - arg) >= 2 && isdigit(argv[arg + 0][0]) && isdigit(argv[arg + 1][0])); } else { // Parse single binding base singleBase = atoi(argv[arg++]); diff --git a/3rdparty/glslang/glslang/HLSL/hlslParseHelper.cpp b/3rdparty/glslang/glslang/HLSL/hlslParseHelper.cpp index d62f39278..02aac3c69 100644 --- a/3rdparty/glslang/glslang/HLSL/hlslParseHelper.cpp +++ b/3rdparty/glslang/glslang/HLSL/hlslParseHelper.cpp @@ -6689,12 +6689,6 @@ void HlslParseContext::globalQualifierFix(const TSourceLoc&, TQualifier& qualifi // // Merge characteristics of the 'src' qualifier into the 'dst'. -// If there is duplication, issue error messages, unless 'force' -// is specified, which means to just override default settings. -// -// Also, when force is false, it will be assumed that 'src' follows -// 'dst', for the purpose of error checking order for versions -// that require specific orderings of qualifiers. // void HlslParseContext::mergeQualifiers(TQualifier& dst, const TQualifier& src) { @@ -6712,8 +6706,7 @@ void HlslParseContext::mergeQualifiers(TQualifier& dst, const TQualifier& src) mergeObjectLayoutQualifiers(dst, src, false); // individual qualifiers - bool repeated = false; -#define MERGE_SINGLETON(field) repeated |= dst.field && src.field; dst.field |= src.field; +#define MERGE_SINGLETON(field) dst.field |= src.field; MERGE_SINGLETON(invariant); MERGE_SINGLETON(noContraction); MERGE_SINGLETON(centroid); diff --git a/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp b/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp index d1123d4a9..027844596 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp +++ b/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp @@ -1739,7 +1739,7 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat case EbtUint: switch (from) { case EbtInt: - return version >= 400 || getSource() == EShSourceHlsl; + return version >= 400 || getSource() == EShSourceHlsl || IsRequestedExtension(E_GL_ARB_gpu_shader5); case EbtBool: return getSource() == EShSourceHlsl; case EbtInt16: @@ -2676,7 +2676,11 @@ TIntermTyped* TIntermediate::addSwizzle(TSwizzleSelectors& selecto // 'swizzleOkay' says whether or not it is okay to consider a swizzle // a valid part of the dereference chain. // -const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool swizzleOkay) +// 'BufferReferenceOk' says if type is buffer_reference, the routine stop to find the most left node. +// +// + +const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool swizzleOkay , bool bufferReferenceOk) { do { const TIntermBinary* binary = node->getAsBinaryNode(); @@ -2694,6 +2698,8 @@ const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool return nullptr; } node = node->getAsBinaryNode()->getLeft(); + if (bufferReferenceOk && node->isReference()) + return node; } while (true); } diff --git a/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp b/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp index c2b9edcf6..35a53e425 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp +++ b/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp @@ -327,6 +327,16 @@ void TParseContext::setAtomicCounterBlockDefaults(TType& block) const block.getQualifier().layoutMatrix = ElmRowMajor; } +void TParseContext::setInvariant(const TSourceLoc& loc, const char* builtin) { + TSymbol* symbol = symbolTable.find(builtin); + if (symbol && symbol->getType().getQualifier().isPipeOutput()) { + if (intermediate.inIoAccessed(builtin)) + warn(loc, "changing qualification after use", "invariant", builtin); + TSymbol* csymbol = symbolTable.copyUp(symbol); + csymbol->getWritableType().getQualifier().invariant = true; + } +} + void TParseContext::handlePragma(const TSourceLoc& loc, const TVector& tokens) { #ifndef GLSLANG_WEB @@ -404,8 +414,33 @@ void TParseContext::handlePragma(const TSourceLoc& loc, const TVector& intermediate.setUseVariablePointers(); } else if (tokens[0].compare("once") == 0) { warn(loc, "not implemented", "#pragma once", ""); - } else if (tokens[0].compare("glslang_binary_double_output") == 0) + } else if (tokens[0].compare("glslang_binary_double_output") == 0) { intermediate.setBinaryDoubleOutput(); + } else if (spvVersion.spv > 0 && tokens[0].compare("STDGL") == 0 && + tokens[1].compare("invariant") == 0 && tokens[3].compare("all") == 0) { + intermediate.setInvariantAll(); + // Set all builtin out variables invariant if declared + setInvariant(loc, "gl_Position"); + setInvariant(loc, "gl_PointSize"); + setInvariant(loc, "gl_ClipDistance"); + setInvariant(loc, "gl_CullDistance"); + setInvariant(loc, "gl_TessLevelOuter"); + setInvariant(loc, "gl_TessLevelInner"); + setInvariant(loc, "gl_PrimitiveID"); + setInvariant(loc, "gl_Layer"); + setInvariant(loc, "gl_ViewportIndex"); + setInvariant(loc, "gl_FragDepth"); + setInvariant(loc, "gl_SampleMask"); + setInvariant(loc, "gl_ClipVertex"); + setInvariant(loc, "gl_FrontColor"); + setInvariant(loc, "gl_BackColor"); + setInvariant(loc, "gl_FrontSecondaryColor"); + setInvariant(loc, "gl_BackSecondaryColor"); + setInvariant(loc, "gl_TexCoord"); + setInvariant(loc, "gl_FogFragCoord"); + setInvariant(loc, "gl_FragColor"); + setInvariant(loc, "gl_FragData"); + } #endif } @@ -2409,6 +2444,14 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan arg0->getType().isFloatingDomain()) { requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float2, fnCandidate.getName().c_str()); } + + const TIntermTyped* base = TIntermediate::findLValueBase(arg0, true , true); + const TType* refType = (base->getType().isReference()) ? base->getType().getReferentType() : nullptr; + const TQualifier& qualifier = (refType != nullptr) ? refType->getQualifier() : base->getType().getQualifier(); + if (qualifier.storage != EvqShared && qualifier.storage != EvqBuffer) + error(loc,"Atomic memory function can only be used for shader storage block member or shared variable.", + fnCandidate.getName().c_str(), ""); + break; } @@ -3651,6 +3694,8 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q profileRequires(loc, ENoProfile, 130, nullptr, "out for stage outputs"); profileRequires(loc, EEsProfile, 300, nullptr, "out for stage outputs"); qualifier.storage = EvqVaryingOut; + if (intermediate.isInvariantAll()) + qualifier.invariant = true; break; case EvqInOut: qualifier.storage = EvqVaryingIn; @@ -3667,7 +3712,7 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q if (blockName == nullptr && qualifier.layoutPacking == ElpStd430) { - error(loc, "it is invalid to declare std430 qualifier on uniform", "", ""); + requireExtensions(loc, 1, &E_GL_EXT_scalar_block_layout, "default std430 layout for uniform"); } break; default: diff --git a/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.h b/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.h index c9e633420..de4488465 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.h +++ b/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.h @@ -241,6 +241,7 @@ protected: // override this to set the language-specific name virtual const char* getAtomicCounterBlockName() const { return ""; } virtual void setAtomicCounterBlockDefaults(TType&) const {} + virtual void setInvariant(const TSourceLoc& loc, const char* builtin) {} virtual void finalizeAtomicCounterBlockLayout(TVariable&) {} bool isAtomicCounterBlock(const TSymbol& symbol) { const TVariable* var = symbol.getAsVariable(); @@ -511,6 +512,7 @@ protected: virtual const char* getAtomicCounterBlockName() const override; virtual void finalizeAtomicCounterBlockLayout(TVariable&) override; virtual void setAtomicCounterBlockDefaults(TType& block) const override; + virtual void setInvariant(const TSourceLoc& loc, const char* builtin) override; public: // diff --git a/3rdparty/glslang/glslang/MachineIndependent/linkValidate.cpp b/3rdparty/glslang/glslang/MachineIndependent/linkValidate.cpp index 42b416dba..9656e2e7e 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/linkValidate.cpp +++ b/3rdparty/glslang/glslang/MachineIndependent/linkValidate.cpp @@ -316,6 +316,7 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit) MERGE_TRUE(useUnknownFormat); MERGE_TRUE(hlslOffsets); MERGE_TRUE(useStorageBuffer); + MERGE_TRUE(invariantAll); MERGE_TRUE(hlslIoMapping); // TODO: sourceFile diff --git a/3rdparty/glslang/glslang/MachineIndependent/localintermediate.h b/3rdparty/glslang/glslang/MachineIndependent/localintermediate.h index 5cc9930ac..6aa9399dc 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/localintermediate.h +++ b/3rdparty/glslang/glslang/MachineIndependent/localintermediate.h @@ -291,6 +291,7 @@ public: numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false), invertY(false), useStorageBuffer(false), + invariantAll(false), nanMinMaxClamp(false), depthReplacing(false), uniqueId(0), @@ -538,7 +539,7 @@ public: TIntermTyped* foldSwizzle(TIntermTyped* node, TSwizzleSelectors& fields, const TSourceLoc&); // Tree ops - static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay); + static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay , bool BufferReferenceOk = false); // Linkage related void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&); @@ -560,6 +561,8 @@ public: void setUseStorageBuffer() { useStorageBuffer = true; } bool usingStorageBuffer() const { return useStorageBuffer; } + void setInvariantAll() { invariantAll = true; } + bool isInvariantAll() const { return invariantAll; } void setDepthReplacing() { depthReplacing = true; } bool isDepthReplacing() const { return depthReplacing; } bool setLocalSize(int dim, int size) @@ -926,6 +929,11 @@ public: return false; } + bool IsRequestedExtension(const char* extension) const + { + return (requestedExtensions.find(extension) != requestedExtensions.end()); + } + void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee); void merge(TInfoSink&, TIntermediate&); void finalCheck(TInfoSink&, bool keepUncalled); @@ -1063,6 +1071,7 @@ protected: bool recursive; bool invertY; bool useStorageBuffer; + bool invariantAll; bool nanMinMaxClamp; // true if desiring min/max/clamp to favor non-NaN over NaN bool depthReplacing; int localSize[3];