diff --git a/renderdoc/driver/shaders/spirv/gen_spirv_code.py b/renderdoc/driver/shaders/spirv/gen_spirv_code.py index e79cd4be9..f5e7c0ba9 100644 --- a/renderdoc/driver/shaders/spirv/gen_spirv_code.py +++ b/renderdoc/driver/shaders/spirv/gen_spirv_code.py @@ -1219,7 +1219,7 @@ std::string ParamToStr(const std::function &idName, const Pa void OpDecoder::AddUsedIDs(std::set &usedids, const ConstIter &it) {{ - switch((rdcspv::Op)it.opcode()) + switch(it.opcode()) {{ {used_ids} case Op::Max: break; @@ -1229,7 +1229,7 @@ void OpDecoder::AddUsedIDs(std::set &usedids, const ConstIter &it) std::string OpDecoder::Disassemble(const ConstIter &it, const std::function &declName, const std::function &idName, const std::function &constIntVal) {{ std::string ret; - switch((rdcspv::Op)it.opcode()) + switch(it.opcode()) {{ {disassemble} case Op::Max: break; @@ -1239,7 +1239,7 @@ std::string OpDecoder::Disassemble(const ConstIter &it, const std::function oldSize) + { + RDCERR("Can't resize up from %zu to %zu", oldSize, newSize); + return *this; + } + + memcpy(&cur(), &op[0], sizeof(uint32_t) * RDCMIN(oldSize, newSize)); + + // set remaining words to NOP if we reduced the size + for(size_t i = newSize; i < oldSize; i++) + word(i) = OpNopWord; + + return *this; +} diff --git a/renderdoc/driver/shaders/spirv/spirv_common.h b/renderdoc/driver/shaders/spirv/spirv_common.h index 609bfc24b..968fe0c9f 100644 --- a/renderdoc/driver/shaders/spirv/spirv_common.h +++ b/renderdoc/driver/shaders/spirv/spirv_common.h @@ -26,7 +26,6 @@ #include #include -#include "3rdparty/glslang/SPIRV/spirv.hpp" #include "api/replay/renderdoc_replay.h" #include "spirv_gen.h" @@ -52,9 +51,9 @@ public: { do { - offset += cur() >> spv::WordCountShift; + offset += cur() >> rdcspv::WordCountShift; // silently skip nops - } while(*this && opcode() == spv::OpNop); + } while(*this && opcode() == rdcspv::Op::Nop); return *this; } @@ -67,10 +66,10 @@ public: // utility functions explicit operator bool() const { return words != NULL && offset < words->size(); } const uint32_t &operator*() const { return cur(); } - spv::Op opcode() const { return spv::Op(cur() & spv::OpCodeMask); } + rdcspv::Op opcode() const { return rdcspv::Op(cur() & rdcspv::OpCodeMask); } const uint32_t &word(size_t idx) const { return words->at(offset + idx); } size_t offs() const { return offset; } - size_t size() const { return cur() >> spv::WordCountShift; } + size_t size() const { return cur() >> rdcspv::WordCountShift; } protected: IterBase() = default; IterBase(ConstOrNotVector &w, size_t o) : words(&w), offset(o) {} @@ -105,6 +104,7 @@ public: void nopRemove(size_t idx, size_t count = 0); // completely remove the operation and replace with NOPs void nopRemove(); + Iter &operator=(const Operation &op); private: friend class Operation; @@ -117,11 +117,9 @@ private: class Operation { public: - // temporary hack so the (unused) generated code will compile - Operation(rdcspv::Op op, const std::vector &data) : Operation((spv::Op)op, data) {} // constructor of a synthetic operation, from an operation & subsequent words, calculates the // length then constructs the first word with opcode + length. - Operation(spv::Op op, const std::vector &data) + Operation(rdcspv::Op op, const std::vector &data) { words.push_back(MakeHeader(op, data.size() + 1)); words.insert(words.begin() + 1, data.begin(), data.end()); @@ -146,6 +144,17 @@ public: return ret; } + // helper for fixed size ops that don't want to generate a temporary vector to use the above + // constructor + template + Operation(const FixedOpHelper &helper) + { + words.resize(WordCopyCount); + memcpy(words.data(), &helper, WordCopyCount * sizeof(uint32_t)); + + iter = Iter(words, 0); + } + // constructor that takes existing words from elsewhere and just references it. // Since this is iterator based, normal iteration invalidation rules apply, if you modify earlier // in the SPIR-V this operation will become invalid. @@ -159,9 +168,9 @@ public: { dest.insert(dest.begin() + offset, begin(), end()); } - inline static uint32_t MakeHeader(spv::Op op, size_t WordCount) + inline static uint32_t MakeHeader(rdcspv::Op op, size_t WordCount) { - return (uint32_t(op) & spv::OpCodeMask) | (uint16_t(WordCount) << spv::WordCountShift); + return (uint32_t(op) & rdcspv::OpCodeMask) | (uint16_t(WordCount) << rdcspv::WordCountShift); } private: @@ -174,6 +183,7 @@ private: // may not be used, if we refer to an external iterator std::vector words; }; + }; // namespace rdcspv DECLARE_STRINGISE_TYPE(rdcspv::Id); diff --git a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp index 0a04e59c8..b88caafbc 100644 --- a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp @@ -30,7 +30,6 @@ #include "maths/formatpacking.h" #include "serialise/serialiser.h" #include "strings/string_utils.h" -#include "spirv_common.h" #undef min #undef max diff --git a/renderdoc/driver/shaders/spirv/spirv_editor.cpp b/renderdoc/driver/shaders/spirv/spirv_editor.cpp index 2249279b5..8867b3020 100644 --- a/renderdoc/driver/shaders/spirv/spirv_editor.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_editor.cpp @@ -22,77 +22,75 @@ * THE SOFTWARE. ******************************************************************************/ -#define SPV_ENABLE_UTILITY_CODE - #include "spirv_editor.h" #include #include #include "common/common.h" #include "serialise/serialiser.h" - -static const uint32_t FirstRealWord = 5; +#include "spirv_op_helpers.h" SPIRVScalar::SPIRVScalar(rdcspv::Iter it) { type = it.opcode(); - if(type == spv::OpTypeInt || type == spv::OpTypeFloat) - width = it.word(2); - else - width = 0; - - if(type == spv::OpTypeInt) - signedness = it.word(3) == 1; - else + if(type == rdcspv::Op::TypeInt) + { + rdcspv::OpTypeInt decoded(it); + width = decoded.width; + signedness = decoded.signedness == 1; + } + else if(type == rdcspv::Op::TypeFloat) + { + rdcspv::OpTypeFloat decoded(it); + width = decoded.width; signedness = false; + } + else + { + width = 0; + signedness = false; + } } rdcspv::Operation SPIRVVector::decl(SPIRVEditor &editor) const { - return rdcspv::Operation(spv::OpTypeVector, {0U, editor.DeclareType(scalar).value(), count}); + return rdcspv::OpTypeVector(rdcspv::Id(), editor.DeclareType(scalar), count); } rdcspv::Operation SPIRVMatrix::decl(SPIRVEditor &editor) const { - return rdcspv::Operation(spv::OpTypeMatrix, {0U, editor.DeclareType(vector).value(), count}); + return rdcspv::OpTypeMatrix(rdcspv::Id(), editor.DeclareType(vector), count); } rdcspv::Operation SPIRVPointer::decl(SPIRVEditor &editor) const { - return rdcspv::Operation(spv::OpTypePointer, {0U, (uint32_t)storage, baseId.value()}); + return rdcspv::OpTypePointer(rdcspv::Id(), storage, baseId); } rdcspv::Operation SPIRVImage::decl(SPIRVEditor &editor) const { - return rdcspv::Operation(spv::OpTypeImage, {0U, editor.DeclareType(retType).value(), (uint32_t)dim, - depth, arrayed, ms, sampled, (uint32_t)format}); + return rdcspv::OpTypeImage(rdcspv::Id(), editor.DeclareType(retType), dim, depth, arrayed, ms, + sampled, format); } rdcspv::Operation SPIRVSampler::decl(SPIRVEditor &editor) const { - return rdcspv::Operation(spv::OpTypeSampler, {0U}); + return rdcspv::OpTypeSampler(rdcspv::Id()); } rdcspv::Operation SPIRVSampledImage::decl(SPIRVEditor &editor) const { - return rdcspv::Operation(spv::OpTypeSampledImage, {0U, baseId.value()}); + return rdcspv::OpTypeSampledImage(rdcspv::Id(), baseId); } rdcspv::Operation SPIRVFunction::decl(SPIRVEditor &editor) const { - std::vector words; - - words.push_back(0U); - words.push_back(returnId.value()); - for(rdcspv::Id id : argumentIds) - words.push_back(id.value()); - - return rdcspv::Operation(spv::OpTypeFunction, words); + return rdcspv::OpTypeFunction(rdcspv::Id(), returnId, argumentIds); } SPIRVEditor::SPIRVEditor(std::vector &spirvWords) : spirv(spirvWords) { - if(spirv.size() < FirstRealWord || spirv[0] != spv::MagicNumber) + if(spirv.size() < rdcspv::FirstRealWord || spirv[0] != rdcspv::MagicNumber) { RDCERR("Empty or invalid SPIR-V module"); return; @@ -133,48 +131,49 @@ SPIRVEditor::SPIRVEditor(std::vector &spirvWords) : spirv(spirvWords) if(sections[section].startOffset == 0) \ sections[section].startOffset = it.offs(); - for(rdcspv::Iter it(spirv, FirstRealWord); it; it++) + for(rdcspv::Iter it(spirv, rdcspv::FirstRealWord); it; it++) { - spv::Op opcode = it.opcode(); + rdcspv::Op opcode = it.opcode(); - if(opcode == spv::OpCapability) + if(opcode == rdcspv::Op::Capability) { START_SECTION(SPIRVSection::Capabilities); } - else if(opcode == spv::OpExtension) + else if(opcode == rdcspv::Op::Extension) { START_SECTION(SPIRVSection::Extensions); } - else if(opcode == spv::OpExtInstImport) + else if(opcode == rdcspv::Op::ExtInstImport) { START_SECTION(SPIRVSection::ExtInst); } - else if(opcode == spv::OpMemoryModel) + else if(opcode == rdcspv::Op::MemoryModel) { START_SECTION(SPIRVSection::MemoryModel); } - else if(opcode == spv::OpEntryPoint) + else if(opcode == rdcspv::Op::EntryPoint) { START_SECTION(SPIRVSection::EntryPoints); } - else if(opcode == spv::OpExecutionMode || opcode == spv::OpExecutionModeId) + else if(opcode == rdcspv::Op::ExecutionMode || opcode == rdcspv::Op::ExecutionModeId) { START_SECTION(SPIRVSection::ExecutionMode); } - else if(opcode == spv::OpString || opcode == spv::OpSource || - opcode == spv::OpSourceContinued || opcode == spv::OpSourceExtension || - opcode == spv::OpName || opcode == spv::OpMemberName || opcode == spv::OpModuleProcessed) + else if(opcode == rdcspv::Op::String || opcode == rdcspv::Op::Source || + opcode == rdcspv::Op::SourceContinued || opcode == rdcspv::Op::SourceExtension || + opcode == rdcspv::Op::Name || opcode == rdcspv::Op::MemberName || + opcode == rdcspv::Op::ModuleProcessed) { START_SECTION(SPIRVSection::Debug); } - else if(opcode == spv::OpDecorate || opcode == spv::OpMemberDecorate || - opcode == spv::OpGroupDecorate || opcode == spv::OpGroupMemberDecorate || - opcode == spv::OpDecorationGroup || opcode == spv::OpDecorateStringGOOGLE || - opcode == spv::OpMemberDecorateStringGOOGLE) + else if(opcode == rdcspv::Op::Decorate || opcode == rdcspv::Op::MemberDecorate || + opcode == rdcspv::Op::GroupDecorate || opcode == rdcspv::Op::GroupMemberDecorate || + opcode == rdcspv::Op::DecorationGroup || opcode == rdcspv::Op::DecorateStringGOOGLE || + opcode == rdcspv::Op::MemberDecorateStringGOOGLE) { START_SECTION(SPIRVSection::Annotations); } - else if(opcode == spv::OpFunction) + else if(opcode == rdcspv::Op::Function) { START_SECTION(SPIRVSection::Functions); } @@ -195,7 +194,7 @@ SPIRVEditor::SPIRVEditor(std::vector &spirvWords) : spirv(spirvWords) #undef START_SECTION // ensure we got everything right. First section should start at the beginning - RDCASSERTEQUAL(sections[SPIRVSection::First].startOffset, FirstRealWord); + RDCASSERTEQUAL(sections[SPIRVSection::First].startOffset, rdcspv::FirstRealWord); // we now set the endOffset of each section to the start of the next. Any empty sections // temporarily have startOffset set to endOffset, we'll pad them with a nop below. @@ -250,7 +249,7 @@ SPIRVEditor::SPIRVEditor(std::vector &spirvWords) : spirv(spirvWords) void SPIRVEditor::StripNops() { - for(size_t i = FirstRealWord; i < spirv.size();) + for(size_t i = rdcspv::FirstRealWord; i < spirv.size();) { while(spirv[i] == rdcspv::OpNopWord) { @@ -258,7 +257,7 @@ void SPIRVEditor::StripNops() addWords(i, -1); } - uint32_t len = spirv[i] >> spv::WordCountShift; + uint32_t len = spirv[i] >> rdcspv::WordCountShift; if(len == 0) { @@ -287,14 +286,14 @@ void SPIRVEditor::SetName(rdcspv::Id id, const char *name) uintName.insert(uintName.begin(), id.value()); - rdcspv::Operation op(spv::OpName, uintName); + rdcspv::Operation op(rdcspv::Op::Name, uintName); rdcspv::Iter it; // OpName must be before OpModuleProcessed. for(it = Begin(SPIRVSection::Debug); it < End(SPIRVSection::Debug); ++it) { - if(it.opcode() == spv::OpModuleProcessed) + if(it.opcode() == rdcspv::Op::ModuleProcessed) break; } @@ -311,30 +310,30 @@ void SPIRVEditor::AddDecoration(const rdcspv::Operation &op) addWords(offset, op.size()); } -void SPIRVEditor::AddCapability(spv::Capability cap) +void SPIRVEditor::AddCapability(rdcspv::Capability cap) { // don't add duplicate capabilities if(capabilities.find(cap) != capabilities.end()) return; // insert the operation at the very start - rdcspv::Operation op(spv::OpCapability, {(uint32_t)cap}); - op.insertInto(spirv, FirstRealWord); - RegisterOp(rdcspv::Iter(spirv, FirstRealWord)); - addWords(FirstRealWord, op.size()); + rdcspv::Operation op(rdcspv::Op::Capability, {(uint32_t)cap}); + op.insertInto(spirv, rdcspv::FirstRealWord); + RegisterOp(rdcspv::Iter(spirv, rdcspv::FirstRealWord)); + addWords(rdcspv::FirstRealWord, op.size()); } -void SPIRVEditor::AddExtension(const std::string &extension) +void SPIRVEditor::AddExtension(const rdcstr &extension) { // don't add duplicate extensions if(extensions.find(extension) != extensions.end()) return; // start at the beginning - rdcspv::Iter it(spirv, FirstRealWord); + rdcspv::Iter it(spirv, rdcspv::FirstRealWord); // skip past any capabilities - while(it.opcode() == spv::OpCapability) + while(it.opcode() == rdcspv::Op::Capability) it++; // insert the extension instruction @@ -342,24 +341,19 @@ void SPIRVEditor::AddExtension(const std::string &extension) std::vector uintName((sz / 4) + 1); memcpy(&uintName[0], extension.c_str(), sz); - rdcspv::Operation op(spv::OpExtension, uintName); + rdcspv::Operation op(rdcspv::Op::Extension, uintName); op.insertInto(spirv, it.offs()); RegisterOp(it); addWords(it.offs(), op.size()); } -void SPIRVEditor::AddExecutionMode(rdcspv::Id entry, spv::ExecutionMode mode, - std::vector params) +void SPIRVEditor::AddExecutionMode(const rdcspv::Operation &mode) { size_t offset = sections[SPIRVSection::ExecutionMode].endOffset; - params.insert(params.begin(), (uint32_t)mode); - params.insert(params.begin(), entry.value()); - - rdcspv::Operation op(spv::OpExecutionMode, params); - op.insertInto(spirv, offset); + mode.insertInto(spirv, offset); RegisterOp(rdcspv::Iter(spirv, offset)); - addWords(offset, op.size()); + addWords(offset, mode.size()); } rdcspv::Id SPIRVEditor::ImportExtInst(const char *setname) @@ -370,10 +364,10 @@ rdcspv::Id SPIRVEditor::ImportExtInst(const char *setname) return ret; // start at the beginning - rdcspv::Iter it(spirv, FirstRealWord); + rdcspv::Iter it(spirv, rdcspv::FirstRealWord); // skip past any capabilities and extensions - while(it.opcode() == spv::OpCapability || it.opcode() == spv::OpExtension) + while(it.opcode() == rdcspv::Op::Capability || it.opcode() == rdcspv::Op::Extension) it++; // insert the import instruction @@ -385,7 +379,7 @@ rdcspv::Id SPIRVEditor::ImportExtInst(const char *setname) uintName.insert(uintName.begin(), ret.value()); - rdcspv::Operation op(spv::OpExtInstImport, uintName); + rdcspv::Operation op(rdcspv::Op::ExtInstImport, uintName); op.insertInto(spirv, it.offs()); RegisterOp(it); addWords(it.offs(), op.size()); @@ -458,7 +452,9 @@ rdcspv::Iter SPIRVEditor::GetEntry(rdcspv::Id id) while(it && it < end) { - if(it.word(2) == id.value()) + rdcspv::OpEntryPoint entry(it); + + if(entry.entryPoint == id.value()) return it; it++; } @@ -468,11 +464,8 @@ rdcspv::Iter SPIRVEditor::GetEntry(rdcspv::Id id) rdcspv::Id SPIRVEditor::DeclareStructType(const std::vector &members) { - std::vector words(members.size()); - memcpy(words.data(), members.data(), words.size() * sizeof(uint32_t)); rdcspv::Id typeId = MakeId(); - words.insert(words.begin(), typeId.value()); - AddType(rdcspv::Operation(spv::OpTypeStruct, words)); + AddType(rdcspv::OpTypeStruct(typeId, members)); return typeId; } @@ -490,363 +483,303 @@ void SPIRVEditor::AddOperation(rdcspv::Iter iter, const rdcspv::Operation &op) void SPIRVEditor::RegisterOp(rdcspv::Iter it) { - spv::Op opcode = it.opcode(); + rdcspv::Op opcode = it.opcode(); + rdcspv::OpDecoder opdata(it); + if(opdata.result != rdcspv::Id() && opdata.resultType != rdcspv::Id()) { - bool hasResult = false, hasResultType = false; - spv::HasResultAndType(opcode, &hasResult, &hasResultType); - - if(hasResult && hasResultType) - { - RDCASSERT(it.word(2) < idTypes.size()); - idTypes[it.word(2)] = rdcspv::Id::fromWord(it.word(1)); - } + RDCASSERT(opdata.result.value() < idTypes.size()); + idTypes[opdata.result.value()] = opdata.resultType; } - if(opcode == spv::OpEntryPoint) - { - SPIRVEntry entry; - entry.id = rdcspv::Id::fromWord(it.word(2)); - entry.name = (const char *)&it.word(3); + if(opdata.result != rdcspv::Id()) + idOffsets[opdata.result.value()] = it.offs(); - entries.push_back(entry); - } - else if(opcode == spv::OpMemoryModel) + if(opcode == rdcspv::Op::EntryPoint) { - addressmodel = (spv::AddressingModel)it.word(2); - memorymodel = (spv::MemoryModel)it.word(3); + entries.push_back(rdcspv::OpEntryPoint(it)); } - else if(opcode == spv::OpCapability) + else if(opcode == rdcspv::Op::MemoryModel) { - capabilities.insert((spv::Capability)it.word(1)); + rdcspv::OpMemoryModel decoded(it); + addressmodel = decoded.addressingModel; + memorymodel = decoded.memoryModel; } - else if(opcode == spv::OpExtension) + else if(opcode == rdcspv::Op::Capability) { - const char *name = (const char *)&it.word(1); - extensions.insert(name); + rdcspv::OpCapability decoded(it); + capabilities.insert(decoded.capability); } - else if(opcode == spv::OpExtInstImport) + else if(opcode == rdcspv::Op::Extension) { - rdcspv::Id id = rdcspv::Id::fromWord(it.word(1)); - const char *name = (const char *)&it.word(2); - extSets[name] = id; + rdcspv::OpExtension decoded(it); + extensions.insert(decoded.name); } - else if(opcode == spv::OpFunction) + else if(opcode == rdcspv::Op::ExtInstImport) { - rdcspv::Id id = rdcspv::Id::fromWord(it.word(2)); - idOffsets[id.value()] = it.offs(); + rdcspv::OpExtInstImport decoded(it); + extSets[decoded.name] = decoded.result; + } + else if(opcode == rdcspv::Op::Function) + { + functions.push_back(opdata.result); + } + else if(opcode == rdcspv::Op::Variable) + { + variables.push_back(rdcspv::OpVariable(it)); + } + else if(opcode == rdcspv::Op::Decorate) + { + rdcspv::OpDecorate decorate(it); - functions.push_back(id); + auto it = std::lower_bound( + decorations.begin(), decorations.end(), decorate, + [](const rdcspv::OpDecorate &a, const rdcspv::OpDecorate &b) { return a < b; }); + decorations.insert(it, decorate); + + if(decorate.decoration == rdcspv::Decoration::DescriptorSet) + bindings[decorate.target].set = decorate.decoration.descriptorSet; + if(decorate.decoration == rdcspv::Decoration::Binding) + bindings[decorate.target].binding = decorate.decoration.binding; } - else if(opcode == spv::OpVariable) + else if(opcode == rdcspv::Op::TypeVoid || opcode == rdcspv::Op::TypeBool || + opcode == rdcspv::Op::TypeInt || opcode == rdcspv::Op::TypeFloat) { - SPIRVVariable var; - var.type = rdcspv::Id::fromWord(it.word(1)); - var.id = rdcspv::Id::fromWord(it.word(2)); - var.storageClass = (spv::StorageClass)it.word(3); - if(it.size() > 4) - var.init = rdcspv::Id::fromWord(it.word(4)); - - variables.push_back(var); - } - else if(opcode == spv::OpDecorate) - { - SPIRVDecoration decoration; - decoration.id = rdcspv::Id::fromWord(it.word(1)); - decoration.dec = (spv::Decoration)it.word(2); - - RDCASSERTMSG("Too many parameters in decoration", it.size() <= 7, it.size()); - - for(size_t i = 0; i + 3 < it.size() && i < ARRAY_COUNT(decoration.parameters); i++) - decoration.parameters[i] = it.word(i + 3); - - auto it = std::lower_bound(decorations.begin(), decorations.end(), decoration); - decorations.insert(it, decoration); - - if(decoration.dec == spv::DecorationDescriptorSet) - bindings[decoration.id].set = decoration.parameters[0]; - if(decoration.dec == spv::DecorationBinding) - bindings[decoration.id].binding = decoration.parameters[0]; - } - else if(opcode == spv::OpTypeVoid || opcode == spv::OpTypeBool || opcode == spv::OpTypeInt || - opcode == spv::OpTypeFloat) - { - rdcspv::Id id = rdcspv::Id::fromWord(it.word(1)); - idOffsets[id.value()] = it.offs(); - SPIRVScalar scalar(it); - scalarTypes[scalar] = id; + scalarTypes[scalar] = opdata.result; } - else if(opcode == spv::OpTypeVector) + else if(opcode == rdcspv::Op::TypeVector) { - rdcspv::Id id = rdcspv::Id::fromWord(it.word(1)); - idOffsets[id.value()] = it.offs(); + rdcspv::OpTypeVector decoded(it); - rdcspv::Iter scalarIt = GetID(rdcspv::Id::fromWord(it.word(2))); + rdcspv::Iter scalarIt = GetID(decoded.componentType); if(!scalarIt) { - RDCERR("Vector type declared with unknown scalar component type %u", it.word(2)); + RDCERR("Vector type declared with unknown scalar component type %u", decoded.componentType); return; } - vectorTypes[SPIRVVector(scalarIt, it.word(3))] = id; + vectorTypes[SPIRVVector(scalarIt, decoded.componentCount)] = decoded.result; } - else if(opcode == spv::OpTypeMatrix) + else if(opcode == rdcspv::Op::TypeMatrix) { - rdcspv::Id id = rdcspv::Id::fromWord(it.word(1)); - idOffsets[id.value()] = it.offs(); + rdcspv::OpTypeMatrix decodedMatrix(it); - rdcspv::Iter vectorIt = GetID(rdcspv::Id::fromWord(it.word(2))); + rdcspv::Iter vectorIt = GetID(decodedMatrix.columnType); if(!vectorIt) { - RDCERR("Matrix type declared with unknown vector component type %u", it.word(2)); + RDCERR("Matrix type declared with unknown vector component type %u", decodedMatrix.columnType); return; } - rdcspv::Iter scalarIt = GetID(rdcspv::Id::fromWord(vectorIt.word(2))); - uint32_t vectorDim = vectorIt.word(3); + rdcspv::OpTypeVector decodedVector(vectorIt); - matrixTypes[SPIRVMatrix(SPIRVVector(scalarIt, vectorDim), it.word(3))] = id; + rdcspv::Iter scalarIt = GetID(decodedVector.componentType); + + matrixTypes[SPIRVMatrix(SPIRVVector(scalarIt, decodedVector.componentCount), + decodedMatrix.columnCount)] = decodedMatrix.result; } - else if(opcode == spv::OpTypeImage) + else if(opcode == rdcspv::Op::TypeImage) { - rdcspv::Id id = rdcspv::Id::fromWord(it.word(1)); - idOffsets[id.value()] = it.offs(); + rdcspv::OpTypeImage decoded(it); - rdcspv::Iter scalarIt = GetID(rdcspv::Id::fromWord(it.word(2))); + rdcspv::Iter scalarIt = GetID(decoded.sampledType); if(!scalarIt) { - RDCERR("Image type declared with unknown scalar component type %u", it.word(2)); + RDCERR("Image type declared with unknown scalar component type %u", decoded.sampledType); return; } - imageTypes[SPIRVImage(scalarIt, (spv::Dim)it.word(3), it.word(4), it.word(5), it.word(6), - it.word(7), (spv::ImageFormat)it.word(8))] = id; + imageTypes[SPIRVImage(scalarIt, decoded.dim, decoded.depth, decoded.arrayed, decoded.mS, + decoded.sampled, decoded.imageFormat)] = decoded.result; } - else if(opcode == spv::OpTypeSampler) + else if(opcode == rdcspv::Op::TypeSampler) { - rdcspv::Id id = rdcspv::Id::fromWord(it.word(1)); - idOffsets[id.value()] = it.offs(); - - samplerTypes[SPIRVSampler()] = id; + samplerTypes[SPIRVSampler()] = opdata.result; } - else if(opcode == spv::OpTypeSampledImage) + else if(opcode == rdcspv::Op::TypeSampledImage) { - rdcspv::Id id = rdcspv::Id::fromWord(it.word(1)); - idOffsets[id.value()] = it.offs(); + rdcspv::OpTypeSampledImage decoded(it); - rdcspv::Id base = rdcspv::Id::fromWord(it.word(2)); - - sampledImageTypes[SPIRVSampledImage(base)] = id; + sampledImageTypes[SPIRVSampledImage(decoded.imageType)] = decoded.result; } - else if(opcode == spv::OpTypePointer) + else if(opcode == rdcspv::Op::TypePointer) { - rdcspv::Id id = rdcspv::Id::fromWord(it.word(1)); - idOffsets[id.value()] = it.offs(); + rdcspv::OpTypePointer decoded(it); - pointerTypes[SPIRVPointer(rdcspv::Id::fromWord(it.word(3)), (spv::StorageClass)it.word(2))] = id; + pointerTypes[SPIRVPointer(decoded.type, decoded.storageClass)] = decoded.result; } - else if(opcode == spv::OpTypeStruct) + else if(opcode == rdcspv::Op::TypeStruct) { - rdcspv::Id id = rdcspv::Id::fromWord(it.word(1)); - idOffsets[id.value()] = it.offs(); - - structTypes.insert(id); + structTypes.insert(opdata.result); } - else if(opcode == spv::OpTypeFunction) + else if(opcode == rdcspv::Op::TypeFunction) { - rdcspv::Id id = rdcspv::Id::fromWord(it.word(1)); - idOffsets[id.value()] = it.offs(); + rdcspv::OpTypeFunction decoded(it); - std::vector args; - - for(size_t i = 3; i < it.size(); i++) - args.push_back(rdcspv::Id::fromWord(it.word(i))); - - functionTypes[SPIRVFunction(rdcspv::Id::fromWord(it.word(2)), args)] = id; + functionTypes[SPIRVFunction(decoded.returnType, decoded.parameters)] = decoded.result; } } void SPIRVEditor::UnregisterOp(rdcspv::Iter it) { - spv::Op opcode = it.opcode(); + rdcspv::Op opcode = it.opcode(); + rdcspv::OpDecoder opdata(it); + if(opdata.result != rdcspv::Id() && opdata.resultType != rdcspv::Id()) + idTypes[opdata.result.value()] = rdcspv::Id(); + + if(opdata.result != rdcspv::Id()) + idOffsets[opdata.result.value()] = 0; + + if(opcode == rdcspv::Op::EntryPoint) { - bool hasResult = false, hasResultType = false; - spv::HasResultAndType(opcode, &hasResult, &hasResultType); + rdcspv::OpEntryPoint decoded(it); - if(hasResult && hasResultType) - idTypes[it.word(2)] = rdcspv::Id(); - } - - rdcspv::Id id; - - if(opcode == spv::OpEntryPoint) - { for(auto entryIt = entries.begin(); entryIt != entries.end(); ++entryIt) { - if(entryIt->id == it.word(2)) + if(entryIt->entryPoint == decoded.entryPoint) { entries.erase(entryIt); break; } } } - else if(opcode == spv::OpFunction) + else if(opcode == rdcspv::Op::Function) { - id = rdcspv::Id::fromWord(it.word(2)); for(auto funcIt = functions.begin(); funcIt != functions.end(); ++funcIt) { - if(*funcIt == id) + if(*funcIt == opdata.result) { functions.erase(funcIt); break; } } } - else if(opcode == spv::OpVariable) + else if(opcode == rdcspv::Op::Variable) { - id = rdcspv::Id::fromWord(it.word(2)); for(auto varIt = variables.begin(); varIt != variables.end(); ++varIt) { - if(varIt->id == id) + if(varIt->result == opdata.result) { variables.erase(varIt); break; } } } - else if(opcode == spv::OpDecorate) + else if(opcode == rdcspv::Op::Decorate) { - SPIRVDecoration decoration; - decoration.id = rdcspv::Id::fromWord(it.word(1)); - decoration.dec = (spv::Decoration)it.word(2); + rdcspv::OpDecorate decorate(it); - RDCASSERTMSG("Too many parameters in decoration", it.size() <= 7, it.size()); - - for(size_t i = 0; i + 3 < it.size() && i < ARRAY_COUNT(decoration.parameters); i++) - decoration.parameters[i] = it.word(i + 3); - - auto it = std::find(decorations.begin(), decorations.end(), decoration); - if(it != decorations.end()) + auto it = std::lower_bound( + decorations.begin(), decorations.end(), decorate, + [](const rdcspv::OpDecorate &a, const rdcspv::OpDecorate &b) { return a < b; }); + if(it != decorations.end() && *it == decorate) decorations.erase(it); - if(decoration.dec == spv::DecorationDescriptorSet) - bindings[decoration.id].set = SPIRVBinding().set; - if(decoration.dec == spv::DecorationBinding) - bindings[decoration.id].binding = SPIRVBinding().binding; + if(decorate.decoration == rdcspv::Decoration::DescriptorSet) + bindings[decorate.target].set = SPIRVBinding().set; + if(decorate.decoration == rdcspv::Decoration::Binding) + bindings[decorate.target].binding = SPIRVBinding().binding; } - else if(opcode == spv::OpCapability) + else if(opcode == rdcspv::Op::Capability) { - capabilities.erase((spv::Capability)it.word(1)); + rdcspv::OpCapability decoded(it); + capabilities.erase(decoded.capability); } - else if(opcode == spv::OpExtension) + else if(opcode == rdcspv::Op::Extension) { - const char *name = (const char *)&it.word(1); - extensions.erase(name); + rdcspv::OpExtension decoded(it); + extensions.erase(decoded.name); } - else if(opcode == spv::OpExtInstImport) + else if(opcode == rdcspv::Op::ExtInstImport) { - const char *name = (const char *)&it.word(2); - extSets.erase(name); + rdcspv::OpExtInstImport decoded(it); + extSets.erase(decoded.name); } - else if(opcode == spv::OpTypeVoid || opcode == spv::OpTypeBool || opcode == spv::OpTypeInt || - opcode == spv::OpTypeFloat) + else if(opcode == rdcspv::Op::TypeVoid || opcode == rdcspv::Op::TypeBool || + opcode == rdcspv::Op::TypeInt || opcode == rdcspv::Op::TypeFloat) { - id = rdcspv::Id::fromWord(it.word(1)); - SPIRVScalar scalar(it); scalarTypes.erase(scalar); } - else if(opcode == spv::OpTypeVector) + else if(opcode == rdcspv::Op::TypeVector) { - id = rdcspv::Id::fromWord(it.word(1)); + rdcspv::OpTypeVector decoded(it); - rdcspv::Iter scalarIt = GetID(rdcspv::Id::fromWord(it.word(2))); + rdcspv::Iter scalarIt = GetID(decoded.componentType); if(!scalarIt) { - RDCERR("Vector type declared with unknown scalar component type %u", it.word(2)); + RDCERR("Vector type declared with unknown scalar component type %u", decoded.componentType); return; } - vectorTypes.erase(SPIRVVector(scalarIt, it.word(3))); + vectorTypes.erase(SPIRVVector(scalarIt, decoded.componentCount)); } - else if(opcode == spv::OpTypeMatrix) + else if(opcode == rdcspv::Op::TypeMatrix) { - id = rdcspv::Id::fromWord(it.word(1)); + rdcspv::OpTypeMatrix decodedMatrix(it); - rdcspv::Iter vectorIt = GetID(rdcspv::Id::fromWord(it.word(2))); + rdcspv::Iter vectorIt = GetID(decodedMatrix.columnType); if(!vectorIt) { - RDCERR("Matrix type declared with unknown vector component type %u", it.word(2)); + RDCERR("Matrix type declared with unknown vector component type %u", decodedMatrix.columnType); return; } - rdcspv::Iter scalarIt = GetID(rdcspv::Id::fromWord(vectorIt.word(2))); - uint32_t vectorDim = vectorIt.word(3); + rdcspv::OpTypeVector decodedVector(vectorIt); - matrixTypes.erase(SPIRVMatrix(SPIRVVector(scalarIt, vectorDim), it.word(3))); + rdcspv::Iter scalarIt = GetID(decodedVector.componentType); + + matrixTypes.erase(SPIRVMatrix(SPIRVVector(scalarIt, decodedVector.componentCount), + decodedMatrix.columnCount)); } - else if(opcode == spv::OpTypeImage) + else if(opcode == rdcspv::Op::TypeImage) { - id = rdcspv::Id::fromWord(it.word(1)); + rdcspv::OpTypeImage decoded(it); - rdcspv::Iter scalarIt = GetID(rdcspv::Id::fromWord(it.word(2))); + rdcspv::Iter scalarIt = GetID(decoded.sampledType); if(!scalarIt) { - RDCERR("Image type declared with unknown scalar component type %u", it.word(2)); + RDCERR("Image type declared with unknown scalar component type %u", decoded.sampledType); return; } - imageTypes.erase(SPIRVImage(scalarIt, (spv::Dim)it.word(3), it.word(4), it.word(5), it.word(6), - it.word(7), (spv::ImageFormat)it.word(8))); + imageTypes.erase(SPIRVImage(scalarIt, decoded.dim, decoded.depth, decoded.arrayed, decoded.mS, + decoded.sampled, decoded.imageFormat)); } - else if(opcode == spv::OpTypeSampler) + else if(opcode == rdcspv::Op::TypeSampler) { - id = rdcspv::Id::fromWord(it.word(1)); - samplerTypes.erase(SPIRVSampler()); } - else if(opcode == spv::OpTypeSampledImage) + else if(opcode == rdcspv::Op::TypeSampledImage) { - id = rdcspv::Id::fromWord(it.word(1)); + rdcspv::OpTypeSampledImage decoded(it); - rdcspv::Id base = rdcspv::Id::fromWord(it.word(2)); - - sampledImageTypes.erase(SPIRVSampledImage(base)); + sampledImageTypes.erase(SPIRVSampledImage(decoded.imageType)); } - else if(opcode == spv::OpTypePointer) + else if(opcode == rdcspv::Op::TypePointer) { - id = rdcspv::Id::fromWord(it.word(1)); + rdcspv::OpTypePointer decoded(it); - pointerTypes.erase(SPIRVPointer(rdcspv::Id::fromWord(it.word(3)), (spv::StorageClass)it.word(2))); + pointerTypes.erase(SPIRVPointer(decoded.type, decoded.storageClass)); } - else if(opcode == spv::OpTypeStruct) + else if(opcode == rdcspv::Op::TypeStruct) { - id = rdcspv::Id::fromWord(it.word(1)); - - structTypes.erase(id); + structTypes.erase(opdata.result); } - else if(opcode == spv::OpTypeFunction) + else if(opcode == rdcspv::Op::TypeFunction) { - id = rdcspv::Id::fromWord(it.word(1)); + rdcspv::OpTypeFunction decoded(it); - std::vector args; - - for(size_t i = 3; i < it.size(); i++) - args.push_back(rdcspv::Id::fromWord(it.word(i))); - - functionTypes.erase(SPIRVFunction(rdcspv::Id::fromWord(it.word(2)), args)); + functionTypes.erase(SPIRVFunction(decoded.returnType, decoded.parameters)); } - - if(id) - idOffsets[id.value()] = 0; } void SPIRVEditor::addWords(size_t offs, int32_t num) @@ -954,7 +887,7 @@ static void CheckSPIRV(SPIRVEditor &ed, size_t offsets[SPIRVSection::Count][2]) // should only be one entry point REQUIRE(ed.GetEntries().size() == 1); - rdcspv::Id entryId = ed.GetEntries()[0].id; + rdcspv::Id entryId = ed.GetEntries()[0].entryPoint; // check that the iterator places us precisely at the start of the functions section CHECK(ed.GetID(entryId).offs() == ed.Begin(SPIRVSection::Functions).offs()); diff --git a/renderdoc/driver/shaders/spirv/spirv_editor.h b/renderdoc/driver/shaders/spirv/spirv_editor.h index 2fc8e6474..d257006f3 100644 --- a/renderdoc/driver/shaders/spirv/spirv_editor.h +++ b/renderdoc/driver/shaders/spirv/spirv_editor.h @@ -32,67 +32,10 @@ #include "api/replay/renderdoc_replay.h" #include "common/common.h" #include "spirv_common.h" +#include "spirv_op_helpers.h" class SPIRVEditor; -struct SPIRVEntry -{ - rdcspv::Id id; - std::string name; -}; - -struct SPIRVVariable -{ - rdcspv::Id id; - rdcspv::Id type; - spv::StorageClass storageClass; - rdcspv::Id init; - - bool operator<(const SPIRVVariable &o) const - { - if(id != o.id) - return id < o.id; - if(type != o.type) - return type < o.type; - if(storageClass != o.storageClass) - return storageClass < o.storageClass; - return init < o.init; - } - - bool operator!=(const SPIRVVariable &o) const { return !operator==(o); } - bool operator==(const SPIRVVariable &o) const - { - return id == o.id && type == o.type && storageClass == o.storageClass && init == o.init; - } -}; - -struct SPIRVDecoration -{ - rdcspv::Id id; - spv::Decoration dec = spv::DecorationMax; - uint32_t parameters[4] = {}; - - bool operator<(const SPIRVDecoration &o) const - { - if(id != o.id) - return id < o.id; - if(dec != o.dec) - return dec < o.dec; - - for(size_t i = 0; i < ARRAY_COUNT(parameters); i++) - if(parameters[i] != o.parameters[i]) - return parameters[i] < o.parameters[i]; - - return false; - } - - bool operator!=(const SPIRVDecoration &o) const { return !operator==(o); } - bool operator==(const SPIRVDecoration &o) const - { - return id == o.id && dec == o.dec && !memcmp(parameters, o.parameters, sizeof(parameters)); - } -}; - struct SPIRVBinding { SPIRVBinding() = default; @@ -113,11 +56,11 @@ struct SPIRVBinding struct SPIRVScalar { - SPIRVScalar() : type(spv::OpMax), width(0), signedness(false) {} - constexpr SPIRVScalar(spv::Op t, uint32_t w, bool s) : type(t), width(w), signedness(s) {} + SPIRVScalar() : type(rdcspv::Op::Max), width(0), signedness(false) {} + constexpr SPIRVScalar(rdcspv::Op t, uint32_t w, bool s) : type(t), width(w), signedness(s) {} SPIRVScalar(rdcspv::Iter op); - spv::Op type; + rdcspv::Op type; uint32_t width; bool signedness; @@ -138,16 +81,16 @@ struct SPIRVScalar rdcspv::Operation decl(SPIRVEditor &editor) const { - if(type == spv::OpTypeVoid) - return rdcspv::Operation(type, {0}); - else if(type == spv::OpTypeBool) - return rdcspv::Operation(type, {0}); - else if(type == spv::OpTypeFloat) - return rdcspv::Operation(type, {0, width}); - else if(type == spv::OpTypeInt) - return rdcspv::Operation(type, {0, width, signedness ? 1U : 0U}); + if(type == rdcspv::Op::TypeVoid) + return rdcspv::OpTypeVoid(rdcspv::Id()); + else if(type == rdcspv::Op::TypeBool) + return rdcspv::OpTypeBool(rdcspv::Id()); + else if(type == rdcspv::Op::TypeFloat) + return rdcspv::OpTypeFloat(rdcspv::Id(), width); + else if(type == rdcspv::Op::TypeInt) + return rdcspv::OpTypeInt(rdcspv::Id(), width, signedness ? 1U : 0U); else - return rdcspv::Operation(spv::OpNop, {0}); + return rdcspv::OpNop(); } }; @@ -162,18 +105,18 @@ inline constexpr SPIRVScalar scalar(); return SPIRVScalar(op, width, sign); \ } -SCALAR_TYPE(void, spv::OpTypeVoid, 0, false); -SCALAR_TYPE(bool, spv::OpTypeBool, 0, false); -SCALAR_TYPE(uint8_t, spv::OpTypeInt, 8, false); -SCALAR_TYPE(uint16_t, spv::OpTypeInt, 16, false); -SCALAR_TYPE(uint32_t, spv::OpTypeInt, 32, false); -SCALAR_TYPE(uint64_t, spv::OpTypeInt, 64, false); -SCALAR_TYPE(int8_t, spv::OpTypeInt, 8, true); -SCALAR_TYPE(int16_t, spv::OpTypeInt, 16, true); -SCALAR_TYPE(int32_t, spv::OpTypeInt, 32, true); -SCALAR_TYPE(int64_t, spv::OpTypeInt, 64, true); -SCALAR_TYPE(float, spv::OpTypeFloat, 32, false); -SCALAR_TYPE(double, spv::OpTypeFloat, 64, false); +SCALAR_TYPE(void, rdcspv::Op::TypeVoid, 0, false); +SCALAR_TYPE(bool, rdcspv::Op::TypeBool, 0, false); +SCALAR_TYPE(uint8_t, rdcspv::Op::TypeInt, 8, false); +SCALAR_TYPE(uint16_t, rdcspv::Op::TypeInt, 16, false); +SCALAR_TYPE(uint32_t, rdcspv::Op::TypeInt, 32, false); +SCALAR_TYPE(uint64_t, rdcspv::Op::TypeInt, 64, false); +SCALAR_TYPE(int8_t, rdcspv::Op::TypeInt, 8, true); +SCALAR_TYPE(int16_t, rdcspv::Op::TypeInt, 16, true); +SCALAR_TYPE(int32_t, rdcspv::Op::TypeInt, 32, true); +SCALAR_TYPE(int64_t, rdcspv::Op::TypeInt, 64, true); +SCALAR_TYPE(float, rdcspv::Op::TypeFloat, 32, false); +SCALAR_TYPE(double, rdcspv::Op::TypeFloat, 64, false); struct SPIRVVector { @@ -213,9 +156,9 @@ struct SPIRVMatrix struct SPIRVPointer { - SPIRVPointer(rdcspv::Id b, spv::StorageClass s) : baseId(b), storage(s) {} + SPIRVPointer(rdcspv::Id b, rdcspv::StorageClass s) : baseId(b), storage(s) {} rdcspv::Id baseId; - spv::StorageClass storage; + rdcspv::StorageClass storage; bool operator<(const SPIRVPointer &o) const { @@ -234,19 +177,19 @@ struct SPIRVPointer struct SPIRVImage { - SPIRVImage(SPIRVScalar ret, spv::Dim d, uint32_t dp, uint32_t ar, uint32_t m, uint32_t samp, - spv::ImageFormat f) + SPIRVImage(SPIRVScalar ret, rdcspv::Dim d, uint32_t dp, uint32_t ar, uint32_t m, uint32_t samp, + rdcspv::ImageFormat f) : retType(ret), dim(d), depth(dp), arrayed(ar), ms(m), sampled(samp), format(f) { } SPIRVScalar retType; - spv::Dim dim; + rdcspv::Dim dim; uint32_t depth; uint32_t arrayed; uint32_t ms; uint32_t sampled; - spv::ImageFormat format; + rdcspv::ImageFormat format; bool operator<(const SPIRVImage &o) const { @@ -295,12 +238,11 @@ struct SPIRVSampledImage struct SPIRVFunction { - SPIRVFunction(rdcspv::Id ret, const std::vector &args) - : returnId(ret), argumentIds(args) + SPIRVFunction(rdcspv::Id ret, const rdcarray &args) : returnId(ret), argumentIds(args) { } rdcspv::Id returnId; - std::vector argumentIds; + rdcarray argumentIds; bool operator<(const SPIRVFunction &o) const { @@ -374,9 +316,9 @@ public: void SetName(rdcspv::Id id, const char *name); void AddDecoration(const rdcspv::Operation &op); - void AddCapability(spv::Capability cap); - void AddExtension(const std::string &extension); - void AddExecutionMode(rdcspv::Id entry, spv::ExecutionMode mode, std::vector params = {}); + void AddCapability(rdcspv::Capability cap); + void AddExtension(const rdcstr &extension); + void AddExecutionMode(const rdcspv::Operation &mode); rdcspv::Id ImportExtInst(const char *setname); rdcspv::Id AddType(const rdcspv::Operation &op); rdcspv::Id AddVariable(const rdcspv::Operation &op); @@ -469,7 +411,7 @@ public: memcpy(&words[2], &t, sizeof(T)); - return AddConstant(rdcspv::Operation(spv::OpConstant, words)); + return AddConstant(rdcspv::Operation(rdcspv::Op::Constant, words)); } // simple properties that are public. @@ -479,12 +421,12 @@ public: } moduleVersion; uint32_t generator = 0; - spv::SourceLanguage sourceLang = spv::SourceLanguageUnknown; + rdcspv::SourceLanguage sourceLang = rdcspv::SourceLanguage::Unknown; uint32_t sourceVer = 0; // accessors to structs/vectors of data - const std::vector &GetEntries() { return entries; } - const std::vector &GetVariables() { return variables; } + const std::vector &GetEntries() { return entries; } + const std::vector &GetVariables() { return variables; } const std::vector &GetFunctions() { return functions; } rdcspv::Id GetIDType(rdcspv::Id id) { return idTypes[id.value()]; } private: @@ -502,23 +444,23 @@ private: LogicalSection sections[SPIRVSection::Count]; - spv::AddressingModel addressmodel; - spv::MemoryModel memorymodel; + rdcspv::AddressingModel addressmodel; + rdcspv::MemoryModel memorymodel; - std::vector decorations; + std::vector decorations; std::map bindings; std::vector idOffsets; std::vector idTypes; - std::vector entries; - std::vector variables; + std::vector entries; + std::vector variables; std::vector functions; - std::set extensions; - std::set capabilities; + std::set extensions; + std::set capabilities; - std::map extSets; + std::map extSets; std::map scalarTypes; std::map vectorTypes; @@ -538,4 +480,19 @@ private: const std::map &GetTable() const; std::vector &spirv; -}; \ No newline at end of file +}; + +inline bool operator<(const rdcspv::OpDecorate &a, const rdcspv::OpDecorate &b) +{ + if(a.target != b.target) + return a.target < b.target; + if(a.decoration.value != b.decoration.value) + return a.decoration.value < b.decoration.value; + + return memcmp(&a.decoration, &b.decoration, sizeof(a.decoration)) < 0; +} + +inline bool operator==(const rdcspv::OpDecorate &a, const rdcspv::OpDecorate &b) +{ + return a.target == b.target && !memcmp(&a.decoration, &b.decoration, sizeof(a.decoration)); +} \ No newline at end of file diff --git a/renderdoc/driver/shaders/spirv/spirv_gen.cpp b/renderdoc/driver/shaders/spirv/spirv_gen.cpp index 607c37f4b..6aec0f858 100644 --- a/renderdoc/driver/shaders/spirv/spirv_gen.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_gen.cpp @@ -1705,7 +1705,7 @@ std::string ParamToStr(const std::function &idName, const rd void OpDecoder::AddUsedIDs(std::set &usedids, const ConstIter &it) { - switch((rdcspv::Op)it.opcode()) + switch(it.opcode()) { case rdcspv::Op::Nop: break; @@ -4629,7 +4629,7 @@ void OpDecoder::AddUsedIDs(std::set &usedids, const ConstIter &it) std::string OpDecoder::Disassemble(const ConstIter &it, const std::function &declName, const std::function &idName, const std::function &constIntVal) { std::string ret; - switch((rdcspv::Op)it.opcode()) + switch(it.opcode()) { case rdcspv::Op::Nop: { @@ -8230,7 +8230,7 @@ std::string OpDecoder::Disassemble(const ConstIter &it, const std::function outpatch = patchData.outputs; rdcspv::Id entryid; - for(const SPIRVEntry &entry : editor.GetEntries()) + for(const rdcspv::OpEntryPoint &entry : editor.GetEntries()) { if(entry.name == entryName) { - entryid = entry.id; + entryid = entry.entryPoint; break; } } @@ -77,8 +77,9 @@ void AddXFBAnnotations(const ShaderReflection &refl, const SPIRVPatchData &patch for(rdcspv::Iter it = editor.Begin(SPIRVSection::ExecutionMode); it < editor.End(SPIRVSection::ExecutionMode); ++it) { - if(it.opcode() == spv::OpExecutionMode && rdcspv::Id::fromWord(it.word(1)) == entryid && - it.word(2) == spv::ExecutionModeXfb) + rdcspv::OpExecutionMode execMode(it); + + if(execMode.entryPoint == entryid && execMode.mode == rdcspv::ExecutionMode::Xfb) { hasXFB = true; break; @@ -91,21 +92,28 @@ void AddXFBAnnotations(const ShaderReflection &refl, const SPIRVPatchData &patch it < editor.End(SPIRVSection::Annotations); ++it) { // remove any existing xfb decorations - if(it.opcode() == spv::OpDecorate && - (it.word(2) == spv::DecorationXfbBuffer || it.word(2) == spv::DecorationXfbStride)) + if(it.opcode() == rdcspv::Op::Decorate) { - editor.Remove(it); + rdcspv::OpDecorate decorate(it); + + if(decorate.decoration == rdcspv::Decoration::XfbBuffer || + decorate.decoration == rdcspv::Decoration::XfbStride) + { + editor.Remove(it); + } } // offset is trickier, need to see if it'll match one we want later - if((it.opcode() == spv::OpDecorate && it.word(2) == spv::DecorationOffset) || - (it.opcode() == spv::OpMemberDecorate && it.word(3) == spv::DecorationOffset)) + if((it.opcode() == rdcspv::Op::Decorate && + rdcspv::OpDecorate(it).decoration == rdcspv::Decoration::Offset) || + (it.opcode() == rdcspv::Op::MemberDecorate && + rdcspv::OpMemberDecorate(it).decoration == rdcspv::Decoration::Offset)) { for(size_t i = 0; i < outsig.size(); i++) { if(outpatch[i].structID) { - if(it.opcode() == spv::OpMemberDecorate && it.word(1) == outpatch[i].structID && + if(it.opcode() == rdcspv::Op::MemberDecorate && it.word(1) == outpatch[i].structID && it.word(2) == outpatch[i].structMemberIndex) { editor.Remove(it); @@ -113,7 +121,7 @@ void AddXFBAnnotations(const ShaderReflection &refl, const SPIRVPatchData &patch } else { - if(it.opcode() == spv::OpDecorate && it.word(1) == outpatch[i].ID) + if(it.opcode() == rdcspv::Op::Decorate && rdcspv::OpDecorate(it).target == outpatch[i].ID) { editor.Remove(it); } @@ -124,10 +132,10 @@ void AddXFBAnnotations(const ShaderReflection &refl, const SPIRVPatchData &patch } else { - editor.AddExecutionMode(entryid, spv::ExecutionModeXfb); + editor.AddExecutionMode(rdcspv::OpExecutionMode(entryid, rdcspv::ExecutionMode::Xfb)); } - editor.AddCapability(spv::CapabilityTransformFeedback); + editor.AddCapability(rdcspv::Capability::TransformFeedback); // find the position output and move it to the front for(size_t i = 0; i < outsig.size(); i++) @@ -149,16 +157,17 @@ void AddXFBAnnotations(const ShaderReflection &refl, const SPIRVPatchData &patch { // do not patch anything as we only patch the base array, but reserve space in the stride } - else if(outpatch[i].structID) + else if(outpatch[i].structID && !outpatch[i].accessChain.empty()) { - editor.AddDecoration(rdcspv::Operation( - spv::OpMemberDecorate, - {outpatch[i].structID, outpatch[i].structMemberIndex, spv::DecorationOffset, xfbStride})); + editor.AddDecoration(rdcspv::OpMemberDecorate( + rdcspv::Id::fromWord(outpatch[i].structID), outpatch[i].structMemberIndex, + rdcspv::DecorationParam(xfbStride))); } else if(outpatch[i].ID) { - editor.AddDecoration(rdcspv::Operation( - spv::OpDecorate, {outpatch[i].ID, (uint32_t)spv::DecorationOffset, xfbStride})); + editor.AddDecoration( + rdcspv::OpDecorate(rdcspv::Id::fromWord(outpatch[i].ID), + rdcspv::DecorationParam(xfbStride))); } uint32_t compByteSize = 4; @@ -176,10 +185,12 @@ void AddXFBAnnotations(const ShaderReflection &refl, const SPIRVPatchData &patch if(outpatch[i].ID && !outpatch[i].isArraySubsequentElement && vars.find(outpatch[i].ID) == vars.end()) { - editor.AddDecoration(rdcspv::Operation( - spv::OpDecorate, {outpatch[i].ID, (uint32_t)spv::DecorationXfbBuffer, 0})); - editor.AddDecoration(rdcspv::Operation( - spv::OpDecorate, {outpatch[i].ID, (uint32_t)spv::DecorationXfbStride, xfbStride})); + editor.AddDecoration( + rdcspv::OpDecorate(rdcspv::Id::fromWord(outpatch[i].ID), + rdcspv::DecorationParam(0))); + editor.AddDecoration( + rdcspv::OpDecorate(rdcspv::Id::fromWord(outpatch[i].ID), + rdcspv::DecorationParam(xfbStride))); vars.insert(outpatch[i].ID); } } diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.h b/renderdoc/driver/shaders/spirv/spirv_reflect.h index 712f1101b..59e06e84f 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.h +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.h @@ -25,7 +25,6 @@ #pragma once #include -#include "3rdparty/glslang/SPIRV/spirv.hpp" #include "api/replay/renderdoc_replay.h" struct SPVInstruction; @@ -72,6 +71,14 @@ struct SPIRVPatchData Topology outTopo = Topology::Unknown; }; +#ifndef spirv_HPP +namespace spv +{ +using SourceLanguage = uint32_t; +using Capability = uint32_t; +}; +#endif + struct SPVModule { SPVModule(); diff --git a/renderdoc/driver/vulkan/vk_bindless_feedback.cpp b/renderdoc/driver/vulkan/vk_bindless_feedback.cpp index 363d81a49..644a280c6 100644 --- a/renderdoc/driver/vulkan/vk_bindless_feedback.cpp +++ b/renderdoc/driver/vulkan/vk_bindless_feedback.cpp @@ -23,9 +23,8 @@ ******************************************************************************/ #include -#include "3rdparty/glslang/SPIRV/GLSL.std.450.h" -#include "3rdparty/glslang/SPIRV/spirv.hpp" #include "driver/shaders/spirv/spirv_editor.h" +#include "driver/shaders/spirv/spirv_op_helpers.h" #include "vk_core.h" #include "vk_debug.h" #include "vk_shader_cache.h" @@ -56,22 +55,19 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, uint64ID = editor.DeclareType(scalar()); int64ID = editor.DeclareType(scalar()); - uint32StructID = editor.AddType( - rdcspv::Operation(spv::OpTypeStruct, {editor.MakeId().value(), uint32ID.value()})); + uint32StructID = editor.AddType(rdcspv::OpTypeStruct(editor.MakeId(), {uint32ID})); // any function parameters we add are uint64 byte offsets funcParamType = uint64ID; } else { - rdcspv::Id runtimeArrayID = editor.AddType( - rdcspv::Operation(spv::OpTypeRuntimeArray, {editor.MakeId().value(), uint32ID.value()})); + rdcspv::Id runtimeArrayID = editor.AddType(rdcspv::OpTypeRuntimeArray(editor.MakeId(), uint32ID)); - editor.AddDecoration(rdcspv::Operation( - spv::OpDecorate, {runtimeArrayID.value(), spv::DecorationArrayStride, sizeof(uint32_t)})); + editor.AddDecoration(rdcspv::OpDecorate( + runtimeArrayID, rdcspv::DecorationParam(sizeof(uint32_t)))); - uint32StructID = editor.AddType( - rdcspv::Operation(spv::OpTypeStruct, {editor.MakeId().value(), runtimeArrayID.value()})); + uint32StructID = editor.AddType(rdcspv::OpTypeStruct(editor.MakeId(), {runtimeArrayID})); // any function parameters we add are uint32 indices funcParamType = uint32ID; @@ -79,8 +75,8 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, editor.SetName(uint32StructID, "__rd_feedbackStruct"); - editor.AddDecoration(rdcspv::Operation(spv::OpMemberDecorate, - {uint32StructID.value(), 0, spv::DecorationOffset, 0})); + editor.AddDecoration(rdcspv::OpMemberDecorate( + uint32StructID, 0, rdcspv::DecorationParam(0))); // map from variable ID to watch, to variable ID to get offset from (as a SPIR-V constant, // or as either uint64 byte offset for buffer addressing or uint32 ssbo index otherwise) @@ -88,16 +84,16 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, // iterate over all variables. We do this here because in the absence of the buffer address // extension we might declare our own below and patch bindings - so we need to look these up now - for(const SPIRVVariable &var : editor.GetVariables()) + for(const rdcspv::OpVariable &var : editor.GetVariables()) { // skip variables without one of these storage classes, as they are not descriptors - if(var.storageClass != spv::StorageClassUniformConstant && - var.storageClass != spv::StorageClassUniform && - var.storageClass != spv::StorageClassStorageBuffer) + if(var.storageClass != rdcspv::StorageClass::UniformConstant && + var.storageClass != rdcspv::StorageClass::Uniform && + var.storageClass != rdcspv::StorageClass::StorageBuffer) continue; // get this variable's binding info - SPIRVBinding bind = editor.GetBinding(var.id); + SPIRVBinding bind = editor.GetBinding(var.result); // if this is one of the bindings we care about auto it = offsetMap.find(bind); @@ -106,7 +102,8 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, // store the offset for this variable so we watch for access chains and know where to store to if(useBufferAddress) { - rdcspv::Id id = varLookup[var.id] = editor.AddConstantImmediate(it->second.offset); + rdcspv::Id id = varLookup[var.result] = + editor.AddConstantImmediate(it->second.offset); editor.SetName( id, StringFormat::Fmt("__feedbackOffset_set%u_bind%u", it->first.set, it->first.binding) @@ -117,7 +114,8 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, // check that the offset fits in 32-bit word, convert byte offset to uint32 index uint64_t index = it->second.offset / 4; RDCASSERT(index < 0xFFFFFFFFULL, bind.set, bind.binding, it->second.offset); - rdcspv::Id id = varLookup[var.id] = editor.AddConstantImmediate(uint32_t(index)); + rdcspv::Id id = varLookup[var.result] = + editor.AddConstantImmediate(uint32_t(index)); editor.SetName( id, StringFormat::Fmt("__feedbackIndex_set%u_bind%u", it->first.set, it->first.binding) @@ -134,30 +132,31 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, editor.AddExtension("SPV_EXT_physical_storage_buffer"); // change the memory model to physical storage buffer 64 - rdcspv::Operation op(editor.Begin(SPIRVSection::MemoryModel)); - op[1] = spv::AddressingModelPhysicalStorageBuffer64EXT; + rdcspv::Iter it = editor.Begin(SPIRVSection::MemoryModel); + rdcspv::OpMemoryModel model(it); + model.addressingModel = rdcspv::AddressingModel::PhysicalStorageBuffer64EXT; + it = model; // add capabilities - editor.AddCapability(spv::CapabilityPhysicalStorageBufferAddressesEXT); - editor.AddCapability(spv::CapabilityInt64); + editor.AddCapability(rdcspv::Capability::PhysicalStorageBufferAddressesEXT); + editor.AddCapability(rdcspv::Capability::Int64); // declare the address constants and make our pointers physical storage buffer pointers bufferAddressConst = editor.AddConstantImmediate(addr); uint32ptrtype = - editor.DeclareType(SPIRVPointer(uint32ID, spv::StorageClassPhysicalStorageBufferEXT)); + editor.DeclareType(SPIRVPointer(uint32ID, rdcspv::StorageClass::PhysicalStorageBufferEXT)); editor.SetName(bufferAddressConst, "__rd_feedbackAddress"); // struct is block decorated - editor.AddDecoration( - rdcspv::Operation(spv::OpDecorate, {uint32StructID.value(), spv::DecorationBlock})); + editor.AddDecoration(rdcspv::OpDecorate(uint32StructID, rdcspv::Decoration::Block)); } else { // the pointers are uniform pointers rdcspv::Id bufptrtype = - editor.DeclareType(SPIRVPointer(uint32StructID, spv::StorageClassUniform)); - uint32ptrtype = editor.DeclareType(SPIRVPointer(uint32ID, spv::StorageClassUniform)); + editor.DeclareType(SPIRVPointer(uint32StructID, rdcspv::StorageClass::Uniform)); + uint32ptrtype = editor.DeclareType(SPIRVPointer(uint32ID, rdcspv::StorageClass::Uniform)); // patch all bindings up by 1 for(rdcspv::Iter it = editor.Begin(SPIRVSection::Annotations), @@ -171,47 +170,50 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, // where all descriptor sets are already used. In theory we only have to do this with set 0, // but that requires knowing which variables are in set 0 and it's simpler to increase all // bindings. - if(it.opcode() == spv::OpDecorate && it.word(2) == spv::DecorationBinding) + if(it.opcode() == rdcspv::Op::Decorate) { - RDCASSERT(it.word(3) != 0xffffffff); - it.word(3) += 1; + rdcspv::OpDecorate dec(it); + if(dec.decoration == rdcspv::Decoration::Binding) + { + RDCASSERT(dec.decoration.binding != 0xffffffff); + dec.decoration.binding += 1; + it = dec; + } } } // add our SSBO variable, at set 0 binding 0 ssboVar = editor.MakeId(); - editor.AddVariable(rdcspv::Operation( - spv::OpVariable, {bufptrtype.value(), ssboVar.value(), spv::StorageClassUniform})); - editor.AddDecoration(rdcspv::Operation( - spv::OpDecorate, {ssboVar.value(), (uint32_t)spv::DecorationDescriptorSet, 0})); + editor.AddDecoration(rdcspv::OpVariable(bufptrtype, ssboVar, rdcspv::StorageClass::Uniform)); editor.AddDecoration( - rdcspv::Operation(spv::OpDecorate, {ssboVar.value(), (uint32_t)spv::DecorationBinding, 0})); + rdcspv::OpDecorate(ssboVar, rdcspv::DecorationParam(0))); + editor.AddDecoration( + rdcspv::OpDecorate(ssboVar, rdcspv::DecorationParam(0))); editor.SetName(ssboVar, "__rd_feedbackBuffer"); // struct is bufferblock decorated - editor.AddDecoration(rdcspv::Operation( - spv::OpDecorate, {uint32StructID.value(), (uint32_t)spv::DecorationBufferBlock})); + editor.AddDecoration(rdcspv::OpDecorate(uint32StructID, rdcspv::Decoration::BufferBlock)); } rdcspv::Id rtarrayOffset = editor.AddConstantImmediate(0U); rdcspv::Id usedValue = editor.AddConstantImmediate(0xFFFFFFFFU); - rdcspv::Id scope = editor.AddConstantImmediate(spv::ScopeInvocation); + rdcspv::Id scope = editor.AddConstantImmediate((uint32_t)rdcspv::Scope::Invocation); rdcspv::Id semantics = editor.AddConstantImmediate(0U); rdcspv::Id uint32shift = editor.AddConstantImmediate(2U); std::map intTypeLookup; for(auto scalarType : editor.GetTypeInfo()) - if(scalarType.first.type == spv::OpTypeInt) + if(scalarType.first.type == rdcspv::Op::TypeInt) intTypeLookup[scalarType.second] = scalarType.first; rdcspv::Id entryID; - for(const SPIRVEntry &entry : editor.GetEntries()) + for(const rdcspv::OpEntryPoint &entry : editor.GetEntries()) { if(entry.name == entryName) { - entryID = entry.id; + entryID = entry.entryPoint; break; } } @@ -245,14 +247,16 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, rdcspv::Iter it = editor.GetID(funcId); - RDCASSERT(it.opcode() == spv::OpFunction); + RDCASSERT(it.opcode() == rdcspv::Op::Function); if(!patchArgIndices.empty()) { + rdcspv::OpFunction func(it); + // find the function's type declaration, add the necessary arguments, redeclare and patch it for(const SPIRVTypeId &funcType : funcTypes) { - if(funcType.second == it.word(4)) + if(funcType.second == func.functionType) { SPIRVFunction patchedFuncType = funcType.first; for(size_t i = 0; i < patchArgIndices.size(); i++) @@ -264,7 +268,13 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, it = editor.GetID(funcId); // change the declared function type - it.word(4) = newFuncTypeID.value(); + func.functionType = newFuncTypeID; + + editor.PreModify(it); + + it = func; + + editor.PostModify(it); break; } @@ -280,13 +290,15 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, size_t argIndex = 0; size_t watchIndex = 0; - while(it.opcode() == spv::OpFunctionParameter) + while(it.opcode() == rdcspv::Op::FunctionParameter) { + rdcspv::OpFunctionParameter param(it); + // if this is a parameter we're patching, add it into varLookup if(watchIndex < patchArgIndices.size() && patchArgIndices[watchIndex] == argIndex) { // when we see use of this parameter, patch it using the added parameter - varLookup[rdcspv::Id::fromWord(it.word(2))] = patchedParamIDs[watchIndex]; + varLookup[param.result] = patchedParamIDs[watchIndex]; // watch for the next argument watchIndex++; } @@ -298,8 +310,7 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, // we're past the existing function parameters, now declare our new ones for(size_t i = 0; i < patchedParamIDs.size(); i++) { - editor.AddOperation(it, rdcspv::Operation(spv::OpFunctionParameter, - {funcParamType.value(), patchedParamIDs[i].value()})); + editor.AddOperation(it, rdcspv::OpFunctionParameter(funcParamType, patchedParamIDs[i])); ++it; } @@ -307,40 +318,42 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, for(; it; ++it) { // finish when we hit the end of the function - if(it.opcode() == spv::OpFunctionEnd) + if(it.opcode() == rdcspv::Op::FunctionEnd) break; // if we see an OpCopyObject, just add it to the map pointing to the same value - if(it.opcode() == spv::OpCopyObject) + if(it.opcode() == rdcspv::Op::CopyObject) { - rdcspv::Id sourcevar = rdcspv::Id::fromWord(it.word(3)); + rdcspv::OpCopyObject copy(it); // is this a var we want to snoop? - auto varIt = varLookup.find(sourcevar); + auto varIt = varLookup.find(copy.operand); if(varIt != varLookup.end()) { - varLookup[rdcspv::Id::fromWord(it.word(2))] = varIt->second; + varLookup[copy.result] = varIt->second; } } - if(it.opcode() == spv::OpFunctionCall) + if(it.opcode() == rdcspv::Op::FunctionCall) { + rdcspv::OpFunctionCall call(it); + // check if any of the variables being passed are ones we care about. Accumulate the added // parameters std::vector funccall; std::vector patchArgs; // examine each argument to see if it's one we care about - for(size_t i = 4; i < it.size(); i++) + for(size_t i = 0; i < call.arguments.size(); i++) { // if this param we're snooping then pass our offset - whether it's a constant or a // function // argument itself - into the function call - auto varIt = varLookup.find(rdcspv::Id::fromWord(it.word(i))); + auto varIt = varLookup.find(call.arguments[i]); if(varIt != varLookup.end()) { funccall.push_back(varIt->second.value()); - patchArgs.push_back(i - 4); + patchArgs.push_back(i); } } @@ -355,35 +368,35 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, // add our patched call afterwards it++; - editor.AddOperation(it, rdcspv::Operation(spv::OpFunctionCall, funccall)); + editor.AddOperation(it, rdcspv::Operation(rdcspv::Op::FunctionCall, funccall)); // remove the old call editor.Remove(oldCall); } // if this function isn't marked for patching yet, and isn't patched, queue it - rdcspv::Id funcid = rdcspv::Id::fromWord(it.word(3)); - if(functionPatchQueue[funcid].empty() && - patchedFunctions.find(funcid) == patchedFunctions.end()) - functionPatchQueue[funcid] = patchArgs; + if(functionPatchQueue[call.function].empty() && + patchedFunctions.find(call.function) == patchedFunctions.end()) + functionPatchQueue[call.function] = patchArgs; } // if we see an access chain of a variable we're snooping, save out the result - if(it.opcode() == spv::OpAccessChain || it.opcode() == spv::OpInBoundsAccessChain) + if(it.opcode() == rdcspv::Op::AccessChain || it.opcode() == rdcspv::Op::InBoundsAccessChain) { - rdcspv::Id sourcevar = rdcspv::Id::fromWord(it.word(3)); + rdcspv::OpAccessChain chain(it); + chain.op = it.opcode(); // is this a var we want to snoop? - auto varIt = varLookup.find(sourcevar); + auto varIt = varLookup.find(chain.base); if(varIt != varLookup.end()) { // multi-dimensional arrays of descriptors is not allowed - however an access chain could // be longer than 5 words (1 index). Think of the case of a uniform buffer where the first // index goes into the descriptor array, and further indices go inside the uniform buffer // members. - RDCASSERT(it.size() >= 5, it.size()); + RDCASSERT(chain.indexes.size() > 1, chain.indexes.size()); - rdcspv::Id index = rdcspv::Id::fromWord(it.word(4)); + rdcspv::Id index = chain.indexes[0]; // patch after the access chain it++; @@ -418,8 +431,7 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, rdcspv::Id unsignedIndex = editor.MakeId(); editor.AddOperation( - it, rdcspv::Operation(spv::OpBitcast, {editor.DeclareType(indexTypeData).value(), - unsignedIndex.value(), index.value()})); + it, rdcspv::OpBitcast(editor.DeclareType(indexTypeData), unsignedIndex, index)); it++; index = unsignedIndex; @@ -429,11 +441,9 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, if(indexTypeData.width != targetIndexWidth) { rdcspv::Id extendedtype = - editor.DeclareType(SPIRVScalar(spv::OpTypeInt, targetIndexWidth, false)); + editor.DeclareType(SPIRVScalar(rdcspv::Op::TypeInt, targetIndexWidth, false)); rdcspv::Id extendedindex = editor.MakeId(); - editor.AddOperation( - it, rdcspv::Operation(spv::OpUConvert, {extendedtype.value(), - extendedindex.value(), index.value()})); + editor.AddOperation(it, rdcspv::OpUConvert(extendedtype, extendedindex, index)); it++; index = extendedindex; @@ -450,33 +460,26 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, // baseaddr = bufferAddressConst + bindingOffset rdcspv::Id baseaddr = editor.MakeId(); editor.AddOperation( - it, - rdcspv::Operation(spv::OpIAdd, {uint64ID.value(), baseaddr.value(), - bufferAddressConst.value(), varIt->second.value()})); + it, rdcspv::OpIAdd(uint64ID, baseaddr, bufferAddressConst, varIt->second)); it++; // shift the index since this is a byte offset // shiftedindex = index << uint32shift rdcspv::Id shiftedindex = editor.MakeId(); - editor.AddOperation(it, rdcspv::Operation(spv::OpShiftLeftLogical, - {uint64ID.value(), shiftedindex.value(), - index.value(), uint32shift.value()})); + editor.AddOperation( + it, rdcspv::OpShiftLeftLogical(uint64ID, shiftedindex, index, uint32shift)); it++; // add the index on top of that // offsetaddr = baseaddr + shiftedindex rdcspv::Id offsetaddr = editor.MakeId(); - editor.AddOperation( - it, rdcspv::Operation(spv::OpIAdd, {uint64ID.value(), offsetaddr.value(), - baseaddr.value(), shiftedindex.value()})); + editor.AddOperation(it, rdcspv::OpIAdd(uint64ID, offsetaddr, baseaddr, shiftedindex)); it++; // make a pointer out of it // uint32_t *bufptr = (uint32_t *)offsetaddr bufptr = editor.MakeId(); - editor.AddOperation( - it, rdcspv::Operation(spv::OpConvertUToPtr, - {uint32ptrtype.value(), bufptr.value(), offsetaddr.value()})); + editor.AddOperation(it, rdcspv::OpConvertUToPtr(uint32ptrtype, bufptr, offsetaddr)); it++; } else @@ -486,27 +489,21 @@ void AnnotateShader(const SPIRVPatchData &patchData, const char *entryName, // add the index to this binding's base index // ssboindex = bindingOffset + index rdcspv::Id ssboindex = editor.MakeId(); - editor.AddOperation( - it, rdcspv::Operation(spv::OpIAdd, {uint32ID.value(), ssboindex.value(), - index.value(), varIt->second.value()})); + editor.AddOperation(it, rdcspv::OpIAdd(uint32ID, ssboindex, index, varIt->second)); it++; // accesschain to get the pointer we'll atomic into. // accesschain is 0 to access rtarray (first member) then ssboindex for array index // uint32_t *bufptr = (uint32_t *)&buf.rtarray[ssboindex]; bufptr = editor.MakeId(); - editor.AddOperation( - it, rdcspv::Operation(spv::OpAccessChain, - {uint32ptrtype.value(), bufptr.value(), ssboVar.value(), - rtarrayOffset.value(), ssboindex.value()})); + editor.AddOperation(it, rdcspv::OpAccessChain(uint32ptrtype, bufptr, ssboVar, + {rtarrayOffset, ssboindex})); it++; } // atomically set the uint32 that's pointed to - editor.AddOperation( - it, rdcspv::Operation(spv::OpAtomicUMax, - {uint32ID.value(), editor.MakeId().value(), bufptr.value(), - scope.value(), semantics.value(), usedValue.value()})); + editor.AddOperation(it, rdcspv::OpAtomicUMax(uint32ID, editor.MakeId(), bufptr, scope, + semantics, usedValue)); // no it++ here, it will happen implicitly on loop continue } diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 149a06801..00f73d123 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -24,7 +24,6 @@ #include "vk_debug.h" #include -#include "3rdparty/glslang/SPIRV/spirv.hpp" #include "data/glsl_shaders.h" #include "driver/ihv/amd/amd_counters.h" #include "driver/ihv/amd/official/GPUPerfAPI/Include/GPUPerfAPI-VK.h" diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index e6c126c34..7c0c19178 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -23,7 +23,6 @@ ******************************************************************************/ #include "vk_info.h" -#include "3rdparty/glslang/SPIRV/spirv.hpp" VkDynamicState ConvertDynamicState(VulkanDynamicStateIndex idx) { diff --git a/renderdoc/driver/vulkan/vk_overlay.cpp b/renderdoc/driver/vulkan/vk_overlay.cpp index bd53d4d94..3cab3ec67 100644 --- a/renderdoc/driver/vulkan/vk_overlay.cpp +++ b/renderdoc/driver/vulkan/vk_overlay.cpp @@ -23,9 +23,9 @@ ******************************************************************************/ #include -#include "3rdparty/glslang/SPIRV/spirv.hpp" #include "data/glsl_shaders.h" #include "driver/shaders/spirv/spirv_common.h" +#include "driver/shaders/spirv/spirv_gen.h" #include "maths/camera.h" #include "maths/formatpacking.h" #include "maths/matrix.h" @@ -145,10 +145,11 @@ struct VulkanQuadOverdrawCallback : public VulkanDrawcallCallback size_t it = 5; while(it < spirv.size()) { - uint16_t WordCount = spirv[it] >> spv::WordCountShift; - spv::Op opcode = spv::Op(spirv[it] & spv::OpCodeMask); + uint16_t WordCount = spirv[it] >> rdcspv::WordCountShift; + rdcspv::Op opcode = rdcspv::Op(spirv[it] & rdcspv::OpCodeMask); - if(opcode == spv::OpDecorate && spirv[it + 2] == spv::DecorationDescriptorSet) + if(opcode == rdcspv::Op::Decorate && + spirv[it + 2] == (uint32_t)rdcspv::Decoration::DescriptorSet) { spirv[it + 3] = descSet; break; @@ -288,10 +289,10 @@ void VulkanDebugManager::PatchFixedColShader(VkShaderModule &mod, float col[4]) size_t it = 5; while(it < spirvLength) { - uint16_t WordCount = alias.spirv[it] >> spv::WordCountShift; - spv::Op opcode = spv::Op(alias.spirv[it] & spv::OpCodeMask); + uint16_t WordCount = alias.spirv[it] >> rdcspv::WordCountShift; + rdcspv::Op opcode = rdcspv::Op(alias.spirv[it] & rdcspv::OpCodeMask); - if(opcode == spv::OpConstant) + if(opcode == rdcspv::Op::Constant) { if(alias.data[it + 3] >= 1.0f && alias.data[it + 3] <= 1.5f) alias.data[it + 3] = col[0]; diff --git a/renderdoc/driver/vulkan/vk_postvs.cpp b/renderdoc/driver/vulkan/vk_postvs.cpp index cbcb36c21..b0cb6410d 100644 --- a/renderdoc/driver/vulkan/vk_postvs.cpp +++ b/renderdoc/driver/vulkan/vk_postvs.cpp @@ -23,13 +23,14 @@ ******************************************************************************/ #include -#include "3rdparty/glslang/SPIRV/GLSL.std.450.h" -#include "3rdparty/glslang/SPIRV/spirv.hpp" #include "driver/shaders/spirv/spirv_editor.h" +#include "driver/shaders/spirv/spirv_op_helpers.h" #include "vk_core.h" #include "vk_debug.h" #include "vk_shader_cache.h" +#undef None + struct VkXfbQueryResult { uint64_t numPrimitivesWritten; @@ -70,10 +71,15 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV // redeclare the descriptor set layouts and pipeline layout. This is inevitable in the case // where all descriptor sets are already used. In theory we only have to do this with set 0, but // that requires knowing which variables are in set 0 and it's simpler to increase all bindings. - if(it.opcode() == spv::OpDecorate && it.word(2) == spv::DecorationBinding) + if(it.opcode() == rdcspv::Op::Decorate) { - RDCASSERT(it.word(3) < (0xffffffff - MeshOutputReservedBindings)); - it.word(3) += MeshOutputReservedBindings; + rdcspv::OpDecorate dec(it); + if(dec.decoration == rdcspv::Decoration::Binding) + { + RDCASSERT(dec.decoration.binding < (0xffffffff - MeshOutputReservedBindings)); + dec.decoration.binding += MeshOutputReservedBindings; + it = dec; + } } } @@ -124,30 +130,30 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV it < end; ++it) { // rewrite any input/output variables to private, and build up inputs/outputs list - if(it.opcode() == spv::OpTypePointer) + if(it.opcode() == rdcspv::Op::TypePointer) { + rdcspv::OpTypePointer ptr(it); + rdcspv::Id id; - if(it.word(2) == spv::StorageClassInput) + if(ptr.storageClass == rdcspv::StorageClass::Input) { - id = rdcspv::Id::fromWord(it.word(1)); + id = ptr.result; inputs.insert(id); } - else if(it.word(2) == spv::StorageClassOutput) + else if(ptr.storageClass == rdcspv::StorageClass::Output) { - id = rdcspv::Id::fromWord(it.word(1)); + id = ptr.result; outputs.insert(id); - rdcspv::Id baseId = rdcspv::Id::fromWord(it.word(3)); - - rdcspv::Iter baseIt = editor.GetID(baseId); - if(baseIt && baseIt.opcode() == spv::OpTypeStruct) - outputs.insert(baseId); + rdcspv::Iter baseIt = editor.GetID(ptr.type); + if(baseIt && baseIt.opcode() == rdcspv::Op::TypeStruct) + outputs.insert(ptr.type); } if(id) { - SPIRVPointer privPtr(rdcspv::Id::fromWord(it.word(3)), spv::StorageClassPrivate); + SPIRVPointer privPtr(ptr.type, rdcspv::StorageClass::Private); rdcspv::Id origId = editor.GetType(privPtr); @@ -164,45 +170,53 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV { editor.PreModify(it); - it.word(2) = spv::StorageClassPrivate; + ptr.storageClass = rdcspv::StorageClass::Private; + it = ptr; // if we didn't already have this pointer, process the modified type declaration editor.PostModify(it); } } } - else if(it.opcode() == spv::OpVariable) + else if(it.opcode() == rdcspv::Op::Variable) { + rdcspv::OpVariable var(it); + bool mod = false; - if(it.word(3) == spv::StorageClassInput) + if(var.storageClass == rdcspv::StorageClass::Input) { mod = true; editor.PreModify(it); - it.word(3) = spv::StorageClassPrivate; - inputs.insert(rdcspv::Id::fromWord(it.word(2))); + var.storageClass = rdcspv::StorageClass::Private; + + inputs.insert(var.result); } - else if(it.word(3) == spv::StorageClassOutput) + else if(var.storageClass == rdcspv::StorageClass::Output) { mod = true; editor.PreModify(it); - it.word(3) = spv::StorageClassPrivate; - outputs.insert(rdcspv::Id::fromWord(it.word(2))); + var.storageClass = rdcspv::StorageClass::Private; + + outputs.insert(var.result); } - auto replIt = typeReplacements.find(rdcspv::Id::fromWord(it.word(1))); + auto replIt = typeReplacements.find(var.resultType); if(replIt != typeReplacements.end()) { if(!mod) editor.PreModify(it); mod = true; - it.word(1) = typeReplacements[rdcspv::Id::fromWord(it.word(1))].value(); + var.resultType = typeReplacements[var.resultType]; } if(mod) + { + it = var; editor.PostModify(it); + } // if we repointed this variable to an existing private declaration, we must also move it to // the end of the section. The reason being that the private pointer type declared may be @@ -218,40 +232,48 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV editor.AddVariable(op); } } - else if(it.opcode() == spv::OpTypeFunction) + else if(it.opcode() == rdcspv::Op::TypeFunction) { + rdcspv::OpTypeFunction func(it); + bool mod = false; - auto replIt = typeReplacements.find(rdcspv::Id::fromWord(it.word(1))); + auto replIt = typeReplacements.find(func.result); if(replIt != typeReplacements.end()) { editor.PreModify(it); mod = true; - it.word(1) = typeReplacements[rdcspv::Id::fromWord(it.word(1))].value(); + func.result = typeReplacements[func.result]; } - for(size_t i = 4; i < it.size(); it++) + for(size_t i = 0; i < func.parameters.size(); it++) { - replIt = typeReplacements.find(rdcspv::Id::fromWord(it.word(i))); + replIt = typeReplacements.find(func.parameters[i]); if(replIt != typeReplacements.end()) { if(!mod) editor.PreModify(it); mod = true; - it.word(i) = typeReplacements[rdcspv::Id::fromWord(it.word(i))].value(); + func.parameters[i] = typeReplacements[func.parameters[i]]; } } if(mod) + { + it = func; editor.PostModify(it); + } } - else if(it.opcode() == spv::OpConstantNull) + else if(it.opcode() == rdcspv::Op::ConstantNull) { - auto replIt = typeReplacements.find(rdcspv::Id::fromWord(it.word(1))); + rdcspv::OpConstantNull nullconst(it); + + auto replIt = typeReplacements.find(nullconst.resultType); if(replIt != typeReplacements.end()) { editor.PreModify(it); - it.word(1) = typeReplacements[rdcspv::Id::fromWord(it.word(1))].value(); + nullconst.resultType = typeReplacements[nullconst.resultType]; + it = nullconst; editor.PostModify(it); } } @@ -260,18 +282,19 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV for(rdcspv::Iter it = editor.Begin(SPIRVSection::Functions); it; ++it) { // identify functions with result types we might want to replace - if(it.opcode() == spv::OpFunction || it.opcode() == spv::OpFunctionParameter || - it.opcode() == spv::OpVariable || it.opcode() == spv::OpAccessChain || - it.opcode() == spv::OpInBoundsAccessChain || it.opcode() == spv::OpBitcast || - it.opcode() == spv::OpUndef || it.opcode() == spv::OpExtInst || - it.opcode() == spv::OpFunctionCall || it.opcode() == spv::OpPhi) + if(it.opcode() == rdcspv::Op::Function || it.opcode() == rdcspv::Op::FunctionParameter || + it.opcode() == rdcspv::Op::Variable || it.opcode() == rdcspv::Op::AccessChain || + it.opcode() == rdcspv::Op::InBoundsAccessChain || it.opcode() == rdcspv::Op::Bitcast || + it.opcode() == rdcspv::Op::Undef || it.opcode() == rdcspv::Op::ExtInst || + it.opcode() == rdcspv::Op::FunctionCall || it.opcode() == rdcspv::Op::Phi) { editor.PreModify(it); - uint32_t &id = it.word(1); - auto replIt = typeReplacements.find(rdcspv::Id::fromWord(id)); + rdcspv::Id id = rdcspv::Id::fromWord(it.word(1)); + auto replIt = typeReplacements.find(id); if(replIt != typeReplacements.end()) - id = typeReplacements[rdcspv::Id::fromWord(id)].value(); + id = typeReplacements[id]; + it.word(1) = id.value(); editor.PostModify(it); } @@ -282,37 +305,42 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV end = editor.End(SPIRVSection::Annotations); it < end; ++it) { - // remove any builtin decorations - if(it.opcode() == spv::OpDecorate && it.word(2) == spv::DecorationBuiltIn) + if(it.opcode() == rdcspv::Op::Decorate) { - // we don't have to do anything, the ID mapping is in the SPIRVPatchData, so just discard the - // location information - editor.Remove(it); - } - - if(it.opcode() == spv::OpMemberDecorate && it.word(3) == spv::DecorationBuiltIn) - editor.Remove(it); - - // remove block decoration from input or output structs - if(it.opcode() == spv::OpDecorate && it.word(2) == spv::DecorationBlock) - { - rdcspv::Id id = rdcspv::Id::fromWord(it.word(1)); - - if(outputs.find(id) != outputs.end() || inputs.find(id) != inputs.end()) + rdcspv::OpDecorate decorate(it); + // remove any builtin decorations + if(decorate.decoration == rdcspv::Decoration::BuiltIn) + { + // we don't have to do anything, the ID mapping is in the SPIRVPatchData, so just discard + // the + // location information editor.Remove(it); + } + // remove all invariant decorations + else if(decorate.decoration == rdcspv::Decoration::Invariant) + { + editor.Remove(it); + } + else if(decorate.decoration == rdcspv::Decoration::Location) + { + // we don't have to do anything, the ID mapping is in the SPIRVPatchData, so just discard + // the location information + editor.Remove(it); + } + // remove block decoration from input or output structs + else if(decorate.decoration == rdcspv::Decoration::Block) + { + if(outputs.find(decorate.target) != outputs.end() || + inputs.find(decorate.target) != inputs.end()) + editor.Remove(it); + } } - // remove all invariant decoreations - if(it.opcode() == spv::OpDecorate && it.word(2) == spv::DecorationInvariant) + if(it.opcode() == rdcspv::Op::MemberDecorate) { - editor.Remove(it); - } - - if(it.opcode() == spv::OpDecorate && it.word(2) == spv::DecorationLocation) - { - // we don't have to do anything, the ID mapping is in the SPIRVPatchData, so just discard the - // location information - editor.Remove(it); + rdcspv::OpMemberDecorate memberDecorate(it); + if(memberDecorate.decoration == rdcspv::Decoration::BuiltIn) + editor.Remove(it); } } @@ -320,12 +348,12 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV std::set entries; - for(const SPIRVEntry &entry : editor.GetEntries()) + for(const rdcspv::OpEntryPoint &entry : editor.GetEntries()) { if(entry.name == entryName) - entryID = entry.id; + entryID = entry.entryPoint; - entries.insert(entry.id); + entries.insert(entry.entryPoint); } RDCASSERT(entryID); @@ -333,20 +361,21 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV for(rdcspv::Iter it = editor.Begin(SPIRVSection::Debug), end2 = editor.End(SPIRVSection::Debug); it < end2; ++it) { - if(it.opcode() == spv::OpName && - (inputs.find(rdcspv::Id::fromWord(it.word(1))) != inputs.end() || - outputs.find(rdcspv::Id::fromWord(it.word(1))) != outputs.end())) + if(it.opcode() == rdcspv::Op::Name) { - rdcspv::Id id = rdcspv::Id::fromWord(it.word(1)); - std::string oldName = (const char *)&it.word(2); - editor.Remove(it); - if(typeReplacements.find(id) == typeReplacements.end()) - editor.SetName(id, ("emulated_" + oldName).c_str()); - } + rdcspv::OpName name(it); - // remove any OpName for the old entry points - if(it.opcode() == spv::OpName && entries.find(rdcspv::Id::fromWord(it.word(1))) != entries.end()) - editor.Remove(it); + if(inputs.find(name.target) != inputs.end() || outputs.find(name.target) != outputs.end()) + { + editor.Remove(it); + if(typeReplacements.find(name.target) == typeReplacements.end()) + editor.SetName(name.target, ("emulated_" + name.name).c_str()); + } + + // remove any OpName for the old entry points + if(entries.find(name.target) != entries.end()) + editor.Remove(it); + } } // declare necessary variables per-output, types and constants. We do this last so that we don't @@ -385,8 +414,8 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV io.basetypeID = editor.DeclareType(scalarType); } - io.uniformPtrID = editor.DeclareType(SPIRVPointer(io.basetypeID, spv::StorageClassUniform)); - io.privatePtrID = editor.DeclareType(SPIRVPointer(io.basetypeID, spv::StorageClassPrivate)); + io.uniformPtrID = editor.DeclareType(SPIRVPointer(io.basetypeID, rdcspv::StorageClass::Uniform)); + io.privatePtrID = editor.DeclareType(SPIRVPointer(io.basetypeID, rdcspv::StorageClass::Private)); RDCASSERT(io.basetypeID && io.vec4ID && io.constID && io.privatePtrID && io.uniformPtrID, io.basetypeID, io.vec4ID, io.constID, io.privatePtrID, io.uniformPtrID); @@ -440,7 +469,7 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV else io.basetypeID = editor.DeclareType(scalarType); - io.privatePtrID = editor.DeclareType(SPIRVPointer(io.basetypeID, spv::StorageClassPrivate)); + io.privatePtrID = editor.DeclareType(SPIRVPointer(io.basetypeID, rdcspv::StorageClass::Private)); RDCASSERT(io.basetypeID && io.vec4ID && io.constID && io.privatePtrID, io.basetypeID, io.vec4ID, io.constID, io.privatePtrID); @@ -473,33 +502,28 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV } tbuffers[tb].imageTypeID = editor.DeclareType( - SPIRVImage(scalarType, spv::DimBuffer, 0, 0, 0, 1, spv::ImageFormatUnknown)); + SPIRVImage(scalarType, rdcspv::Dim::Buffer, 0, 0, 0, 1, rdcspv::ImageFormat::Unknown)); tbuffers[tb].imageSampledTypeID = editor.DeclareType(SPIRVSampledImage(tbuffers[tb].imageTypeID)); rdcspv::Id arrayType = editor.MakeId(); - editor.AddType(rdcspv::Operation( - spv::OpTypeArray, - {arrayType.value(), tbuffers[tb].imageSampledTypeID.value(), arraySize.value()})); + editor.AddType(rdcspv::OpTypeArray(arrayType, tbuffers[tb].imageSampledTypeID, arraySize)); rdcspv::Id arrayPtrType = - editor.DeclareType(SPIRVPointer(arrayType, spv::StorageClassUniformConstant)); + editor.DeclareType(SPIRVPointer(arrayType, rdcspv::StorageClass::UniformConstant)); tbuffers[tb].pointerTypeID = editor.DeclareType( - SPIRVPointer(tbuffers[tb].imageSampledTypeID, spv::StorageClassUniformConstant)); + SPIRVPointer(tbuffers[tb].imageSampledTypeID, rdcspv::StorageClass::UniformConstant)); tbuffers[tb].variableID = editor.MakeId(); - editor.AddVariable(rdcspv::Operation( - spv::OpVariable, - {arrayPtrType.value(), tbuffers[tb].variableID.value(), spv::StorageClassUniformConstant})); + editor.AddVariable(rdcspv::OpVariable(arrayPtrType, tbuffers[tb].variableID, + rdcspv::StorageClass::UniformConstant)); editor.SetName(tbuffers[tb].variableID, name); - editor.AddDecoration(rdcspv::Operation( - spv::OpDecorate, - {tbuffers[tb].variableID.value(), (uint32_t)spv::DecorationDescriptorSet, 0})); - editor.AddDecoration(rdcspv::Operation( - spv::OpDecorate, - {tbuffers[tb].variableID.value(), (uint32_t)spv::DecorationBinding, (uint32_t)tb})); + editor.AddDecoration(rdcspv::OpDecorate( + tbuffers[tb].variableID, rdcspv::DecorationParam(0))); + editor.AddDecoration(rdcspv::OpDecorate( + tbuffers[tb].variableID, rdcspv::DecorationParam(tb))); } rdcspv::Id uint32Vec4ID; @@ -511,29 +535,28 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV { uint32Vec4ID = editor.DeclareType(SPIRVVector(scalar(), 4)); - idxImageTypeID = editor.DeclareType( - SPIRVImage(scalar(), spv::DimBuffer, 0, 0, 0, 1, spv::ImageFormatUnknown)); + idxImageTypeID = editor.DeclareType(SPIRVImage(scalar(), rdcspv::Dim::Buffer, 0, 0, 0, + 1, rdcspv::ImageFormat::Unknown)); idxSampledTypeID = editor.DeclareType(SPIRVSampledImage(idxImageTypeID)); rdcspv::Id idxImagePtrType = - editor.DeclareType(SPIRVPointer(idxSampledTypeID, spv::StorageClassUniformConstant)); + editor.DeclareType(SPIRVPointer(idxSampledTypeID, rdcspv::StorageClass::UniformConstant)); idxImagePtr = editor.MakeId(); - editor.AddVariable(rdcspv::Operation( - spv::OpVariable, - {idxImagePtrType.value(), idxImagePtr.value(), spv::StorageClassUniformConstant})); + editor.AddVariable( + rdcspv::OpVariable(idxImagePtrType, idxImagePtr, rdcspv::StorageClass::UniformConstant)); editor.SetName(idxImagePtr, "ibuffer"); - editor.AddDecoration(rdcspv::Operation( - spv::OpDecorate, {idxImagePtr.value(), (uint32_t)spv::DecorationDescriptorSet, 0})); - editor.AddDecoration(rdcspv::Operation( - spv::OpDecorate, {idxImagePtr.value(), (uint32_t)spv::DecorationBinding, 1})); + editor.AddDecoration(rdcspv::OpDecorate( + idxImagePtr, rdcspv::DecorationParam(0))); + editor.AddDecoration( + rdcspv::OpDecorate(idxImagePtr, rdcspv::DecorationParam(1))); } if(numInputs > 0) { - editor.AddCapability(spv::CapabilitySampledBuffer); + editor.AddCapability(rdcspv::Capability::SampledBuffer); } rdcspv::Id outBufferVarID; @@ -547,17 +570,17 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV // declare the output buffer and its type { - std::vector words; + std::vector members; for(uint32_t o = 0; o < numOutputs; o++) - words.push_back(outs[o].basetypeID); + members.push_back(outs[o].basetypeID); // struct vertex { ... outputs }; - rdcspv::Id vertStructID = editor.DeclareStructType(words); + rdcspv::Id vertStructID = editor.DeclareStructType(members); editor.SetName(vertStructID, "vertex_struct"); // vertex vertArray[]; - rdcspv::Id runtimeArrayID = editor.AddType(rdcspv::Operation( - spv::OpTypeRuntimeArray, {editor.MakeId().value(), vertStructID.value()})); + rdcspv::Id runtimeArrayID = + editor.AddType(rdcspv::OpTypeRuntimeArray(editor.MakeId(), vertStructID)); editor.SetName(runtimeArrayID, "vertex_array"); // struct meshOutput { vertex vertArray[]; }; @@ -566,13 +589,12 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV // meshOutput * rdcspv::Id outputStructPtrID = - editor.DeclareType(SPIRVPointer(outputStructID, spv::StorageClassUniform)); + editor.DeclareType(SPIRVPointer(outputStructID, rdcspv::StorageClass::Uniform)); editor.SetName(outputStructPtrID, "meshOutput_ptr"); // meshOutput *outputData; - outBufferVarID = editor.AddVariable(rdcspv::Operation( - spv::OpVariable, - {outputStructPtrID.value(), editor.MakeId().value(), spv::StorageClassUniform})); + outBufferVarID = editor.AddVariable( + rdcspv::OpVariable(outputStructPtrID, editor.MakeId(), rdcspv::StorageClass::Uniform)); editor.SetName(outBufferVarID, "outputData"); uint32_t memberOffset = 0; @@ -597,8 +619,8 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV memberOffset = AlignUp(memberOffset, 4U * elemSize); // apply decoration to each member in the struct with its offset in the struct - editor.AddDecoration(rdcspv::Operation( - spv::OpMemberDecorate, {vertStructID.value(), o, spv::DecorationOffset, memberOffset})); + editor.AddDecoration(rdcspv::OpMemberDecorate( + vertStructID, o, rdcspv::DecorationParam(memberOffset))); memberOffset += elemSize * refl.outputSignature[o].compCount; } @@ -611,31 +633,31 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV // the array is the only element in the output struct, so // it's at offset 0 - editor.AddDecoration(rdcspv::Operation(spv::OpMemberDecorate, - {outputStructID.value(), 0, spv::DecorationOffset, 0})); + editor.AddDecoration(rdcspv::OpMemberDecorate( + outputStructID, 0, rdcspv::DecorationParam(0))); // set array stride - editor.AddDecoration(rdcspv::Operation( - spv::OpDecorate, {runtimeArrayID.value(), spv::DecorationArrayStride, bufStride})); + editor.AddDecoration(rdcspv::OpDecorate( + runtimeArrayID, rdcspv::DecorationParam(bufStride))); // set object type - editor.AddDecoration( - rdcspv::Operation(spv::OpDecorate, {outputStructID.value(), spv::DecorationBufferBlock})); + editor.AddDecoration(rdcspv::OpDecorate(outputStructID, rdcspv::Decoration::BufferBlock)); // set binding - editor.AddDecoration(rdcspv::Operation( - spv::OpDecorate, {outBufferVarID.value(), spv::DecorationDescriptorSet, 0})); - editor.AddDecoration( - rdcspv::Operation(spv::OpDecorate, {outBufferVarID.value(), spv::DecorationBinding, 0})); + editor.AddDecoration(rdcspv::OpDecorate( + outBufferVarID, rdcspv::DecorationParam(0))); + editor.AddDecoration(rdcspv::OpDecorate( + outBufferVarID, rdcspv::DecorationParam(0))); } rdcspv::Id uint32Vec3ID = editor.DeclareType(SPIRVVector(scalar(), 3)); - rdcspv::Id invocationPtr = editor.DeclareType(SPIRVPointer(uint32Vec3ID, spv::StorageClassInput)); - rdcspv::Id invocationId = editor.AddVariable(rdcspv::Operation( - spv::OpVariable, {invocationPtr.value(), editor.MakeId().value(), spv::StorageClassInput})); - editor.AddDecoration(rdcspv::Operation( - spv::OpDecorate, - {invocationId.value(), spv::DecorationBuiltIn, spv::BuiltInGlobalInvocationId})); + rdcspv::Id invocationPtr = + editor.DeclareType(SPIRVPointer(uint32Vec3ID, rdcspv::StorageClass::Input)); + rdcspv::Id invocationId = editor.AddVariable( + rdcspv::OpVariable(invocationPtr, editor.MakeId(), rdcspv::StorageClass::Input)); + editor.AddDecoration(rdcspv::OpDecorate( + invocationId, + rdcspv::DecorationParam(rdcspv::BuiltIn::GlobalInvocationId))); editor.SetName(invocationId, "rdoc_invocation"); @@ -651,19 +673,21 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV { // there should already have been at least one entry point - RDCASSERT(it.opcode() == spv::OpEntryPoint); - // and it should have been at least 5 words (if not more) since a vertex shader cannot function - // without at least one interface ID. We only need one, so there should be plenty space. - RDCASSERT(it.size() >= 5); + RDCASSERT(it.opcode() == rdcspv::Op::EntryPoint); + + rdcspv::OpEntryPoint entry(it); + // and it should have been at least one interface ID, since a vertex shader must at least write + // position. We only need one, so there should be plenty space. + RDCASSERT(entry.iface.size() >= 1); editor.PreModify(it); - it.nopRemove(5); + entry.executionModel = rdcspv::ExecutionModel::GLCompute; + entry.entryPoint = wrapperEntry; + entry.name = PatchedMeshOutputEntryPoint; + entry.iface = {invocationId}; - it.word(1) = spv::ExecutionModelGLCompute; - it.word(2) = wrapperEntry.value(); - it.word(3) = MAKE_FOURCC('r', 'd', 'c', 0); - it.word(4) = invocationId.value(); + it = entry; editor.PostModify(it); @@ -677,20 +701,19 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV for(it = editor.Begin(SPIRVSection::ExecutionMode); it < editor.End(SPIRVSection::ExecutionMode); ++it) { - if(it.opcode() == spv::OpExecutionMode) + if(it.opcode() == rdcspv::Op::ExecutionMode) { - rdcspv::Id modeEntryID = rdcspv::Id::fromWord(it.word(1)); + rdcspv::OpExecutionMode execMode(it); // We only need to be cautious about what we are stripping for the entry // that we are actually translating, the rest aren't used anyways. - if(modeEntryID == entryID) + if(execMode.entryPoint == entryID) { // Lets check to make sure we don't blindly strip away execution modes that // might actually have an impact on the behaviour of the shader. - spv::ExecutionMode execMode = spv::ExecutionMode(it.word(2)); - switch(execMode) + switch(execMode.mode) { - case spv::ExecutionModeXfb: break; + case rdcspv::ExecutionMode::Xfb: break; default: RDCERR("Unexpected execution mode"); } } @@ -700,7 +723,9 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV } // Add our compute shader execution mode - editor.AddExecutionMode(wrapperEntry, spv::ExecutionModeLocalSize, {MeshOutputDispatchWidth, 1, 1}); + editor.AddExecutionMode(rdcspv::OpExecutionMode( + wrapperEntry, + rdcspv::ExecutionModeParam(MeshOutputDispatchWidth, 1, 1))); rdcspv::Id uint32ID = editor.DeclareType(scalar()); @@ -711,22 +736,17 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV rdcspv::Id voidType = editor.DeclareType(scalar()); rdcspv::Id funcType = editor.DeclareType(SPIRVFunction(voidType, {})); - ops.push_back(rdcspv::Operation( - spv::OpFunction, - {voidType.value(), wrapperEntry.value(), spv::FunctionControlMaskNone, funcType.value()})); + ops.push_back(rdcspv::OpFunction(voidType, wrapperEntry, rdcspv::FunctionControl::None, funcType)); - ops.push_back(rdcspv::Operation(spv::OpLabel, {editor.MakeId().value()})); + ops.push_back(rdcspv::OpLabel(editor.MakeId())); { // uint3 invocationVec = gl_GlobalInvocationID; rdcspv::Id invocationVector = editor.MakeId(); - ops.push_back(rdcspv::Operation( - spv::OpLoad, {uint32Vec3ID.value(), invocationVector.value(), invocationId.value()})); + ops.push_back(rdcspv::OpLoad(uint32Vec3ID, invocationVector, invocationId)); // uint invocation = invocationVec.x rdcspv::Id uintInvocationID = editor.MakeId(); - ops.push_back(rdcspv::Operation( - spv::OpCompositeExtract, - {uint32ID.value(), uintInvocationID.value(), invocationVector.value(), 0U})); + ops.push_back(rdcspv::OpCompositeExtract(uint32ID, uintInvocationID, invocationVector, {0U})); // arraySlotID = uintInvocationID; rdcspv::Id arraySlotID = uintInvocationID; @@ -735,46 +755,37 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV // uint viewinst = uintInvocationID / numVerts rdcspv::Id viewinstID = editor.MakeId(); - ops.push_back( - rdcspv::Operation(spv::OpUDiv, {uint32ID.value(), viewinstID.value(), - uintInvocationID.value(), numVertsConstID.value()})); + ops.push_back(rdcspv::OpUDiv(uint32ID, viewinstID, uintInvocationID, numVertsConstID)); editor.SetName(viewinstID, "viewInstance"); rdcspv::Id instID = editor.MakeId(); - ops.push_back(rdcspv::Operation(spv::OpUMod, {uint32ID.value(), instID.value(), - viewinstID.value(), numInstConstID.value()})); + ops.push_back(rdcspv::OpUMod(uint32ID, instID, viewinstID, numInstConstID)); editor.SetName(instID, "instanceID"); rdcspv::Id viewID = editor.MakeId(); - ops.push_back(rdcspv::Operation(spv::OpUDiv, {uint32ID.value(), viewID.value(), - viewinstID.value(), numInstConstID.value()})); + ops.push_back(rdcspv::OpUDiv(uint32ID, viewID, viewinstID, numInstConstID)); editor.SetName(viewID, "viewID"); // bool inBounds = viewID < numViews; rdcspv::Id inBounds = editor.MakeId(); - ops.push_back(rdcspv::Operation(spv::OpULessThan, - {editor.DeclareType(scalar()).value(), inBounds.value(), - viewID.value(), numViewsConstID.value()})); + ops.push_back(rdcspv::OpULessThan(editor.DeclareType(scalar()), inBounds, viewID, + numViewsConstID)); // if(inBounds) goto continueLabel; else goto killLabel; rdcspv::Id killLabel = editor.MakeId(); rdcspv::Id continueLabel = editor.MakeId(); - ops.push_back(rdcspv::Operation(spv::OpSelectionMerge, - {killLabel.value(), spv::SelectionControlMaskNone})); - ops.push_back(rdcspv::Operation( - spv::OpBranchConditional, {inBounds.value(), continueLabel.value(), killLabel.value()})); + ops.push_back(rdcspv::OpSelectionMerge(killLabel, rdcspv::SelectionControl::None)); + ops.push_back(rdcspv::OpBranchConditional(inBounds, continueLabel, killLabel)); // continueLabel: - ops.push_back(rdcspv::Operation(spv::OpLabel, {continueLabel.value()})); + ops.push_back(rdcspv::OpLabel(continueLabel)); // uint vtx = uintInvocationID % numVerts rdcspv::Id vtxID = editor.MakeId(); - ops.push_back(rdcspv::Operation( - spv::OpUMod, - {uint32ID.value(), vtxID.value(), uintInvocationID.value(), numVertsConstID.value()})); + ops.push_back(rdcspv::OpUMod(uint32ID, vtxID, uintInvocationID, numVertsConstID)); editor.SetName(vtxID, "vertexID"); @@ -786,23 +797,19 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV { // sampledimage idximg = *idximgPtr; rdcspv::Id loaded = editor.MakeId(); - ops.push_back(rdcspv::Operation( - spv::OpLoad, {idxSampledTypeID.value(), loaded.value(), idxImagePtr.value()})); + ops.push_back(rdcspv::OpLoad(idxSampledTypeID, loaded, idxImagePtr)); // image rawimg = imageFromSampled(idximg); rdcspv::Id rawimg = editor.MakeId(); - ops.push_back(rdcspv::Operation(spv::OpImage, - {idxImageTypeID.value(), rawimg.value(), loaded.value()})); + ops.push_back(rdcspv::OpImage(idxImageTypeID, rawimg, loaded)); // uvec4 result = texelFetch(rawimg, vtxID); rdcspv::Id result = editor.MakeId(); - ops.push_back(rdcspv::Operation(spv::OpImageFetch, {uint32Vec4ID.value(), result.value(), - rawimg.value(), vertexIndexID.value()})); + ops.push_back(rdcspv::OpImageFetch(uint32Vec4ID, result, rawimg, vertexIndexID)); // vertexIndex = result.x; vertexIndexID = editor.MakeId(); - ops.push_back(rdcspv::Operation( - spv::OpCompositeExtract, {uint32ID.value(), vertexIndexID.value(), result.value(), 0})); + ops.push_back(rdcspv::OpCompositeExtract(uint32ID, vertexIndexID, result, {0})); } // we use the current value of vertexIndex and use instID, to lookup per-vertex and @@ -817,17 +824,15 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV // for non-indexed draws, we manually apply the vertex offset, but here after we used the // 0-based one to calculate the array slot vertexIndexID = editor.MakeId(); - ops.push_back(rdcspv::Operation( - spv::OpIAdd, {uint32ID.value(), vertexIndexID.value(), vtxID.value(), - editor.AddConstantImmediate(draw->vertexOffset).value()})); + ops.push_back(rdcspv::OpIAdd(uint32ID, vertexIndexID, vtxID, + editor.AddConstantImmediate(draw->vertexOffset))); } editor.SetName(vertexIndexID, "vertexIndex"); // instIndex = inst + instOffset rdcspv::Id instIndexID = editor.MakeId(); - ops.push_back(rdcspv::Operation( - spv::OpIAdd, {uint32ID.value(), instIndexID.value(), instID.value(), - editor.AddConstantImmediate(draw->instanceOffset).value()})); + ops.push_back(rdcspv::OpIAdd(uint32ID, instIndexID, instID, + editor.AddConstantImmediate(draw->instanceOffset))); editor.SetName(instIndexID, "instanceIndex"); rdcspv::Id idxs[64] = {}; @@ -877,17 +882,14 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV { if(refl.inputSignature[i].compType == compType) { - ops.push_back( - rdcspv::Operation(spv::OpStore, {ins[i].variableID.value(), valueID.value()})); + ops.push_back(rdcspv::OpStore(ins[i].variableID, valueID)); } else { rdcspv::Id castedValue = editor.MakeId(); // assume we can just bitcast - ops.push_back(rdcspv::Operation( - spv::OpBitcast, {ins[i].basetypeID.value(), castedValue.value(), valueID.value()})); - ops.push_back(rdcspv::Operation(spv::OpStore, - {ins[i].variableID.value(), castedValue.value()})); + ops.push_back(rdcspv::OpBitcast(ins[i].basetypeID, castedValue, valueID)); + ops.push_back(rdcspv::OpStore(ins[i].variableID, castedValue)); } } else @@ -910,19 +912,16 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV rdcspv::Id ptrId = editor.MakeId(); // sampledimage *imgPtr = xxx_tbuffers[i]; - ops.push_back(rdcspv::Operation( - spv::OpAccessChain, {tb.pointerTypeID.value(), ptrId.value(), tb.variableID.value(), - idxs[refl.inputSignature[i].regIndex].value()})); + ops.push_back(rdcspv::OpAccessChain(tb.pointerTypeID, ptrId, tb.variableID, + {idxs[refl.inputSignature[i].regIndex]})); // sampledimage img = *imgPtr; rdcspv::Id loaded = editor.MakeId(); - ops.push_back(rdcspv::Operation( - spv::OpLoad, {tb.imageSampledTypeID.value(), loaded.value(), ptrId.value()})); + ops.push_back(rdcspv::OpLoad(tb.imageSampledTypeID, loaded, ptrId)); // image rawimg = imageFromSampled(img); rdcspv::Id rawimg = editor.MakeId(); - ops.push_back(rdcspv::Operation( - spv::OpImage, {tb.imageTypeID.value(), rawimg.value(), loaded.value()})); + ops.push_back(rdcspv::OpImage(tb.imageTypeID, rawimg, loaded)); // vec4 result = texelFetch(rawimg, vtxID or instID); rdcspv::Id idx = vertexLookupID; @@ -951,9 +950,7 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV // otherwise we divide by the divisor idx = editor.MakeId(); rdcspv::Id divisorId = editor.AddConstantImmediate(divisor); - ops.push_back(rdcspv::Operation( - spv::OpUDiv, - {uint32ID.value(), idx.value(), instanceLookupID.value(), divisorId.value()})); + ops.push_back(rdcspv::OpUDiv(uint32ID, idx, instanceLookupID, divisorId)); } } @@ -962,14 +959,12 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV // since doubles are packed into two uints, we need to multiply the index by two rdcspv::Id doubled = editor.MakeId(); ops.push_back( - rdcspv::Operation(spv::OpIMul, {uint32ID.value(), doubled.value(), idx.value(), - editor.AddConstantImmediate(2).value()})); + rdcspv::OpIMul(uint32ID, doubled, idx, editor.AddConstantImmediate(2))); idx = doubled; } rdcspv::Id result = editor.MakeId(); - ops.push_back(rdcspv::Operation(spv::OpImageFetch, {ins[i].vec4ID.value(), result.value(), - rawimg.value(), idx.value()})); + ops.push_back(rdcspv::OpImageFetch(ins[i].vec4ID, result, rawimg, idx)); if(refl.inputSignature[i].compType == CompType::Double) { @@ -979,13 +974,10 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV rdcspv::Id nextidx = editor.MakeId(); ops.push_back( - rdcspv::Operation(spv::OpIAdd, {uint32ID.value(), nextidx.value(), idx.value(), - editor.AddConstantImmediate(1).value()})); + rdcspv::OpIAdd(uint32ID, nextidx, idx, editor.AddConstantImmediate(1))); rdcspv::Id result2 = editor.MakeId(); - ops.push_back(rdcspv::Operation( - spv::OpImageFetch, - {ins[i].vec4ID.value(), result2.value(), rawimg.value(), nextidx.value()})); + ops.push_back(rdcspv::OpImageFetch(ins[i].vec4ID, result2, rawimg, nextidx)); rdcspv::Id glsl450 = editor.ImportExtInst("GLSL.std.450"); @@ -998,9 +990,8 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV rdcspv::Id packed = editor.MakeId(); // uvec2 packed = result.[xy/zw] / result2.[xy/zw]; - ops.push_back(rdcspv::Operation(spv::OpVectorShuffle, - {uvec2Type.value(), packed.value(), result.value(), - result2.value(), c * 2 + 0, c * 2 + 1})); + ops.push_back(rdcspv::OpVectorShuffle(uvec2Type, packed, result, result2, + {c * 2 + 0, c * 2 + 1})); char swizzle[] = "xyzw"; @@ -1009,10 +1000,11 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV // double comp = PackDouble2x32(packed); comps[c] = editor.MakeId(); ops.push_back(rdcspv::Operation( - spv::OpExtInst, { - editor.DeclareType(scalar()).value(), comps[c].value(), - glsl450.value(), GLSLstd450PackDouble2x32, packed.value(), - })); + rdcspv::Op::ExtInst, + { + editor.DeclareType(scalar()).value(), comps[c].value(), + glsl450.value(), (uint32_t)rdcspv::GLSLstd450::PackDouble2x32, packed.value(), + })); } // if there's only one component it's ready, otherwise construct a vector @@ -1024,13 +1016,13 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV { result = editor.MakeId(); - std::vector words = {ins[i].basetypeID.value(), result.value()}; + std::vector ids; for(uint32_t c = 0; c < refl.inputSignature[i].compCount; c++) - words.push_back(comps[c].value()); + ids.push_back(comps[c]); // baseTypeN value = result.xyz; - ops.push_back(rdcspv::Operation(spv::OpCompositeConstruct, words)); + ops.push_back(rdcspv::OpCompositeConstruct(ins[i].basetypeID, result, ids)); } } else if(refl.inputSignature[i].compCount == 1) @@ -1041,9 +1033,7 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV result = editor.MakeId(); // baseType value = result.x; - ops.push_back(rdcspv::Operation( - spv::OpCompositeExtract, - {ins[i].basetypeID.value(), result.value(), swizzleIn.value(), 0})); + ops.push_back(rdcspv::OpCompositeExtract(ins[i].basetypeID, result, swizzleIn, {0})); } else if(refl.inputSignature[i].compCount != 4) { @@ -1051,14 +1041,14 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV rdcspv::Id swizzleIn = result; result = editor.MakeId(); - std::vector words = {ins[i].basetypeID.value(), result.value(), - swizzleIn.value(), swizzleIn.value()}; + std::vector swizzle; for(uint32_t c = 0; c < refl.inputSignature[i].compCount; c++) - words.push_back(c); + swizzle.push_back(c); // baseTypeN value = result.xyz; - ops.push_back(rdcspv::Operation(spv::OpVectorShuffle, words)); + ops.push_back( + rdcspv::OpVectorShuffle(ins[i].basetypeID, result, swizzleIn, swizzleIn, swizzle)); } // copy the 4 component result directly @@ -1067,34 +1057,32 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV if(patchData.inputs[i].accessChain.empty()) { // *global = value - ops.push_back( - rdcspv::Operation(spv::OpStore, {ins[i].variableID.value(), result.value()})); + ops.push_back(rdcspv::OpStore(ins[i].variableID, result)); } else { // for composite types we need to access chain first rdcspv::Id subElement = editor.MakeId(); - std::vector words = {ins[i].privatePtrID.value(), subElement.value(), - patchData.inputs[i].ID}; + std::vector chain; for(uint32_t accessIdx : patchData.inputs[i].accessChain) { if(idxs[accessIdx] == 0) idxs[accessIdx] = editor.AddConstantImmediate(accessIdx); - words.push_back(idxs[accessIdx].value()); + chain.push_back(idxs[accessIdx]); } - ops.push_back(rdcspv::Operation(spv::OpAccessChain, words)); + ops.push_back(rdcspv::OpAccessChain(ins[i].privatePtrID, subElement, + rdcspv::Id::fromWord(patchData.inputs[i].ID), chain)); - ops.push_back(rdcspv::Operation(spv::OpStore, {subElement.value(), result.value()})); + ops.push_back(rdcspv::OpStore(subElement, result)); } } } // real_main(); - ops.push_back(rdcspv::Operation( - spv::OpFunctionCall, {voidType.value(), editor.MakeId().value(), entryID.value()})); + ops.push_back(rdcspv::OpFunctionCall(voidType, editor.MakeId(), entryID)); rdcspv::Id zero = editor.AddConstantImmediate(0); @@ -1107,8 +1095,8 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV { loaded = editor.MakeId(); // type loaded = *globalvar; - ops.push_back(rdcspv::Operation( - spv::OpLoad, {outs[o].basetypeID.value(), loaded.value(), patchData.outputs[o].ID})); + ops.push_back(rdcspv::OpLoad(outs[o].basetypeID, loaded, + rdcspv::Id::fromWord(patchData.outputs[o].ID))); } else { @@ -1116,45 +1104,42 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV loaded = editor.MakeId(); // structure member, need to access chain first - std::vector words = {outs[o].privatePtrID.value(), readPtr.value(), - patchData.outputs[o].ID}; + std::vector chain; for(uint32_t idx : patchData.outputs[o].accessChain) { if(idxs[idx] == 0) idxs[idx] = editor.AddConstantImmediate(idx); - words.push_back(idxs[idx].value()); + chain.push_back(idxs[idx]); } // type *readPtr = globalvar.globalsub...; - ops.push_back(rdcspv::Operation(spv::OpAccessChain, words)); + ops.push_back(rdcspv::OpAccessChain( + outs[o].privatePtrID, readPtr, rdcspv::Id::fromWord(patchData.outputs[o].ID), chain)); // type loaded = *readPtr; - ops.push_back(rdcspv::Operation( - spv::OpLoad, {outs[o].basetypeID.value(), loaded.value(), readPtr.value()})); + ops.push_back(rdcspv::OpLoad(outs[o].basetypeID, loaded, readPtr)); } // access chain the destination // type *writePtr = outBuffer.verts[arraySlot].outputN rdcspv::Id writePtr = editor.MakeId(); - ops.push_back(rdcspv::Operation( - spv::OpAccessChain, - {outs[o].uniformPtrID.value(), writePtr.value(), outBufferVarID.value(), zero.value(), - arraySlotID.value(), outs[o].constID.value()})); + ops.push_back(rdcspv::OpAccessChain(outs[o].uniformPtrID, writePtr, outBufferVarID, + {zero, arraySlotID, outs[o].constID})); // *writePtr = loaded; - ops.push_back(rdcspv::Operation(spv::OpStore, {writePtr.value(), loaded.value()})); + ops.push_back(rdcspv::OpStore(writePtr, loaded)); } // goto killLabel; - ops.push_back(rdcspv::Operation(spv::OpBranch, {killLabel.value()})); + ops.push_back(rdcspv::OpBranch(killLabel)); // killLabel: - ops.push_back(rdcspv::Operation(spv::OpLabel, {killLabel.value()})); + ops.push_back(rdcspv::OpLabel(killLabel)); } - ops.push_back(rdcspv::Operation(spv::OpReturn, {})); + ops.push_back(rdcspv::OpReturn()); - ops.push_back(rdcspv::Operation(spv::OpFunctionEnd, {})); + ops.push_back(rdcspv::OpFunctionEnd()); editor.AddFunction(ops.data(), ops.size()); }