Use generated helpers for SPIRVEditor

This commit is contained in:
baldurk
2019-08-16 17:38:34 +01:00
parent 9cc8ce6c3b
commit e2b8085d78
14 changed files with 719 additions and 802 deletions
@@ -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;
}
+20 -10
View File
@@ -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
+215 -282
View File
@@ -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());
+64 -107
View File
@@ -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));
}
+3 -3
View File
@@ -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
}
-1
View File
@@ -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"
-1
View File
@@ -23,7 +23,6 @@
******************************************************************************/
#include "vk_info.h"
#include "3rdparty/glslang/SPIRV/spirv.hpp"
VkDynamicState ConvertDynamicState(VulkanDynamicStateIndex idx)
{
+8 -7
View File
@@ -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];
+250 -265
View File
@@ -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());
}