From e9bdf630f7da1816cb732f7dcf16911015a5cd4e 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: Tue, 21 Oct 2025 19:22:15 -0700 Subject: [PATCH] Updated glslang. --- 3rdparty/glslang/LICENSE.txt | 3 - 3rdparty/glslang/SPIRV/GlslangToSpv.cpp | 35 +- 3rdparty/glslang/SPIRV/SPVRemapper.cpp | 1563 ----------------- 3rdparty/glslang/SPIRV/SPVRemapper.h | 300 ---- 3rdparty/glslang/SPIRV/SpvBuilder.cpp | 100 +- 3rdparty/glslang/SPIRV/SpvBuilder.h | 32 +- 3rdparty/glslang/StandAlone/StandAlone.cpp | 254 +-- 3rdparty/glslang/StandAlone/spirv-remap.cpp | 402 ----- 3rdparty/glslang/build_info.h | 4 +- .../CInterface/glslang_c_interface.cpp | 8 + 3rdparty/glslang/glslang/Include/PoolAlloc.h | 3 +- .../glslang/Include/glslang_c_interface.h | 2 + .../glslang/Include/glslang_c_shader_types.h | 3 + 3rdparty/glslang/glslang/Include/visibility.h | 6 +- .../MachineIndependent/Intermediate.cpp | 15 +- .../MachineIndependent/ParseHelper.cpp | 10 +- .../glslang/MachineIndependent/iomapper.cpp | 25 + .../glslang/MachineIndependent/iomapper.h | 22 +- 3rdparty/glslang/glslang/Public/ShaderLang.h | 170 +- .../glslang/Public/resource_limits_c.h | 2 +- .../ResourceLimits/resource_limits_c.cpp | 2 +- 21 files changed, 420 insertions(+), 2541 deletions(-) delete mode 100644 3rdparty/glslang/SPIRV/SPVRemapper.cpp delete mode 100644 3rdparty/glslang/SPIRV/SPVRemapper.h delete mode 100644 3rdparty/glslang/StandAlone/spirv-remap.cpp diff --git a/3rdparty/glslang/LICENSE.txt b/3rdparty/glslang/LICENSE.txt index 054e68a46..1ea89c03d 100644 --- a/3rdparty/glslang/LICENSE.txt +++ b/3rdparty/glslang/LICENSE.txt @@ -13,9 +13,6 @@ Other parts, outside of glslang proper, include: - update_glslang_sources.py, which is not part of the project proper and does not need to be used. -- the SPIR-V "remapper", which is optional, but has the same license as - glslang proper - - Google tests and SPIR-V tools, and anything in the external subdirectory are external and optional; see them for their respective licenses. diff --git a/3rdparty/glslang/SPIRV/GlslangToSpv.cpp b/3rdparty/glslang/SPIRV/GlslangToSpv.cpp index b409ba3fb..eec68596b 100644 --- a/3rdparty/glslang/SPIRV/GlslangToSpv.cpp +++ b/3rdparty/glslang/SPIRV/GlslangToSpv.cpp @@ -5596,6 +5596,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0, // except sometimes for blocks std::vector > deferredForwardPointers; + std::vector memberDebugInfo; for (int i = 0; i < (int)glslangMembers->size(); i++) { auto& glslangMember = (*glslangMembers)[i]; if (glslangMember.type->hiddenMember()) { @@ -5646,15 +5647,39 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy // + Not as clean as desired. Traverser queries/sets persistent state. This is fragile. // + Table lookup during creation of composite debug types. This really shouldn't be necessary. if(options.emitNonSemanticShaderDebugInfo) { - builder.debugTypeLocs[spvMember].name = glslangMember.type->getFieldName().c_str(); - builder.debugTypeLocs[spvMember].line = glslangMember.loc.line; - builder.debugTypeLocs[spvMember].column = glslangMember.loc.column; + spv::StructMemberDebugInfo debugInfo{}; + debugInfo.name = glslangMember.type->getFieldName(); + debugInfo.line = glslangMember.loc.line; + debugInfo.column = glslangMember.loc.column; + + // Per the GLSL spec, bool variables inside of a uniform or buffer block are generated as uint. + // But for debug info, we want to represent them as bool because that is the original type in + // the source code. The bool type can be nested within a vector or a multidimensional array, + // so we must construct the chain of types up from the scalar bool. + if (glslangIntermediate->getSource() == glslang::EShSourceGlsl && explicitLayout != glslang::ElpNone && + glslangMember.type->getBasicType() == glslang::EbtBool) { + auto typeId = builder.makeBoolType(); + if (glslangMember.type->isVector()) { + typeId = builder.makeVectorType(typeId, glslangMember.type->getVectorSize()); + } + if (glslangMember.type->isArray()) { + const auto* arraySizes = glslangMember.type->getArraySizes(); + int dims = arraySizes->getNumDims(); + for (int i = dims - 1; i >= 0; --i) { + spv::Id size = builder.makeIntConstant(arraySizes->getDimSize(i)); + typeId = builder.makeArrayType(typeId, size, 0); + } + } + debugInfo.debugTypeOverride = builder.getDebugType(typeId); + } + + memberDebugInfo.push_back(debugInfo); } } } // Make the SPIR-V type - spv::Id spvType = builder.makeStructType(spvMembers, type.getTypeName().c_str(), false); + spv::Id spvType = builder.makeStructType(spvMembers, memberDebugInfo, type.getTypeName().c_str(), false); if (! HasNonLayoutQualifiers(type, qualifier)) structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers] = spvType; @@ -7073,7 +7098,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO for (int i = 0; i < 5; i++) { members.push_back(builder.getContainedTypeId(resultStructType, i)); } - spv::Id resType = builder.makeStructType(members, "ResType"); + spv::Id resType = builder.makeStructType(members, {}, "ResType"); //call ImageFootprintNV spv::Id res = builder.createTextureCall(precision, resType, sparse, cracked.fetch, cracked.proj, diff --git a/3rdparty/glslang/SPIRV/SPVRemapper.cpp b/3rdparty/glslang/SPIRV/SPVRemapper.cpp deleted file mode 100644 index 02ecb3c53..000000000 --- a/3rdparty/glslang/SPIRV/SPVRemapper.cpp +++ /dev/null @@ -1,1563 +0,0 @@ -// -// Copyright (C) 2015 LunarG, Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// -// Neither the name of 3Dlabs Inc. Ltd. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// - -#include "SPVRemapper.h" -#include "doc.h" -#include "spvUtil.h" - -#include -#include - -namespace spv { - - // By default, just abort on error. Can be overridden via RegisterErrorHandler - spirvbin_t::errorfn_t spirvbin_t::errorHandler = [](const std::string&) { exit(5); }; - // By default, eat log messages. Can be overridden via RegisterLogHandler - spirvbin_t::logfn_t spirvbin_t::logHandler = [](const std::string&) { }; - - // This can be overridden to provide other message behavior if needed - void spirvbin_t::msg(int minVerbosity, int indent, const std::string& txt) const - { - if (verbose >= minVerbosity) - logHandler(std::string(indent, ' ') + txt); - } - - // hash opcode, with special handling for OpExtInst - std::uint32_t spirvbin_t::asOpCodeHash(unsigned word) - { - const spv::Op opCode = asOpCode(word); - - std::uint32_t offset = 0; - - switch (opCode) { - case spv::Op::OpExtInst: - offset += asId(word + 4); break; - default: - break; - } - - return ((unsigned)opCode) * 19 + offset; // 19 = small prime - } - - spirvbin_t::range_t spirvbin_t::literalRange(spv::Op opCode) const - { - static const int maxCount = 1<<30; - - switch (opCode) { - case spv::Op::OpTypeFloat: // fall through... - case spv::Op::OpTypePointer: return range_t(2, 3); - case spv::Op::OpTypeInt: return range_t(2, 4); - // TODO: case spv::OpTypeImage: - // TODO: case spv::OpTypeSampledImage: - case spv::Op::OpTypeSampler: return range_t(3, 8); - case spv::Op::OpTypeVector: // fall through - case spv::Op::OpTypeMatrix: // ... - case spv::Op::OpTypePipe: return range_t(3, 4); - case spv::Op::OpConstant: return range_t(3, maxCount); - default: return range_t(0, 0); - } - } - - spirvbin_t::range_t spirvbin_t::typeRange(spv::Op opCode) const - { - static const int maxCount = 1<<30; - - if (isConstOp(opCode)) - return range_t(1, 2); - - switch (opCode) { - case spv::Op::OpTypeVector: // fall through - case spv::Op::OpTypeMatrix: // ... - case spv::Op::OpTypeSampler: // ... - case spv::Op::OpTypeArray: // ... - case spv::Op::OpTypeRuntimeArray: // ... - case spv::Op::OpTypePipe: return range_t(2, 3); - case spv::Op::OpTypeStruct: // fall through - case spv::Op::OpTypeFunction: return range_t(2, maxCount); - case spv::Op::OpTypePointer: return range_t(3, 4); - default: return range_t(0, 0); - } - } - - spirvbin_t::range_t spirvbin_t::constRange(spv::Op opCode) const - { - static const int maxCount = 1<<30; - - switch (opCode) { - case spv::Op::OpTypeArray: // fall through... - case spv::Op::OpTypeRuntimeArray: return range_t(3, 4); - case spv::Op::OpConstantComposite: return range_t(3, maxCount); - default: return range_t(0, 0); - } - } - - // Return the size of a type in 32-bit words. This currently only - // handles ints and floats, and is only invoked by queries which must be - // integer types. If ever needed, it can be generalized. - unsigned spirvbin_t::typeSizeInWords(spv::Id id) const - { - const unsigned typeStart = idPos(id); - const spv::Op opCode = asOpCode(typeStart); - - if (errorLatch) - return 0; - - switch (opCode) { - case spv::Op::OpTypeInt: // fall through... - case spv::Op::OpTypeFloat: return (spv[typeStart + 2] + 31) / 32; - default: - return 0; - } - } - - // Looks up the type of a given const or variable ID, and - // returns its size in 32-bit words. - unsigned spirvbin_t::idTypeSizeInWords(spv::Id id) const - { - const auto tid_it = idTypeSizeMap.find(id); - if (tid_it == idTypeSizeMap.end()) { - error("type size for ID not found"); - return 0; - } - - return tid_it->second; - } - - // Is this an opcode we should remove when using --strip? - bool spirvbin_t::isStripOp(spv::Op opCode, unsigned start) const - { - switch (opCode) { - case spv::Op::OpSource: - case spv::Op::OpSourceExtension: - case spv::Op::OpName: - case spv::Op::OpMemberName: - case spv::Op::OpLine: - { - const std::string name = literalString(start + 2); - - std::vector::const_iterator it; - for (it = stripWhiteList.begin(); it < stripWhiteList.end(); it++) - { - if (name.find(*it) != std::string::npos) { - return false; - } - } - - return true; - } - default : - return false; - } - } - - // Return true if this opcode is flow control - bool spirvbin_t::isFlowCtrl(spv::Op opCode) const - { - switch (opCode) { - case spv::Op::OpBranchConditional: - case spv::Op::OpBranch: - case spv::Op::OpSwitch: - case spv::Op::OpLoopMerge: - case spv::Op::OpSelectionMerge: - case spv::Op::OpLabel: - case spv::Op::OpFunction: - case spv::Op::OpFunctionEnd: return true; - default: return false; - } - } - - // Return true if this opcode defines a type - bool spirvbin_t::isTypeOp(spv::Op opCode) const - { - switch (opCode) { - case spv::Op::OpTypeVoid: - case spv::Op::OpTypeBool: - case spv::Op::OpTypeInt: - case spv::Op::OpTypeFloat: - case spv::Op::OpTypeVector: - case spv::Op::OpTypeMatrix: - case spv::Op::OpTypeImage: - case spv::Op::OpTypeSampler: - case spv::Op::OpTypeArray: - case spv::Op::OpTypeRuntimeArray: - case spv::Op::OpTypeStruct: - case spv::Op::OpTypeOpaque: - case spv::Op::OpTypePointer: - case spv::Op::OpTypeFunction: - case spv::Op::OpTypeEvent: - case spv::Op::OpTypeDeviceEvent: - case spv::Op::OpTypeReserveId: - case spv::Op::OpTypeQueue: - case spv::Op::OpTypeSampledImage: - case spv::Op::OpTypePipe: return true; - default: return false; - } - } - - // Return true if this opcode defines a constant - bool spirvbin_t::isConstOp(spv::Op opCode) const - { - switch (opCode) { - case spv::Op::OpConstantSampler: - error("unimplemented constant type"); - return true; - - case spv::Op::OpConstantNull: - case spv::Op::OpConstantTrue: - case spv::Op::OpConstantFalse: - case spv::Op::OpConstantComposite: - case spv::Op::OpConstant: - return true; - - default: - return false; - } - } - - const auto inst_fn_nop = [](spv::Op, unsigned) { return false; }; - const auto op_fn_nop = [](spv::Id&) { }; - - // g++ doesn't like these defined in the class proper in an anonymous namespace. - // Dunno why. Also MSVC doesn't like the constexpr keyword. Also dunno why. - // Defining them externally seems to please both compilers, so, here they are. - const spv::Id spirvbin_t::unmapped = spv::Id(-10000); - const spv::Id spirvbin_t::unused = spv::Id(-10001); - const int spirvbin_t::header_size = 5; - - spv::Id spirvbin_t::nextUnusedId(spv::Id id) - { - while (isNewIdMapped(id)) // search for an unused ID - ++id; - - return id; - } - - spv::Id spirvbin_t::localId(spv::Id id, spv::Id newId) - { - //assert(id != spv::NoResult && newId != spv::NoResult); - - if (id > bound()) { - error(std::string("ID out of range: ") + std::to_string(id)); - return spirvbin_t::unused; - } - - if (id >= idMapL.size()) - idMapL.resize(id+1, unused); - - if (newId != unmapped && newId != unused) { - if (isOldIdUnused(id)) { - error(std::string("ID unused in module: ") + std::to_string(id)); - return spirvbin_t::unused; - } - - if (!isOldIdUnmapped(id)) { - error(std::string("ID already mapped: ") + std::to_string(id) + " -> " - + std::to_string(localId(id))); - - return spirvbin_t::unused; - } - - if (isNewIdMapped(newId)) { - error(std::string("ID already used in module: ") + std::to_string(newId)); - return spirvbin_t::unused; - } - - msg(4, 4, std::string("map: ") + std::to_string(id) + " -> " + std::to_string(newId)); - setMapped(newId); - largestNewId = std::max(largestNewId, newId); - } - - return idMapL[id] = newId; - } - - // Parse a literal string from the SPIR binary and return it as an std::string - // Due to C++11 RValue references, this doesn't copy the result string. - std::string spirvbin_t::literalString(unsigned word) const - { - std::string literal; - const spirword_t * pos = spv.data() + word; - - literal.reserve(16); - - do { - spirword_t word = *pos; - for (int i = 0; i < 4; i++) { - char c = word & 0xff; - if (c == '\0') - return literal; - literal += c; - word >>= 8; - } - pos++; - } while (true); - } - - void spirvbin_t::applyMap() - { - msg(3, 2, std::string("Applying map: ")); - - // Map local IDs through the ID map - process(inst_fn_nop, // ignore instructions - [this](spv::Id& id) { - id = localId(id); - - if (errorLatch) - return; - - assert(id != unused && id != unmapped); - } - ); - } - - // Find free IDs for anything we haven't mapped - void spirvbin_t::mapRemainder() - { - msg(3, 2, std::string("Remapping remainder: ")); - - spv::Id unusedId = 1; // can't use 0: that's NoResult - spirword_t maxBound = 0; - - for (spv::Id id = 0; id < idMapL.size(); ++id) { - if (isOldIdUnused(id)) - continue; - - // Find a new mapping for any used but unmapped IDs - if (isOldIdUnmapped(id)) { - localId(id, unusedId = nextUnusedId(unusedId)); - if (errorLatch) - return; - } - - if (isOldIdUnmapped(id)) { - error(std::string("old ID not mapped: ") + std::to_string(id)); - return; - } - - // Track max bound - maxBound = std::max(maxBound, localId(id) + 1); - - if (errorLatch) - return; - } - - bound(maxBound); // reset header ID bound to as big as it now needs to be - } - - // Mark debug instructions for stripping - void spirvbin_t::stripDebug() - { - // Strip instructions in the stripOp set: debug info. - process( - [&](spv::Op opCode, unsigned start) { - // remember opcodes we want to strip later - if (isStripOp(opCode, start)) - stripInst(start); - return true; - }, - op_fn_nop); - } - - // Mark instructions that refer to now-removed IDs for stripping - void spirvbin_t::stripDeadRefs() - { - process( - [&](spv::Op opCode, unsigned start) { - // strip opcodes pointing to removed data - switch (opCode) { - case spv::Op::OpName: - case spv::Op::OpMemberName: - case spv::Op::OpDecorate: - case spv::Op::OpMemberDecorate: - if (idPosR.find(asId(start+1)) == idPosR.end()) - stripInst(start); - break; - default: - break; // leave it alone - } - - return true; - }, - op_fn_nop); - - strip(); - } - - // Update local maps of ID, type, etc positions - void spirvbin_t::buildLocalMaps() - { - msg(2, 2, std::string("build local maps: ")); - - mapped.clear(); - idMapL.clear(); -// preserve nameMap, so we don't clear that. - fnPos.clear(); - fnCalls.clear(); - typeConstPos.clear(); - idPosR.clear(); - entryPoint = spv::NoResult; - largestNewId = 0; - - idMapL.resize(bound(), unused); - - int fnStart = 0; - spv::Id fnRes = spv::NoResult; - - // build local Id and name maps - process( - [&](spv::Op opCode, unsigned start) { - unsigned word = start+1; - spv::Id typeId = spv::NoResult; - - if (spv::InstructionDesc[enumCast(opCode)].hasType()) - typeId = asId(word++); - - // If there's a result ID, remember the size of its type - if (spv::InstructionDesc[enumCast(opCode)].hasResult()) { - const spv::Id resultId = asId(word++); - idPosR[resultId] = start; - - if (typeId != spv::NoResult) { - const unsigned idTypeSize = typeSizeInWords(typeId); - - if (errorLatch) - return false; - - if (idTypeSize != 0) - idTypeSizeMap[resultId] = idTypeSize; - } - } - - if (opCode == spv::Op::OpName) { - const spv::Id target = asId(start+1); - const std::string name = literalString(start+2); - nameMap[name] = target; - - } else if (opCode == spv::Op::OpFunctionCall) { - ++fnCalls[asId(start + 3)]; - } else if (opCode == spv::Op::OpEntryPoint) { - entryPoint = asId(start + 2); - } else if (opCode == spv::Op::OpFunction) { - if (fnStart != 0) { - error("nested function found"); - return false; - } - - fnStart = start; - fnRes = asId(start + 2); - } else if (opCode == spv::Op::OpFunctionEnd) { - assert(fnRes != spv::NoResult); - if (fnStart == 0) { - error("function end without function start"); - return false; - } - - fnPos[fnRes] = range_t(fnStart, start + asWordCount(start)); - fnStart = 0; - } else if (isConstOp(opCode)) { - if (errorLatch) - return false; - - assert(asId(start + 2) != spv::NoResult); - typeConstPos.insert(start); - } else if (isTypeOp(opCode)) { - assert(asId(start + 1) != spv::NoResult); - typeConstPos.insert(start); - } - - return false; - }, - - [this](spv::Id& id) { localId(id, unmapped); } - ); - } - - // Validate the SPIR header - void spirvbin_t::validate() const - { - msg(2, 2, std::string("validating: ")); - - if (spv.size() < header_size) { - error("file too short: "); - return; - } - - if (magic() != spv::MagicNumber) { - error("bad magic number"); - return; - } - - // field 1 = version - // field 2 = generator magic - // field 3 = result bound - - if (schemaNum() != 0) { - error("bad schema, must be 0"); - return; - } - } - - int spirvbin_t::processInstruction(unsigned word, instfn_t instFn, idfn_t idFn) - { - const auto instructionStart = word; - const unsigned wordCount = asWordCount(instructionStart); - const int nextInst = word++ + wordCount; - spv::Op opCode = asOpCode(instructionStart); - - if (nextInst > int(spv.size())) { - error("spir instruction terminated too early"); - return -1; - } - - // Base for computing number of operands; will be updated as more is learned - unsigned numOperands = wordCount - 1; - - if (instFn(opCode, instructionStart)) - return nextInst; - - // Read type and result ID from instruction desc table - if (spv::InstructionDesc[enumCast(opCode)].hasType()) { - idFn(asId(word++)); - --numOperands; - } - - if (spv::InstructionDesc[enumCast(opCode)].hasResult()) { - idFn(asId(word++)); - --numOperands; - } - - // Extended instructions: currently, assume everything is an ID. - // TODO: add whatever data we need for exceptions to that - if (opCode == spv::Op::OpExtInst) { - - idFn(asId(word)); // Instruction set is an ID that also needs to be mapped - - word += 2; // instruction set, and instruction from set - numOperands -= 2; - - for (unsigned op=0; op < numOperands; ++op) - idFn(asId(word++)); // ID - - return nextInst; - } - - // Circular buffer so we can look back at previous unmapped values during the mapping pass. - static const unsigned idBufferSize = 4; - spv::Id idBuffer[idBufferSize]; - unsigned idBufferPos = 0; - - // Store IDs from instruction in our map - for (int op = 0; numOperands > 0; ++op, --numOperands) { - // SpecConstantOp is special: it includes the operands of another opcode which is - // given as a literal in the 3rd word. We will switch over to pretending that the - // opcode being processed is the literal opcode value of the SpecConstantOp. See the - // SPIRV spec for details. This way we will handle IDs and literals as appropriate for - // the embedded op. - if (opCode == spv::Op::OpSpecConstantOp) { - if (op == 0) { - opCode = asOpCode(word++); // this is the opcode embedded in the SpecConstantOp. - --numOperands; - } - } - - switch (spv::InstructionDesc[enumCast(opCode)].operands.getClass(op)) { - case spv::OperandId: - case spv::OperandScope: - case spv::OperandMemorySemantics: - idBuffer[idBufferPos] = asId(word); - idBufferPos = (idBufferPos + 1) % idBufferSize; - idFn(asId(word++)); - break; - - case spv::OperandVariableIds: - for (unsigned i = 0; i < numOperands; ++i) - idFn(asId(word++)); - return nextInst; - - case spv::OperandVariableLiterals: - // for clarity - // if (opCode == spv::OpDecorate && asDecoration(word - 1) == spv::DecorationBuiltIn) { - // ++word; - // --numOperands; - // } - // word += numOperands; - return nextInst; - - case spv::OperandVariableLiteralId: { - if (opCode == Op::OpSwitch) { - // word-2 is the position of the selector ID. OpSwitch Literals match its type. - // In case the IDs are currently being remapped, we get the word[-2] ID from - // the circular idBuffer. - const unsigned literalSizePos = (idBufferPos+idBufferSize-2) % idBufferSize; - const unsigned literalSize = idTypeSizeInWords(idBuffer[literalSizePos]); - const unsigned numLiteralIdPairs = (nextInst-word) / (1+literalSize); - - if (errorLatch) - return -1; - - for (unsigned arg=0; arg instPos; - instPos.reserve(unsigned(spv.size()) / 16); // initial estimate; can grow if needed. - - // Build local table of instruction start positions - process( - [&](spv::Op, unsigned start) { instPos.push_back(start); return true; }, - op_fn_nop); - - if (errorLatch) - return; - - // Window size for context-sensitive canonicalization values - // Empirical best size from a single data set. TODO: Would be a good tunable. - // We essentially perform a little convolution around each instruction, - // to capture the flavor of nearby code, to hopefully match to similar - // code in other modules. - static const unsigned windowSize = 2; - - for (unsigned entry = 0; entry < unsigned(instPos.size()); ++entry) { - const unsigned start = instPos[entry]; - const spv::Op opCode = asOpCode(start); - - if (opCode == spv::Op::OpFunction) - fnId = asId(start + 2); - - if (opCode == spv::Op::OpFunctionEnd) - fnId = spv::NoResult; - - if (fnId != spv::NoResult) { // if inside a function - if (spv::InstructionDesc[enumCast(opCode)].hasResult()) { - const unsigned word = start + (spv::InstructionDesc[enumCast(opCode)].hasType() ? 2 : 1); - const spv::Id resId = asId(word); - std::uint32_t hashval = fnId * 17; // small prime - - for (unsigned i = entry-1; i >= entry-windowSize; --i) { - if (asOpCode(instPos[i]) == spv::Op::OpFunction) - break; - hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime - } - - for (unsigned i = entry; i <= entry + windowSize; ++i) { - if (asOpCode(instPos[i]) == spv::Op::OpFunctionEnd) - break; - hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime - } - - if (isOldIdUnmapped(resId)) { - localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID)); - if (errorLatch) - return; - } - - } - } - } - - spv::Op thisOpCode(spv::Op::OpNop); - std::unordered_map opCounter; - int idCounter(0); - fnId = spv::NoResult; - - process( - [&](spv::Op opCode, unsigned start) { - switch (opCode) { - case spv::Op::OpFunction: - // Reset counters at each function - idCounter = 0; - opCounter.clear(); - fnId = asId(start + 2); - break; - - case spv::Op::OpImageSampleImplicitLod: - case spv::Op::OpImageSampleExplicitLod: - case spv::Op::OpImageSampleDrefImplicitLod: - case spv::Op::OpImageSampleDrefExplicitLod: - case spv::Op::OpImageSampleProjImplicitLod: - case spv::Op::OpImageSampleProjExplicitLod: - case spv::Op::OpImageSampleProjDrefImplicitLod: - case spv::Op::OpImageSampleProjDrefExplicitLod: - case spv::Op::OpDot: - case spv::Op::OpCompositeExtract: - case spv::Op::OpCompositeInsert: - case spv::Op::OpVectorShuffle: - case spv::Op::OpLabel: - case spv::Op::OpVariable: - - case spv::Op::OpAccessChain: - case spv::Op::OpLoad: - case spv::Op::OpStore: - case spv::Op::OpCompositeConstruct: - case spv::Op::OpFunctionCall: - ++opCounter[enumCast(opCode)]; - idCounter = 0; - thisOpCode = opCode; - break; - default: - thisOpCode = spv::Op::OpNop; - } - - return false; - }, - - [&](spv::Id& id) { - if (thisOpCode != spv::Op::OpNop) { - ++idCounter; - const std::uint32_t hashval = - // Explicitly cast operands to unsigned int to avoid integer - // promotion to signed int followed by integer overflow, - // which would result in undefined behavior. - static_cast(opCounter[enumCast(thisOpCode)]) - * enumCast(thisOpCode) - * 50047 - + idCounter - + static_cast(fnId) * 117; - - if (isOldIdUnmapped(id)) - localId(id, nextUnusedId(hashval % softTypeIdLimit + firstMappedID)); - } - }); - } - - // EXPERIMENTAL: forward IO and uniform load/stores into operands - // This produces invalid Schema-0 SPIRV - void spirvbin_t::forwardLoadStores() - { - idset_t fnLocalVars; // set of function local vars - idmap_t idMap; // Map of load result IDs to what they load - - // EXPERIMENTAL: Forward input and access chain loads into consumptions - process( - [&](spv::Op opCode, unsigned start) { - // Add inputs and uniforms to the map - if ((opCode == spv::Op::OpVariable && asWordCount(start) == 4) && - (spv[start+3] == (unsigned)spv::StorageClass::Uniform || - spv[start+3] == (unsigned)spv::StorageClass::UniformConstant || - spv[start+3] == (unsigned)spv::StorageClass::Input)) - fnLocalVars.insert(asId(start+2)); - - if (opCode == spv::Op::OpAccessChain && fnLocalVars.count(asId(start+3)) > 0) - fnLocalVars.insert(asId(start+2)); - - if (opCode == spv::Op::OpLoad && fnLocalVars.count(asId(start+3)) > 0) { - idMap[asId(start+2)] = asId(start+3); - stripInst(start); - } - - return false; - }, - - [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; } - ); - - if (errorLatch) - return; - - // EXPERIMENTAL: Implicit output stores - fnLocalVars.clear(); - idMap.clear(); - - process( - [&](spv::Op opCode, unsigned start) { - // Add inputs and uniforms to the map - if ((opCode == spv::Op::OpVariable && asWordCount(start) == 4) && - (spv[start+3] == (int)spv::StorageClass::Output)) - fnLocalVars.insert(asId(start+2)); - - if (opCode == spv::Op::OpStore && fnLocalVars.count(asId(start+1)) > 0) { - idMap[asId(start+2)] = asId(start+1); - stripInst(start); - } - - return false; - }, - op_fn_nop); - - if (errorLatch) - return; - - process( - inst_fn_nop, - [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; } - ); - - if (errorLatch) - return; - - strip(); // strip out data we decided to eliminate - } - - // optimize loads and stores - void spirvbin_t::optLoadStore() - { - idset_t fnLocalVars; // candidates for removal (only locals) - idmap_t idMap; // Map of load result IDs to what they load - blockmap_t blockMap; // Map of IDs to blocks they first appear in - int blockNum = 0; // block count, to avoid crossing flow control - - // Find all the function local pointers stored at most once, and not via access chains - process( - [&](spv::Op opCode, unsigned start) { - const int wordCount = asWordCount(start); - - // Count blocks, so we can avoid crossing flow control - if (isFlowCtrl(opCode)) - ++blockNum; - - // Add local variables to the map - if ((opCode == spv::Op::OpVariable && spv[start+3] == (unsigned)spv::StorageClass::Function && asWordCount(start) == 4)) { - fnLocalVars.insert(asId(start+2)); - return true; - } - - // Ignore process vars referenced via access chain - if ((opCode == spv::Op::OpAccessChain || opCode == spv::Op::OpInBoundsAccessChain) && fnLocalVars.count(asId(start+3)) > 0) { - fnLocalVars.erase(asId(start+3)); - idMap.erase(asId(start+3)); - return true; - } - - if (opCode == spv::Op::OpLoad && fnLocalVars.count(asId(start + 3)) > 0) { - const spv::Id varId = asId(start+3); - - // Avoid loads before stores - if (idMap.find(varId) == idMap.end()) { - fnLocalVars.erase(varId); - idMap.erase(varId); - } - - // don't do for volatile references - if (wordCount > 4 && (spv[start+4] & spv::MemoryAccessMask::Volatile)) { - fnLocalVars.erase(varId); - idMap.erase(varId); - } - - // Handle flow control - if (blockMap.find(varId) == blockMap.end()) { - blockMap[varId] = blockNum; // track block we found it in. - } else if (blockMap[varId] != blockNum) { - fnLocalVars.erase(varId); // Ignore if crosses flow control - idMap.erase(varId); - } - - return true; - } - - if (opCode == spv::Op::OpStore && fnLocalVars.count(asId(start+1)) > 0) { - const spv::Id varId = asId(start+1); - - if (idMap.find(varId) == idMap.end()) { - idMap[varId] = asId(start+2); - } else { - // Remove if it has more than one store to the same pointer - fnLocalVars.erase(varId); - idMap.erase(varId); - } - - // don't do for volatile references - if (wordCount > 3 && (spv[start+3] & spv::MemoryAccessMask::Volatile)) { - fnLocalVars.erase(asId(start+3)); - idMap.erase(asId(start+3)); - } - - // Handle flow control - if (blockMap.find(varId) == blockMap.end()) { - blockMap[varId] = blockNum; // track block we found it in. - } else if (blockMap[varId] != blockNum) { - fnLocalVars.erase(varId); // Ignore if crosses flow control - idMap.erase(varId); - } - - return true; - } - - return false; - }, - - // If local var id used anywhere else, don't eliminate - [&](spv::Id& id) { - if (fnLocalVars.count(id) > 0) { - fnLocalVars.erase(id); - idMap.erase(id); - } - } - ); - - if (errorLatch) - return; - - process( - [&](spv::Op opCode, unsigned start) { - if (opCode == spv::Op::OpLoad && fnLocalVars.count(asId(start+3)) > 0) - idMap[asId(start+2)] = idMap[asId(start+3)]; - return false; - }, - op_fn_nop); - - if (errorLatch) - return; - - // Chase replacements to their origins, in case there is a chain such as: - // 2 = store 1 - // 3 = load 2 - // 4 = store 3 - // 5 = load 4 - // We want to replace uses of 5 with 1. - for (const auto& idPair : idMap) { - spv::Id id = idPair.first; - while (idMap.find(id) != idMap.end()) // Chase to end of chain - id = idMap[id]; - - idMap[idPair.first] = id; // replace with final result - } - - // Remove the load/store/variables for the ones we've discovered - process( - [&](spv::Op opCode, unsigned start) { - if ((opCode == spv::Op::OpLoad && fnLocalVars.count(asId(start+3)) > 0) || - (opCode == spv::Op::OpStore && fnLocalVars.count(asId(start+1)) > 0) || - (opCode == spv::Op::OpVariable && fnLocalVars.count(asId(start+2)) > 0)) { - - stripInst(start); - return true; - } - - return false; - }, - - [&](spv::Id& id) { - if (idMap.find(id) != idMap.end()) id = idMap[id]; - } - ); - - if (errorLatch) - return; - - strip(); // strip out data we decided to eliminate - } - - // remove bodies of uncalled functions - void spirvbin_t::dceFuncs() - { - msg(3, 2, std::string("Removing Dead Functions: ")); - - // TODO: There are more efficient ways to do this. - bool changed = true; - - while (changed) { - changed = false; - - for (auto fn = fnPos.begin(); fn != fnPos.end(); ) { - if (fn->first == entryPoint) { // don't DCE away the entry point! - ++fn; - continue; - } - - const auto call_it = fnCalls.find(fn->first); - - if (call_it == fnCalls.end() || call_it->second == 0) { - changed = true; - stripRange.push_back(fn->second); - - // decrease counts of called functions - process( - [&](spv::Op opCode, unsigned start) { - if (opCode == spv::Op::OpFunctionCall) { - const auto call_it = fnCalls.find(asId(start + 3)); - if (call_it != fnCalls.end()) { - if (--call_it->second <= 0) - fnCalls.erase(call_it); - } - } - - return true; - }, - op_fn_nop, - fn->second.first, - fn->second.second); - - if (errorLatch) - return; - - fn = fnPos.erase(fn); - } else ++fn; - } - } - } - - // remove unused function variables + decorations - void spirvbin_t::dceVars() - { - msg(3, 2, std::string("DCE Vars: ")); - - std::unordered_map varUseCount; - - // Count function variable use - process( - [&](spv::Op opCode, unsigned start) { - if (opCode == spv::Op::OpVariable) { - ++varUseCount[asId(start+2)]; - return true; - } else if (opCode == spv::Op::OpEntryPoint) { - const int wordCount = asWordCount(start); - for (int i = 4; i < wordCount; i++) { - ++varUseCount[asId(start+i)]; - } - return true; - } else - return false; - }, - - [&](spv::Id& id) { if (varUseCount[id]) ++varUseCount[id]; } - ); - - if (errorLatch) - return; - - // Remove single-use function variables + associated decorations and names - process( - [&](spv::Op opCode, unsigned start) { - spv::Id id = spv::NoResult; - if (opCode == spv::Op::OpVariable) - id = asId(start+2); - if (opCode == spv::Op::OpDecorate || opCode == spv::Op::OpName) - id = asId(start+1); - - if (id != spv::NoResult && varUseCount[id] == 1) - stripInst(start); - - return true; - }, - op_fn_nop); - } - - // remove unused types - void spirvbin_t::dceTypes() - { - std::vector isType(bound(), false); - - // for speed, make O(1) way to get to type query (map is log(n)) - for (const auto typeStart : typeConstPos) - isType[asTypeConstId(typeStart)] = true; - - std::unordered_map typeUseCount; - - // This is not the most efficient algorithm, but this is an offline tool, and - // it's easy to write this way. Can be improved opportunistically if needed. - bool changed = true; - while (changed) { - changed = false; - strip(); - typeUseCount.clear(); - - // Count total type usage - process(inst_fn_nop, - [&](spv::Id& id) { if (isType[id]) ++typeUseCount[id]; } - ); - - if (errorLatch) - return; - - // Remove single reference types - for (const auto typeStart : typeConstPos) { - const spv::Id typeId = asTypeConstId(typeStart); - if (typeUseCount[typeId] == 1) { - changed = true; - --typeUseCount[typeId]; - stripInst(typeStart); - } - } - - if (errorLatch) - return; - } - } - -#ifdef NOTDEF - bool spirvbin_t::matchType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const - { - // Find the local type id "lt" and global type id "gt" - const auto lt_it = typeConstPosR.find(lt); - if (lt_it == typeConstPosR.end()) - return false; - - const auto typeStart = lt_it->second; - - // Search for entry in global table - const auto gtype = globalTypes.find(gt); - if (gtype == globalTypes.end()) - return false; - - const auto& gdata = gtype->second; - - // local wordcount and opcode - const int wordCount = asWordCount(typeStart); - const spv::Op opCode = asOpCode(typeStart); - - // no type match if opcodes don't match, or operand count doesn't match - if (opCode != opOpCode(gdata[0]) || wordCount != opWordCount(gdata[0])) - return false; - - const unsigned numOperands = wordCount - 2; // all types have a result - - const auto cmpIdRange = [&](range_t range) { - for (int x=range.first; xsecond; - } - - // Hash types to canonical values. This can return ID collisions (it's a bit - // inevitable): it's up to the caller to handle that gracefully. - std::uint32_t spirvbin_t::hashType(unsigned typeStart) const - { - const unsigned wordCount = asWordCount(typeStart); - const spv::Op opCode = asOpCode(typeStart); - - switch (opCode) { - case spv::Op::OpTypeVoid: return 0; - case spv::Op::OpTypeBool: return 1; - case spv::Op::OpTypeInt: return 3 + (spv[typeStart+3]); - case spv::Op::OpTypeFloat: return 5; - case spv::Op::OpTypeVector: - return 6 + hashType(idPos(spv[typeStart+2])) * (spv[typeStart+3] - 1); - case spv::Op::OpTypeMatrix: - return 30 + hashType(idPos(spv[typeStart+2])) * (spv[typeStart+3] - 1); - case spv::Op::OpTypeImage: - return 120 + hashType(idPos(spv[typeStart+2])) + - spv[typeStart+3] + // dimensionality - spv[typeStart+4] * 8 * 16 + // depth - spv[typeStart+5] * 4 * 16 + // arrayed - spv[typeStart+6] * 2 * 16 + // multisampled - spv[typeStart+7] * 1 * 16; // format - case spv::Op::OpTypeSampler: - return 500; - case spv::Op::OpTypeSampledImage: - return 502; - case spv::Op::OpTypeArray: - return 501 + hashType(idPos(spv[typeStart+2])) * spv[typeStart+3]; - case spv::Op::OpTypeRuntimeArray: - return 5000 + hashType(idPos(spv[typeStart+2])); - case spv::Op::OpTypeStruct: - { - std::uint32_t hash = 10000; - for (unsigned w=2; w < wordCount; ++w) - hash += w * hashType(idPos(spv[typeStart+w])); - return hash; - } - - case spv::Op::OpTypeOpaque: return 6000 + spv[typeStart+2]; - case spv::Op::OpTypePointer: return 100000 + hashType(idPos(spv[typeStart+3])); - case spv::Op::OpTypeFunction: - { - std::uint32_t hash = 200000; - for (unsigned w=2; w < wordCount; ++w) - hash += w * hashType(idPos(spv[typeStart+w])); - return hash; - } - - case spv::Op::OpTypeEvent: return 300000; - case spv::Op::OpTypeDeviceEvent: return 300001; - case spv::Op::OpTypeReserveId: return 300002; - case spv::Op::OpTypeQueue: return 300003; - case spv::Op::OpTypePipe: return 300004; - case spv::Op::OpConstantTrue: return 300007; - case spv::Op::OpConstantFalse: return 300008; - case spv::Op::OpTypeRayQueryKHR: return 300009; - case spv::Op::OpTypeAccelerationStructureKHR: return 300010; - case spv::Op::OpConstantComposite: - { - std::uint32_t hash = 300011 + hashType(idPos(spv[typeStart+1])); - for (unsigned w=3; w < wordCount; ++w) - hash += w * hashType(idPos(spv[typeStart+w])); - return hash; - } - case spv::Op::OpConstant: - { - std::uint32_t hash = 400011 + hashType(idPos(spv[typeStart+1])); - for (unsigned w=3; w < wordCount; ++w) - hash += w * spv[typeStart+w]; - return hash; - } - case spv::Op::OpConstantNull: - { - std::uint32_t hash = 500009 + hashType(idPos(spv[typeStart+1])); - return hash; - } - case spv::Op::OpConstantSampler: - { - std::uint32_t hash = 600011 + hashType(idPos(spv[typeStart+1])); - for (unsigned w=3; w < wordCount; ++w) - hash += w * spv[typeStart+w]; - return hash; - } - - default: - error("unknown type opcode"); - return 0; - } - } - - void spirvbin_t::mapTypeConst() - { - globaltypes_t globalTypeMap; - - msg(3, 2, std::string("Remapping Consts & Types: ")); - - static const std::uint32_t softTypeIdLimit = 3011; // small prime. TODO: get from options - static const std::uint32_t firstMappedID = 8; // offset into ID space - - for (auto& typeStart : typeConstPos) { - const spv::Id resId = asTypeConstId(typeStart); - const std::uint32_t hashval = hashType(typeStart); - - if (errorLatch) - return; - - if (isOldIdUnmapped(resId)) { - localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID)); - if (errorLatch) - return; - } - } - } - - // Strip a single binary by removing ranges given in stripRange - void spirvbin_t::strip() - { - if (stripRange.empty()) // nothing to do - return; - - // Sort strip ranges in order of traversal - std::sort(stripRange.begin(), stripRange.end()); - - // Allocate a new binary big enough to hold old binary - // We'll step this iterator through the strip ranges as we go through the binary - auto strip_it = stripRange.begin(); - - int strippedPos = 0; - for (unsigned word = 0; word < unsigned(spv.size()); ++word) { - while (strip_it != stripRange.end() && word >= strip_it->second) - ++strip_it; - - if (strip_it == stripRange.end() || word < strip_it->first || word >= strip_it->second) - spv[strippedPos++] = spv[word]; - } - - spv.resize(strippedPos); - stripRange.clear(); - - buildLocalMaps(); - } - - // Strip a single binary by removing ranges given in stripRange - void spirvbin_t::remap(std::uint32_t opts) - { - options = opts; - - // Set up opcode tables from SpvDoc - spv::Parameterize(); - - validate(); // validate header - buildLocalMaps(); // build ID maps - - msg(3, 4, std::string("ID bound: ") + std::to_string(bound())); - - if (options & STRIP) stripDebug(); - if (errorLatch) return; - - strip(); // strip out data we decided to eliminate - if (errorLatch) return; - - if (options & OPT_LOADSTORE) optLoadStore(); - if (errorLatch) return; - - if (options & OPT_FWD_LS) forwardLoadStores(); - if (errorLatch) return; - - if (options & DCE_FUNCS) dceFuncs(); - if (errorLatch) return; - - if (options & DCE_VARS) dceVars(); - if (errorLatch) return; - - if (options & DCE_TYPES) dceTypes(); - if (errorLatch) return; - - strip(); // strip out data we decided to eliminate - if (errorLatch) return; - - stripDeadRefs(); // remove references to things we DCEed - if (errorLatch) return; - - // after the last strip, we must clean any debug info referring to now-deleted data - - if (options & MAP_TYPES) mapTypeConst(); - if (errorLatch) return; - - if (options & MAP_NAMES) mapNames(); - if (errorLatch) return; - - if (options & MAP_FUNCS) mapFnBodies(); - if (errorLatch) return; - - if (options & MAP_ALL) { - mapRemainder(); // map any unmapped IDs - if (errorLatch) return; - - applyMap(); // Now remap each shader to the new IDs we've come up with - if (errorLatch) return; - } - } - - // remap from a memory image - void spirvbin_t::remap(std::vector& in_spv, const std::vector& whiteListStrings, - std::uint32_t opts) - { - stripWhiteList = whiteListStrings; - spv.swap(in_spv); - remap(opts); - spv.swap(in_spv); - } - - // remap from a memory image - legacy interface without white list - void spirvbin_t::remap(std::vector& in_spv, std::uint32_t opts) - { - stripWhiteList.clear(); - spv.swap(in_spv); - remap(opts); - spv.swap(in_spv); - } - -} // namespace SPV - diff --git a/3rdparty/glslang/SPIRV/SPVRemapper.h b/3rdparty/glslang/SPIRV/SPVRemapper.h deleted file mode 100644 index d4c2295c9..000000000 --- a/3rdparty/glslang/SPIRV/SPVRemapper.h +++ /dev/null @@ -1,300 +0,0 @@ -// -// Copyright (C) 2015 LunarG, Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// -// Neither the name of 3Dlabs Inc. Ltd. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// - -#ifndef SPIRVREMAPPER_H -#define SPIRVREMAPPER_H - -#include -#include -#include -#include - -#ifdef GLSLANG_IS_SHARED_LIBRARY - #ifdef _WIN32 - #ifdef GLSLANG_EXPORTING - #define GLSLANG_EXPORT __declspec(dllexport) - #else - #define GLSLANG_EXPORT __declspec(dllimport) - #endif - #elif __GNUC__ >= 4 - #define GLSLANG_EXPORT __attribute__((visibility("default"))) - #endif -#endif // GLSLANG_IS_SHARED_LIBRARY -#ifndef GLSLANG_EXPORT -#define GLSLANG_EXPORT -#endif - -namespace spv { - -class spirvbin_base_t -{ -public: - enum Options { - NONE = 0, - STRIP = (1<<0), - MAP_TYPES = (1<<1), - MAP_NAMES = (1<<2), - MAP_FUNCS = (1<<3), - DCE_FUNCS = (1<<4), - DCE_VARS = (1<<5), - DCE_TYPES = (1<<6), - OPT_LOADSTORE = (1<<7), - OPT_FWD_LS = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV - MAP_ALL = (MAP_TYPES | MAP_NAMES | MAP_FUNCS), - DCE_ALL = (DCE_FUNCS | DCE_VARS | DCE_TYPES), - OPT_ALL = (OPT_LOADSTORE), - - ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL), - DO_EVERYTHING = (STRIP | ALL_BUT_STRIP) - }; -}; - -} // namespace SPV - -#include -#include -#include -#include -#include -#include -#include - -#include "spirv.hpp11" - -namespace spv { - -static inline constexpr Id NoResult = 0; - -// class to hold SPIR-V binary data for remapping, DCE, and debug stripping -class GLSLANG_EXPORT spirvbin_t : public spirvbin_base_t -{ -public: - spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose), errorLatch(false) - { } - - virtual ~spirvbin_t() { } - - // remap on an existing binary in memory - void remap(std::vector& spv, const std::vector& whiteListStrings, - std::uint32_t opts = DO_EVERYTHING); - - // remap on an existing binary in memory - legacy interface without white list - void remap(std::vector& spv, std::uint32_t opts = DO_EVERYTHING); - - // Type for error/log handler functions - typedef std::function errorfn_t; - typedef std::function logfn_t; - - // Register error/log handling functions (can be lambda fn / functor / etc) - static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; } - static void registerLogHandler(logfn_t handler) { logHandler = handler; } - -protected: - // This can be overridden to provide other message behavior if needed - virtual void msg(int minVerbosity, int indent, const std::string& txt) const; - -private: - // Local to global, or global to local ID map - typedef std::unordered_map idmap_t; - typedef std::unordered_set idset_t; - typedef std::unordered_map blockmap_t; - - void remap(std::uint32_t opts = DO_EVERYTHING); - - // Map of names to IDs - typedef std::unordered_map namemap_t; - - typedef std::uint32_t spirword_t; - - typedef std::pair range_t; - typedef std::function idfn_t; - typedef std::function instfn_t; - - // Special Values for ID map: - static const spv::Id unmapped; // unchanged from default value - static const spv::Id unused; // unused ID - static const int header_size; // SPIR header = 5 words - - class id_iterator_t; - - // For mapping type entries between different shaders - typedef std::vector typeentry_t; - typedef std::map globaltypes_t; - - // A set that preserves position order, and a reverse map - typedef std::set posmap_t; - typedef std::unordered_map posmap_rev_t; - - // Maps and ID to the size of its base type, if known. - typedef std::unordered_map typesize_map_t; - - // handle error - void error(const std::string& txt) const { errorLatch = true; errorHandler(txt); } - - bool isConstOp(spv::Op opCode) const; - bool isTypeOp(spv::Op opCode) const; - bool isStripOp(spv::Op opCode) const; - bool isFlowCtrl(spv::Op opCode) const; - range_t literalRange(spv::Op opCode) const; - range_t typeRange(spv::Op opCode) const; - range_t constRange(spv::Op opCode) const; - unsigned typeSizeInWords(spv::Id id) const; - unsigned idTypeSizeInWords(spv::Id id) const; - - bool isStripOp(spv::Op opCode, unsigned start) const; - - spv::Id& asId(unsigned word) { return spv[word]; } - const spv::Id& asId(unsigned word) const { return spv[word]; } - spv::Op asOpCode(unsigned word) const { return opOpCode(spv[word]); } - std::uint32_t asOpCodeHash(unsigned word); - spv::Decoration asDecoration(unsigned word) const { return spv::Decoration(spv[word]); } - unsigned asWordCount(unsigned word) const { return opWordCount(spv[word]); } - spv::Id asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); } - unsigned idPos(spv::Id id) const; - - static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; } - static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); } - - // Header access & set methods - spirword_t magic() const { return spv[0]; } // return magic number - spirword_t bound() const { return spv[3]; } // return Id bound from header - spirword_t bound(spirword_t b) { return spv[3] = b; } - spirword_t genmagic() const { return spv[2]; } // generator magic - spirword_t genmagic(spirword_t m) { return spv[2] = m; } - spirword_t schemaNum() const { return spv[4]; } // schema number from header - - // Mapping fns: get - spv::Id localId(spv::Id id) const { return idMapL[id]; } - - // Mapping fns: set - inline spv::Id localId(spv::Id id, spv::Id newId); - void countIds(spv::Id id); - - // Return next unused new local ID. - // NOTE: boost::dynamic_bitset would be more efficient due to find_next(), - // which std::vector doens't have. - inline spv::Id nextUnusedId(spv::Id id); - - void buildLocalMaps(); - std::string literalString(unsigned word) const; // Return literal as a std::string - int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; } - - bool isNewIdMapped(spv::Id newId) const { return isMapped(newId); } - bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; } - bool isOldIdUnused(spv::Id oldId) const { return localId(oldId) == unused; } - bool isOldIdMapped(spv::Id oldId) const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); } - bool isFunction(spv::Id oldId) const { return fnPos.find(oldId) != fnPos.end(); } - - // bool matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const; - // spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const; - std::uint32_t hashType(unsigned typeStart) const; - - spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0); - int processInstruction(unsigned word, instfn_t, idfn_t); - - void validate() const; - void mapTypeConst(); - void mapFnBodies(); - void optLoadStore(); - void dceFuncs(); - void dceVars(); - void dceTypes(); - void mapNames(); - void foldIds(); // fold IDs to smallest space - void forwardLoadStores(); // load store forwarding (EXPERIMENTAL) - void offsetIds(); // create relative offset IDs - - void applyMap(); // remap per local name map - void mapRemainder(); // map any IDs we haven't touched yet - void stripDebug(); // strip all debug info - void stripDeadRefs(); // strips debug info for now-dead references after DCE - void strip(); // remove debug symbols - - std::vector spv; // SPIR words - - std::vector stripWhiteList; - - namemap_t nameMap; // ID names from OpName - - // Since we want to also do binary ops, we can't use std::vector. we could use - // boost::dynamic_bitset, but we're trying to avoid a boost dependency. - typedef std::uint64_t bits_t; - std::vector mapped; // which new IDs have been mapped - static const int mBits = sizeof(bits_t) * 4; - - bool isMapped(spv::Id id) const { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); } - void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); } - void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); } - size_t maxMappedId() const { return mapped.size() * mBits; } - - // Add a strip range for a given instruction starting at 'start' - // Note: avoiding brace initializers to please older versions os MSVC. - void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); } - - // Function start and end. use unordered_map because we'll have - // many fewer functions than IDs. - std::unordered_map fnPos; - - // Which functions are called, anywhere in the module, with a call count - std::unordered_map fnCalls; - - posmap_t typeConstPos; // word positions that define types & consts (ordered) - posmap_rev_t idPosR; // reverse map from IDs to positions - typesize_map_t idTypeSizeMap; // maps each ID to its type size, if known. - - std::vector idMapL; // ID {M}ap from {L}ocal to {G}lobal IDs - - spv::Id entryPoint; // module entry point - spv::Id largestNewId; // biggest new ID we have mapped anything to - - // Sections of the binary to strip, given as [begin,end) - std::vector stripRange; - - // processing options: - std::uint32_t options; - int verbose; // verbosity level - - // Error latch: this is set if the error handler is ever executed. It would be better to - // use a try/catch block and throw, but that's not desired for certain environments, so - // this is the alternative. - mutable bool errorLatch; - - static errorfn_t errorHandler; - static logfn_t logHandler; -}; - -} // namespace SPV - -#endif // SPIRVREMAPPER_H diff --git a/3rdparty/glslang/SPIRV/SpvBuilder.cpp b/3rdparty/glslang/SPIRV/SpvBuilder.cpp index 5a5affacd..0d77fe676 100644 --- a/3rdparty/glslang/SPIRV/SpvBuilder.cpp +++ b/3rdparty/glslang/SPIRV/SpvBuilder.cpp @@ -138,7 +138,7 @@ Id Builder::makeSamplerType() if (emitNonSemanticShaderDebugInfo) { - auto const debugResultId = makeCompositeDebugType({}, "type.sampler", NonSemanticShaderDebugInfo100Structure, true); + auto const debugResultId = makeOpaqueDebugType("type.sampler"); debugId[type->getResultId()] = debugResultId; } @@ -419,7 +419,9 @@ Id Builder::makeFloatE4M3Type() // See makeStructResultType() for non-decorated structs // needed as the result of some instructions, which does // check for duplicates. -Id Builder::makeStructType(const std::vector& members, const char* name, bool const compilerGenerated) +// For compiler-generated structs, debug info is ignored. +Id Builder::makeStructType(const std::vector& members, const std::vector& memberDebugInfo, + const char* name, bool const compilerGenerated) { // Don't look for previous one, because in the general case, // structs can be duplicated except for decorations. @@ -433,9 +435,10 @@ Id Builder::makeStructType(const std::vector& members, const char* name, boo module.mapInstruction(type); addName(type->getResultId(), name); - if (emitNonSemanticShaderDebugInfo && !compilerGenerated) - { - auto const debugResultId = makeCompositeDebugType(members, name, NonSemanticShaderDebugInfo100Structure); + if (emitNonSemanticShaderDebugInfo && !compilerGenerated) { + assert(members.size() == memberDebugInfo.size()); + auto const debugResultId = + makeCompositeDebugType(members, memberDebugInfo, name, NonSemanticShaderDebugInfo100Structure); debugId[type->getResultId()] = debugResultId; } @@ -463,7 +466,7 @@ Id Builder::makeStructResultType(Id type0, Id type1) members.push_back(type0); members.push_back(type1); - return makeStructType(members, "ResType"); + return makeStructType(members, {}, "ResType"); } Id Builder::makeVectorType(Id component, int size) @@ -587,7 +590,7 @@ Id Builder::makeCooperativeMatrixTypeKHR(Id component, Id scope, Id rows, Id col debugName += std::string(findName(cols)) + ">"; // There's no nonsemantic debug info instruction for cooperative matrix types, // use opaque composite instead. - auto const debugResultId = makeCompositeDebugType({}, debugName.c_str(), NonSemanticShaderDebugInfo100Structure, true); + auto const debugResultId = makeOpaqueDebugType(debugName.c_str()); debugId[type->getResultId()] = debugResultId; } @@ -929,7 +932,7 @@ Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, boo } }; - auto const debugResultId = makeCompositeDebugType({}, TypeName(), NonSemanticShaderDebugInfo100Class, true); + auto const debugResultId = makeOpaqueDebugType(TypeName()); debugId[type->getResultId()] = debugResultId; } @@ -956,7 +959,7 @@ Id Builder::makeSampledImageType(Id imageType) if (emitNonSemanticShaderDebugInfo) { - auto const debugResultId = makeCompositeDebugType({}, "type.sampled.image", NonSemanticShaderDebugInfo100Class, true); + auto const debugResultId = makeOpaqueDebugType("type.sampled.image"); debugId[type->getResultId()] = debugResultId; } @@ -1153,7 +1156,7 @@ Id Builder::makeMatrixDebugType(Id const vectorType, int const vectorCount, bool return type->getResultId(); } -Id Builder::makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTypeLoc) +Id Builder::makeMemberDebugType(Id const memberType, StructMemberDebugInfo const& debugTypeLoc) { assert(debugId[memberType] != 0); @@ -1162,12 +1165,13 @@ Id Builder::makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTy type->addIdOperand(nonSemanticShaderDebugInfo); type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMember); type->addIdOperand(getStringId(debugTypeLoc.name)); // name id - type->addIdOperand(debugId[memberType]); // type id - type->addIdOperand(makeDebugSource(currentFileId)); // source id - type->addIdOperand(makeUintConstant(debugTypeLoc.line)); // line id TODO: currentLine is always zero + type->addIdOperand(debugTypeLoc.debugTypeOverride != 0 ? debugTypeLoc.debugTypeOverride + : debugId[memberType]); // type id + type->addIdOperand(makeDebugSource(currentFileId)); // source id + type->addIdOperand(makeUintConstant(debugTypeLoc.line)); // line id TODO: currentLine is always zero type->addIdOperand(makeUintConstant(debugTypeLoc.column)); // TODO: column id - type->addIdOperand(makeUintConstant(0)); // TODO: offset id - type->addIdOperand(makeUintConstant(0)); // TODO: size id + type->addIdOperand(makeUintConstant(0)); // TODO: offset id + type->addIdOperand(makeUintConstant(0)); // TODO: size id type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); // flags id groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMember].push_back(type); @@ -1177,23 +1181,16 @@ Id Builder::makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTy return type->getResultId(); } -// Note: To represent a source language opaque type, this instruction must have no Members operands, Size operand must be -// DebugInfoNone, and Name must start with @ to avoid clashes with user defined names. -Id Builder::makeCompositeDebugType(std::vector const& memberTypes, char const*const name, - NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType) +Id Builder::makeCompositeDebugType(std::vector const& memberTypes, std::vector const& memberDebugInfo, + char const* const name, NonSemanticShaderDebugInfo100DebugCompositeType const tag) { // Create the debug member types. std::vector memberDebugTypes; - for(auto const memberType : memberTypes) { - assert(debugTypeLocs.find(memberType) != debugTypeLocs.end()); - - // There _should_ be debug types for all the member types but currently buffer references - // do not have member debug info generated. - if (debugId[memberType]) - memberDebugTypes.emplace_back(makeMemberDebugType(memberType, debugTypeLocs[memberType])); - - // TODO: Need to rethink this method of passing location information. - // debugTypeLocs.erase(memberType); + assert(memberTypes.size() == memberDebugInfo.size()); + for (size_t i = 0; i < memberTypes.size(); i++) { + if (debugId[memberTypes[i]]) { + memberDebugTypes.emplace_back(makeMemberDebugType(memberTypes[i], memberDebugInfo[i])); + } } // Create The structure debug type. @@ -1207,16 +1204,9 @@ Id Builder::makeCompositeDebugType(std::vector const& memberTypes, char cons type->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero? type->addIdOperand(makeUintConstant(0)); // TODO: column id type->addIdOperand(makeDebugCompilationUnit()); // scope id - if(isOpaqueType == true) { - // Prepend '@' to opaque types. - type->addIdOperand(getStringId('@' + std::string(name))); // linkage name id - type->addIdOperand(makeDebugInfoNone()); // size id - } else { - type->addIdOperand(getStringId(name)); // linkage name id - type->addIdOperand(makeUintConstant(0)); // TODO: size id - } + type->addIdOperand(getStringId(name)); // linkage name id + type->addIdOperand(makeUintConstant(0)); // TODO: size id type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); // flags id - assert(isOpaqueType == false || (isOpaqueType == true && memberDebugTypes.empty())); for(auto const memberDebugType : memberDebugTypes) { type->addIdOperand(memberDebugType); } @@ -1228,6 +1218,34 @@ Id Builder::makeCompositeDebugType(std::vector const& memberTypes, char cons return type->getResultId(); } +// The NonSemantic Shader Debug Info doesn't really have a dedicated opcode for opaque types. Instead, we use DebugTypeComposite. +// To represent a source language opaque type, this instruction must have no Members operands, Size operand must be +// DebugInfoNone, and Name must start with @ to avoid clashes with user defined names. +Id Builder::makeOpaqueDebugType(char const* const name) +{ + // Create The structure debug type. + Instruction* type = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst); + type->reserveOperands(11); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeComposite); + type->addIdOperand(getStringId(name)); // name id + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Structure)); // tag id + type->addIdOperand(makeDebugSource(currentFileId)); // source id + type->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero? + type->addIdOperand(makeUintConstant(0)); // TODO: column id + type->addIdOperand(makeDebugCompilationUnit()); // scope id + // Prepend '@' to opaque types. + type->addIdOperand(getStringId('@' + std::string(name))); // linkage name id + type->addIdOperand(makeDebugInfoNone()); // size id + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); // flags id + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeComposite].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + Id Builder::makePointerDebugType(StorageClass storageClass, Id const baseType) { const Id debugBaseType = debugId[baseType]; @@ -1401,7 +1419,7 @@ Id Builder::createDebugLocalVariable(Id type, char const*const name, size_t cons inst->addIdOperand(currentDebugScopeId.top()); // scope id inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsLocal)); // flags id if(argNumber != 0) { - inst->addIdOperand(makeUintConstant(argNumber)); + inst->addIdOperand(makeUintConstant(static_cast(argNumber))); } constantsTypesGlobals.push_back(std::unique_ptr(inst)); @@ -1465,7 +1483,7 @@ Id Builder::makeAccelerationStructureType() constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); if (emitNonSemanticShaderDebugInfo) { - spv::Id debugType = makeCompositeDebugType({}, "accelerationStructure", NonSemanticShaderDebugInfo100Structure, true); + spv::Id debugType = makeOpaqueDebugType("accelerationStructure"); debugId[type->getResultId()] = debugType; } } else { @@ -1484,7 +1502,7 @@ Id Builder::makeRayQueryType() constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); if (emitNonSemanticShaderDebugInfo) { - spv::Id debugType = makeCompositeDebugType({}, "rayQuery", NonSemanticShaderDebugInfo100Structure, true); + spv::Id debugType = makeOpaqueDebugType("rayQuery"); debugId[type->getResultId()] = debugType; } } else { diff --git a/3rdparty/glslang/SPIRV/SpvBuilder.h b/3rdparty/glslang/SPIRV/SpvBuilder.h index 9b5bc9e41..2ab7d02c2 100644 --- a/3rdparty/glslang/SPIRV/SpvBuilder.h +++ b/3rdparty/glslang/SPIRV/SpvBuilder.h @@ -82,6 +82,14 @@ typedef enum { Spv_1_6 = (1 << 16) | (6 << 8), } SpvVersion; +struct StructMemberDebugInfo { + std::string name {}; + int line {0}; + int column {0}; + // Set if the caller knows a better debug type than what is associated with the functional SPIR-V type. + spv::Id debugTypeOverride {0}; +}; + class Builder { public: Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger); @@ -198,6 +206,14 @@ public: return id; } + // Maps the given OpType Id to a Non-Semantic DebugType Id. + Id getDebugType(Id type) { + if (emitNonSemanticShaderDebugInfo) { + return debugId[type]; + } + return 0; + } + // For creating new types (will return old type if the requested one was already made). Id makeVoidType(); Id makeBoolType(); @@ -211,7 +227,8 @@ public: Id makeBFloat16Type(); Id makeFloatE5M2Type(); Id makeFloatE4M3Type(); - Id makeStructType(const std::vector& members, const char* name, bool const compilerGenerated = true); + Id makeStructType(const std::vector& members, const std::vector& memberDebugInfo, + const char* name, bool const compilerGenerated = true); Id makeStructResultType(Id type0, Id type1); Id makeVectorType(Id component, int size); Id makeMatrixType(Id component, int cols, int rows); @@ -229,12 +246,6 @@ public: Id makeGenericType(spv::Op opcode, std::vector& operands); // SPIR-V NonSemantic Shader DebugInfo Instructions - struct DebugTypeLoc { - std::string name {}; - int line {0}; - int column {0}; - }; - std::unordered_map debugTypeLocs; Id makeDebugInfoNone(); Id makeBoolDebugType(int const size); Id makeIntegerDebugType(int const width, bool const hasSign); @@ -243,9 +254,10 @@ public: Id makeArrayDebugType(Id const baseType, Id const componentCount); Id makeVectorDebugType(Id const baseType, int const componentCount); Id makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor = true); - Id makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTypeLoc); - Id makeCompositeDebugType(std::vector const& memberTypes, char const*const name, - NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType = false); + Id makeMemberDebugType(Id const memberType, StructMemberDebugInfo const& debugTypeLoc); + Id makeCompositeDebugType(std::vector const& memberTypes, std::vector const& memberDebugInfo, + char const* const name, NonSemanticShaderDebugInfo100DebugCompositeType const tag); + Id makeOpaqueDebugType(char const* const name); Id makePointerDebugType(StorageClass storageClass, Id const baseType); Id makeForwardPointerDebugType(StorageClass storageClass); Id makeDebugSource(const Id fileName); diff --git a/3rdparty/glslang/StandAlone/StandAlone.cpp b/3rdparty/glslang/StandAlone/StandAlone.cpp index b1853b024..be7f44212 100644 --- a/3rdparty/glslang/StandAlone/StandAlone.cpp +++ b/3rdparty/glslang/StandAlone/StandAlone.cpp @@ -815,6 +815,14 @@ void ProcessArguments(std::vector>& workItem lowerword == "shift-ssbo-binding" || lowerword == "sbb") { ProcessBindingBase(argc, argv, glslang::EResSsbo); + } else if (lowerword == "shift-combined-sampler-bindings" || + lowerword == "shift-combined-sampler-binding" || + lowerword == "scsb") { + ProcessBindingBase(argc, argv, glslang::EResCombinedSampler); + } else if (lowerword == "shift-as-bindings" || + lowerword == "shift-as-binding" || + lowerword == "sab") { + ProcessBindingBase(argc, argv, glslang::EResAs); } else if (lowerword == "source-entrypoint" || // synonyms lowerword == "sep") { if (argc <= 1) @@ -874,7 +882,7 @@ void ProcessArguments(std::vector>& workItem TargetVersion = glslang::EShTargetSpv_1_6; } else Error("--target-env expected one of: vulkan1.0, vulkan1.1, vulkan1.2,\n" - "vulkan1.3, opengl, spirv1.0, spirv1.1, spirv1.2, spirv1.3,\n" + "vulkan1.3, vulkan1.4, opengl, spirv1.0, spirv1.1, spirv1.2, spirv1.3,\n" "spirv1.4, spirv1.5 or spirv1.6"); } bumpArg(); @@ -1972,47 +1980,45 @@ void usage() " rcall for a ray callable shader\n" "2) ..glsl or ..hlsl compound suffix, where stage options are\n" " described above\n" - "3) .conf, to provide a config file that replaces the default configuration\n" - " (see -c option below for generating a template)\n" + "3) .conf, to provide a config file that replaces the default configuration (see\n" + " -c option below for generating a template)\n" "\n" "Options:\n" " -C cascading errors; risk crash from accumulation of error recoveries\n" " -D input is HLSL (this is the default when any suffix is .hlsl)\n" - " -D | --define-macro | --D \n" + " -D | --D | --define-macro \n" " define a pre-processor macro\n" - " -E print pre-processed GLSL; cannot be used with -l;\n" - " errors will appear on stderr\n" - " -G[ver] create SPIR-V binary, under OpenGL semantics; turns on -l;\n" - " default file name is .spv (-o overrides this);\n" - " 'ver', when present, is the version of the input semantics,\n" - " which will appear in #define GL_SPIRV ver;\n" - " '--client opengl100' is the same as -G100;\n" - " a '--target-env' for OpenGL will also imply '-G';\n" - " currently only supports GLSL\n" + " -E print pre-processed GLSL; cannot be used with -l; errors will\n" + " appear on stderr\n" + " -G[ver] create SPIR-V binary under OpenGL semantics; turns on -l; default\n" + " file name is .spv (-o overrides this); ver, when present,\n" + " is the version of the input semantics which will appear in\n" + " '#define GL_SPIRV ver'; --client opengl100 is the same as -G100; a\n" + " --target-env for OpenGL will also imply -G; currently only\n" + " supports GLSL\n" " -H print human readable form of SPIR-V; turns on -V\n" - " -I add dir to the include search path; includer's directory\n" - " is searched first, followed by left-to-right order of -I\n" + " -I add to the include search path; includer's directory is\n" + " searched first, followed by left-to-right order of -I\n" " -Od disables optimization; may cause illegal SPIR-V for HLSL\n" " -Os optimizes SPIR-V to minimize size\n" - " -P | --preamble-text | --P \n" - " inject custom preamble text, which is treated as if it\n" - " appeared immediately after the version declaration (if any).\n" + " -P | --P | --preamble-text \n" + " inject custom preamble text which is treated as if it appeared\n" + " immediately after the version declaration (if any)\n" " -R use relaxed verification rules for generating Vulkan SPIR-V,\n" - " allowing the use of default uniforms, atomic_uints, and\n" - " gl_VertexID and gl_InstanceID keywords.\n" - " -S uses specified stage rather than parsing the file extension\n" - " choices for include vert, tesc, tese, geom, frag, comp.\n" - " A full list of options is given above." + " allowing the use of default uniforms, atomic_uints, and the\n" + " gl_VertexID and gl_InstanceID keywords\n" + " -S uses the specified rather than parsing the file extension;\n" + " choices for include vert, tesc, tese, geom, frag, and\n" + " comp; a full list of options is given above\n" " -U | --undef-macro | --U \n" " undefine a pre-processor macro\n" - " -V[ver] create SPIR-V binary, under Vulkan semantics; turns on -l;\n" - " default file name is .spv (-o overrides this)\n" - " 'ver', when present, is the version of the input semantics,\n" - " which will appear in #define VULKAN ver\n" - " '--client vulkan100' is the same as -V100\n" - " a '--target-env' for Vulkan will also imply '-V'\n" - " -c configuration dump;\n" - " creates the default configuration file (redirect to a .conf file)\n" + " -V[ver] create SPIR-V binary under Vulkan semantics; turns on -l; default\n" + " file name is .spv (-o overrides this); ver, when present,\n" + " is the version of the input semantics which will appear in\n" + " '#define VULKAN ver'; --client vulkan100 is the same as -V100; a\n" + " '--target-env' for Vulkan will also imply '-V'\n" + " -c configuration dump; creates the default configuration file\n" + " (redirect to a .conf file)\n" " -d default to desktop (#version 110) when there is no shader #version\n" " (default is ES version 100)\n" " -e | --entry-point \n" @@ -2024,148 +2030,170 @@ void usage() " -g0 strip debug information\n" " -gV generate nonsemantic shader debug information\n" " -gVS generate nonsemantic shader debug information with source\n" - " -h print this usage message\n" + " -h | --help print this usage message\n" " -i intermediate tree (glslang AST) is printed out\n" " -l link all input files together to form a single module\n" " -m memory leak mode\n" - " -o save binary to , requires a binary option (e.g., -V)\n" + " -o save binary to ; requires a binary option (e.g., -V)\n" " -q dump reflection query database; requires -l for linking\n" " -r | --relaxed-errors\n" " relaxed GLSL semantic error-checking mode\n" " -s silence syntax and semantic error reporting\n" " -t multi-threaded mode\n" + " -u:\n" + " specify a uniform location override for --aml\n" " -v | --version\n" " print version strings\n" " -w | --suppress-warnings\n" - " suppress GLSL warnings, except as required by \"#extension : warn\"\n" + " suppress GLSL warnings, except as required by '#extension : warn'\n" " -x save binary output as text-based 32-bit hexadecimal numbers\n" - " -u: specify a uniform location override for --aml\n" - " --uniform-base set a base to use for generated uniform locations\n" - " --auto-map-bindings | --amb automatically bind uniform variables\n" - " without explicit bindings\n" + " --absolute-path prints absolute path for messages\n" + " --auto-map-binding | --auto-map-bindings | --amb\n" + " automatically bind uniform variables without\n" + " explicit bindings\n" " --auto-map-locations | --aml automatically locate input/output lacking\n" " 'location' (fragile, not cross stage)\n" - " --absolute-path Prints absolute path for messages\n" - " --auto-sampled-textures Removes sampler variables and converts\n" + " --auto-sampled-textures removes sampler variables and converts\n" " existing textures to sampled textures\n" - " --client {vulkan|opengl} see -V and -G\n" + " --client {vulkan | opengl}\n" + " see -V and -G\n" " --depfile writes depfile for build systems\n" - " --dump-builtin-symbols prints builtin symbol table prior each compile\n" + " --dump-builtin-symbols prints builtin symbol table prior each\n" + " compile\n" " -dumpfullversion | -dumpversion print bare major.minor.patchlevel\n" - " --flatten-uniform-arrays | --fua flatten uniform texture/sampler arrays to\n" + " --enhanced-msgs print more readable error messages (GLSL\n" + " only)\n" + " --error-column display the column of the error along the\n" + " line\n" + " --flatten-uniform-array | --flatten-uniform-arrays | --fua\n" + " flatten uniform texture/sampler arrays to\n" " scalars\n" " --glsl-version {100 | 110 | 120 | 130 | 140 | 150 |\n" - " 300es | 310es | 320es | 330\n" + " 300es | 310es | 320es | 330 |\n" " 400 | 410 | 420 | 430 | 440 | 450 | 460}\n" - " set GLSL version, overrides #version\n" - " in shader source\n" - " --hlsl-offsets allow block offsets to follow HLSL rules\n" - " works independently of source language\n" - " --hlsl-iomap perform IO mapping in HLSL register space\n" - " --hlsl-enable-16bit-types allow 16-bit types in SPIR-V for HLSL\n" + " set GLSL version; overrides #version in\n" + " shader source\n" + " --hlsl-dx-position-w W component of SV_Position in HLSL fragment\n" + " shaders compatible with DirectX\n" " --hlsl-dx9-compatible interprets sampler declarations as a\n" " texture/sampler combo like DirectX9 would,\n" " and recognizes DirectX9-specific semantics\n" - " --hlsl-dx-position-w W component of SV_Position in HLSL fragment\n" - " shaders compatible with DirectX\n" + " --hlsl-enable-16bit-types allow 16-bit types in SPIR-V for HLSL\n" + " --hlsl-iomap | --hlsl-iomapper | --hlsl-iomapping\n" + " perform IO mapping in HLSL register space\n" + " --hlsl-offsets allow block offsets to follow HLSL rules;\n" + " works independently of source language\n" " --invert-y | --iy invert position.Y output in vertex shader\n" - " --enhanced-msgs print more readable error messages (GLSL only)\n" - " --error-column display the column of the error along the line\n" " --keep-uncalled | --ku don't eliminate uncalled functions\n" + " --lto perform link time optimization\n" " --nan-clamp favor non-NaN operand in min, max, and clamp\n" + " --no-link only compile shader; do not link (GLSL only)\n" + " NOTE: this option will set the export\n" + " linkage attribute on all functions\n" " --no-storage-format | --nsf use Unknown image format\n" - " --quiet do not print anything to stdout, unless\n" + " --quiet do not print anything to stdout unless\n" " requested by another option\n" - " --reflect-strict-array-suffix use strict array suffix rules when\n" - " reflecting\n" + " --reflect-all-block-variables reflect all variables in blocks, whether\n" + " inactive or active\n" " --reflect-basic-array-suffix arrays of basic types will have trailing [0]\n" " --reflect-intermediate-io reflection includes inputs/outputs of linked\n" " shaders rather than just vertex/fragment\n" " --reflect-separate-buffers reflect buffer variables and blocks\n" " separately to uniforms\n" - " --reflect-all-block-variables reflect all variables in blocks, whether\n" - " inactive or active\n" + " --reflect-strict-array-suffix use strict array suffix rules when\n" + " reflecting\n" " --reflect-unwrap-io-blocks unwrap input/output blocks the same as\n" " uniform blocks\n" - " --resource-set-binding [stage] name set binding\n" + " --resource-set-binding [name] [binding]...\n" " set descriptor set and binding for\n" " individual resources\n" - " --resource-set-binding [stage] set\n" + " --resource-set-binding [stage] \n" " set descriptor set for all resources\n" - " --rsb synonym for --resource-set-binding\n" - " --set-block-backing name {uniform|buffer|push_constant}\n" - " changes the backing type of a uniform, buffer,\n" - " or push_constant block declared in\n" - " in the program, when using -R option.\n" - " This can be used to change the backing\n" - " for existing blocks as well as implicit ones\n" - " such as 'gl_DefaultUniformBlock'.\n" - " --sbs synonym for set-block-storage\n" - " --set-atomic-counter-block name set\n" - " set name, and descriptor set for\n" - " atomic counter blocks, with -R opt\n" + " --resource-set-bindings | --rsb synonyms for --resource-set-binding\n" + " --set-atomic-counter-block \n" + " set name and descriptor set for atomic\n" + " counter blocks with -R opt\n" " --sacb synonym for set-atomic-counter-block\n" - " --set-default-uniform-block name set binding\n" + " --set-block-backing name {uniform | buffer | push_constant}\n" + " changes the backing type of a uniform,\n" + " buffer, or push_constant block declared in\n" + " the program when using the -R option; this\n" + " can be used to change the backing for\n" + " existing blocks as well as implicit ones\n" + " such as 'gl_DefaultUniformBlock'\n" + " --set-default-uniform-block \n" " set name, descriptor set, and binding for\n" - " global default-uniform-block, with -R opt\n" + " global default-uniform-block with -R opt\n" " --sdub synonym for set-default-uniform-block\n" - " --shift-image-binding [stage] num\n" - " base binding number for images (uav)\n" - " --shift-image-binding [stage] [num set]...\n" + " --shift-image-binding [stage] \n" + " base binding number for images (UAV)\n" + " --shift-image-binding [stage] ...\n" " per-descriptor-set shift values\n" - " --sib synonym for --shift-image-binding\n" - " --shift-sampler-binding [stage] num\n" + " --shift-image-bindings | --sib synonyms for --shift-image-binding\n" + " --shift-sampler-binding [stage] \n" " base binding number for samplers\n" - " --shift-sampler-binding [stage] [num set]...\n" + " --shift-sampler-binding [stage] ...\n" " per-descriptor-set shift values\n" - " --ssb synonym for --shift-sampler-binding\n" - " --shift-ssbo-binding [stage] num base binding number for SSBOs\n" - " --shift-ssbo-binding [stage] [num set]...\n" + " --shift-sampler-bindings | --ssb synonyms for --shift-sampler-binding\n" + " --shift-ssbo-binding [stage] \n" + " base binding number for SSBOs\n" + " --shift-ssbo-binding [stage] ...\n" " per-descriptor-set shift values\n" - " --sbb synonym for --shift-ssbo-binding\n" - " --shift-texture-binding [stage] num\n" + " --shift-ssbo-bindings | --sbb synonyms for --shift-ssbo-binding\n" + " --shift-texture-binding [stage] \n" " base binding number for textures\n" - " --shift-texture-binding [stage] [num set]...\n" + " --shift-texture-binding [stage] ...\n" " per-descriptor-set shift values\n" - " --stb synonym for --shift-texture-binding\n" - " --shift-uav-binding [stage] num base binding number for UAVs\n" - " --shift-uav-binding [stage] [num set]...\n" + " --shift-texture-bindings | --stb synonyms for --shift-texture-binding\n" + " --shift-uav-binding [stage] base binding number for UAVs\n" + " --shift-uav-binding [stage] ...\n" " per-descriptor-set shift values\n" - " --suavb synonym for --shift-uav-binding\n" - " --shift-UBO-binding [stage] num base binding number for UBOs\n" - " --shift-UBO-binding [stage] [num set]...\n" + " --shift-uav-bindings | --suavb synonyms for --shift-uav-binding\n" + " --shift-ubo-binding [stage] base binding number for UBOs\n" + " --shift-ubo-binding [stage] ...\n" " per-descriptor-set shift values\n" - " --sub synonym for --shift-UBO-binding\n" - " --shift-cbuffer-binding | --scb synonyms for --shift-UBO-binding\n" + " --shift-ubo-bindings | --sub |\n" + " --shift-cbuffer-binding | --shift-cbuffer-bindings | --scb\n" + " synonyms for --shift-ubo-binding\n" + " --shift-combined-sampler-binding [stage] \n" + " base binding number for combined samplers\n" + " --shift-combined-sampler-binding [stage] ...\n" + " per-descriptor-set shift values\n" + " --shift-combined-sampler-bindings | --scsb\n" + " synonyms for --shift-combined-sampler-binding\n" + " --shift-as-binding [stage] \n" + " base binding number for acceleration structures\n" + " --shift-as-binding [stage] ...\n" + " per-descriptor-set shift values\n" + " --shift-as-bindings | --sab\n" + " synonyms for --shift-as-binding\n" " --spirv-dis output standard-form disassembly; works only\n" " when a SPIR-V generation option is also used\n" " --spirv-val execute the SPIRV-Tools validator\n" - " --source-entrypoint the given shader source function is\n" - " renamed to be the given in -e\n" - " --sep synonym for --source-entrypoint\n" + " --source-entrypoint | --sep \n" + " the given shader source function is renamed\n" + " to be the given in -e\n" " --stdin read from stdin instead of from a file;\n" " requires providing the shader stage using -S\n" - " --target-env {vulkan1.0 | vulkan1.1 | vulkan1.2 | vulkan1.3 | opengl |\n" - " spirv1.0 | spirv1.1 | spirv1.2 | spirv1.3 | spirv1.4 |\n" - " spirv1.5 | spirv1.6}\n" - " Set the execution environment that the\n" - " generated code will be executed in.\n" - " Defaults to:\n" + " --target-env {vulkan1.0 | vulkan1.1 | vulkan1.2 | vulkan1.3 | vulkan1.4 |\n" + " opengl | spirv1.0 | spirv1.1 | spirv1.2 | spirv1.3 |\n" + " spirv1.4 | spirv1.5 | spirv1.6}\n" + " set the execution environment the generated\n" + " code will be executed in; defaults to:\n" " * vulkan1.0 under --client vulkan\n" " * opengl under --client opengl\n" " * spirv1.0 under --target-env vulkan1.0\n" " * spirv1.3 under --target-env vulkan1.1\n" " * spirv1.5 under --target-env vulkan1.2\n" " * spirv1.6 under --target-env vulkan1.3\n" - " Multiple --target-env can be specified.\n" - " --variable-name \n" - " --vn creates a C header file that contains a\n" - " uint32_t array named \n" - " initialized with the shader binary code\n" - " --no-link Only compile shader; do not link (GLSL-only)\n" - " NOTE: this option will set the export linkage\n" - " attribute on all functions\n" - " --lto perform link time optimization\n" + " * spirv1.6 under --target-env vulkan1.4\n" + " multiple --target-env can be specified\n" + " --uniform-base set a base to use for generated uniform\n" + " locations\n" + " --variable-name | --vn \n" + " creates a C header file that contains a\n" + " uint32_t array named initialized with\n" + " the shader binary code\n" " --validate-io validate cross stage IO\n"); exit(EFailUsage); diff --git a/3rdparty/glslang/StandAlone/spirv-remap.cpp b/3rdparty/glslang/StandAlone/spirv-remap.cpp deleted file mode 100644 index b1f032664..000000000 --- a/3rdparty/glslang/StandAlone/spirv-remap.cpp +++ /dev/null @@ -1,402 +0,0 @@ -// -// Copyright (C) 2015 LunarG, Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// -// Neither the name of 3Dlabs Inc. Ltd. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// - -#include -#include -#include -#include -#include - -// -// Include remapper -// -#include "../SPIRV/SPVRemapper.h" - -namespace { - - typedef unsigned int SpvWord; - - // Poor man's basename: given a complete path, return file portion. - // E.g: - // Linux: /foo/bar/test -> test - // Win: c:\foo\bar\test -> test - // It's not very efficient, but that doesn't matter for our minimal-duty use. - // Using boost::filesystem would be better in many ways, but want to avoid that dependency. - - // OS dependent path separator (avoiding boost::filesystem dependency) -#if defined(_WIN32) - char path_sep_char() { return '\\'; } -#else - char path_sep_char() { return '/'; } -#endif - - std::string basename(const std::string filename) - { - const size_t sepLoc = filename.find_last_of(path_sep_char()); - - return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1); - } - - void errHandler(const std::string& str) { - std::cout << str << std::endl; - exit(5); - } - - void logHandler(const std::string& str) { - std::cout << str << std::endl; - } - - // Read word stream from disk - void read(std::vector& spv, const std::string& inFilename, int verbosity) - { - std::ifstream fp; - - if (verbosity > 0) - logHandler(std::string(" reading: ") + inFilename); - - spv.clear(); - fp.open(inFilename, std::fstream::in | std::fstream::binary); - - if (fp.fail()) - errHandler("error opening file for read: "); - - // Reserve space (for efficiency, not for correctness) - fp.seekg(0, fp.end); - spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord)); - fp.seekg(0, fp.beg); - - while (!fp.eof()) { - SpvWord inWord; - fp.read((char *)&inWord, sizeof(inWord)); - - if (!fp.eof()) { - spv.push_back(inWord); - if (fp.fail()) - errHandler(std::string("error reading file: ") + inFilename); - } - } - } - - // Read strings from a file - void read(std::vector& strings, const std::string& inFilename, int verbosity) - { - std::ifstream fp; - - if (verbosity > 0) - logHandler(std::string(" reading: ") + inFilename); - - strings.clear(); - fp.open(inFilename, std::fstream::in); - - if (fp.fail()) - errHandler("error opening file for read: "); - - std::string line; - while (std::getline(fp, line)) - { - // Ignore empty lines and lines starting with the comment marker '#'. - if (line.length() == 0 || line[0] == '#') { - continue; - } - - strings.push_back(line); - } - } - - void write(std::vector& spv, const std::string& outFile, int verbosity) - { - if (outFile.empty()) - errHandler("missing output filename."); - - std::ofstream fp; - - if (verbosity > 0) - logHandler(std::string(" writing: ") + outFile); - - fp.open(outFile, std::fstream::out | std::fstream::binary); - - if (fp.fail()) - errHandler(std::string("error opening file for write: ") + outFile); - - for (auto it = spv.cbegin(); it != spv.cend(); ++it) { - SpvWord word = *it; - fp.write((char *)&word, sizeof(word)); - if (fp.fail()) - errHandler(std::string("error writing file: ") + outFile); - } - - // file is closed by destructor - } - - // Print helpful usage message to stdout, and exit - void usage(const char* const name, const char* const msg = nullptr) - { - if (msg) - std::cout << msg << std::endl << std::endl; - - std::cout << "Usage: " << std::endl; - - std::cout << " " << basename(name) - << " [-v[v[...]] | --verbose [int]]" - << " [--map (all|types|names|funcs)]" - << " [--dce (all|types|funcs)]" - << " [--opt (all|loadstore)]" - << " [--strip-all | --strip all | -s]" - << " [--strip-white-list]" - << " [--do-everything]" - << " --input | -i file1 [file2...] --output|-o DESTDIR | destfile1 [destfile2...]" - << std::endl; - - std::cout << " " << basename(name) << " [--version | -V]" << std::endl; - std::cout << " " << basename(name) << " [--help | -?]" << std::endl; - - exit(0); - } - - // grind through each SPIR in turn - void execute(const std::vector& inputFiles, - const std::vector& outputDirOrFiles, - const bool isSingleOutputDir, - const std::string& whiteListFile, - int opts, - int verbosity) - { - std::vector whiteListStrings; - if (!whiteListFile.empty()) - read(whiteListStrings, whiteListFile, verbosity); - - for (std::size_t ii=0; ii spv; - read(spv, inputFiles[ii], verbosity); - - spv::spirvbin_t(verbosity).remap(spv, whiteListStrings, opts); - - if (isSingleOutputDir) { - // write all outputs to same directory - const std::string outFile = outputDirOrFiles[0] + path_sep_char() + basename(inputFiles[ii]); - write(spv, outFile, verbosity); - } else { - // write each input to its associated output - write(spv, outputDirOrFiles[ii], verbosity); - } - } - - if (verbosity > 0) - std::cout << "Done: " << inputFiles.size() << " file(s) processed" << std::endl; - } - - // Parse command line options - void parseCmdLine(int argc, - char** argv, - std::vector& inputFiles, - std::vector& outputDirOrFiles, - std::string& stripWhiteListFile, - int& options, - int& verbosity) - { - if (argc < 2) - usage(argv[0]); - - verbosity = 0; - options = spv::spirvbin_t::NONE; - - // Parse command line. - // boost::program_options would be quite a bit nicer, but we don't want to - // introduce a dependency on boost. - for (int a=1; a inputFiles; - std::vector outputDirOrFiles; - std::string whiteListFile; - int opts; - int verbosity; - - // handle errors by exiting - spv::spirvbin_t::registerErrorHandler(errHandler); - - // Log messages to std::cout - spv::spirvbin_t::registerLogHandler(logHandler); - - if (argc < 2) - usage(argv[0]); - - parseCmdLine(argc, argv, inputFiles, outputDirOrFiles, whiteListFile, opts, verbosity); - - if (outputDirOrFiles.empty()) - usage(argv[0], "Output directory or file(s) required."); - - const bool isMultiInput = inputFiles.size() > 1; - const bool isMultiOutput = outputDirOrFiles.size() > 1; - const bool isSingleOutputDir = !isMultiOutput && std::filesystem::is_directory(outputDirOrFiles[0]); - - if (isMultiInput && !isMultiOutput && !isSingleOutputDir) - usage(argv[0], "Output is not a directory."); - - - if (isMultiInput && isMultiOutput && (outputDirOrFiles.size() != inputFiles.size())) - usage(argv[0], "Output must be either a single directory or one output file per input."); - - // Main operations: read, remap, and write. - execute(inputFiles, outputDirOrFiles, isSingleOutputDir, whiteListFile, opts, verbosity); - - // If we get here, everything went OK! Nothing more to be done. -} diff --git a/3rdparty/glslang/build_info.h b/3rdparty/glslang/build_info.h index 327c69e25..d8f2a74ce 100644 --- a/3rdparty/glslang/build_info.h +++ b/3rdparty/glslang/build_info.h @@ -34,8 +34,8 @@ #ifndef GLSLANG_BUILD_INFO #define GLSLANG_BUILD_INFO -#define GLSLANG_VERSION_MAJOR 15 -#define GLSLANG_VERSION_MINOR 4 +#define GLSLANG_VERSION_MAJOR 16 +#define GLSLANG_VERSION_MINOR 0 #define GLSLANG_VERSION_PATCH 0 #define GLSLANG_VERSION_FLAVOR "" diff --git a/3rdparty/glslang/glslang/CInterface/glslang_c_interface.cpp b/3rdparty/glslang/glslang/CInterface/glslang_c_interface.cpp index d391c1d04..72841c15d 100644 --- a/3rdparty/glslang/glslang/CInterface/glslang_c_interface.cpp +++ b/3rdparty/glslang/glslang/CInterface/glslang_c_interface.cpp @@ -351,6 +351,14 @@ GLSLANG_EXPORT void glslang_shader_set_preamble(glslang_shader_t* shader, const shader->shader->setPreamble(s); } +GLSLANG_EXPORT void glslang_shader_set_entry_point(glslang_shader_t* shader, const char* s) { + shader->shader->setEntryPoint(s); +} + +GLSLANG_EXPORT void glslang_shader_set_invert_y(glslang_shader_t* shader, bool y) { + shader->shader->setInvertY(y); +} + GLSLANG_EXPORT void glslang_shader_shift_binding(glslang_shader_t* shader, glslang_resource_type_t res, unsigned int base) { const glslang::TResourceType res_type = glslang::TResourceType(res); diff --git a/3rdparty/glslang/glslang/Include/PoolAlloc.h b/3rdparty/glslang/glslang/Include/PoolAlloc.h index 8a9284144..6b6dfd64d 100644 --- a/3rdparty/glslang/glslang/Include/PoolAlloc.h +++ b/3rdparty/glslang/glslang/Include/PoolAlloc.h @@ -292,8 +292,7 @@ public: template pool_allocator(const pool_allocator& p) : allocator(p.getAllocator()) { } - - GLSLANG_EXPORT_FOR_TESTS + pointer allocate(size_type n) { return reinterpret_cast(getAllocator().allocate(n * sizeof(T))); } pointer allocate(size_type n, const void*) { diff --git a/3rdparty/glslang/glslang/Include/glslang_c_interface.h b/3rdparty/glslang/glslang/Include/glslang_c_interface.h index 06120219d..4eec55b58 100644 --- a/3rdparty/glslang/glslang/Include/glslang_c_interface.h +++ b/3rdparty/glslang/glslang/Include/glslang_c_interface.h @@ -253,6 +253,8 @@ GLSLANG_EXPORT void glslang_finalize_process(void); GLSLANG_EXPORT glslang_shader_t* glslang_shader_create(const glslang_input_t* input); GLSLANG_EXPORT void glslang_shader_delete(glslang_shader_t* shader); GLSLANG_EXPORT void glslang_shader_set_preamble(glslang_shader_t* shader, const char* s); +GLSLANG_EXPORT void glslang_shader_set_entry_point(glslang_shader_t* shader, const char* s); +GLSLANG_EXPORT void glslang_shader_set_invert_y(glslang_shader_t* shader, bool y); GLSLANG_EXPORT void glslang_shader_shift_binding(glslang_shader_t* shader, glslang_resource_type_t res, unsigned int base); GLSLANG_EXPORT void glslang_shader_shift_binding_for_set(glslang_shader_t* shader, glslang_resource_type_t res, unsigned int base, unsigned int set); GLSLANG_EXPORT void glslang_shader_set_options(glslang_shader_t* shader, int options); // glslang_shader_options_t diff --git a/3rdparty/glslang/glslang/Include/glslang_c_shader_types.h b/3rdparty/glslang/glslang/Include/glslang_c_shader_types.h index 34bfbdb9d..ccba2fde6 100644 --- a/3rdparty/glslang/glslang/Include/glslang_c_shader_types.h +++ b/3rdparty/glslang/glslang/Include/glslang_c_shader_types.h @@ -224,6 +224,9 @@ typedef enum { GLSLANG_RESOURCE_TYPE_UBO, GLSLANG_RESOURCE_TYPE_SSBO, GLSLANG_RESOURCE_TYPE_UAV, + GLSLANG_RESOURCE_TYPE_COMBINED_SAMPLER, + GLSLANG_RESOURCE_TYPE_AS, + GLSLANG_RESOURCE_TYPE_TENSOR, LAST_ELEMENT_MARKER(GLSLANG_RESOURCE_TYPE_COUNT), } glslang_resource_type_t; diff --git a/3rdparty/glslang/glslang/Include/visibility.h b/3rdparty/glslang/glslang/Include/visibility.h index 9bb8f3faa..dd32351f8 100644 --- a/3rdparty/glslang/glslang/Include/visibility.h +++ b/3rdparty/glslang/glslang/Include/visibility.h @@ -51,4 +51,8 @@ // Symbols marked with this macro are only meant for public use by the test suite // and do not appear in publicly installed headers. They are not considered to be // part of the glslang library ABI. -#define GLSLANG_EXPORT_FOR_TESTS GLSLANG_EXPORT +#ifdef GLSLANG_TEST_BUILD + #define GLSLANG_EXPORT_FOR_TESTS GLSLANG_EXPORT +#else + #define GLSLANG_EXPORT_FOR_TESTS +#endif diff --git a/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp b/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp index 203430e95..60116efcb 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp +++ b/3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp @@ -3904,12 +3904,15 @@ void TIntermediate::performTextureUpgradeAndSamplerRemovalTransformation(TInterm const char* TIntermediate::getResourceName(TResourceType res) { switch (res) { - case EResSampler: return "shift-sampler-binding"; - case EResTexture: return "shift-texture-binding"; - case EResImage: return "shift-image-binding"; - case EResUbo: return "shift-UBO-binding"; - case EResSsbo: return "shift-ssbo-binding"; - case EResUav: return "shift-uav-binding"; + case EResSampler: return "shift-sampler-binding"; + case EResTexture: return "shift-texture-binding"; + case EResImage: return "shift-image-binding"; + case EResUbo: return "shift-ubo-binding"; + case EResSsbo: return "shift-ssbo-binding"; + case EResUav: return "shift-uav-binding"; + case EResCombinedSampler: return "shift-combined-sampler-binding"; + case EResAs: return "shift-as-binding"; + case EResTensor: return nullptr; default: assert(0); // internal error: should only be called with valid resource types. return nullptr; diff --git a/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp b/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp index 845020afa..b9bd7640d 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp +++ b/3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp @@ -1862,8 +1862,8 @@ void TParseContext::handleVector2CoopMatConversionCall(const TSourceLoc& loc, co error(loc, "source and destination element types are not compatible", "", ""); uint32_t scope = spv_Scope_Subgroup; - uint32_t coopMatKHRuse = -1u; - uint32_t coopMatNumRows = -1u, coopMatNumCols = -1u; + uint32_t coopMatKHRuse = !0u; + uint32_t coopMatNumRows = !0u, coopMatNumCols = !0u; TIntermTyped *nodeNumRows = nullptr, *nodeNumCols = nullptr; const TTypeParameters* dstTypeParameters = dstType.getTypeParameters(); if (dstTypeParameters->arraySizes == nullptr || dstTypeParameters->arraySizes->getNumDims() != 4) { @@ -1946,7 +1946,7 @@ void TParseContext::handleVector2CoopMatConversionCall(const TSourceLoc& loc, co error(loc, "source and destination element types are not compatible", "", ""); uint32_t scope = spv_Scope_Subgroup; - unsigned coopMatKHRuse = -1u; + unsigned coopMatKHRuse = !0u; const TTypeParameters* srcTypeParameters = srcType.getTypeParameters(); if (srcTypeParameters->arraySizes == nullptr || srcTypeParameters->arraySizes->getNumDims() != 4) { error(loc, "source cooperative matrix has an unsupported type", "", ""); @@ -2008,7 +2008,7 @@ void TParseContext::handleVector2CoopMatConversionCall(const TSourceLoc& loc, co { //int coopMatKHRuse = srcTypeParameters->arraySizes->getDimSize(3); - uint32_t index = -1u; + uint32_t index = !0u; if (coopMatKHRuse == CM_MatrixUseA) { index = 2; } else if (coopMatKHRuse == CM_MatrixUseB) { @@ -8642,7 +8642,7 @@ static void ForEachOpaque(const TType& type, const TString& path, Function callb for (size_t dimIndex = 0; dimIndex < indices.size(); ++dimIndex) { ++indices[dimIndex]; - if (indices[dimIndex] < type.getArraySizes()->getDimSize(dimIndex)) + if (indices[dimIndex] < type.getArraySizes()->getDimSize(static_cast(dimIndex))) break; else indices[dimIndex] = 0; diff --git a/3rdparty/glslang/glslang/MachineIndependent/iomapper.cpp b/3rdparty/glslang/glslang/MachineIndependent/iomapper.cpp index 26c3eaa62..0e5941a97 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/iomapper.cpp +++ b/3rdparty/glslang/glslang/MachineIndependent/iomapper.cpp @@ -1019,6 +1019,7 @@ uint32_t TDefaultIoResolverBase::computeTypeLocationSize(const TType& type, EShL //TDefaultGlslIoResolver TResourceType TDefaultGlslIoResolver::getResourceType(const glslang::TType& type) { + assert(isValidGlslType(type)); if (isImageType(type)) { return EResImage; } @@ -1034,6 +1035,15 @@ TResourceType TDefaultGlslIoResolver::getResourceType(const glslang::TType& type if (isUboType(type)) { return EResUbo; } + if (isCombinedSamplerType(type)) { + return EResCombinedSampler; + } + if (isAsType(type)) { + return EResAs; + } + if (isTensorType(type)) { + return EResTensor; + } return EResCount; } @@ -1383,6 +1393,7 @@ struct TDefaultIoResolver : public TDefaultIoResolverBase { bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; } TResourceType getResourceType(const glslang::TType& type) override { + assert(isValidGlslType(type)); if (isImageType(type)) { return EResImage; } @@ -1398,6 +1409,15 @@ struct TDefaultIoResolver : public TDefaultIoResolverBase { if (isUboType(type)) { return EResUbo; } + if (isCombinedSamplerType(type)) { + return EResCombinedSampler; + } + if (isAsType(type)) { + return EResAs; + } + if (isTensorType(type)) { + return EResTensor; + } return EResCount; } @@ -1483,6 +1503,11 @@ struct TDefaultHlslIoResolver : public TDefaultIoResolverBase { if (isUboType(type)) { return EResUbo; } + // no support for combined samplers in HLSL + if (isAsType(type)) { + return EResAs; + } + // no support for tensors in HLSL return EResCount; } diff --git a/3rdparty/glslang/glslang/MachineIndependent/iomapper.h b/3rdparty/glslang/glslang/MachineIndependent/iomapper.h index ef513d9a6..de0a0d7dc 100644 --- a/3rdparty/glslang/glslang/MachineIndependent/iomapper.h +++ b/3rdparty/glslang/glslang/MachineIndependent/iomapper.h @@ -120,12 +120,12 @@ protected: } static bool isTextureType(const glslang::TType& type) { - return (type.getBasicType() == glslang::EbtSampler && + return (type.getBasicType() == glslang::EbtSampler && !type.getSampler().isCombined() && (type.getSampler().isTexture() || type.getSampler().isSubpass())); } static bool isUboType(const glslang::TType& type) { - return type.getQualifier().storage == EvqUniform; + return type.getQualifier().storage == EvqUniform && type.isStruct(); } static bool isImageType(const glslang::TType& type) { @@ -136,6 +136,24 @@ protected: return type.getQualifier().storage == EvqBuffer; } + static bool isCombinedSamplerType(const glslang::TType& type) { + return type.getBasicType() == glslang::EbtSampler && type.getSampler().isCombined(); + } + + static bool isAsType(const glslang::TType& type) { + return type.getBasicType() == glslang::EbtAccStruct; + } + + static bool isTensorType(const glslang::TType& type) { + return type.isTensorARM(); + } + + static bool isValidGlslType(const glslang::TType& type) { + // at most one must be true + return (isSamplerType(type) + isTextureType(type) + isUboType(type) + isImageType(type) + + isSsboType(type) + isCombinedSamplerType(type) + isAsType(type) + isTensorType(type)) <= 1; + } + // Return true if this is a SRV (shader resource view) type: static bool isSrvType(const glslang::TType& type) { return isTextureType(type) || type.getQualifier().storage == EvqBuffer; diff --git a/3rdparty/glslang/glslang/Public/ShaderLang.h b/3rdparty/glslang/glslang/Public/ShaderLang.h index 0536cc58f..8ca4ed9ce 100644 --- a/3rdparty/glslang/glslang/Public/ShaderLang.h +++ b/3rdparty/glslang/glslang/Public/ShaderLang.h @@ -434,6 +434,9 @@ enum TResourceType { EResUbo, EResSsbo, EResUav, + EResCombinedSampler, + EResAs, + EResTensor, EResCount }; @@ -463,59 +466,59 @@ enum TBlockStorageClass // // N.B.: Destruct a linked program *before* destructing the shaders linked into it. // -class TShader { +class GLSLANG_EXPORT TShader { public: - GLSLANG_EXPORT explicit TShader(EShLanguage); - GLSLANG_EXPORT virtual ~TShader(); - GLSLANG_EXPORT void setStrings(const char* const* s, int n); - GLSLANG_EXPORT void setStringsWithLengths( + explicit TShader(EShLanguage); + virtual ~TShader(); + void setStrings(const char* const* s, int n); + void setStringsWithLengths( const char* const* s, const int* l, int n); - GLSLANG_EXPORT void setStringsWithLengthsAndNames( + void setStringsWithLengthsAndNames( const char* const* s, const int* l, const char* const* names, int n); void setPreamble(const char* s) { preamble = s; } - GLSLANG_EXPORT void setEntryPoint(const char* entryPoint); - GLSLANG_EXPORT void setSourceEntryPoint(const char* sourceEntryPointName); - GLSLANG_EXPORT void addProcesses(const std::vector&); - GLSLANG_EXPORT void setUniqueId(unsigned long long id); - GLSLANG_EXPORT void setOverrideVersion(int version); - GLSLANG_EXPORT void setDebugInfo(bool debugInfo); + void setEntryPoint(const char* entryPoint); + void setSourceEntryPoint(const char* sourceEntryPointName); + void addProcesses(const std::vector&); + void setUniqueId(unsigned long long id); + void setOverrideVersion(int version); + void setDebugInfo(bool debugInfo); // IO resolver binding data: see comments in ShaderLang.cpp - GLSLANG_EXPORT void setShiftBinding(TResourceType res, unsigned int base); - GLSLANG_EXPORT void setShiftSamplerBinding(unsigned int base); // DEPRECATED: use setShiftBinding - GLSLANG_EXPORT void setShiftTextureBinding(unsigned int base); // DEPRECATED: use setShiftBinding - GLSLANG_EXPORT void setShiftImageBinding(unsigned int base); // DEPRECATED: use setShiftBinding - GLSLANG_EXPORT void setShiftUboBinding(unsigned int base); // DEPRECATED: use setShiftBinding - GLSLANG_EXPORT void setShiftUavBinding(unsigned int base); // DEPRECATED: use setShiftBinding - GLSLANG_EXPORT void setShiftCbufferBinding(unsigned int base); // synonym for setShiftUboBinding - GLSLANG_EXPORT void setShiftSsboBinding(unsigned int base); // DEPRECATED: use setShiftBinding - GLSLANG_EXPORT void setShiftBindingForSet(TResourceType res, unsigned int base, unsigned int set); - GLSLANG_EXPORT void setResourceSetBinding(const std::vector& base); - GLSLANG_EXPORT void setAutoMapBindings(bool map); - GLSLANG_EXPORT void setAutoMapLocations(bool map); - GLSLANG_EXPORT void addUniformLocationOverride(const char* name, int loc); - GLSLANG_EXPORT void setUniformLocationBase(int base); - GLSLANG_EXPORT void setInvertY(bool invert); - GLSLANG_EXPORT void setDxPositionW(bool dxPosW); - GLSLANG_EXPORT void setEnhancedMsgs(); + void setShiftBinding(TResourceType res, unsigned int base); + void setShiftSamplerBinding(unsigned int base); // DEPRECATED: use setShiftBinding + void setShiftTextureBinding(unsigned int base); // DEPRECATED: use setShiftBinding + void setShiftImageBinding(unsigned int base); // DEPRECATED: use setShiftBinding + void setShiftUboBinding(unsigned int base); // DEPRECATED: use setShiftBinding + void setShiftUavBinding(unsigned int base); // DEPRECATED: use setShiftBinding + void setShiftCbufferBinding(unsigned int base); // synonym for setShiftUboBinding + void setShiftSsboBinding(unsigned int base); // DEPRECATED: use setShiftBinding + void setShiftBindingForSet(TResourceType res, unsigned int base, unsigned int set); + void setResourceSetBinding(const std::vector& base); + void setAutoMapBindings(bool map); + void setAutoMapLocations(bool map); + void addUniformLocationOverride(const char* name, int loc); + void setUniformLocationBase(int base); + void setInvertY(bool invert); + void setDxPositionW(bool dxPosW); + void setEnhancedMsgs(); #ifdef ENABLE_HLSL - GLSLANG_EXPORT void setHlslIoMapping(bool hlslIoMap); - GLSLANG_EXPORT void setFlattenUniformArrays(bool flatten); + void setHlslIoMapping(bool hlslIoMap); + void setFlattenUniformArrays(bool flatten); #endif - GLSLANG_EXPORT void setNoStorageFormat(bool useUnknownFormat); - GLSLANG_EXPORT void setNanMinMaxClamp(bool nanMinMaxClamp); - GLSLANG_EXPORT void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode); - GLSLANG_EXPORT void addBlockStorageOverride(const char* nameStr, glslang::TBlockStorageClass backing); + void setNoStorageFormat(bool useUnknownFormat); + void setNanMinMaxClamp(bool nanMinMaxClamp); + void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode); + void addBlockStorageOverride(const char* nameStr, glslang::TBlockStorageClass backing); - GLSLANG_EXPORT void setGlobalUniformBlockName(const char* name); - GLSLANG_EXPORT void setAtomicCounterBlockName(const char* name); - GLSLANG_EXPORT void setGlobalUniformSet(unsigned int set); - GLSLANG_EXPORT void setGlobalUniformBinding(unsigned int binding); - GLSLANG_EXPORT void setAtomicCounterBlockSet(unsigned int set); - GLSLANG_EXPORT void setAtomicCounterBlockBinding(unsigned int binding); + void setGlobalUniformBlockName(const char* name); + void setAtomicCounterBlockName(const char* name); + void setGlobalUniformSet(unsigned int set); + void setGlobalUniformBinding(unsigned int binding); + void setAtomicCounterBlockSet(unsigned int set); + void setAtomicCounterBlockBinding(unsigned int binding); - GLSLANG_EXPORT void addSourceText(const char* text, size_t len); - GLSLANG_EXPORT void setSourceFile(const char* file); + void addSourceText(const char* text, size_t len); + void setSourceFile(const char* file); // For setting up the environment (cleared to nothingness in the constructor). // These must be called so that parsing is done for the right source language and @@ -664,7 +667,7 @@ public: virtual void releaseInclude(IncludeResult*) override { } }; - GLSLANG_EXPORT bool parse( + bool parse( const TBuiltInResource*, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile, bool forwardCompatible, EShMessages, Includer&); @@ -690,14 +693,14 @@ public: // NOTE: Doing just preprocessing to obtain a correct preprocessed shader string // is not an officially supported or fully working path. - GLSLANG_EXPORT bool preprocess( + bool preprocess( const TBuiltInResource* builtInResources, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile, bool forwardCompatible, EShMessages message, std::string* outputString, Includer& includer); - GLSLANG_EXPORT const char* getInfoLog(); - GLSLANG_EXPORT const char* getInfoDebugLog(); + const char* getInfoLog(); + const char* getInfoDebugLog(); EShLanguage getStage() const { return stage; } TIntermediate* getIntermediate() const { return intermediate; } @@ -744,16 +747,16 @@ private: // // Data needed for just a single object at the granularity exchanged by the reflection API -class TObjectReflection { +class GLSLANG_EXPORT TObjectReflection { public: - GLSLANG_EXPORT TObjectReflection(const std::string& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex); + TObjectReflection(const std::string& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex); const TType* getType() const { return type; } - GLSLANG_EXPORT int getBinding() const; - GLSLANG_EXPORT void dump() const; + int getBinding() const; + void dump() const; static TObjectReflection badReflection() { return TObjectReflection(); } - GLSLANG_EXPORT unsigned int layoutLocation() const; + unsigned int layoutLocation() const; std::string name; int offset; @@ -804,8 +807,7 @@ struct TVarEntryInfo; // // NOTE: that still limit checks are applied to bindings and sets // and may result in an error. -class TIoMapResolver -{ +class GLSLANG_EXPORT TIoMapResolver { public: virtual ~TIoMapResolver() {} @@ -877,41 +879,41 @@ GLSLANG_EXPORT TIoMapper* GetGlslIoMapper(); // // N.B.: Destruct a linked program *before* destructing the shaders linked into it. // -class TProgram { +class GLSLANG_EXPORT TProgram { public: - GLSLANG_EXPORT TProgram(); - GLSLANG_EXPORT virtual ~TProgram(); + TProgram(); + virtual ~TProgram(); void addShader(TShader* shader) { stages[shader->stage].push_back(shader); } std::list& getShaders(EShLanguage stage) { return stages[stage]; } // Link Validation interface - GLSLANG_EXPORT bool link(EShMessages); - GLSLANG_EXPORT const char* getInfoLog(); - GLSLANG_EXPORT const char* getInfoDebugLog(); + bool link(EShMessages); + const char* getInfoLog(); + const char* getInfoDebugLog(); TIntermediate* getIntermediate(EShLanguage stage) const { return intermediate[stage]; } // Reflection Interface // call first, to do liveness analysis, index mapping, etc.; returns false on failure - GLSLANG_EXPORT bool buildReflection(int opts = EShReflectionDefault); - GLSLANG_EXPORT unsigned getLocalSize(int dim) const; // return dim'th local size - GLSLANG_EXPORT unsigned getTileShadingRateQCOM(int dim) const; // return dim'th tile shading rate QCOM - GLSLANG_EXPORT int getReflectionIndex(const char *name) const; - GLSLANG_EXPORT int getReflectionPipeIOIndex(const char* name, const bool inOrOut) const; - GLSLANG_EXPORT int getNumUniformVariables() const; - GLSLANG_EXPORT const TObjectReflection& getUniform(int index) const; - GLSLANG_EXPORT int getNumUniformBlocks() const; - GLSLANG_EXPORT const TObjectReflection& getUniformBlock(int index) const; - GLSLANG_EXPORT int getNumPipeInputs() const; - GLSLANG_EXPORT const TObjectReflection& getPipeInput(int index) const; - GLSLANG_EXPORT int getNumPipeOutputs() const; - GLSLANG_EXPORT const TObjectReflection& getPipeOutput(int index) const; - GLSLANG_EXPORT int getNumBufferVariables() const; - GLSLANG_EXPORT const TObjectReflection& getBufferVariable(int index) const; - GLSLANG_EXPORT int getNumBufferBlocks() const; - GLSLANG_EXPORT const TObjectReflection& getBufferBlock(int index) const; - GLSLANG_EXPORT int getNumAtomicCounters() const; - GLSLANG_EXPORT const TObjectReflection& getAtomicCounter(int index) const; + bool buildReflection(int opts = EShReflectionDefault); + unsigned getLocalSize(int dim) const; // return dim'th local size + unsigned getTileShadingRateQCOM(int dim) const; // return dim'th tile shading rate QCOM + int getReflectionIndex(const char *name) const; + int getReflectionPipeIOIndex(const char* name, const bool inOrOut) const; + int getNumUniformVariables() const; + const TObjectReflection& getUniform(int index) const; + int getNumUniformBlocks() const; + const TObjectReflection& getUniformBlock(int index) const; + int getNumPipeInputs() const; + const TObjectReflection& getPipeInput(int index) const; + int getNumPipeOutputs() const; + const TObjectReflection& getPipeOutput(int index) const; + int getNumBufferVariables() const; + const TObjectReflection& getBufferVariable(int index) const; + int getNumBufferBlocks() const; + const TObjectReflection& getBufferBlock(int index) const; + int getNumAtomicCounters() const; + const TObjectReflection& getAtomicCounter(int index) const; // Legacy Reflection Interface - expressed in terms of above interface @@ -978,19 +980,19 @@ public: // returns a TType* const TType *getAttributeTType(int index) const { return getPipeInput(index).getType(); } - GLSLANG_EXPORT void dumpReflection(); + void dumpReflection(); // Get the IO resolver to use for mapIO - GLSLANG_EXPORT TIoMapResolver* getGlslIoResolver(EShLanguage stage); + TIoMapResolver* getGlslIoResolver(EShLanguage stage); // I/O mapping: apply base offsets and map live unbound variables // If resolver is not provided it uses the previous approach // and respects auto assignment and offsets. - GLSLANG_EXPORT bool mapIO(TIoMapResolver* pResolver = nullptr, TIoMapper* pIoMapper = nullptr); + bool mapIO(TIoMapResolver* pResolver = nullptr, TIoMapper* pIoMapper = nullptr); protected: - GLSLANG_EXPORT bool linkStage(EShLanguage, EShMessages); - GLSLANG_EXPORT bool crossStageCheck(EShMessages); + bool linkStage(EShLanguage, EShMessages); + bool crossStageCheck(EShMessages); TPoolAllocator* pool; std::list stages[EShLangCount]; diff --git a/3rdparty/glslang/glslang/Public/resource_limits_c.h b/3rdparty/glslang/glslang/Public/resource_limits_c.h index 3cf7442f4..4ad052b0b 100644 --- a/3rdparty/glslang/glslang/Public/resource_limits_c.h +++ b/3rdparty/glslang/glslang/Public/resource_limits_c.h @@ -46,7 +46,7 @@ GLSLANG_EXPORT const glslang_resource_t* glslang_default_resource(void); // Returns the DefaultTBuiltInResource as a human-readable string. // NOTE: User is responsible for freeing this string. -GLSLANG_EXPORT const char* glslang_default_resource_string(); +GLSLANG_EXPORT const char* glslang_default_resource_string(void); // Decodes the resource limits from |config| to |resources|. GLSLANG_EXPORT void glslang_decode_resource_limits(glslang_resource_t* resources, char* config); diff --git a/3rdparty/glslang/glslang/ResourceLimits/resource_limits_c.cpp b/3rdparty/glslang/glslang/ResourceLimits/resource_limits_c.cpp index 8909d9ef5..64b530846 100644 --- a/3rdparty/glslang/glslang/ResourceLimits/resource_limits_c.cpp +++ b/3rdparty/glslang/glslang/ResourceLimits/resource_limits_c.cpp @@ -42,7 +42,7 @@ const glslang_resource_t* glslang_default_resource(void) return reinterpret_cast(GetDefaultResources()); } -const char* glslang_default_resource_string() +const char* glslang_default_resource_string(void) { std::string cpp_str = GetDefaultTBuiltInResourceString(); char* c_str = (char*)malloc(cpp_str.length() + 1);