mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-27 08:56:44 +00:00
Use generated helpers for SPIRVEditor
This commit is contained in:
@@ -1219,7 +1219,7 @@ std::string ParamToStr(const std::function<rdcstr(rdcspv::Id)> &idName, const Pa
|
||||
|
||||
void OpDecoder::AddUsedIDs(std::set<Id> &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<Id> &usedids, const ConstIter &it)
|
||||
std::string OpDecoder::Disassemble(const ConstIter &it, const std::function<rdcstr(Id,Id)> &declName, const std::function<rdcstr(rdcspv::Id)> &idName, const std::function<uint32_t(Id)> &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<rdcs
|
||||
|
||||
OpDecoder::OpDecoder(const ConstIter &it)
|
||||
{{
|
||||
op = (rdcspv::Op)it.opcode();
|
||||
op = it.opcode();
|
||||
wordCount = (uint16_t)it.size();
|
||||
switch(op)
|
||||
{{
|
||||
|
||||
@@ -67,4 +67,23 @@ void rdcspv::Iter::nopRemove()
|
||||
{
|
||||
for(size_t i = 0, sz = size(); i < sz; i++)
|
||||
word(i) = OpNopWord;
|
||||
}
|
||||
}
|
||||
|
||||
rdcspv::Iter &rdcspv::Iter::operator=(const Operation &op)
|
||||
{
|
||||
size_t newSize = op.size();
|
||||
size_t oldSize = size();
|
||||
if(newSize > 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;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#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<uint32_t> &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<uint32_t> &data)
|
||||
Operation(rdcspv::Op op, const std::vector<uint32_t> &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 <typename FixedOpHelper, size_t WordCopyCount = FixedOpHelper::FixedWordSize>
|
||||
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<uint32_t> words;
|
||||
};
|
||||
|
||||
}; // namespace rdcspv
|
||||
|
||||
DECLARE_STRINGISE_TYPE(rdcspv::Id);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -22,77 +22,75 @@
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#define SPV_ENABLE_UTILITY_CODE
|
||||
|
||||
#include "spirv_editor.h"
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#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<uint32_t> 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<uint32_t> &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<uint32_t> &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<uint32_t> &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<uint32_t> &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<uint32_t> 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<uint32_t> 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<rdcspv::Id> &members)
|
||||
{
|
||||
std::vector<uint32_t> 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<rdcspv::Id> 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<rdcspv::Id> 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());
|
||||
|
||||
@@ -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<rdcspv::Id> &args)
|
||||
: returnId(ret), argumentIds(args)
|
||||
SPIRVFunction(rdcspv::Id ret, const rdcarray<rdcspv::Id> &args) : returnId(ret), argumentIds(args)
|
||||
{
|
||||
}
|
||||
rdcspv::Id returnId;
|
||||
std::vector<rdcspv::Id> argumentIds;
|
||||
rdcarray<rdcspv::Id> 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<uint32_t> 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<SPIRVEntry> &GetEntries() { return entries; }
|
||||
const std::vector<SPIRVVariable> &GetVariables() { return variables; }
|
||||
const std::vector<rdcspv::OpEntryPoint> &GetEntries() { return entries; }
|
||||
const std::vector<rdcspv::OpVariable> &GetVariables() { return variables; }
|
||||
const std::vector<rdcspv::Id> &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<SPIRVDecoration> decorations;
|
||||
std::vector<rdcspv::OpDecorate> decorations;
|
||||
|
||||
std::map<rdcspv::Id, SPIRVBinding> bindings;
|
||||
|
||||
std::vector<size_t> idOffsets;
|
||||
std::vector<rdcspv::Id> idTypes;
|
||||
|
||||
std::vector<SPIRVEntry> entries;
|
||||
std::vector<SPIRVVariable> variables;
|
||||
std::vector<rdcspv::OpEntryPoint> entries;
|
||||
std::vector<rdcspv::OpVariable> variables;
|
||||
std::vector<rdcspv::Id> functions;
|
||||
std::set<std::string> extensions;
|
||||
std::set<spv::Capability> capabilities;
|
||||
std::set<rdcstr> extensions;
|
||||
std::set<rdcspv::Capability> capabilities;
|
||||
|
||||
std::map<std::string, rdcspv::Id> extSets;
|
||||
std::map<rdcstr, rdcspv::Id> extSets;
|
||||
|
||||
std::map<SPIRVScalar, rdcspv::Id> scalarTypes;
|
||||
std::map<SPIRVVector, rdcspv::Id> vectorTypes;
|
||||
@@ -538,4 +480,19 @@ private:
|
||||
const std::map<SPIRVType, rdcspv::Id> &GetTable() const;
|
||||
|
||||
std::vector<uint32_t> &spirv;
|
||||
};
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
@@ -1705,7 +1705,7 @@ std::string ParamToStr(const std::function<rdcstr(rdcspv::Id)> &idName, const rd
|
||||
|
||||
void OpDecoder::AddUsedIDs(std::set<Id> &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<Id> &usedids, const ConstIter &it)
|
||||
std::string OpDecoder::Disassemble(const ConstIter &it, const std::function<rdcstr(Id,Id)> &declName, const std::function<rdcstr(rdcspv::Id)> &idName, const std::function<uint32_t(Id)> &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<rdcs
|
||||
|
||||
OpDecoder::OpDecoder(const ConstIter &it)
|
||||
{
|
||||
op = (rdcspv::Op)it.opcode();
|
||||
op = it.opcode();
|
||||
wordCount = (uint16_t)it.size();
|
||||
switch(op)
|
||||
{
|
||||
|
||||
@@ -63,11 +63,11 @@ void AddXFBAnnotations(const ShaderReflection &refl, const SPIRVPatchData &patch
|
||||
std::vector<SPIRVPatchData::InterfaceAccess> 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<rdcspv::Decoration::Offset>(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<rdcspv::Decoration::Offset>(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<rdcspv::Decoration::XfbBuffer>(0)));
|
||||
editor.AddDecoration(
|
||||
rdcspv::OpDecorate(rdcspv::Id::fromWord(outpatch[i].ID),
|
||||
rdcspv::DecorationParam<rdcspv::Decoration::XfbStride>(xfbStride)));
|
||||
vars.insert(outpatch[i].ID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#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();
|
||||
|
||||
@@ -23,9 +23,8 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include <float.h>
|
||||
#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<uint64_t>());
|
||||
int64ID = editor.DeclareType(scalar<int64_t>());
|
||||
|
||||
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<rdcspv::Decoration::ArrayStride>(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<rdcspv::Decoration::Offset>(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<uint64_t>(it->second.offset);
|
||||
rdcspv::Id id = varLookup[var.result] =
|
||||
editor.AddConstantImmediate<uint64_t>(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>(uint32_t(index));
|
||||
rdcspv::Id id = varLookup[var.result] =
|
||||
editor.AddConstantImmediate<uint32_t>(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<uint64_t>(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<rdcspv::Decoration::DescriptorSet>(0)));
|
||||
editor.AddDecoration(
|
||||
rdcspv::OpDecorate(ssboVar, rdcspv::DecorationParam<rdcspv::Decoration::Binding>(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<uint32_t>(0U);
|
||||
rdcspv::Id usedValue = editor.AddConstantImmediate<uint32_t>(0xFFFFFFFFU);
|
||||
rdcspv::Id scope = editor.AddConstantImmediate<uint32_t>(spv::ScopeInvocation);
|
||||
rdcspv::Id scope = editor.AddConstantImmediate<uint32_t>((uint32_t)rdcspv::Scope::Invocation);
|
||||
rdcspv::Id semantics = editor.AddConstantImmediate<uint32_t>(0U);
|
||||
rdcspv::Id uint32shift = editor.AddConstantImmediate<uint32_t>(2U);
|
||||
|
||||
std::map<rdcspv::Id, SPIRVScalar> intTypeLookup;
|
||||
|
||||
for(auto scalarType : editor.GetTypeInfo<SPIRVScalar>())
|
||||
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<SPIRVFunction> &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<uint32_t> funccall;
|
||||
std::vector<size_t> 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
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
#include "vk_debug.h"
|
||||
#include <float.h>
|
||||
#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"
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "vk_info.h"
|
||||
#include "3rdparty/glslang/SPIRV/spirv.hpp"
|
||||
|
||||
VkDynamicState ConvertDynamicState(VulkanDynamicStateIndex idx)
|
||||
{
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include <float.h>
|
||||
#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];
|
||||
|
||||
@@ -23,13 +23,14 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include <float.h>
|
||||
#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<rdcspv::Id> 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<rdcspv::Decoration::DescriptorSet>(0)));
|
||||
editor.AddDecoration(rdcspv::OpDecorate(
|
||||
tbuffers[tb].variableID, rdcspv::DecorationParam<rdcspv::Decoration::Binding>(tb)));
|
||||
}
|
||||
|
||||
rdcspv::Id uint32Vec4ID;
|
||||
@@ -511,29 +535,28 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV
|
||||
{
|
||||
uint32Vec4ID = editor.DeclareType(SPIRVVector(scalar<uint32_t>(), 4));
|
||||
|
||||
idxImageTypeID = editor.DeclareType(
|
||||
SPIRVImage(scalar<uint32_t>(), spv::DimBuffer, 0, 0, 0, 1, spv::ImageFormatUnknown));
|
||||
idxImageTypeID = editor.DeclareType(SPIRVImage(scalar<uint32_t>(), 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<rdcspv::Decoration::DescriptorSet>(0)));
|
||||
editor.AddDecoration(
|
||||
rdcspv::OpDecorate(idxImagePtr, rdcspv::DecorationParam<rdcspv::Decoration::Binding>(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<rdcspv::Id> words;
|
||||
std::vector<rdcspv::Id> 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<rdcspv::Decoration::Offset>(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<rdcspv::Decoration::Offset>(0)));
|
||||
|
||||
// set array stride
|
||||
editor.AddDecoration(rdcspv::Operation(
|
||||
spv::OpDecorate, {runtimeArrayID.value(), spv::DecorationArrayStride, bufStride}));
|
||||
editor.AddDecoration(rdcspv::OpDecorate(
|
||||
runtimeArrayID, rdcspv::DecorationParam<rdcspv::Decoration::ArrayStride>(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<rdcspv::Decoration::DescriptorSet>(0)));
|
||||
editor.AddDecoration(rdcspv::OpDecorate(
|
||||
outBufferVarID, rdcspv::DecorationParam<rdcspv::Decoration::Binding>(0)));
|
||||
}
|
||||
|
||||
rdcspv::Id uint32Vec3ID = editor.DeclareType(SPIRVVector(scalar<uint32_t>(), 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::Decoration::BuiltIn>(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<rdcspv::ExecutionMode::LocalSize>(MeshOutputDispatchWidth, 1, 1)));
|
||||
|
||||
rdcspv::Id uint32ID = editor.DeclareType(scalar<uint32_t>());
|
||||
|
||||
@@ -711,22 +736,17 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV
|
||||
rdcspv::Id voidType = editor.DeclareType(scalar<void>());
|
||||
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<bool>()).value(), inBounds.value(),
|
||||
viewID.value(), numViewsConstID.value()}));
|
||||
ops.push_back(rdcspv::OpULessThan(editor.DeclareType(scalar<bool>()), 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<uint32_t>(draw->vertexOffset).value()}));
|
||||
ops.push_back(rdcspv::OpIAdd(uint32ID, vertexIndexID, vtxID,
|
||||
editor.AddConstantImmediate<uint32_t>(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<uint32_t>(draw->instanceOffset).value()}));
|
||||
ops.push_back(rdcspv::OpIAdd(uint32ID, instIndexID, instID,
|
||||
editor.AddConstantImmediate<uint32_t>(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<uint32_t>(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<uint32_t>(2).value()}));
|
||||
rdcspv::OpIMul(uint32ID, doubled, idx, editor.AddConstantImmediate<uint32_t>(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<uint32_t>(1).value()}));
|
||||
rdcspv::OpIAdd(uint32ID, nextidx, idx, editor.AddConstantImmediate<uint32_t>(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<double>()).value(), comps[c].value(),
|
||||
glsl450.value(), GLSLstd450PackDouble2x32, packed.value(),
|
||||
}));
|
||||
rdcspv::Op::ExtInst,
|
||||
{
|
||||
editor.DeclareType(scalar<double>()).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<uint32_t> words = {ins[i].basetypeID.value(), result.value()};
|
||||
std::vector<rdcspv::Id> 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<uint32_t> words = {ins[i].basetypeID.value(), result.value(),
|
||||
swizzleIn.value(), swizzleIn.value()};
|
||||
std::vector<uint32_t> 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<uint32_t> words = {ins[i].privatePtrID.value(), subElement.value(),
|
||||
patchData.inputs[i].ID};
|
||||
std::vector<rdcspv::Id> chain;
|
||||
|
||||
for(uint32_t accessIdx : patchData.inputs[i].accessChain)
|
||||
{
|
||||
if(idxs[accessIdx] == 0)
|
||||
idxs[accessIdx] = editor.AddConstantImmediate<uint32_t>(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<uint32_t>(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<uint32_t> words = {outs[o].privatePtrID.value(), readPtr.value(),
|
||||
patchData.outputs[o].ID};
|
||||
std::vector<rdcspv::Id> chain;
|
||||
|
||||
for(uint32_t idx : patchData.outputs[o].accessChain)
|
||||
{
|
||||
if(idxs[idx] == 0)
|
||||
idxs[idx] = editor.AddConstantImmediate<uint32_t>(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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user