diff --git a/renderdoc/data/hlsl/d3d12_pixelhistory.hlsl b/renderdoc/data/hlsl/d3d12_pixelhistory.hlsl new file mode 100644 index 000000000..deb79b61e --- /dev/null +++ b/renderdoc/data/hlsl/d3d12_pixelhistory.hlsl @@ -0,0 +1,171 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2023 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +cbuffer CopyPixelShaderInput : register(b0) +{ + uint4 src_coord; // x, y, mip/sample, slice + + uint dst_slot; + bool copy_depth; + bool copy_stencil; + + bool multisampled; + bool is_float; + bool is_uint; + bool is_int; +}; + +Texture2DArray copyin_depth : register(t0); +Texture2DArray copyin_stencil : register(t1); + +Texture2DMSArray copyin_depth_ms : register(t2); +Texture2DMSArray copyin_stencil_ms : register(t3); + +Texture2DArray copyin_float : register(t4); +Texture2DMSArray copyin_float_ms : register(t5); + +Texture2DArray copyin_uint : register(t6); +Texture2DMSArray copyin_uint_ms : register(t7); + +Texture2DArray copyin_int : register(t8); +Texture2DMSArray copyin_int_ms : register(t9); + +RWBuffer copyout_depth : register(u0); +RWBuffer copyout_stencil : register(u1); +RWBuffer copyout_float : register(u2); +RWBuffer copyout_uint : register(u3); +RWBuffer copyout_int : register(u4); + +[numthreads(1, 1, 1)] void RENDERDOC_PixelHistoryUnused() { copyout_depth[dst_slot] = -1.0f; } + + [numthreads(1, 1, 1)] void RENDERDOC_PixelHistoryCopyPixel() +{ + if(multisampled) + { + if(copy_depth) + { + float val = copyin_depth_ms.sample[src_coord.z][uint3(src_coord.xy, src_coord.w)]; + copyout_depth[dst_slot] = val; + } + else if(copy_stencil) + { + uint val = copyin_stencil_ms.sample[src_coord.z][uint3(src_coord.xy, src_coord.w)]; + copyout_stencil[dst_slot] = val; + } + else + { + if(is_float) + { + float4 val = copyin_float_ms.sample[src_coord.z][uint3(src_coord.xy, src_coord.w)]; + copyout_float[dst_slot] = val.x; + copyout_float[dst_slot + 1] = val.y; + copyout_float[dst_slot + 2] = val.z; + copyout_float[dst_slot + 3] = val.w; + } + else if(is_uint) + { + uint4 val = copyin_uint_ms.sample[src_coord.z][uint3(src_coord.xy, src_coord.w)]; + copyout_uint[dst_slot] = val.x; + copyout_uint[dst_slot + 1] = val.y; + copyout_uint[dst_slot + 2] = val.z; + copyout_uint[dst_slot + 3] = val.w; + } + else if(is_int) + { + int4 val = copyin_int_ms.sample[src_coord.z][uint3(src_coord.xy, src_coord.w)]; + copyout_int[dst_slot] = val.x; + copyout_int[dst_slot + 1] = val.y; + copyout_int[dst_slot + 2] = val.z; + copyout_int[dst_slot + 3] = val.w; + } + } + } + else + { + if(copy_depth) + { + float val = copyin_depth.mips[src_coord.z][uint3(src_coord.xy, src_coord.w)]; + copyout_depth[dst_slot] = val; + } + else if(copy_stencil) + { + uint val = copyin_stencil.mips[src_coord.z][uint3(src_coord.xy, src_coord.w)]; + copyout_stencil[dst_slot] = val; + } + else + { + if(is_float) + { + float4 val = copyin_float.mips[src_coord.z][uint3(src_coord.xy, src_coord.w)]; + copyout_float[dst_slot] = val.x; + copyout_float[dst_slot + 1] = val.y; + copyout_float[dst_slot + 2] = val.z; + copyout_float[dst_slot + 3] = val.w; + } + else if(is_uint) + { + uint4 val = copyin_uint.mips[src_coord.z][uint3(src_coord.xy, src_coord.w)]; + copyout_uint[dst_slot] = val.x; + copyout_uint[dst_slot + 1] = val.y; + copyout_uint[dst_slot + 2] = val.z; + copyout_uint[dst_slot + 3] = val.w; + } + else if(is_int) + { + int4 val = copyin_int.mips[src_coord.z][uint3(src_coord.xy, src_coord.w)]; + copyout_int[dst_slot] = val.x; + copyout_int[dst_slot + 1] = val.y; + copyout_int[dst_slot + 2] = val.z; + copyout_int[dst_slot + 3] = val.w; + } + } + } +} + +float4 RENDERDOC_PrimitiveIDPS(uint prim : SV_PrimitiveID) : SV_Target0 +{ + return asfloat(prim).xxxx; +} + +struct MultipleOutput +{ + float4 col0 : SV_Target0; + float4 col1 : SV_Target1; + float4 col2 : SV_Target2; + float4 col3 : SV_Target3; + float4 col4 : SV_Target4; + float4 col5 : SV_Target5; + float4 col6 : SV_Target6; + float4 col7 : SV_Target7; +}; + +MultipleOutput RENDERDOC_PixelHistoryFixedColPS() +{ + MultipleOutput OUT = (MultipleOutput)0; + + float4 color = float4(0.1f, 0.2f, 0.3f, 0.4f); + OUT.col0 = OUT.col1 = OUT.col2 = OUT.col3 = OUT.col4 = OUT.col5 = OUT.col6 = OUT.col7 = color; + + return OUT; +} diff --git a/renderdoc/data/renderdoc.rc b/renderdoc/data/renderdoc.rc index 312a77517..260d37e37 100644 --- a/renderdoc/data/renderdoc.rc +++ b/renderdoc/data/renderdoc.rc @@ -115,6 +115,7 @@ RESOURCE_quadoverdraw_hlsl TYPE_EMBED "hlsl/quadoverdraw.hlsl" RESOURCE_texremap_hlsl TYPE_EMBED "hlsl/texremap.hlsl" RESOURCE_fixedcol_hlsl TYPE_EMBED "hlsl/fixedcol.hlsl" RESOURCE_shaderdebug_hlsl TYPE_EMBED "hlsl/shaderdebug.hlsl" +RESOURCE_d3d12_pixelhistory_hlsl TYPE_EMBED "hlsl/d3d12_pixelhistory.hlsl" #ifdef RENDERDOC_BAKED_DXC_SHADERS diff --git a/renderdoc/data/resource.h b/renderdoc/data/resource.h index 0ef0d8c96..f5ebdc8a1 100644 --- a/renderdoc/data/resource.h +++ b/renderdoc/data/resource.h @@ -18,6 +18,7 @@ #define RESOURCE_texremap_hlsl 111 #define RESOURCE_fixedcol_hlsl 112 #define RESOURCE_shaderdebug_hlsl 118 +#define RESOURCE_d3d12_pixelhistory_hlsl 119 #define RESOURCE_fixedcol_0_dxbc 113 #define RESOURCE_fixedcol_1_dxbc 114 diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index bf4568edf..0fe04970b 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -337,6 +337,43 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, "ps_5_0", &m_DepthArray2MS); } + { + ID3DBlob *root = shaderCache->MakeRootSig({ + cbvParam(D3D12_SHADER_VISIBILITY_ALL, 0, 0), + tableParam(D3D12_SHADER_VISIBILITY_ALL, D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0, 0, 5), + tableParam(D3D12_SHADER_VISIBILITY_ALL, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 0, 10), + }); + + RDCASSERT(root); + + hr = m_pDevice->CreateRootSignature(0, root->GetBufferPointer(), root->GetBufferSize(), + __uuidof(ID3D12RootSignature), + (void **)&m_PixelHistoryCopySig); + m_pDevice->InternalRef(); + + SAFE_RELEASE(root); + + rm->SetInternalResource(m_PixelHistoryCopySig); + + rdcstr hlsl = GetEmbeddedResource(d3d12_pixelhistory_hlsl); + + shaderCache->GetShaderBlob(hlsl.c_str(), "RENDERDOC_PixelHistoryCopyPixel", + D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, "cs_5_0", &m_PixelHistoryCopyCS); + + D3D12_COMPUTE_PIPELINE_STATE_DESC pipeDesc = {}; + pipeDesc.CS.pShaderBytecode = m_PixelHistoryCopyCS->GetBufferPointer(); + pipeDesc.CS.BytecodeLength = m_PixelHistoryCopyCS->GetBufferSize(); + pipeDesc.pRootSignature = m_PixelHistoryCopySig; + hr = m_pDevice->CreateComputePipelineState(&pipeDesc, __uuidof(ID3D12PipelineState), + (void **)&m_PixelHistoryCopyPso); + if(FAILED(hr)) + { + RDCERR("Failed to create PSO for pixel history HRESULT: %s", ToStr(hr).c_str()); + return; + } + m_pDevice->GetResourceManager()->SetInternalResource(m_PixelHistoryCopyPso); + } + shaderCache->SetCaching(false); D3D12_RESOURCE_DESC readbackDesc; @@ -490,6 +527,10 @@ D3D12DebugManager::~D3D12DebugManager() SAFE_RELEASE(m_FloatArray2MS); SAFE_RELEASE(m_DepthArray2MS); + SAFE_RELEASE(m_PixelHistoryCopyCS); + SAFE_RELEASE(m_PixelHistoryCopySig); + SAFE_RELEASE(m_PixelHistoryCopyPso); + SAFE_RELEASE(m_ReadbackBuffer); SAFE_RELEASE(m_RingConstantBuffer); diff --git a/renderdoc/driver/d3d12/d3d12_debug.h b/renderdoc/driver/d3d12/d3d12_debug.h index 96c16fb58..3634a1032 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.h +++ b/renderdoc/driver/d3d12/d3d12_debug.h @@ -31,7 +31,9 @@ class WrappedID3D12Device; class D3D12ResourceManager; +struct D3D12CopyPixelParams; struct D3D12Descriptor; +struct D3D12PixelHistoryResources; namespace DXBC { @@ -80,6 +82,14 @@ enum CBVUAVSRVSlot FIRST_SHADDEBUG_SRV, LAST_SHADDEBUG_SRV = FIRST_SHADDEBUG_SRV + 25, + FIRST_PIXELHISTORY_SRV, + LAST_PIXELHISTORY_SRV = FIRST_PIXELHISTORY_SRV + 10, + FIRST_PIXELHISTORY_SCRATCH_SRV, + LAST_PIXELHISTORY_SCRATCH_SRV = LAST_PIXELHISTORY_SRV + 10, + + FIRST_PIXELHISTORY_UAV, + LAST_PIXELHISTORY_UAV = FIRST_PIXELHISTORY_UAV + 5, + MAX_SRV_SLOT, }; @@ -91,6 +101,7 @@ enum RTVSlot GET_TEX_RTV, MSAA_RTV, SHADER_DEBUG_RTV, + PIXEL_HISTORY_RTV, FIRST_TMP_RTV, LAST_TMP_RTV = FIRST_TMP_RTV + 16, FIRST_WIN_RTV, @@ -110,6 +121,7 @@ enum DSVSlot { OVERLAY_DSV, MSAA_DSV, + PIXEL_HISTORY_DSV, TMP_DSV, FIRST_WIN_DSV, LAST_WIN_DSV = FIRST_WIN_DSV + 64, @@ -192,6 +204,14 @@ public: ID3D12Resource *srcMS); void CopyArrayToTex2DMS(ID3D12Resource *destMS, ID3D12Resource *srcArray, UINT selectedSlice); + void PixelHistoryCopyPixel(ID3D12GraphicsCommandListX *cmd, ID3D12Resource *dstBuffer, + D3D12CopyPixelParams ¶ms, size_t offset); + + bool PixelHistorySetupResources(D3D12PixelHistoryResources &resources, + WrappedID3D12Resource *targetImage, + const D3D12_RESOURCE_DESC &desc, uint32_t numEvents); + bool PixelHistoryDestroyResources(D3D12PixelHistoryResources &resources); + private: bool CreateShaderDebugResources(); @@ -230,6 +250,11 @@ private: ID3D12PipelineState *m_TexSamplePso = NULL; std::map m_OffsetTexSamplePso; + // PixelHistoryCopyPixel + ID3D12RootSignature *m_PixelHistoryCopySig = NULL; + ID3DBlob *m_PixelHistoryCopyCS = NULL; + ID3D12PipelineState *m_PixelHistoryCopyPso = NULL; + // GetBufferData static const uint64_t m_ReadbackSize = 16 * 1024 * 1024; diff --git a/renderdoc/driver/d3d12/d3d12_pixelhistory.cpp b/renderdoc/driver/d3d12/d3d12_pixelhistory.cpp new file mode 100644 index 000000000..c72f822fe --- /dev/null +++ b/renderdoc/driver/d3d12/d3d12_pixelhistory.cpp @@ -0,0 +1,371 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2023 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "driver/dxgi/dxgi_common.h" +#include "d3d12_command_queue.h" +#include "d3d12_debug.h" + +struct D3D12CopyPixelParams +{ + // The image being copied from + ID3D12Resource *srcImage; + + // The source image format and format to use when copying. In most cases these are + // the same, but for some planar formats, the copy format will correspond to a single + // plane's typeless format, not the multi-plane format. + DXGI_FORMAT srcImageFormat; + DXGI_FORMAT copyFormat; + D3D12_RESOURCE_STATES srcImageState; + + // Data about the pixel we want to copy + uint32_t x; + uint32_t y; + uint32_t mip; + uint32_t sample; + uint32_t planeSlice; + uint32_t arraySlice; + + // Additional info to inform how to copy + bool depthcopy; + bool multisampled; + bool scratchBuffer; +}; + +struct D3D12PixelHistoryResources +{ + ID3D12Resource *dstBuffer; + + // Used for offscreen color/depth/stencil rendering for draw call events. + ID3D12Resource *colorImage; + D3D12Descriptor *colorDescriptor; + ID3D12Resource *dsImage; + D3D12Descriptor *dsDescriptor; +}; + +struct D3D12PixelHistoryValue +{ + // Max size is 4 component with 8 byte component width + uint8_t color[32]; + union + { + uint32_t udepth; + float fdepth; + } depth; + int8_t stencil; + uint8_t padding[3 + 8]; +}; + +struct D3D12EventInfo +{ + D3D12PixelHistoryValue premod; + D3D12PixelHistoryValue postmod; + uint8_t dsWithoutShaderDiscard[8]; + uint8_t padding[8]; + uint8_t dsWithShaderDiscard[8]; + uint8_t padding1[8]; +}; + +// Helper function to copy a single pixel out of a source texture, which will handle any texture +// type and binding type, doing any copying as needed. Writes the result to a given buffer UAV. +void D3D12DebugManager::PixelHistoryCopyPixel(ID3D12GraphicsCommandListX *cmd, + ID3D12Resource *dstBuffer, D3D12CopyPixelParams &p, + size_t offset) +{ + D3D12RenderState &state = m_pDevice->GetQueue()->GetCommandData()->GetCurRenderState(); + D3D12RenderState prevState = state; + + state.pipe = GetResID(m_PixelHistoryCopyPso); + state.compute.rootsig = GetResID(m_PixelHistoryCopySig); + + bool floatTex = false, uintTex = false, intTex = false; + DXGI_FORMAT srvFormat = p.srcImageFormat; + bool uintStencil = p.depthcopy && p.planeSlice == 1 && + (p.srcImageFormat == DXGI_FORMAT_X24_TYPELESS_G8_UINT || + p.srcImageFormat == DXGI_FORMAT_X32_TYPELESS_G8X24_UINT); + if(IsUIntFormat(p.srcImageFormat) || uintStencil) + { + uintTex = true; + srvFormat = GetUIntTypedFormat(srvFormat); + } + else if(IsIntFormat(p.srcImageFormat)) + { + intTex = true; + srvFormat = GetSIntTypedFormat(srvFormat); + } + else + { + floatTex = true; + srvFormat = GetFloatTypedFormat(srvFormat); + } + + UINT srvIndex = 0; + UINT uavIndex = 0; + + // SRV indices by type: + // 0 - depth + // 1 - stencil + // 2 - depth MSAA + // 3 - stencil MSAA + // 4 - float + // 5 - float MSAA + // 6 - uint + // 7 - uint MSAA + // 8 - int + // 9 - int MSAA + + // UAV indices by type: + // 0 - depth + // 1 - stencil + // 2 - float + // 3 - uint + // 4 - int + + // Determine which SRV we will read from in the shader + if(p.depthcopy) + { + srvIndex = p.planeSlice; + if(p.multisampled) + srvIndex += 2; + + // This should already be the SRV format for depth/stencil copies + srvFormat = p.srcImageFormat; + } + else + { + if(floatTex) + srvIndex = 4; + else if(uintTex) + srvIndex = 6; + else if(intTex) + srvIndex = 8; + + if(p.multisampled) + srvIndex++; + } + + // Determine which UAV we will write to in the shader + if(p.depthcopy && p.planeSlice == 0) + uavIndex = 0; + else if(p.depthcopy && p.planeSlice == 1) + uavIndex = 1; + else if(floatTex) + uavIndex = 2; + else if(uintTex) + uavIndex = 3; + else + uavIndex = 4; + + struct CopyPixelShaderInput + { + Vec4u src_coord; // x, y, mip/sample, slice + + uint32_t dst_slot; + uint32_t copy_depth; + uint32_t copy_stencil; + + uint32_t multisampled; + uint32_t is_float; + uint32_t is_uint; + uint32_t is_int; + } inputData; + + inputData.src_coord = {p.x, p.y, p.multisampled ? p.sample : p.mip, p.arraySlice}; + inputData.multisampled = p.multisampled; + inputData.is_float = floatTex; + inputData.is_uint = uintTex; + inputData.is_int = intTex; + + inputData.dst_slot = (uint32_t)(offset / sizeof(float)); + inputData.copy_depth = p.depthcopy && p.planeSlice == 0; + inputData.copy_stencil = p.depthcopy && p.planeSlice == 1; + + // When copying a scratch buffer, we need to use a different SRV range from the heap + CBVUAVSRVSlot srvStartSlot = + p.scratchBuffer ? FIRST_PIXELHISTORY_SCRATCH_SRV : FIRST_PIXELHISTORY_SRV; + D3D12_CPU_DESCRIPTOR_HANDLE srv = m_pDevice->GetDebugManager()->GetCPUHandle(srvStartSlot); + D3D12_CPU_DESCRIPTOR_HANDLE uav = + m_pDevice->GetDebugManager()->GetCPUHandle(FIRST_PIXELHISTORY_UAV); + + m_pDevice->GetDebugManager()->SetDescriptorHeaps(state.heaps, true, false); + state.compute.sigelems = { + D3D12RenderState::SignatureElement( + eRootCBV, m_pDevice->GetDebugManager()->UploadConstants(&inputData, sizeof(inputData))), + D3D12RenderState::SignatureElement(eRootTable, uav), + D3D12RenderState::SignatureElement(eRootTable, srv), + }; + + srv.ptr += srvIndex * sizeof(D3D12Descriptor); + + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.ViewDimension = + p.multisampled ? D3D12_SRV_DIMENSION_TEXTURE2DMS : D3D12_SRV_DIMENSION_TEXTURE2D; + srvDesc.Format = p.srcImageFormat; + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + if(!p.multisampled) + { + srvDesc.Texture2D.MipLevels = 1; + srvDesc.Texture2D.PlaneSlice = p.planeSlice; + } + m_pDevice->CreateShaderResourceView(p.srcImage, &srvDesc, srv); + + uav.ptr += uavIndex * sizeof(D3D12Descriptor); + + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; + uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; + uavDesc.Format = DXGI_FORMAT_UNKNOWN; + uavDesc.Buffer.NumElements = (UINT)(dstBuffer->GetDesc().Width / sizeof(float)); + uavDesc.Buffer.FirstElement = 0; + uavDesc.Buffer.StructureByteStride = sizeof(float); + m_pDevice->CreateUnorderedAccessView(dstBuffer, NULL, &uavDesc, uav); + + state.ApplyState(m_pDevice, cmd); + cmd->Dispatch(1, 1, 1); + + state = prevState; + state.ApplyState(m_pDevice, cmd); +} + +bool D3D12DebugManager::PixelHistorySetupResources(D3D12PixelHistoryResources &resources, + WrappedID3D12Resource *targetImage, + const D3D12_RESOURCE_DESC &desc, + uint32_t numEvents) +{ + D3D12MarkerRegion region( + m_pDevice->GetQueue()->GetReal(), + StringFormat::Fmt("PixelHistorySetupResources %ux%ux%u %s %ux MSAA", desc.Width, desc.Height, + desc.DepthOrArraySize, ToStr(desc.Format).c_str(), desc.SampleDesc.Count)); + + ResourceFormat targetFmt = MakeResourceFormat(desc.Format); + + ID3D12Resource *colorImage; + ID3D12Resource *dsImage; + ID3D12Resource *dstBuffer; + + HRESULT hr = S_OK; + + D3D12_HEAP_PROPERTIES heapProps; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 1; + heapProps.VisibleNodeMask = 1; + + D3D12_RESOURCE_DESC imageDesc = desc; + imageDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + imageDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + imageDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + + hr = m_pDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &imageDesc, + D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, + __uuidof(ID3D12Resource), (void **)&colorImage); + m_pDevice->CheckHRESULT(hr); + if(FAILED(hr)) + { + RDCERR("Failed to create scratch render target for pixel history: %s", ToStr(hr).c_str()); + return false; + } + colorImage->SetName(L"Pixel History Color Image"); + + D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; + rtvDesc.Format = imageDesc.Format; + rtvDesc.ViewDimension = imageDesc.SampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS + : D3D12_RTV_DIMENSION_TEXTURE2D; + D3D12_CPU_DESCRIPTOR_HANDLE rtv = m_pDevice->GetDebugManager()->GetCPUHandle(PIXEL_HISTORY_RTV); + m_pDevice->CreateRenderTargetView(colorImage, &rtvDesc, rtv); + + imageDesc.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + imageDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + hr = m_pDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &imageDesc, + D3D12_RESOURCE_STATE_DEPTH_WRITE, NULL, + __uuidof(ID3D12Resource), (void **)&dsImage); + m_pDevice->CheckHRESULT(hr); + if(FAILED(hr)) + { + RDCERR("Failed to create scratch depth stencil for pixel history: %s", ToStr(hr).c_str()); + SAFE_RELEASE(colorImage); + + return false; + } + dsImage->SetName(L"Pixel History Depth Stencil"); + + D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; + dsvDesc.Format = imageDesc.Format; + dsvDesc.ViewDimension = imageDesc.SampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS + : D3D12_DSV_DIMENSION_TEXTURE2D; + D3D12_CPU_DESCRIPTOR_HANDLE dsv = m_pDevice->GetDebugManager()->GetCPUHandle(PIXEL_HISTORY_DSV); + m_pDevice->CreateDepthStencilView(dsImage, &dsvDesc, dsv); + + // With a readback heap, buffers cannot be created with the UAV flag. As a workaround, a custom heap + // can be created with the same properties as a readback heap, and then the UAV flag is permitted. + D3D12_HEAP_PROPERTIES readbackHeapProps = + m_pDevice->GetCustomHeapProperties(0, D3D12_HEAP_TYPE_READBACK); + + D3D12_RESOURCE_DESC bufDesc; + bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + bufDesc.Alignment = 0; + bufDesc.Height = 1; + bufDesc.DepthOrArraySize = 1; + bufDesc.MipLevels = 1; + bufDesc.Format = DXGI_FORMAT_UNKNOWN; + bufDesc.SampleDesc.Count = 1; + bufDesc.SampleDesc.Quality = 0; + bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + bufDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + + bufDesc.Width = AlignUp((uint32_t)(numEvents * sizeof(D3D12EventInfo)), 4096U); + + hr = m_pDevice->CreateCommittedResource(&readbackHeapProps, D3D12_HEAP_FLAG_NONE, &bufDesc, + D3D12_RESOURCE_STATE_COPY_DEST, NULL, + __uuidof(ID3D12Resource), (void **)&dstBuffer); + m_pDevice->CheckHRESULT(hr); + if(FAILED(hr)) + { + RDCERR("Failed to create readback buffer for pixel history: %s", ToStr(hr).c_str()); + SAFE_RELEASE(colorImage); + SAFE_RELEASE(dsImage); + return false; + } + dstBuffer->SetName(L"Pixel History DstBuffer"); + + resources.colorImage = colorImage; + resources.colorDescriptor = GetWrapped(rtv); + + resources.dsImage = dsImage; + resources.dsDescriptor = GetWrapped(dsv); + + resources.dstBuffer = dstBuffer; + + return true; +} + +bool D3D12DebugManager::PixelHistoryDestroyResources(D3D12PixelHistoryResources &r) +{ + SAFE_RELEASE(r.colorImage); + r.colorDescriptor = NULL; + SAFE_RELEASE(r.dsImage); + r.dsDescriptor = NULL; + SAFE_RELEASE(r.dstBuffer); + + return true; +} diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj index d4bf8c49d..9fdcb43e6 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj @@ -136,6 +136,7 @@ + diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters index 2bef07bde..5b32ff1df 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters @@ -227,5 +227,8 @@ Wrapped + + Replay + \ No newline at end of file diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index 538551b7d..a56345ad2 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -720,6 +720,7 @@ + diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index 666f949e4..3571c74e0 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -1084,6 +1084,9 @@ Resources\hlsl + + Resources\hlsl + Resources\hlsl