diff --git a/renderdoc/driver/shaders/spirv/spirv_editor.cpp b/renderdoc/driver/shaders/spirv/spirv_editor.cpp index 02d9df65c..1f4efeb0e 100644 --- a/renderdoc/driver/shaders/spirv/spirv_editor.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_editor.cpp @@ -27,12 +27,49 @@ #include "common/common.h" #include "serialise/serialiser.h" +static const uint32_t FirstRealWord = 5; + template <> std::string DoStringise(const SPIRVId &el) { return StringFormat::Fmt("%u", el.id); } +void SPIRVOperation::nopRemove(size_t idx, size_t count) +{ + RDCASSERT(idx >= 1); + size_t oldSize = size(); + + if(count == 0) + count = oldSize - idx; + + // reduce the size of this op + *iter = MakeHeader(iter.opcode(), oldSize - count); + + if(idx + count < oldSize) + { + // move any words on the end into the middle, then nop them + for(size_t i = 0; i < count; i++) + { + iter.word(idx + i) = iter.word(idx + count + i); + iter.word(oldSize - i - 1) = SPV_NOP; + } + } + else + { + for(size_t i = 0; i < count; i++) + { + iter.word(idx + i) = SPV_NOP; + } + } +} + +void SPIRVOperation::nopRemove() +{ + for(size_t i = 0, sz = size(); i < sz; i++) + iter.word(i) = SPV_NOP; +} + SPIRVScalar::SPIRVScalar(SPIRVIterator it) { type = it.opcode(); @@ -88,7 +125,7 @@ SPIRVOperation SPIRVFunction::decl(SPIRVEditor &editor) const SPIRVEditor::SPIRVEditor(std::vector &spirvWords) : spirv(spirvWords) { - if(spirv.size() < 5 || spirv[0] != spv::MagicNumber) + if(spirv.size() < FirstRealWord || spirv[0] != spv::MagicNumber) { RDCERR("Empty or invalid SPIR-V module"); return; @@ -102,19 +139,12 @@ SPIRVEditor::SPIRVEditor(std::vector &spirvWords) : spirv(spirvWords) // [4] is reserved RDCASSERT(spirv[4] == 0); - for(SPIRVIterator it(spirv, 5); it; it++) + for(SPIRVIterator it(spirv, FirstRealWord); it; it++) { spv::Op opcode = it.opcode(); - // identify entry points if(opcode == spv::OpEntryPoint) { - SPIRVEntry entry; - entry.id = it.word(2); - entry.name = (const char *)&it.word(3); - - entries.push_back(entry); - // first entry point marks the start of this section if(entryPointSection.startOffset == 0) entryPointSection.startOffset = it.offset; @@ -153,7 +183,6 @@ SPIRVEditor::SPIRVEditor(std::vector &spirvWords) : spirv(spirvWords) } } - // identify functions if(opcode == spv::OpFunction) { // if we don't have the end of the types/variables section, this is it @@ -170,85 +199,15 @@ SPIRVEditor::SPIRVEditor(std::vector &spirvWords) : spirv(spirvWords) decorationSection.startOffset = decorationSection.endOffset = it.offset; } } - - SPIRVId id = it.word(2); - idOffsets[id] = it.offset; - - functions.push_back(id); } - // identify declared scalar/vector/matrix types - if(opcode == spv::OpTypeVoid || opcode == spv::OpTypeBool || opcode == spv::OpTypeInt || - opcode == spv::OpTypeFloat) - { - uint32_t id = it.word(1); - idOffsets[id] = it.offset; - - SPIRVScalar scalar(it); - scalarTypes[scalar] = id; - } - - if(opcode == spv::OpTypeVector) - { - uint32_t id = it.word(1); - idOffsets[id] = it.offset; - - SPIRVIterator scalarIt = GetID(it.word(2)); - - if(!scalarIt) - { - RDCERR("Vector type declared with unknown scalar component type %u", it.word(2)); - continue; - } - - vectorTypes[SPIRVVector(scalarIt, it.word(3))] = id; - } - - if(opcode == spv::OpTypeMatrix) - { - uint32_t id = it.word(1); - idOffsets[id] = it.offset; - - SPIRVIterator vectorIt = GetID(it.word(2)); - - if(!vectorIt) - { - RDCERR("Matrix type declared with unknown vector component type %u", it.word(2)); - continue; - } - - SPIRVIterator scalarIt = GetID(vectorIt.word(2)); - uint32_t vectorDim = vectorIt.word(3); - - matrixTypes[SPIRVMatrix(SPIRVVector(scalarIt, vectorDim), it.word(3))] = id; - } - - if(opcode == spv::OpTypePointer) - { - uint32_t id = it.word(1); - idOffsets[id] = it.offset; - - pointerTypes[SPIRVPointer(it.word(3), (spv::StorageClass)it.word(2))] = id; - } - - if(opcode == spv::OpTypeFunction) - { - uint32_t id = it.word(1); - idOffsets[id] = it.offset; - - std::vector args; - - for(size_t i = 3; i < it.size(); i++) - args.push_back(it.word(i)); - - functionTypes[SPIRVFunction(it.word(2), args)] = id; - } + RegisterOp(it); } } void SPIRVEditor::StripNops() { - for(size_t i = 5; i < spirv.size();) + for(size_t i = FirstRealWord; i < spirv.size();) { while(spirv[i] == SPV_NOP) { @@ -287,12 +246,14 @@ void SPIRVEditor::SetName(uint32_t id, const char *name) SPIRVOperation op(spv::OpName, uintName); spirv.insert(spirv.begin() + debugSection.endOffset, op.begin(), op.end()); + RegisterOp(SPIRVIterator(spirv, debugSection.endOffset)); addWords(debugSection.endOffset, op.size()); } void SPIRVEditor::AddDecoration(const SPIRVOperation &op) { spirv.insert(spirv.begin() + decorationSection.endOffset, op.begin(), op.end()); + RegisterOp(SPIRVIterator(spirv, decorationSection.endOffset)); addWords(decorationSection.endOffset, op.size()); } @@ -301,6 +262,7 @@ SPIRVId SPIRVEditor::AddType(const SPIRVOperation &op) SPIRVId id = op[1]; idOffsets[id] = typeVarSection.endOffset; spirv.insert(spirv.begin() + typeVarSection.endOffset, op.begin(), op.end()); + RegisterOp(SPIRVIterator(spirv, typeVarSection.endOffset)); addWords(typeVarSection.endOffset, op.size()); return id; } @@ -310,6 +272,7 @@ SPIRVId SPIRVEditor::AddVariable(const SPIRVOperation &op) SPIRVId id = op[2]; idOffsets[id] = typeVarSection.endOffset; spirv.insert(spirv.begin() + typeVarSection.endOffset, op.begin(), op.end()); + RegisterOp(SPIRVIterator(spirv, typeVarSection.endOffset)); addWords(typeVarSection.endOffset, op.size()); return id; } @@ -319,6 +282,7 @@ SPIRVId SPIRVEditor::AddConstant(const SPIRVOperation &op) SPIRVId id = op[2]; idOffsets[id] = typeVarSection.endOffset; spirv.insert(spirv.begin() + typeVarSection.endOffset, op.begin(), op.end()); + RegisterOp(SPIRVIterator(spirv, typeVarSection.endOffset)); addWords(typeVarSection.endOffset, op.size()); return id; } @@ -329,6 +293,8 @@ void SPIRVEditor::AddFunction(const SPIRVOperation *ops, size_t count) for(size_t i = 0; i < count; i++) spirv.insert(spirv.end(), ops[i].begin(), ops[i].end()); + + RegisterOp(SPIRVIterator(spirv, idOffsets[ops[0][2]])); } SPIRVIterator SPIRVEditor::GetID(SPIRVId id) @@ -431,6 +397,250 @@ void SPIRVEditor::AddWord(SPIRVIterator iter, uint32_t word) addWords(iter.offset + iter.size(), 1); } +void SPIRVEditor::AddOperation(SPIRVIterator iter, const SPIRVOperation &op) +{ + if(!iter) + return; + + // if it's just pointing at a SPIRVOperation, this is invalid + if(iter.words != &spirv) + return; + + // add op + spirv.insert(spirv.begin() + iter.offset, op.begin(), op.end()); + + // update offsets + addWords(iter.offset, op.size()); +} + +void SPIRVEditor::RegisterOp(SPIRVIterator it) +{ + spv::Op opcode = it.opcode(); + + if(opcode == spv::OpEntryPoint) + { + SPIRVEntry entry; + entry.id = it.word(2); + entry.name = (const char *)&it.word(3); + + entries.push_back(entry); + } + else if(opcode == spv::OpFunction) + { + SPIRVId id = it.word(2); + idOffsets[id] = it.offset; + + functions.push_back(id); + } + else if(opcode == spv::OpTypeVoid || opcode == spv::OpTypeBool || opcode == spv::OpTypeInt || + opcode == spv::OpTypeFloat) + { + SPIRVId id = it.word(1); + idOffsets[id] = it.offset; + + SPIRVScalar scalar(it); + scalarTypes[scalar] = id; + } + else if(opcode == spv::OpTypeVector) + { + SPIRVId id = it.word(1); + idOffsets[id] = it.offset; + + SPIRVIterator scalarIt = GetID(it.word(2)); + + if(!scalarIt) + { + RDCERR("Vector type declared with unknown scalar component type %u", it.word(2)); + return; + } + + vectorTypes[SPIRVVector(scalarIt, it.word(3))] = id; + } + else if(opcode == spv::OpTypeMatrix) + { + SPIRVId id = it.word(1); + idOffsets[id] = it.offset; + + SPIRVIterator vectorIt = GetID(it.word(2)); + + if(!vectorIt) + { + RDCERR("Matrix type declared with unknown vector component type %u", it.word(2)); + return; + } + + SPIRVIterator scalarIt = GetID(vectorIt.word(2)); + uint32_t vectorDim = vectorIt.word(3); + + matrixTypes[SPIRVMatrix(SPIRVVector(scalarIt, vectorDim), it.word(3))] = id; + } + else if(opcode == spv::OpTypeImage) + { + SPIRVId id = it.word(1); + idOffsets[id] = it.offset; + + SPIRVIterator scalarIt = GetID(it.word(2)); + + if(!scalarIt) + { + RDCERR("Image type declared with unknown scalar component type %u", it.word(2)); + 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; + } + else if(opcode == spv::OpTypeSampledImage) + { + SPIRVId id = it.word(1); + idOffsets[id] = it.offset; + + SPIRVId base = it.word(2); + + sampledImageTypes[SPIRVSampledImage(base)] = id; + } + else if(opcode == spv::OpTypePointer) + { + SPIRVId id = it.word(1); + idOffsets[id] = it.offset; + + pointerTypes[SPIRVPointer(it.word(3), (spv::StorageClass)it.word(2))] = id; + } + else if(opcode == spv::OpTypeStruct) + { + idOffsets[it.word(1)] = it.offset; + } + else if(opcode == spv::OpTypeFunction) + { + SPIRVId id = it.word(1); + idOffsets[id] = it.offset; + + std::vector args; + + for(size_t i = 3; i < it.size(); i++) + args.push_back(it.word(i)); + + functionTypes[SPIRVFunction(it.word(2), args)] = id; + } +} + +void SPIRVEditor::UnregisterOp(SPIRVIterator it) +{ + spv::Op opcode = it.opcode(); + + SPIRVId id; + + if(opcode == spv::OpEntryPoint) + { + for(auto entryIt = entries.begin(); entryIt != entries.end(); ++entryIt) + { + if(entryIt->id == it.word(2)) + { + entries.erase(entryIt); + break; + } + } + } + else if(opcode == spv::OpFunction) + { + id = it.word(2); + for(auto funcIt = functions.begin(); funcIt != functions.end(); ++funcIt) + { + if(*funcIt == id) + { + functions.erase(funcIt); + break; + } + } + } + else if(opcode == spv::OpTypeVoid || opcode == spv::OpTypeBool || opcode == spv::OpTypeInt || + opcode == spv::OpTypeFloat) + { + id = it.word(1); + + SPIRVScalar scalar(it); + scalarTypes.erase(scalar); + } + else if(opcode == spv::OpTypeVector) + { + id = it.word(1); + + SPIRVIterator scalarIt = GetID(it.word(2)); + + if(!scalarIt) + { + RDCERR("Vector type declared with unknown scalar component type %u", it.word(2)); + return; + } + + vectorTypes.erase(SPIRVVector(scalarIt, it.word(3))); + } + else if(opcode == spv::OpTypeMatrix) + { + id = it.word(1); + + SPIRVIterator vectorIt = GetID(it.word(2)); + + if(!vectorIt) + { + RDCERR("Matrix type declared with unknown vector component type %u", it.word(2)); + return; + } + + SPIRVIterator scalarIt = GetID(vectorIt.word(2)); + uint32_t vectorDim = vectorIt.word(3); + + matrixTypes.erase(SPIRVMatrix(SPIRVVector(scalarIt, vectorDim), it.word(3))); + } + else if(opcode == spv::OpTypeImage) + { + id = it.word(1); + + SPIRVIterator scalarIt = GetID(it.word(2)); + + if(!scalarIt) + { + RDCERR("Image type declared with unknown scalar component type %u", it.word(2)); + 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))); + } + else if(opcode == spv::OpTypeSampledImage) + { + id = it.word(1); + + SPIRVId base = it.word(2); + + sampledImageTypes.erase(SPIRVSampledImage(base)); + } + else if(opcode == spv::OpTypePointer) + { + id = it.word(1); + + pointerTypes.erase(SPIRVPointer(it.word(3), (spv::StorageClass)it.word(2))); + } + else if(opcode == spv::OpTypeStruct) + { + id = it.word(1); + } + else if(opcode == spv::OpTypeFunction) + { + id = it.word(1); + + std::vector args; + + for(size_t i = 3; i < it.size(); i++) + args.push_back(it.word(i)); + + functionTypes.erase(SPIRVFunction(it.word(2), args)); + } + + if(id) + idOffsets[id] = 0; +} + void SPIRVEditor::addWords(size_t offs, int32_t num) { // look through every section, any that are >= this point, adjust the offsets diff --git a/renderdoc/driver/shaders/spirv/spirv_editor.h b/renderdoc/driver/shaders/spirv/spirv_editor.h index 2b7d6538b..477de3d2a 100644 --- a/renderdoc/driver/shaders/spirv/spirv_editor.h +++ b/renderdoc/driver/shaders/spirv/spirv_editor.h @@ -128,28 +128,9 @@ public: uint32_t &operator[](size_t idx) { return iter.word(idx); } const uint32_t &operator[](size_t idx) const { return iter.word(idx); } size_t size() const { return iter.size(); } - void nopRemove() - { - for(size_t i = 0, sz = size(); i < sz; i++) - iter.word(i) = SPV_NOP; - } - void nopRemove(size_t idx, size_t count = 0) - { - size_t oldSize = size(); - - if(count == 0) - count = oldSize - idx; - - // reduce the size of this op - *iter = MakeHeader(iter.opcode(), oldSize - count); - - // move any words on the end into the middle, then nop them - for(size_t i = 0; i < count; i++) - { - iter.word(idx + i) = iter.word(idx + count + i); - iter.word(oldSize - i - 1) = SPV_NOP; - } - } + // replace part of this operation with NOPs and update the length. Cannot completely erase the + // operation + void nopRemove(size_t idx, size_t count = 0); private: friend class SPIRVEditor; @@ -160,6 +141,7 @@ private: { return (uint32_t(op) & spv::OpCodeMask) | (uint16_t(WordCount) << spv::WordCountShift); } + void nopRemove(); // everything is based around this iterator, which may point into our local storage or to external // storage. @@ -373,7 +355,22 @@ public: SPIRVId MakeId(); - void AddWord(SPIRVIterator entry, uint32_t word); + void AddWord(SPIRVIterator iter, uint32_t word); + void AddOperation(SPIRVIterator iter, const SPIRVOperation &op); + + // callbacks to allow us to update our internal structures over changes + + // called before any modifications are made. Removes the operation from internal structures. + void PreModify(SPIRVIterator iter) { UnregisterOp(iter); } + // called after any modifications, re-adds the operation to internal structures with its new + // properties + void PostModify(SPIRVIterator iter) { RegisterOp(iter); } + // removed an operation and replaces it with nops + void Remove(SPIRVIterator iter) + { + UnregisterOp(iter); + SPIRVOperation(iter).nopRemove(); + } void SetName(uint32_t id, const char *name); void AddDecoration(const SPIRVOperation &op); @@ -461,6 +458,9 @@ private: inline void addWords(size_t offs, size_t num) { addWords(offs, (int32_t)num); } void addWords(size_t offs, int32_t num); + void RegisterOp(SPIRVIterator iter); + void UnregisterOp(SPIRVIterator iter); + struct LogicalSection { size_t startOffset = 0;