diff --git a/renderdoc/driver/shaders/spirv/spirv_common.h b/renderdoc/driver/shaders/spirv/spirv_common.h index d890bd7d5..1acfbe4e9 100644 --- a/renderdoc/driver/shaders/spirv/spirv_common.h +++ b/renderdoc/driver/shaders/spirv/spirv_common.h @@ -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 accessChain; + }; + + // matches the output signature array, with details of where to fetch the output from in the + // SPIR-V. + std::vector 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 &sources, diff --git a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp index 1d8b78271..d3ecf4f61 100644 --- a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp @@ -3695,19 +3695,18 @@ struct bindpair typedef bindpair cblockpair; typedef bindpair shaderrespair; -void AddSignatureParameter(ShaderStage stage, uint32_t id, uint32_t childIdx, string varName, - SPVTypeData *type, const vector &decorations, - vector &sigarray) +void AddSignatureParameter(bool isInput, ShaderStage stage, uint32_t id, + std::vector accessChain, string varName, SPVTypeData *type, + const vector &decorations, vector &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 inputs; vector 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(), 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 &arr) : sigArray(arr) {} + const vector &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 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 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; } } diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 8d496677d..03806d944 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -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 &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 &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 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 = { diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index 130c9d5fd..be0a7cdd3 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -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; diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index 848c7e8e2..7fb115e96 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -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 specdata; struct SpecInfo @@ -346,6 +347,7 @@ struct VulkanCreationInfo string entryPoint; ShaderReflection refl; ShaderBindpointMapping mapping; + SPIRVPatchData patchData; }; map m_Reflections; };