mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-29 09:56:39 +00:00
Add proper support for mesh dumping with nested struct outputs
* Instead of hacking in some data in unused fields in the output sig we side-band the data we need to form the access chain. * We also fix some issues with the SPIR-V generation for mesh dumping that were caught by validation.
This commit is contained in:
@@ -53,6 +53,24 @@ enum class ShaderStage : uint32_t;
|
||||
struct ShaderReflection;
|
||||
struct ShaderBindpointMapping;
|
||||
|
||||
// extra information that goes along with a ShaderReflection that has extra information for SPIR-V
|
||||
// patching
|
||||
struct SPIRVPatchData
|
||||
{
|
||||
struct OutputAccess
|
||||
{
|
||||
// ID of the base output variable
|
||||
uint32_t ID;
|
||||
|
||||
// the access chain of indices
|
||||
std::vector<uint32_t> accessChain;
|
||||
};
|
||||
|
||||
// matches the output signature array, with details of where to fetch the output from in the
|
||||
// SPIR-V.
|
||||
std::vector<OutputAccess> outputs;
|
||||
};
|
||||
|
||||
struct SPVModule
|
||||
{
|
||||
SPVModule();
|
||||
@@ -90,8 +108,8 @@ struct SPVModule
|
||||
SPVInstruction *GetByID(uint32_t id);
|
||||
string Disassemble(const string &entryPoint);
|
||||
|
||||
void MakeReflection(ShaderStage stage, const string &entryPoint, ShaderReflection *reflection,
|
||||
ShaderBindpointMapping *mapping);
|
||||
void MakeReflection(ShaderStage stage, const string &entryPoint, ShaderReflection &reflection,
|
||||
ShaderBindpointMapping &mapping, SPIRVPatchData &patchData);
|
||||
};
|
||||
|
||||
string CompileSPIRV(SPIRVShaderStage shadType, const vector<string> &sources,
|
||||
|
||||
@@ -3695,19 +3695,18 @@ struct bindpair
|
||||
typedef bindpair<ConstantBlock> cblockpair;
|
||||
typedef bindpair<ShaderResource> shaderrespair;
|
||||
|
||||
void AddSignatureParameter(ShaderStage stage, uint32_t id, uint32_t childIdx, string varName,
|
||||
SPVTypeData *type, const vector<SPVDecoration> &decorations,
|
||||
vector<SigParameter> &sigarray)
|
||||
void AddSignatureParameter(bool isInput, ShaderStage stage, uint32_t id,
|
||||
std::vector<uint32_t> accessChain, string varName, SPVTypeData *type,
|
||||
const vector<SPVDecoration> &decorations, vector<SigParameter> &sigarray,
|
||||
SPIRVPatchData &patchData)
|
||||
{
|
||||
SigParameter sig;
|
||||
|
||||
sig.needSemanticIndex = false;
|
||||
|
||||
// this is super cheeky, but useful to pick up when doing output dumping and
|
||||
// these properties won't be used elsewhere. We should really share the data
|
||||
// in a better way though.
|
||||
sig.semanticIdxName = StringFormat::Fmt("%u", id);
|
||||
sig.semanticIndex = childIdx;
|
||||
SPIRVPatchData::OutputAccess patch;
|
||||
patch.accessChain = accessChain;
|
||||
patch.ID = id;
|
||||
|
||||
bool rowmajor = true;
|
||||
|
||||
@@ -3742,9 +3741,6 @@ void AddSignatureParameter(ShaderStage stage, uint32_t id, uint32_t childIdx, st
|
||||
|
||||
if(type->type == SPVTypeData::eStruct)
|
||||
{
|
||||
// we don't support nested structs yet
|
||||
RDCASSERT(childIdx == ~0U);
|
||||
|
||||
// it's invalid to include built-in and 'normal' outputs in the same struct. One
|
||||
// way this can happen is if a SPIR-V generator incorrectly puts in legacy elements
|
||||
// into an implicit gl_PerVertex struct, but they don't have a builtin to associate
|
||||
@@ -3766,6 +3762,8 @@ void AddSignatureParameter(ShaderStage stage, uint32_t id, uint32_t childIdx, st
|
||||
|
||||
for(uint32_t a = 0; a < arraySize; a++)
|
||||
{
|
||||
patch.accessChain.push_back(0U);
|
||||
|
||||
for(size_t c = 0; c < type->children.size(); c++)
|
||||
{
|
||||
// if this struct has builtins, see if this child is a builtin
|
||||
@@ -3789,8 +3787,11 @@ void AddSignatureParameter(ShaderStage stage, uint32_t id, uint32_t childIdx, st
|
||||
|
||||
string baseName = isArray ? StringFormat::Fmt("%s[%u]", varName.c_str(), a) : varName;
|
||||
|
||||
AddSignatureParameter(stage, id, (uint32_t)c, baseName + "." + type->children[c].second,
|
||||
type->children[c].first, type->childDecorations[c], sigarray);
|
||||
AddSignatureParameter(isInput, stage, id, patch.accessChain,
|
||||
baseName + "." + type->children[c].second, type->children[c].first,
|
||||
type->childDecorations[c], sigarray, patchData);
|
||||
|
||||
patch.accessChain.back()++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3818,6 +3819,10 @@ void AddSignatureParameter(ShaderStage stage, uint32_t id, uint32_t childIdx, st
|
||||
{
|
||||
string n = varName;
|
||||
|
||||
// arrays will need an extra access chain index
|
||||
if(arraySize > 1)
|
||||
patch.accessChain.push_back(0U);
|
||||
|
||||
if(isArray)
|
||||
{
|
||||
n = StringFormat::Fmt("%s[%u]", varName.c_str(), a);
|
||||
@@ -3829,6 +3834,9 @@ void AddSignatureParameter(ShaderStage stage, uint32_t id, uint32_t childIdx, st
|
||||
if(type->matrixSize == 1)
|
||||
{
|
||||
sigarray.push_back(sig);
|
||||
|
||||
if(!isInput)
|
||||
patchData.outputs.push_back(patch);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3841,15 +3849,21 @@ void AddSignatureParameter(ShaderStage stage, uint32_t id, uint32_t childIdx, st
|
||||
RDCASSERT(s.regIndex < 16);
|
||||
|
||||
sigarray.push_back(s);
|
||||
|
||||
if(!isInput)
|
||||
patchData.outputs.push_back(patch);
|
||||
}
|
||||
}
|
||||
|
||||
sig.regIndex += RDCMAX(1U, type->matrixSize);
|
||||
if(arraySize > 1)
|
||||
patch.accessChain.back()++;
|
||||
}
|
||||
}
|
||||
|
||||
void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint,
|
||||
ShaderReflection *reflection, ShaderBindpointMapping *mapping)
|
||||
ShaderReflection &reflection, ShaderBindpointMapping &mapping,
|
||||
SPIRVPatchData &patchData)
|
||||
{
|
||||
vector<SigParameter> inputs;
|
||||
vector<SigParameter> outputs;
|
||||
@@ -3859,24 +3873,24 @@ void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint,
|
||||
// VKTODOLOW filter to only functions/resources used by entryPoint
|
||||
|
||||
// VKTODOLOW set this properly
|
||||
reflection->DebugInfo.entryFile = 0;
|
||||
reflection->DebugInfo.entryFunc = entryPoint;
|
||||
reflection.DebugInfo.entryFile = 0;
|
||||
reflection.DebugInfo.entryFunc = entryPoint;
|
||||
|
||||
if(!sourceFiles.empty())
|
||||
{
|
||||
create_array_uninit(reflection->DebugInfo.files, sourceFiles.size());
|
||||
create_array_uninit(reflection.DebugInfo.files, sourceFiles.size());
|
||||
|
||||
for(size_t i = 0; i < sourceFiles.size(); i++)
|
||||
{
|
||||
reflection->DebugInfo.files[i].first = sourceFiles[i].first;
|
||||
reflection->DebugInfo.files[i].second = sourceFiles[i].second;
|
||||
reflection.DebugInfo.files[i].first = sourceFiles[i].first;
|
||||
reflection.DebugInfo.files[i].second = sourceFiles[i].second;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO need to fetch these
|
||||
reflection->DispatchThreadsDimension[0] = 0;
|
||||
reflection->DispatchThreadsDimension[1] = 0;
|
||||
reflection->DispatchThreadsDimension[2] = 0;
|
||||
reflection.DispatchThreadsDimension[0] = 0;
|
||||
reflection.DispatchThreadsDimension[1] = 0;
|
||||
reflection.DispatchThreadsDimension[2] = 0;
|
||||
|
||||
for(size_t i = 0; i < globals.size(); i++)
|
||||
{
|
||||
@@ -3898,7 +3912,8 @@ void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint,
|
||||
else
|
||||
nm = StringFormat::Fmt("sig%u", inst->id);
|
||||
|
||||
AddSignatureParameter(stage, inst->id, ~0U, nm, inst->var->type, inst->decorations, *sigarray);
|
||||
AddSignatureParameter(isInput, stage, inst->id, std::vector<uint32_t>(), nm, inst->var->type,
|
||||
inst->decorations, *sigarray, patchData);
|
||||
|
||||
// eliminate any members of gl_PerVertex that are actually unused and just came along
|
||||
// for the ride (usually with gl_Position, but maybe declared globally and still unused)
|
||||
@@ -3942,8 +3957,10 @@ void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint,
|
||||
|
||||
if(eliminate)
|
||||
{
|
||||
// variable must be the last one added, just remove it
|
||||
sigarray->pop_back();
|
||||
|
||||
if(patchData.outputs.size() > sigarray->size())
|
||||
patchData.outputs.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4009,12 +4026,15 @@ void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint,
|
||||
if(eliminate)
|
||||
{
|
||||
ShaderBuiltin attr = BuiltInToSystemAttribute(stage, checkBuiltin);
|
||||
|
||||
// find this builtin in the array, and remove
|
||||
for(auto it = sigarray->begin(); it != sigarray->end(); ++it)
|
||||
for(size_t s = 0; s < sigarray->size(); s++)
|
||||
{
|
||||
if(it->systemValue == attr)
|
||||
if((*sigarray)[s].systemValue == attr)
|
||||
{
|
||||
sigarray->erase(it);
|
||||
sigarray->erase(sigarray->begin() + s);
|
||||
if(!isInput)
|
||||
patchData.outputs.erase(patchData.outputs.begin() + s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4326,8 +4346,14 @@ void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint,
|
||||
// sort system value semantics to the start of the list
|
||||
struct sig_param_sort
|
||||
{
|
||||
bool operator()(const SigParameter &a, const SigParameter &b)
|
||||
sig_param_sort(const vector<SigParameter> &arr) : sigArray(arr) {}
|
||||
const vector<SigParameter> &sigArray;
|
||||
|
||||
bool operator()(const size_t idxA, const size_t idxB)
|
||||
{
|
||||
const SigParameter &a = sigArray[idxA];
|
||||
const SigParameter &b = sigArray[idxB];
|
||||
|
||||
if(a.systemValue == b.systemValue)
|
||||
{
|
||||
if(a.regIndex != b.regIndex)
|
||||
@@ -4344,73 +4370,96 @@ void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint,
|
||||
}
|
||||
};
|
||||
|
||||
std::sort(inputs.begin(), inputs.end(), sig_param_sort());
|
||||
std::sort(outputs.begin(), outputs.end(), sig_param_sort());
|
||||
std::vector<size_t> indices;
|
||||
{
|
||||
indices.resize(inputs.size());
|
||||
for(size_t i = 0; i < inputs.size(); i++)
|
||||
indices[i] = i;
|
||||
|
||||
std::sort(indices.begin(), indices.end(), sig_param_sort(inputs));
|
||||
|
||||
create_array_uninit(reflection.InputSig, inputs.size());
|
||||
for(size_t i = 0; i < inputs.size(); i++)
|
||||
reflection.InputSig[i] = inputs[indices[i]];
|
||||
}
|
||||
|
||||
{
|
||||
indices.resize(outputs.size());
|
||||
for(size_t i = 0; i < outputs.size(); i++)
|
||||
indices[i] = i;
|
||||
|
||||
std::sort(indices.begin(), indices.end(), sig_param_sort(outputs));
|
||||
|
||||
create_array_uninit(reflection.OutputSig, outputs.size());
|
||||
for(size_t i = 0; i < outputs.size(); i++)
|
||||
reflection.OutputSig[i] = outputs[indices[i]];
|
||||
|
||||
std::vector<SPIRVPatchData::OutputAccess> outPatch = patchData.outputs;
|
||||
for(size_t i = 0; i < outputs.size(); i++)
|
||||
patchData.outputs[i] = outPatch[indices[i]];
|
||||
}
|
||||
|
||||
size_t numInputs = 16;
|
||||
|
||||
for(size_t i = 0; i < inputs.size(); i++)
|
||||
if(inputs[i].systemValue == ShaderBuiltin::Undefined)
|
||||
numInputs = RDCMAX(numInputs, (size_t)inputs[i].regIndex + 1);
|
||||
for(size_t i = 0; i < reflection.InputSig.size(); i++)
|
||||
if(reflection.InputSig[i].systemValue == ShaderBuiltin::Undefined)
|
||||
numInputs = RDCMAX(numInputs, (size_t)reflection.InputSig[i].regIndex + 1);
|
||||
|
||||
create_array_uninit(mapping->InputAttributes, numInputs);
|
||||
create_array_uninit(mapping.InputAttributes, numInputs);
|
||||
for(size_t i = 0; i < numInputs; i++)
|
||||
mapping->InputAttributes[i] = -1;
|
||||
mapping.InputAttributes[i] = -1;
|
||||
|
||||
for(size_t i = 0; i < inputs.size(); i++)
|
||||
if(inputs[i].systemValue == ShaderBuiltin::Undefined)
|
||||
mapping->InputAttributes[inputs[i].regIndex] = (int32_t)i;
|
||||
|
||||
reflection->InputSig = inputs;
|
||||
reflection->OutputSig = outputs;
|
||||
for(size_t i = 0; i < reflection.InputSig.size(); i++)
|
||||
if(reflection.InputSig[i].systemValue == ShaderBuiltin::Undefined)
|
||||
mapping.InputAttributes[reflection.InputSig[i].regIndex] = (int32_t)i;
|
||||
|
||||
std::sort(cblocks.begin(), cblocks.end());
|
||||
std::sort(roresources.begin(), roresources.end());
|
||||
std::sort(rwresources.begin(), rwresources.end());
|
||||
|
||||
create_array_uninit(mapping->ConstantBlocks, cblocks.size());
|
||||
create_array_uninit(reflection->ConstantBlocks, cblocks.size());
|
||||
create_array_uninit(mapping.ConstantBlocks, cblocks.size());
|
||||
create_array_uninit(reflection.ConstantBlocks, cblocks.size());
|
||||
|
||||
create_array_uninit(mapping->ReadOnlyResources, roresources.size());
|
||||
create_array_uninit(reflection->ReadOnlyResources, roresources.size());
|
||||
create_array_uninit(mapping.ReadOnlyResources, roresources.size());
|
||||
create_array_uninit(reflection.ReadOnlyResources, roresources.size());
|
||||
|
||||
create_array_uninit(mapping->ReadWriteResources, rwresources.size());
|
||||
create_array_uninit(reflection->ReadWriteResources, rwresources.size());
|
||||
create_array_uninit(mapping.ReadWriteResources, rwresources.size());
|
||||
create_array_uninit(reflection.ReadWriteResources, rwresources.size());
|
||||
|
||||
for(size_t i = 0; i < cblocks.size(); i++)
|
||||
{
|
||||
mapping->ConstantBlocks[i] = cblocks[i].map;
|
||||
mapping.ConstantBlocks[i] = cblocks[i].map;
|
||||
// fix up any bind points marked with -1. They were sorted to the end
|
||||
// but from here on we want to just be able to index with the bind point
|
||||
// without any special casing.
|
||||
if(mapping->ConstantBlocks[i].bind == -1)
|
||||
mapping->ConstantBlocks[i].bind = 0;
|
||||
reflection->ConstantBlocks[i] = cblocks[i].bindres;
|
||||
reflection->ConstantBlocks[i].bindPoint = (int32_t)i;
|
||||
if(mapping.ConstantBlocks[i].bind == -1)
|
||||
mapping.ConstantBlocks[i].bind = 0;
|
||||
reflection.ConstantBlocks[i] = cblocks[i].bindres;
|
||||
reflection.ConstantBlocks[i].bindPoint = (int32_t)i;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < roresources.size(); i++)
|
||||
{
|
||||
mapping->ReadOnlyResources[i] = roresources[i].map;
|
||||
mapping.ReadOnlyResources[i] = roresources[i].map;
|
||||
// fix up any bind points marked with -1. They were sorted to the end
|
||||
// but from here on we want to just be able to index with the bind point
|
||||
// without any special casing.
|
||||
if(mapping->ReadOnlyResources[i].bind == -1)
|
||||
mapping->ReadOnlyResources[i].bind = 0;
|
||||
reflection->ReadOnlyResources[i] = roresources[i].bindres;
|
||||
reflection->ReadOnlyResources[i].bindPoint = (int32_t)i;
|
||||
if(mapping.ReadOnlyResources[i].bind == -1)
|
||||
mapping.ReadOnlyResources[i].bind = 0;
|
||||
reflection.ReadOnlyResources[i] = roresources[i].bindres;
|
||||
reflection.ReadOnlyResources[i].bindPoint = (int32_t)i;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < rwresources.size(); i++)
|
||||
{
|
||||
mapping->ReadWriteResources[i] = rwresources[i].map;
|
||||
mapping.ReadWriteResources[i] = rwresources[i].map;
|
||||
// fix up any bind points marked with -1. They were sorted to the end
|
||||
// but from here on we want to just be able to index with the bind point
|
||||
// without any special casing.
|
||||
if(mapping->ReadWriteResources[i].bind == -1)
|
||||
mapping->ReadWriteResources[i].bind = 0;
|
||||
reflection->ReadWriteResources[i] = rwresources[i].bindres;
|
||||
reflection->ReadWriteResources[i].bindPoint = (int32_t)i;
|
||||
if(mapping.ReadWriteResources[i].bind == -1)
|
||||
mapping.ReadWriteResources[i].bind = 0;
|
||||
reflection.ReadWriteResources[i] = rwresources[i].bindres;
|
||||
reflection.ReadWriteResources[i].bindPoint = (int32_t)i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7087,9 +7087,10 @@ inline uint32_t MakeSPIRVOp(spv::Op op, uint32_t WordCount)
|
||||
return (uint32_t(op) & spv::OpCodeMask) | (WordCount << spv::WordCountShift);
|
||||
}
|
||||
|
||||
static void AddOutputDumping(const ShaderReflection &refl, const char *entryName, uint32_t descSet,
|
||||
uint32_t vertexIndexOffset, uint32_t instanceIndexOffset,
|
||||
uint32_t numVerts, vector<uint32_t> &modSpirv, uint32_t &bufStride)
|
||||
static void AddOutputDumping(const ShaderReflection &refl, const SPIRVPatchData &patchData,
|
||||
const char *entryName, uint32_t descSet, uint32_t vertexIndexOffset,
|
||||
uint32_t instanceIndexOffset, uint32_t numVerts,
|
||||
vector<uint32_t> &modSpirv, uint32_t &bufStride)
|
||||
{
|
||||
uint32_t *spirv = &modSpirv[0];
|
||||
size_t spirvLength = modSpirv.size();
|
||||
@@ -7138,10 +7139,7 @@ static void AddOutputDumping(const ShaderReflection &refl, const char *entryName
|
||||
uint32_t constID; // constant ID for the index of this output
|
||||
uint32_t basetypeID; // the type ID for this output. Must be present already by definition!
|
||||
uint32_t uniformPtrID; // Uniform Pointer ID for this output. Used to write the output data
|
||||
|
||||
uint32_t varID; // we get this from the output signature, ID of actual variable
|
||||
uint32_t
|
||||
childIdx; // if the output variable is a struct, this is the member idx of this output
|
||||
uint32_t outputPtrID; // Output Pointer ID for this output. Used to read the output data
|
||||
};
|
||||
outputIDs outs[100] = {};
|
||||
|
||||
@@ -7196,30 +7194,54 @@ static void AddOutputDumping(const ShaderReflection &refl, const char *entryName
|
||||
outs[i].constID = spirv[it + 2];
|
||||
}
|
||||
|
||||
if(refl.OutputSig[i].compCount > 1 && opcode == spv::OpTypeVector)
|
||||
if(outs[i].basetypeID == 0)
|
||||
{
|
||||
uint32_t baseID = 0;
|
||||
if(refl.OutputSig[i].compCount > 1 && opcode == spv::OpTypeVector)
|
||||
{
|
||||
uint32_t baseID = 0;
|
||||
|
||||
if(refl.OutputSig[i].compType == CompType::UInt)
|
||||
baseID = uint32ID;
|
||||
else if(refl.OutputSig[i].compType == CompType::SInt)
|
||||
baseID = sint32ID;
|
||||
else if(refl.OutputSig[i].compType == CompType::Float)
|
||||
baseID = floatID;
|
||||
else if(refl.OutputSig[i].compType == CompType::Double)
|
||||
baseID = doubleID;
|
||||
else
|
||||
RDCERR("Unexpected component type for output signature element");
|
||||
if(refl.OutputSig[i].compType == CompType::UInt)
|
||||
baseID = uint32ID;
|
||||
else if(refl.OutputSig[i].compType == CompType::SInt)
|
||||
baseID = sint32ID;
|
||||
else if(refl.OutputSig[i].compType == CompType::Float)
|
||||
baseID = floatID;
|
||||
else if(refl.OutputSig[i].compType == CompType::Double)
|
||||
baseID = doubleID;
|
||||
else
|
||||
RDCERR("Unexpected component type for output signature element");
|
||||
|
||||
// if we have the base type, see if this is the right sized vector of that type
|
||||
if(baseID != 0 && spirv[it + 2] == baseID && spirv[it + 3] == refl.OutputSig[i].compCount)
|
||||
outs[i].basetypeID = spirv[it + 1];
|
||||
// if we have the base type, see if this is the right sized vector of that type
|
||||
if(baseID != 0 && spirv[it + 2] == baseID && spirv[it + 3] == refl.OutputSig[i].compCount)
|
||||
outs[i].basetypeID = spirv[it + 1];
|
||||
}
|
||||
|
||||
// handle non-vectors
|
||||
if(refl.OutputSig[i].compCount == 1)
|
||||
{
|
||||
if(refl.OutputSig[i].compType == CompType::UInt)
|
||||
outs[i].basetypeID = uint32ID;
|
||||
else if(refl.OutputSig[i].compType == CompType::SInt)
|
||||
outs[i].basetypeID = sint32ID;
|
||||
else if(refl.OutputSig[i].compType == CompType::Float)
|
||||
outs[i].basetypeID = floatID;
|
||||
else if(refl.OutputSig[i].compType == CompType::Double)
|
||||
outs[i].basetypeID = doubleID;
|
||||
}
|
||||
}
|
||||
|
||||
// if we've found the base type, try and identify uniform pointers to that type
|
||||
// if we've found the base type, try and identify pointers to that type
|
||||
if(outs[i].basetypeID != 0 && opcode == spv::OpTypePointer &&
|
||||
spirv[it + 2] == spv::StorageClassUniform && spirv[it + 3] == outs[i].basetypeID)
|
||||
{
|
||||
outs[i].uniformPtrID = spirv[it + 1];
|
||||
}
|
||||
|
||||
if(outs[i].basetypeID != 0 && opcode == spv::OpTypePointer &&
|
||||
spirv[it + 2] == spv::StorageClassOutput && spirv[it + 3] == outs[i].basetypeID)
|
||||
{
|
||||
outs[i].outputPtrID = spirv[it + 1];
|
||||
}
|
||||
}
|
||||
|
||||
if(opcode == spv::OpEntryPoint)
|
||||
@@ -7259,27 +7281,8 @@ static void AddOutputDumping(const ShaderReflection &refl, const char *entryName
|
||||
|
||||
for(int i = 0; i < numOutputs; i++)
|
||||
{
|
||||
// handle non-vectors once here
|
||||
if(refl.OutputSig[i].compCount == 1)
|
||||
{
|
||||
if(refl.OutputSig[i].compType == CompType::UInt)
|
||||
outs[i].basetypeID = uint32ID;
|
||||
else if(refl.OutputSig[i].compType == CompType::SInt)
|
||||
outs[i].basetypeID = sint32ID;
|
||||
else if(refl.OutputSig[i].compType == CompType::Float)
|
||||
outs[i].basetypeID = floatID;
|
||||
else if(refl.OutputSig[i].compType == CompType::Double)
|
||||
outs[i].basetypeID = doubleID;
|
||||
else
|
||||
RDCERR("Unexpected component type for output signature element");
|
||||
}
|
||||
|
||||
// must have at least found the base type, or something has gone seriously wrong
|
||||
RDCASSERT(outs[i].basetypeID != 0);
|
||||
|
||||
// bit of a hack, these were stored from SPIR-V disassembly
|
||||
outs[i].varID = atoi(refl.OutputSig[i].semanticIdxName.elems);
|
||||
outs[i].childIdx = refl.OutputSig[i].semanticIndex;
|
||||
}
|
||||
|
||||
// if needed add new ID for sint32 type
|
||||
@@ -7474,6 +7477,39 @@ static void AddOutputDumping(const ShaderReflection &refl, const char *entryName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// it would be very strange to have no output pointer ID, since the original SPIR-V would have
|
||||
// had to use some other mechanism to write to the output variable. But just to be safe we
|
||||
// ensure that we have it here too.
|
||||
if(outs[i].outputPtrID == 0)
|
||||
{
|
||||
RDCERR("No output pointer ID found for output %d: %s (%u %u)", i,
|
||||
refl.OutputSig[i].varName.c_str(), refl.OutputSig[i].compType,
|
||||
refl.OutputSig[i].compCount);
|
||||
|
||||
outs[i].outputPtrID = idBound++;
|
||||
|
||||
uint32_t typeOp[] = {
|
||||
MakeSPIRVOp(spv::OpTypePointer, 4), outs[i].outputPtrID, spv::StorageClassOutput,
|
||||
outs[i].basetypeID,
|
||||
};
|
||||
|
||||
// insert at the end of the types/variables/constants section
|
||||
modSpirv.insert(modSpirv.begin() + typeVarOffset, typeOp, typeOp + ARRAY_COUNT(typeOp));
|
||||
|
||||
// update offsets to account for inserted op
|
||||
typeVarOffset += ARRAY_COUNT(typeOp);
|
||||
|
||||
// update subsequent outputs of identical type
|
||||
for(int j = i + 1; j < numOutputs; j++)
|
||||
{
|
||||
if(outs[i].basetypeID == outs[j].basetypeID)
|
||||
{
|
||||
RDCASSERT(outs[j].outputPtrID == 0);
|
||||
outs[j].outputPtrID = outs[i].outputPtrID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t outBufferVarID = 0;
|
||||
@@ -7735,42 +7771,29 @@ static void AddOutputDumping(const ShaderReflection &refl, const char *entryName
|
||||
uint32_t loaded = 0;
|
||||
|
||||
// not a structure member or array child, can load directly
|
||||
if(outs[o].childIdx == ~0U && refl.OutputSig[o].arrayIndex == ~0U)
|
||||
if(patchData.outputs[o].accessChain.empty())
|
||||
{
|
||||
loaded = idBound++;
|
||||
|
||||
dumpCode.push_back(MakeSPIRVOp(spv::OpLoad, 4));
|
||||
dumpCode.push_back(outs[o].basetypeID);
|
||||
dumpCode.push_back(loaded);
|
||||
dumpCode.push_back(outs[o].varID);
|
||||
dumpCode.push_back(patchData.outputs[o].ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t readPtr = idBound++;
|
||||
loaded = idBound++;
|
||||
|
||||
uint32_t chainLength = 1;
|
||||
|
||||
if(outs[o].childIdx != ~0U && refl.OutputSig[o].arrayIndex != ~0U)
|
||||
chainLength = 2;
|
||||
|
||||
// structure member, need to access chain first
|
||||
dumpCode.push_back(MakeSPIRVOp(spv::OpAccessChain, 4 + chainLength));
|
||||
dumpCode.push_back(outs[o].uniformPtrID);
|
||||
dumpCode.push_back(readPtr); // readPtr =
|
||||
dumpCode.push_back(outs[o].varID); // outStructWhatever
|
||||
dumpCode.push_back(
|
||||
MakeSPIRVOp(spv::OpAccessChain, 4 + (uint32_t)patchData.outputs[o].accessChain.size()));
|
||||
dumpCode.push_back(outs[o].outputPtrID);
|
||||
dumpCode.push_back(readPtr); // readPtr =
|
||||
dumpCode.push_back(patchData.outputs[o].ID); // outStructWhatever
|
||||
|
||||
if(outs[o].childIdx != ~0U)
|
||||
{
|
||||
RDCASSERT(outs[o].childIdx < (uint32_t)numOutputs);
|
||||
dumpCode.push_back(outs[outs[o].childIdx].constID); // .actualOut
|
||||
}
|
||||
|
||||
if(refl.OutputSig[o].arrayIndex != ~0U)
|
||||
{
|
||||
RDCASSERT(refl.OutputSig[o].arrayIndex < (uint32_t)numOutputs);
|
||||
dumpCode.push_back(outs[refl.OutputSig[o].arrayIndex].constID); // [element]
|
||||
}
|
||||
for(uint32_t idx : patchData.outputs[o].accessChain)
|
||||
dumpCode.push_back(outs[idx].constID);
|
||||
|
||||
dumpCode.push_back(MakeSPIRVOp(spv::OpLoad, 4));
|
||||
dumpCode.push_back(outs[o].basetypeID);
|
||||
@@ -8130,8 +8153,9 @@ void VulkanDebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
uint32_t bufStride = 0;
|
||||
vector<uint32_t> modSpirv = moduleInfo.spirv.spirv;
|
||||
|
||||
AddOutputDumping(*refl, pipeInfo.shaders[0].entryPoint.c_str(), descSet, vertexIndexOffset,
|
||||
drawcall->instanceOffset, numVerts, modSpirv, bufStride);
|
||||
AddOutputDumping(*refl, *pipeInfo.shaders[0].patchData, pipeInfo.shaders[0].entryPoint.c_str(),
|
||||
descSet, vertexIndexOffset, drawcall->instanceOffset, numVerts, modSpirv,
|
||||
bufStride);
|
||||
|
||||
// create vertex shader with modified code
|
||||
VkShaderModuleCreateInfo moduleCreateInfo = {
|
||||
|
||||
@@ -112,7 +112,8 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, Vulk
|
||||
reflData.entryPoint = shad.entryPoint;
|
||||
reflData.stage = stageIndex;
|
||||
info.m_ShaderModule[id].spirv.MakeReflection(ShaderStage(reflData.stage), reflData.entryPoint,
|
||||
&reflData.refl, &reflData.mapping);
|
||||
reflData.refl, reflData.mapping,
|
||||
reflData.patchData);
|
||||
}
|
||||
|
||||
if(pCreateInfo->pStages[i].pSpecializationInfo)
|
||||
@@ -135,6 +136,7 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, Vulk
|
||||
|
||||
shad.refl = &reflData.refl;
|
||||
shad.mapping = &reflData.mapping;
|
||||
shad.patchData = &reflData.patchData;
|
||||
}
|
||||
|
||||
if(pCreateInfo->pVertexInputState)
|
||||
@@ -326,7 +328,8 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, Vulk
|
||||
{
|
||||
reflData.entryPoint = shad.entryPoint;
|
||||
info.m_ShaderModule[id].spirv.MakeReflection(ShaderStage::Compute, reflData.entryPoint,
|
||||
&reflData.refl, &reflData.mapping);
|
||||
reflData.refl, reflData.mapping,
|
||||
reflData.patchData);
|
||||
}
|
||||
|
||||
if(pCreateInfo->stage.pSpecializationInfo)
|
||||
@@ -347,6 +350,7 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, Vulk
|
||||
|
||||
shad.refl = &reflData.refl;
|
||||
shad.mapping = &reflData.mapping;
|
||||
shad.patchData = &reflData.patchData;
|
||||
}
|
||||
|
||||
topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
|
||||
@@ -92,11 +92,12 @@ struct VulkanCreationInfo
|
||||
// VkPipelineShaderStageCreateInfo
|
||||
struct Shader
|
||||
{
|
||||
Shader() : refl(NULL), mapping(NULL) {}
|
||||
Shader() : refl(NULL), mapping(NULL), patchData(NULL) {}
|
||||
ResourceId module;
|
||||
string entryPoint;
|
||||
ShaderReflection *refl;
|
||||
ShaderBindpointMapping *mapping;
|
||||
SPIRVPatchData *patchData;
|
||||
|
||||
vector<byte> specdata;
|
||||
struct SpecInfo
|
||||
@@ -346,6 +347,7 @@ struct VulkanCreationInfo
|
||||
string entryPoint;
|
||||
ShaderReflection refl;
|
||||
ShaderBindpointMapping mapping;
|
||||
SPIRVPatchData patchData;
|
||||
};
|
||||
map<string, Reflection> m_Reflections;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user