From bc52be931a7666d751d2796e7d7cb8c1035f4aef Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 5 Aug 2026 11:51:10 +0100 Subject: [PATCH] Correctly handle debugging double PS inputs in SPIR-V --- renderdoc/driver/shaders/spirv/spirv_debug.h | 3 + renderdoc/driver/vulkan/vk_shaderdebug.cpp | 71 ++++++++++++++------ 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/renderdoc/driver/shaders/spirv/spirv_debug.h b/renderdoc/driver/shaders/spirv/spirv_debug.h index fc39849b1..01d47ed74 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug.h +++ b/renderdoc/driver/shaders/spirv/spirv_debug.h @@ -186,6 +186,9 @@ struct ResultDataBase uint32_t shadRate; uint32_t padding[2]; + // padding so overall struct size is 8-byte aligned for if LaneData contains 8-byte data + uint32_t paddingForDoubles[4]; + // LaneData lanes[N] // each LaneData is prefixed by the subgroup struct below if needed, and then the stage struct unconditionally }; diff --git a/renderdoc/driver/vulkan/vk_shaderdebug.cpp b/renderdoc/driver/vulkan/vk_shaderdebug.cpp index babaaa6c5..403814684 100644 --- a/renderdoc/driver/vulkan/vk_shaderdebug.cpp +++ b/renderdoc/driver/vulkan/vk_shaderdebug.cpp @@ -53,6 +53,20 @@ struct hash }; } +struct HitStorage +{ + uint32_t hit_count; + uint32_t total_count; + uint32_t dummy; + uint32_t padding; + + // extra padding so the offset of LaneData is 8-byte aligned in case we have user 8-byte inputs + Vec4u paddingForDoubles; + + // dummy entry, used only for offsets of LaneData hits[]; + byte hits; +}; + // should match the descriptor set layout created in ShaderDebugData::Init() enum class ShaderDebugBind { @@ -3907,6 +3921,9 @@ static void CreateInputFetcher(rdcarray &spv, const rdcarray()); rdcspv::Id sint32Type = editor.DeclareType(rdcspv::scalar()); rdcspv::Id floatType = editor.DeclareType(rdcspv::scalar()); @@ -4254,7 +4271,9 @@ static void CreateInputFetcher(rdcarray &spv, const rdcarray &spv, const rdcarray &spv, const rdcarray(numLanes))); @@ -4382,19 +4401,19 @@ static void CreateInputFetcher(rdcarray &spv, const rdcarray( - structStride * numLanes + sizeof(rdcspv::ResultDataBase)))); + ResultDataRTArray, rdcspv::DecorationParam(resultStride))); - rdcspv::Id bufBase = - editor.DeclareStructType("__rd_HitStorage", { - {uint32Type, "hit_count", 0}, - {uint32Type, "total_count", sizeof(uint32_t)}, - {uint32Type, "dummy", sizeof(uint32_t) * 2}, - // uint padding + RDCASSERT((resultStride % paramAlign) == 0); - {ResultDataRTArray, "hits", sizeof(Vec4f)}, - }); + rdcspv::Id bufBase = editor.DeclareStructType( + "__rd_HitStorage", { + {uint32Type, "hit_count", offsetof(HitStorage, hit_count)}, + {uint32Type, "total_count", offsetof(HitStorage, total_count)}, + {uint32Type, "dummy", offsetof(HitStorage, dummy)}, + {ResultDataRTArray, "hits", offsetof(HitStorage, hits)}, + }); rdcspv::StorageClass bufferClass = editor.PrepareAddedBufferAccess(); @@ -5254,22 +5273,27 @@ static void CreateInputFetcher(rdcarray &spv, const rdcarray((uint32_t)val.structIndex)})); + const rdcspv::DataType &dataType = editor.GetDataType(val.type); + rdcspv::MemoryAccessAndParamDatas access = alignedAccess; + if(dataType.scalar().width == 8) + access = aligned8Access; + if(val.base == isHelper) { - ops.add(rdcspv::OpStore(valPtr, isHelperPerQuad[q], alignedAccess)); + ops.add(rdcspv::OpStore(valPtr, isHelperPerQuad[q], access)); } else if(val.base == quadLaneIndex) { - ops.add(rdcspv::OpStore(valPtr, quadIdxConst[q], alignedAccess)); + ops.add(rdcspv::OpStore(valPtr, quadIdxConst[q], access)); } else if(val.flat) { - ops.add(rdcspv::OpStore(valPtr, val.base, alignedAccess)); + ops.add(rdcspv::OpStore(valPtr, val.base, access)); } else { RDCASSERT(!val.quadSwizzledData.empty()); - ops.add(rdcspv::OpStore(valPtr, val.quadSwizzledData[q], alignedAccess)); + ops.add(rdcspv::OpStore(valPtr, val.quadSwizzledData[q], access)); } } @@ -5305,7 +5329,12 @@ static void CreateInputFetcher(rdcarray &spv, const rdcarray((uint32_t)val.structIndex)})); - ops.add(rdcspv::OpStore(valPtr, val.base, alignedAccess)); + const rdcspv::DataType &dataType = editor.GetDataType(val.type); + rdcspv::MemoryAccessAndParamDatas access = alignedAccess; + if(dataType.scalar().width == 8) + access = aligned8Access; + + ops.add(rdcspv::OpStore(valPtr, val.base, access)); } } @@ -5730,7 +5759,7 @@ ShaderDebugTrace *VulkanReplay::DebugVertex(uint32_t eventId, uint32_t vertid, u RDCASSERTMSG("Should only get one hit for vertex shaders", hit_count == 1, hit_count); - base += sizeof(Vec4f); + base += offsetof(HitStorage, hits); rdcspv::ResultDataBase *winner = (rdcspv::ResultDataBase *)base; @@ -6315,7 +6344,7 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_ hit_count = overdrawLevels; } - base += sizeof(Vec4f); + base += offsetof(HitStorage, hits); rdcspv::ResultDataBase *winner = NULL; @@ -6871,7 +6900,7 @@ ShaderDebugTrace *VulkanReplay::DebugComputeCommon(ShaderStage stage, uint32_t e hit_count = maxHits; } - base += sizeof(Vec4f); + base += offsetof(HitStorage, hits); rdcspv::ResultDataBase *winner = (rdcspv::ResultDataBase *)base;