diff --git a/renderdoc/driver/shaders/spirv/CMakeLists.txt b/renderdoc/driver/shaders/spirv/CMakeLists.txt
index d0615469a..d0d96f458 100644
--- a/renderdoc/driver/shaders/spirv/CMakeLists.txt
+++ b/renderdoc/driver/shaders/spirv/CMakeLists.txt
@@ -91,6 +91,8 @@ endif()
set(sources
spirv_common.cpp
spirv_common.h
+ spirv_editor.h
+ spirv_editor.cpp
spirv_compile.cpp
spirv_disassemble.cpp
spirv_stringise.cpp
diff --git a/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj b/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj
index ea5cbffc6..3e30cabad 100644
--- a/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj
+++ b/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj
@@ -163,6 +163,7 @@
precompiled.h
precompiled.h
+
@@ -218,6 +219,7 @@
+
diff --git a/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj.filters b/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj.filters
index 5a31c1c5c..448bb5405 100644
--- a/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj.filters
+++ b/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj.filters
@@ -145,6 +145,7 @@
PCH
+
@@ -301,5 +302,6 @@
PCH
+
\ No newline at end of file
diff --git a/renderdoc/driver/shaders/spirv/spirv_editor.cpp b/renderdoc/driver/shaders/spirv/spirv_editor.cpp
new file mode 100644
index 000000000..a9e1105e1
--- /dev/null
+++ b/renderdoc/driver/shaders/spirv/spirv_editor.cpp
@@ -0,0 +1,72 @@
+/******************************************************************************
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Baldur Karlsson
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ ******************************************************************************/
+
+#include "spirv_editor.h"
+#include "common/common.h"
+
+SPIRVEditor::SPIRVEditor(std::vector &spirvWords) : spirv(spirvWords)
+{
+ if(spirvWords.size() < 5 || spirvWords[0] != spv::MagicNumber)
+ {
+ RDCERR("Empty or invalid SPIR-V module");
+ return;
+ }
+
+ moduleVersion.major = uint8_t((spirvWords[1] & 0x00ff0000) >> 16);
+ moduleVersion.minor = uint8_t((spirvWords[1] & 0x0000ff00) >> 8);
+ generator = spirvWords[2];
+ idBound = SPIRVIterator(spirvWords, 3);
+
+ // [4] is reserved
+ RDCASSERT(spirv[4] == 0);
+
+ SPIRVIterator it(spirvWords, 5);
+
+ while(it)
+ {
+ spv::Op opcode = it.opcode();
+
+ if(opcode == spv::OpEntryPoint)
+ {
+ SPIRVEntry entry;
+ entry.iter = it;
+ entry.id = it.word(2);
+ entry.name = (const char *)&it.word(3);
+
+ entries.push_back(entry);
+ }
+
+ it++;
+ }
+}
+
+uint32_t SPIRVEditor::MakeId()
+{
+ if(!idBound)
+ return 0;
+
+ uint32_t ret = *idBound;
+ (*idBound)++;
+ return ret;
+}
diff --git a/renderdoc/driver/shaders/spirv/spirv_editor.h b/renderdoc/driver/shaders/spirv/spirv_editor.h
new file mode 100644
index 000000000..dafb8732f
--- /dev/null
+++ b/renderdoc/driver/shaders/spirv/spirv_editor.h
@@ -0,0 +1,159 @@
+/******************************************************************************
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Baldur Karlsson
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ ******************************************************************************/
+
+#pragma once
+
+#include
+#include
+#include
+#include "3rdparty/glslang/SPIRV/spirv.hpp"
+
+class SPIRVOperation;
+
+class SPIRVIterator
+{
+public:
+ // constructors
+ SPIRVIterator() = default;
+ SPIRVIterator(std::vector &w, size_t o) : words(&w), offset(o) {}
+ // increment to the next op
+ SPIRVIterator &operator++(int) { return operator++(); }
+ SPIRVIterator &operator++()
+ {
+ offset += cur() >> spv::WordCountShift;
+ return *this;
+ }
+ // utility functions
+ std::vector::iterator it() { return words->begin() + offset; }
+ operator bool() const { return words != NULL && offset < words->size(); }
+ uint32_t &operator*() { return cur(); }
+ const uint32_t &operator*() const { return cur(); }
+ spv::Op opcode() { return spv::Op(cur() & spv::OpCodeMask); }
+ uint32_t &word(size_t idx) { return words->at(offset + idx); }
+ const uint32_t &word(size_t idx) const { return words->at(offset + idx); }
+ size_t size() const { return cur() >> spv::WordCountShift; }
+private:
+ inline uint32_t &cur() { return words->at(offset); }
+ inline const uint32_t &cur() const { return words->at(offset); }
+ // we make this a friend so it can poke directly into words when it wants to edit
+ friend class SPIRVOperation;
+
+ std::vector *words = NULL;
+ size_t offset = 0;
+};
+
+class SPIRVOperation
+{
+public:
+ // constructor of a synthetic operation, from an operation & subsequent words, calculates the
+ // length then constructs the first word with opcode + length.
+ template
+ SPIRVOperation(spv::Op op, const WordContainer &data)
+ {
+ auto a = std::begin(data);
+ auto b = std::end(data);
+ size_t count = 1 + (b - a);
+ words.resize(data.size());
+ words[0] = MakeHeader(op, data.size());
+ words.insert(words.begin() + 1, a, b);
+
+ iter = SPIRVIterator(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.
+ SPIRVOperation(SPIRVIterator it) : iter(it) {}
+ 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 push_back(uint32_t word)
+ {
+ spv::Op op = iter.opcode();
+ size_t count = iter.size();
+ iter.words->insert(iter.it() + count, word);
+
+ // since the length is in the high-order bits, we have to extract/increment/insert instead of
+ // just incrementing. Boo!
+ *iter = MakeHeader(op, count + 1);
+ }
+
+private:
+ inline uint32_t MakeHeader(spv::Op op, size_t WordCount)
+ {
+ return (uint32_t(op) & spv::OpCodeMask) | (uint16_t(WordCount) << spv::WordCountShift);
+ }
+
+ // everything is based around this iterator, which may point into our local storage or to external
+ // storage.
+ SPIRVIterator iter;
+
+ // may not be used, if we refer to an external iterator
+ std::vector words;
+};
+
+struct SPIRVEntry
+{
+ uint32_t id;
+ std::string name;
+ SPIRVIterator iter;
+};
+
+class SPIRVEditor
+{
+public:
+ SPIRVEditor(std::vector &spirvWords);
+
+ std::vector &GetWords() { return spirv; }
+ uint32_t MakeId();
+ void AddDecoration(const SPIRVOperation &op);
+ void AddType(const SPIRVOperation &op);
+ void AddVariable(const SPIRVOperation &op);
+ void AddFunction(const SPIRVOperation *ops, size_t count);
+
+ // simple properties that are public.
+ struct
+ {
+ uint8_t major = 1, minor = 0;
+ } moduleVersion;
+ uint32_t generator = 0;
+
+ spv::SourceLanguage sourceLang = spv::SourceLanguageUnknown;
+ uint32_t sourceVer = 0;
+
+ const std::vector &GetEntries() { return entries; }
+private:
+ SPIRVIterator idBound;
+
+ struct
+ {
+ SPIRVIterator decoration;
+ SPIRVIterator typeVar;
+ SPIRVIterator function;
+ } globaliters;
+
+ std::vector entries;
+
+ std::vector &spirv;
+};