diff --git a/renderdoc/data/hlsl/pixelhistory.hlsl b/renderdoc/data/hlsl/pixelhistory.hlsl index a01c5a73b..b0191eb30 100644 --- a/renderdoc/data/hlsl/pixelhistory.hlsl +++ b/renderdoc/data/hlsl/pixelhistory.hlsl @@ -30,6 +30,8 @@ cbuffer cb0 : register(b0) bool is_float; bool is_uint; bool is_int; + + bool is_3d; }; cbuffer cb1 : register(b1) @@ -47,12 +49,15 @@ Texture2DMSArray copyin_stencil_ms : register(t3); Texture2DArray copyin_float : register(t4); Texture2DMSArray copyin_float_ms : register(t5); +Texture3D copyin_float_3d : register(t6); -Texture2DArray copyin_uint : register(t6); -Texture2DMSArray copyin_uint_ms : register(t7); +Texture2DArray copyin_uint : register(t8); +Texture2DMSArray copyin_uint_ms : register(t9); +Texture3D copyin_uint_3d : register(t10); -Texture2DArray copyin_int : register(t8); -Texture2DMSArray copyin_int_ms : register(t9); +Texture2DArray copyin_int : register(t12); +Texture2DMSArray copyin_int_ms : register(t13); +Texture3D copyin_int_3d : register(t14); RWBuffer copyout_depth : register(u0); RWBuffer copyout_float : register(u1); @@ -93,6 +98,21 @@ RWBuffer copyout_int : register(u3); } } } + else if(is_3d) + { + if(is_float) + { + copyout_float[dst_slot] = copyin_float_3d.Load(src_coord.xywz); + } + else if(is_uint) + { + copyout_uint[dst_slot] = copyin_uint_3d.Load(src_coord.xywz); + } + else if(is_int) + { + copyout_int[dst_slot] = copyin_int_3d.Load(src_coord.xywz); + } + } else { if(copy_depth || copy_stencil) diff --git a/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp b/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp index 8830004ce..a592aa540 100644 --- a/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp +++ b/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp @@ -137,6 +137,7 @@ struct D3D11CopyPixelParams bool floatTex; bool uintTex; bool intTex; + bool tex3d; UINT subres; @@ -246,12 +247,14 @@ void D3D11DebugManager::PixelHistoryCopyPixel(D3D11CopyPixelParams &p, size_t ev if(p.floatTex) offs = 4; else if(p.uintTex) - offs = 6; - else if(p.intTex) offs = 8; + else if(p.intTex) + offs = 12; if(p.multisampled) offs++; + else if(p.tex3d) + offs += 2; } m_pImmediateContext->CSSetShaderResources(offs, 2, p.srv); @@ -555,7 +558,7 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event ID3D11Texture2D *depthCopyD16 = NULL; ID3D11ShaderResourceView *depthCopyD16_DepthSRV = NULL; - uint32_t srcxyData[8] = { + uint32_t srcxyData[12] = { x, y, multisampled ? sampleIdx : mip, @@ -565,14 +568,18 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event uint32_t(floatTex), uint32_t(uintTex), uint32_t(intTex), + + uint32_t(details.texType == eTexType_3D), }; - uint32_t shadoutsrcxyData[8]; + uint32_t shadoutsrcxyData[12]; memcpy(shadoutsrcxyData, srcxyData, sizeof(srcxyData)); // shadout texture doesn't have slices/mips, just one of the right dimension shadoutsrcxyData[2] = multisampled ? sampleIdx : 0; shadoutsrcxyData[3] = 0; + // and is not 3D + shadoutsrcxyData[8] = 0; ID3D11Buffer *srcxyCBuf = GetDebugManager()->MakeCBuffer(sizeof(srcxyData)); ID3D11Buffer *shadoutsrcxyCBuf = GetDebugManager()->MakeCBuffer(sizeof(shadoutsrcxyData)); @@ -622,10 +629,16 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event colourCopyParams.intTex = intTex; colourCopyParams.srcxyCBuf = srcxyCBuf; colourCopyParams.storeCBuf = storeCBuf; + colourCopyParams.tex3d = false; if(details.texType == eTexType_3D) + { colourCopyParams.subres = mip; + colourCopyParams.tex3d = true; + } else + { colourCopyParams.subres = details.texMips * slice + mip; + } D3D11CopyPixelParams depthCopyParams = colourCopyParams; @@ -638,6 +651,7 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event depthCopyParams.depthcopy = true; depthCopyParams.uav = pixstoreDepthUAV; + depthCopyParams.tex3d = false; // while issuing the above queries we can check to see which tests are enabled so we don't // bother checking if depth testing failed if the depth test was disabled @@ -2015,11 +2029,13 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event shadoutCopyParams.subres = 0; shadoutCopyParams.uav = shadoutStoreUAV; shadoutCopyParams.srcxyCBuf = shadoutsrcxyCBuf; + shadoutCopyParams.tex3d = false; depthCopyParams.sourceTex = depthCopyParams.srvTex = shaddepthOutput; depthCopyParams.srv[0] = shaddepthOutputDepthSRV; depthCopyParams.srv[1] = shaddepthOutputStencilSRV; depthCopyParams.srcxyCBuf = shadoutsrcxyCBuf; + depthCopyParams.tex3d = false; for(size_t h = 0; h < history.size(); h++) { @@ -2170,12 +2186,25 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event { D3D11MarkerRegion middraw("fetching mid-action"); - m_pImmediateContext->OMSetRenderTargets(rtIndex + 1, RTVs, shaddepthOutputDSV); + // 3D depth is not supported but we need depth for fragment counting - so as a bit of a compromise + // we fetch postmod via an extra shader output slot. This will not properly emulate precision or blending + if(details.texType == eTexType_3D) + { + ID3D11RenderTargetView *sparseRTVs[8] = {0}; + sparseRTVs[rtIndex] = shadOutputRTV; + m_pImmediateContext->OMSetRenderTargets(rtIndex + 1, sparseRTVs, shaddepthOutputDSV); + } + else + { + m_pImmediateContext->OMSetRenderTargets(rtIndex + 1, RTVs, shaddepthOutputDSV); + } m_pDevice->ReplayLog(0, history[h].eventId, eReplay_OnlyDraw); - GetDebugManager()->PixelHistoryCopyPixel(colourCopyParams, postColSlot, 0); - postColSlot++; + if(details.texType != eTexType_3D) + GetDebugManager()->PixelHistoryCopyPixel(colourCopyParams, postColSlot++, 0); + else + GetDebugManager()->PixelHistoryCopyPixel(shadoutCopyParams, shadColSlot++, 0); GetDebugManager()->PixelHistoryCopyPixel(depthCopyParams, depthSlot, 1); } @@ -2301,11 +2330,60 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event { lastMod = false; // colour + if(details.texType != eTexType_3D) { uint32_t offsettedSlot = (postColSlot - discardedOffset); byte *data = pixstoreData + sizeof(Vec4f) * pixstoreStride * offsettedSlot; memcpy(&history[h].postMod.col.uintValue[0], data, sizeof(Vec4f)); } + else + { + // for 3D textures we copied to an extra shader output slot, because we needed a depth + // texture to count fragments and we can't bind depth with 3D + uint32_t offsettedSlot = (shadColSlot - discardedOffset); + RDCASSERT(discardedOffset <= shadColSlot); + + byte *data = shadoutStoreData + sizeof(Vec4f) * pixstoreStride * offsettedSlot; + + memcpy(&history[h].postMod.col.uintValue[0], data, sizeof(Vec4f)); + shadColSlot++; + + // this is a hack - we don't try to emulate precision but at least clamp representable ranges + ResourceFormat fmt = MakeResourceFormat(details.texFmt); + if(fmt.compType == CompType::UNorm) + { + for(uint32_t i = 0; i < 4; i++) + history[h].postMod.col.floatValue[i] = + RDCCLAMP(history[h].postMod.col.floatValue[i], 0.0f, 1.0f); + } + else if(fmt.compType == CompType::Float && fmt.compByteWidth == 2) + { + for(uint32_t i = 0; i < 4; i++) + history[h].postMod.col.floatValue[i] = + RDCCLAMP(history[h].postMod.col.floatValue[i], -65504.0f, 65504.0f); + } + else if(fmt.compType == CompType::UInt && fmt.compByteWidth < 4) + { + uint32_t maxVal = (1U << fmt.compByteWidth) - 1; + for(uint32_t i = 0; i < 4; i++) + history[h].postMod.col.uintValue[i] = RDCMIN(history[h].postMod.col.uintValue[i], maxVal); + } + else if(fmt.compType == CompType::SInt && fmt.compByteWidth == 2) + { + for(uint32_t i = 0; i < 4; i++) + history[h].postMod.col.intValue[i] = + RDCCLAMP(history[h].postMod.col.intValue[i], (int32_t)INT16_MIN, (int32_t)INT16_MAX); + } + else if(fmt.compType == CompType::SInt && fmt.compByteWidth == 1) + { + for(uint32_t i = 0; i < 4; i++) + history[h].postMod.col.intValue[i] = + RDCCLAMP(history[h].postMod.col.intValue[i], (int32_t)INT8_MIN, (int32_t)INT8_MAX); + } + + for(uint32_t i = fmt.compCount; i < 4; i++) + history[h].postMod.col.uintValue[i] = 0; + } { uint32_t offsettedSlot = (depthSlot - discardedOffset); diff --git a/renderdoc/driver/vulkan/vk_pixelhistory.cpp b/renderdoc/driver/vulkan/vk_pixelhistory.cpp index 5abba66fd..8600244f7 100644 --- a/renderdoc/driver/vulkan/vk_pixelhistory.cpp +++ b/renderdoc/driver/vulkan/vk_pixelhistory.cpp @@ -186,6 +186,7 @@ struct PixelHistoryCallbackInfo Subresource targetSubresource; uint32_t x; uint32_t y; + uint32_t z; uint32_t sampleMask; // Image used to get per fragment data. @@ -1535,6 +1536,12 @@ protected: // For pipeline barriers. VkImageSubresourceRange subresource = {aspectFlags, baseMip, 1, baseSlice, 1}; + if(p.srcImage == m_CallbackInfo.targetImage && (m_CallbackInfo.extent.depth > 1)) + { + subresource.baseArrayLayer = baseSlice = 0; + subresource.layerCount = VK_REMAINING_ARRAY_LAYERS; + } + // For multi-sampled images can't call vkCmdCopyImageToBuffer directly, // copy using a compute shader into a staging image first. if(p.multisampled) @@ -1589,6 +1596,11 @@ protected: region.imageSubresource.mipLevel = baseMip; region.imageSubresource.layerCount = 1; + if(p.srcImage == m_CallbackInfo.targetImage) + { + region.imageOffset.z = m_CallbackInfo.z; + } + if(!depthCopy) { region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -4051,6 +4063,8 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imgInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + if(extent.depth > 1) + imgInfo.arrayLayers = extent.depth; if(samples != VK_SAMPLE_COUNT_1_BIT) imgInfo.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; @@ -4543,6 +4557,7 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even callbackInfo.targetSubresource = sub; callbackInfo.x = x; callbackInfo.y = y; + callbackInfo.z = 0; callbackInfo.sampleMask = sampleMask; callbackInfo.subImage = resources.colorImage; callbackInfo.subImageView = resources.colorImageView; @@ -4552,6 +4567,12 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even callbackInfo.dstBuffer = resources.dstBuffer; callbackInfo.multisampled = imginfo.samples != VK_SAMPLE_COUNT_1_BIT; + if(imginfo.type == VK_IMAGE_TYPE_3D) + { + callbackInfo.z = sub.slice; + callbackInfo.targetSubresource.slice = 0; + } + VulkanOcclusionCallback occlCb(m_pDriver, shaderCache, callbackInfo, occlusionPool, events); { VkMarkerRegion occlRegion("VulkanOcclusionCallback");