diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp index 24ebab204..192cd51a6 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp @@ -4218,20 +4218,44 @@ QByteArray VulkanPipelineStateViewer::ReconstructSpecializationData(const VKPipe { bytebuf specData; - // reconstruct the original spec data as best as we can + if(mapEntries->NumChildren() == 0) + return specData; + + if(sh.reflection == NULL) + { + qCritical("Tried to reconstruct specialization constants but reflection data is missing"); + return specData; + } + auto specBlockIt = + std::find_if(sh.reflection->constantBlocks.begin(), sh.reflection->constantBlocks.end(), + [](const ConstantBlock &block) { return block.compileConstants; }); + if(specBlockIt == sh.reflection->constantBlocks.end()) + { + qCritical("Cannot find the constant block for specialization constants"); + return specData; + } + const rdcarray &specVars = specBlockIt->variables; + + // We don't have access to the buffers in the original creation info, so we try to reconstruct + // from our preprocessed pipeline state instead. Note that this data might have a different order + // from the original call or have unused entries eliminated based on shader reflection. const bytebuf &src = sh.specializationData; for(size_t i = 0; i < mapEntries->NumChildren(); i++) { const SDObject *map = mapEntries->GetChild(i); - size_t srcByteOffset = map->FindChild("constantID")->AsUInt32() * sizeof(uint64_t); size_t dstByteOffset = map->FindChild("offset")->AsUInt32(); size_t size = map->FindChild("size")->AsUInt32(); + specData.resize_for_index(dstByteOffset + size - 1); + uint32_t constantId = map->FindChild("constantID")->AsUInt32(); + int32_t idx = sh.specializationIds.indexOf(constantId); + if(idx == -1) + continue; // Entry was eliminated as it was probably unused --- skip it + size_t srcByteOffset = specVars[idx].byteOffset; Q_ASSERT(srcByteOffset + size <= src.size()); - specData.resize_for_index(dstByteOffset + size - 1); memcpy(specData.data() + dstByteOffset, src.data() + srcByteOffset, size); } diff --git a/renderdoc/api/replay/vk_pipestate.h b/renderdoc/api/replay/vk_pipestate.h index e1f90f28c..0d708ca6d 100644 --- a/renderdoc/api/replay/vk_pipestate.h +++ b/renderdoc/api/replay/vk_pipestate.h @@ -596,6 +596,14 @@ value. :type: bytes )"); bytebuf specializationData; + + DOCUMENT(R"(The specialization constant ID for each entry in the specialization constant block of +reflection info. This corresponds to the constantID in VkSpecializationMapEntry, while the offset +and size into specializationData can be obtained from the reflection info. + +:type: List[int] +)") + rdcarray specializationIds; }; DOCUMENT("Describes the state of the fixed-function tessellator."); diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 4234c1e46..f8d9794b3 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -1160,6 +1160,8 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) stage.specializationData.resize_for_index(offs + sizeof(uint64_t)); memcpy(stage.specializationData.data() + offs, &s.value, s.dataSize); } + if(p.shaders[i].patchData) + stage.specializationIds = p.shaders[i].patchData->specIDs; } } else @@ -1279,6 +1281,8 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) stages[i]->specializationData.resize_for_index(offs + sizeof(uint64_t)); memcpy(stages[i]->specializationData.data() + offs, &s.value, s.dataSize); } + if(p.shaders[i].patchData) + stages[i]->specializationIds = p.shaders[i].patchData->specIDs; } // Tessellation diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 6f21c8f51..c9dbf8339 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -2078,8 +2078,9 @@ void DoSerialise(SerialiserType &ser, VKPipe::Shader &el) SERIALISE_MEMBER(pushConstantRangeByteOffset); SERIALISE_MEMBER(pushConstantRangeByteSize); SERIALISE_MEMBER(specializationData); + SERIALISE_MEMBER(specializationIds); - SIZE_CHECK(200); + SIZE_CHECK(224); } template @@ -2348,7 +2349,7 @@ void DoSerialise(SerialiserType &ser, VKPipe::State &el) SERIALISE_MEMBER(conditionalRendering); - SIZE_CHECK(2096); + SIZE_CHECK(2240); } #pragma endregion Vulkan pipeline state