From 159a67b853c9631a012ae64ec4bb785160ebb2c7 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 5 Oct 2018 14:09:30 +0100 Subject: [PATCH] Implement MSAA to Array colour copies. Closes #1023 --- renderdoc/data/hlsl/multisample.hlsl | 8 +- .../driver/d3d11/d3d11_msaa_array_conv.cpp | 10 +- renderdoc/driver/d3d12/d3d12_common.cpp | 8 +- renderdoc/driver/d3d12/d3d12_debug.cpp | 90 ++- renderdoc/driver/d3d12/d3d12_debug.h | 30 + renderdoc/driver/d3d12/d3d12_device.cpp | 3 +- renderdoc/driver/d3d12/d3d12_device.h | 7 +- renderdoc/driver/d3d12/d3d12_initstate.cpp | 364 +++++++++--- renderdoc/driver/d3d12/d3d12_manager.cpp | 2 +- renderdoc/driver/d3d12/d3d12_manager.h | 1 - .../driver/d3d12/d3d12_msaa_array_conv.cpp | 541 ++++++++++++++++++ renderdoc/driver/d3d12/d3d12_replay.cpp | 77 ++- .../driver/d3d12/renderdoc_d3d12.vcxproj | 1 + .../d3d12/renderdoc_d3d12.vcxproj.filters | 3 + 14 files changed, 1041 insertions(+), 104 deletions(-) create mode 100644 renderdoc/driver/d3d12/d3d12_msaa_array_conv.cpp diff --git a/renderdoc/data/hlsl/multisample.hlsl b/renderdoc/data/hlsl/multisample.hlsl index ba2eea3a3..85da21106 100644 --- a/renderdoc/data/hlsl/multisample.hlsl +++ b/renderdoc/data/hlsl/multisample.hlsl @@ -172,7 +172,7 @@ float RENDERDOC_DepthCopyMSToArray(float4 pos : SV_Position) : SV_Depth return 0; } -Texture2DArray sourceArray : register(t0); +Texture2DArray sourceArray : register(t1); uint4 RENDERDOC_CopyArrayToMS(float4 pos : SV_Position, uint curSample : SV_SampleIndex) : SV_Target0 { @@ -181,7 +181,7 @@ uint4 RENDERDOC_CopyArrayToMS(float4 pos : SV_Position, uint curSample : SV_Samp return sourceArray.Load(srcCoord); } -Texture2DArray sourceFloatArray : register(t0); +Texture2DArray sourceFloatArray : register(t1); float4 RENDERDOC_FloatCopyArrayToMS(float4 pos : SV_Position, uint curSample : SV_SampleIndex) : SV_Target0 { @@ -190,8 +190,8 @@ float4 RENDERDOC_FloatCopyArrayToMS(float4 pos : SV_Position, uint curSample : S return sourceFloatArray.Load(srcCoord); } -Texture2DArray sourceDepthArray : register(t0); -Texture2DArray sourceStencilArray : register(t1); +Texture2DArray sourceDepthArray : register(t1); +Texture2DArray sourceStencilArray : register(t11); float RENDERDOC_DepthCopyArrayToMS(float4 pos : SV_Position, uint curSample : SV_SampleIndex) : SV_Depth { diff --git a/renderdoc/driver/d3d11/d3d11_msaa_array_conv.cpp b/renderdoc/driver/d3d11/d3d11_msaa_array_conv.cpp index 7ad26db87..46390b6d8 100644 --- a/renderdoc/driver/d3d11/d3d11_msaa_array_conv.cpp +++ b/renderdoc/driver/d3d11/d3d11_msaa_array_conv.cpp @@ -56,8 +56,8 @@ struct Tex2DMSToArrayStateTracker // only need to save/restore constant buffer 0 PS.ConstantBuffers[0] = UNWRAP(WrappedID3D11Buffer, PS.ConstantBuffers[0]); - // same for the first 8 SRVs - for(int i = 0; i < 8; i++) + // same for the first 16 SRVs + for(int i = 0; i < 16; i++) PS.SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, PS.SRVs[i]); for(int i = 0; i < D3D11_SHADER_MAX_INTERFACES; i++) @@ -88,7 +88,7 @@ struct Tex2DMSToArrayStateTracker context->IASetInputLayout(Layout); context->VSSetShader((ID3D11VertexShader *)VS.Shader, VS.Instances, VS.NumInstances); - context->PSSetShaderResources(0, 8, PS.SRVs); + context->PSSetShaderResources(0, 16, PS.SRVs); context->PSSetShader((ID3D11PixelShader *)PS.Shader, PS.Instances, PS.NumInstances); if(m_WrappedContext->IsFL11_1()) @@ -369,7 +369,7 @@ void D3D11DebugManager::CopyArrayToTex2DMS(ID3D11Texture2D *destMS, ID3D11Textur ID3D11ShaderResourceView *srvs[8] = {NULL}; srvs[0] = srvArray; - m_pImmediateContext->PSSetShaderResources(0, 8, srvs); + m_pImmediateContext->PSSetShaderResources(1, 8, srvs); // loop over every array slice in MS texture for(UINT slice = 0; slice < descMS.ArraySize; slice++) @@ -428,7 +428,7 @@ void D3D11DebugManager::CopyArrayToTex2DMS(ID3D11Texture2D *destMS, ID3D11Textur return; } - m_pImmediateContext->PSSetShaderResources(1, 1, &srvArray); + m_pImmediateContext->PSSetShaderResources(11, 1, &srvArray); D3D11_DEPTH_STENCIL_DESC dsDesc; ID3D11DepthStencilState *dsState = NULL; diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index 3aa6bd7a1..443f6aa90 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -158,7 +158,13 @@ bool D3D12InitParams::IsSupportedVersion(uint64_t ver) if(ver == CurrentVersion) return true; - // see header for explanation of version changes + // 0x5 -> 0x6 - Multiply by number of planes in format when serialising initial states - + // i.e. stencil is saved with depth in initial states. + if(ver == 0x4) + return true; + + // 0x4 -> 0x5 - CPU_DESCRIPTOR_HANDLE serialised inline as D3D12Descriptor in appropriate + // list-recording functions if(ver == 0x4) return true; diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index b52a681d0..3f325c06f 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -104,6 +104,8 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) m_pDevice = wrapper; m_pDevice->InternalRef(); + D3D12ResourceManager *rm = wrapper->GetResourceManager(); + HRESULT hr = S_OK; D3D12_DESCRIPTOR_HEAP_DESC desc; @@ -112,6 +114,8 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) desc.NumDescriptors = 1024; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + RDCCOMPILE_ASSERT(FIRST_WIN_RTV + 256 < 1024, "Increase size of RTV heap"); + hr = m_pDevice->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), (void **)&rtvHeap); if(FAILED(hr)) @@ -119,9 +123,13 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) RDCERR("Couldn't create RTV descriptor heap! HRESULT: %s", ToStr(hr).c_str()); } - desc.NumDescriptors = 16; + rm->SetInternalResource(rtvHeap); + + desc.NumDescriptors = 64; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; + RDCCOMPILE_ASSERT(FIRST_WIN_DSV + 32 < 64, "Increase size of DSV heap"); + hr = m_pDevice->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), (void **)&dsvHeap); if(FAILED(hr)) @@ -129,9 +137,13 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) RDCERR("Couldn't create DSV descriptor heap! HRESULT: %s", ToStr(hr).c_str()); } + rm->SetInternalResource(dsvHeap); + desc.NumDescriptors = 4096; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + RDCCOMPILE_ASSERT(MAX_SRV_SLOT < 4096, "Increase size of CBV/SRV/UAV heap"); + hr = m_pDevice->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), (void **)&uavClearHeap); if(FAILED(hr)) @@ -139,6 +151,8 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) RDCERR("Couldn't create CBV/SRV descriptor heap! HRESULT: %s", ToStr(hr).c_str()); } + rm->SetInternalResource(uavClearHeap); + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; hr = m_pDevice->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), @@ -149,6 +163,8 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) RDCERR("Couldn't create CBV/SRV descriptor heap! HRESULT: %s", ToStr(hr).c_str()); } + rm->SetInternalResource(cbvsrvuavHeap); + desc.NumDescriptors = 16; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; @@ -159,6 +175,8 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) RDCERR("Couldn't create sampler descriptor heap! HRESULT: %s", ToStr(hr).c_str()); } + rm->SetInternalResource(samplerHeap); + // create fixed samplers, point and linear D3D12_CPU_DESCRIPTOR_HANDLE samp; samp = samplerHeap->GetCPUDescriptorHandleForHeapStart(); @@ -207,6 +225,28 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) __uuidof(ID3D12RootSignature), (void **)&m_CBOnlyRootSig); SAFE_RELEASE(root); + + rm->SetInternalResource(m_CBOnlyRootSig); + } + + { + ID3DBlob *root = shaderCache->MakeRootSig({ + // cbuffer + cbvParam(D3D12_SHADER_VISIBILITY_PIXEL, 0, 0), + // normal SRVs (2x, 4x, 8x, 16x, 32x) + tableParam(D3D12_SHADER_VISIBILITY_PIXEL, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, 5), + // stencil SRVs (2x, 4x, 8x, 16x, 32x) + tableParam(D3D12_SHADER_VISIBILITY_PIXEL, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 11, 5), + }); + + RDCASSERT(root); + + hr = m_pDevice->CreateRootSignature(0, root->GetBufferPointer(), root->GetBufferSize(), + __uuidof(ID3D12RootSignature), (void **)&m_ArrayMSAARootSig); + + SAFE_RELEASE(root); + + rm->SetInternalResource(m_ArrayMSAARootSig); } { @@ -220,6 +260,33 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) "ps_5_0", &m_MeshPS); } + { + std::string displayhlsl = GetEmbeddedResource(debugcbuffers_h); + displayhlsl += GetEmbeddedResource(debugcommon_hlsl); + displayhlsl += GetEmbeddedResource(debugdisplay_hlsl); + + shaderCache->GetShaderBlob(displayhlsl.c_str(), "RENDERDOC_FullscreenVS", + D3DCOMPILE_WARNINGS_ARE_ERRORS, "vs_5_0", &m_FullscreenVS); + } + + { + std::string multisamplehlsl = GetEmbeddedResource(multisample_hlsl); + + shaderCache->GetShaderBlob(multisamplehlsl.c_str(), "RENDERDOC_CopyMSToArray", + D3DCOMPILE_WARNINGS_ARE_ERRORS, "ps_5_0", &m_IntMS2Array); + shaderCache->GetShaderBlob(multisamplehlsl.c_str(), "RENDERDOC_FloatCopyMSToArray", + D3DCOMPILE_WARNINGS_ARE_ERRORS, "ps_5_0", &m_FloatMS2Array); + shaderCache->GetShaderBlob(multisamplehlsl.c_str(), "RENDERDOC_DepthCopyMSToArray", + D3DCOMPILE_WARNINGS_ARE_ERRORS, "ps_5_0", &m_DepthMS2Array); + + shaderCache->GetShaderBlob(multisamplehlsl.c_str(), "RENDERDOC_CopyArrayToMS", + D3DCOMPILE_WARNINGS_ARE_ERRORS, "ps_5_0", &m_IntArray2MS); + shaderCache->GetShaderBlob(multisamplehlsl.c_str(), "RENDERDOC_FloatCopyArrayToMS", + D3DCOMPILE_WARNINGS_ARE_ERRORS, "ps_5_0", &m_FloatArray2MS); + shaderCache->GetShaderBlob(multisamplehlsl.c_str(), "RENDERDOC_DepthCopyArrayToMS", + D3DCOMPILE_WARNINGS_ARE_ERRORS, "ps_5_0", &m_DepthArray2MS); + } + shaderCache->SetCaching(false); D3D12_RESOURCE_DESC readbackDesc; @@ -248,6 +315,8 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) m_ReadbackBuffer->SetName(L"m_ReadbackBuffer"); + rm->SetInternalResource(m_ReadbackBuffer); + hr = m_pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), (void **)&m_DebugAlloc); @@ -257,6 +326,8 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) return; } + rm->SetInternalResource(m_DebugAlloc); + ID3D12GraphicsCommandList *list = NULL; hr = m_pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_DebugAlloc, NULL, @@ -271,6 +342,8 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) return; } + rm->SetInternalResource(m_DebugList); + if(m_DebugList) m_DebugList->Close(); } @@ -287,10 +360,16 @@ D3D12DebugManager::~D3D12DebugManager() SAFE_RELEASE(uavClearHeap); SAFE_RELEASE(samplerHeap); + SAFE_RELEASE(m_CBOnlyRootSig); + SAFE_RELEASE(m_ArrayMSAARootSig); + SAFE_RELEASE(m_RingConstantBuffer); SAFE_RELEASE(m_TexResource); + SAFE_RELEASE(m_DebugAlloc); + SAFE_RELEASE(m_DebugList); + m_pDevice->InternalRelease(); if(RenderDoc::Inst().GetCrashHandler()) @@ -361,7 +440,9 @@ D3D12_GPU_VIRTUAL_ADDRESS D3D12DebugManager::UploadConstants(const void *data, s ret += m_RingConstantOffset; - FillBuffer(m_RingConstantBuffer, (size_t)m_RingConstantOffset, data, size); + // passing the unwrapped object here is immaterial as all we do is Map/Unmap, but it means we can + // call this function while capturing without worrying about serialising the map or deadlocking. + FillBuffer(Unwrap(m_RingConstantBuffer), (size_t)m_RingConstantOffset, data, size); m_RingConstantOffset += size; m_RingConstantOffset = @@ -1201,6 +1282,11 @@ void D3D12Replay::TextureRendering::Init(WrappedID3D12Device *device, D3D12Debug hr = device->CreateRootSignature(0, root->GetBufferPointer(), root->GetBufferSize(), __uuidof(ID3D12RootSignature), (void **)&RootSig); + if(FAILED(hr)) + { + RDCERR("Couldn't create tex display RootSig! HRESULT: %s", ToStr(hr).c_str()); + } + SAFE_RELEASE(root); } diff --git a/renderdoc/driver/d3d12/d3d12_debug.h b/renderdoc/driver/d3d12/d3d12_debug.h index ca898c358..623303d72 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.h +++ b/renderdoc/driver/d3d12/d3d12_debug.h @@ -56,6 +56,19 @@ enum CBVUAVSRVSlot PICK_RESULT_CLEAR_UAV, TMP_UAV, + + MSAA_SRV2x, + MSAA_SRV4x, + MSAA_SRV8x, + MSAA_SRV16x, + MSAA_SRV32x, + STENCIL_MSAA_SRV2x, + STENCIL_MSAA_SRV4x, + STENCIL_MSAA_SRV8x, + STENCIL_MSAA_SRV16x, + STENCIL_MSAA_SRV32x, + + MAX_SRV_SLOT, }; enum RTVSlot @@ -64,6 +77,7 @@ enum RTVSlot CUSTOM_SHADER_RTV, OVERLAY_RTV, GET_TEX_RTV, + MSAA_RTV, FIRST_TMP_RTV, LAST_TMP_RTV = FIRST_TMP_RTV + 16, FIRST_WIN_RTV, @@ -79,6 +93,7 @@ enum SamplerSlot enum DSVSlot { OVERLAY_DSV, + MSAA_DSV, TMP_DSV, FIRST_WIN_DSV, }; @@ -139,6 +154,9 @@ public: MeshDisplayPipelines CacheMeshDisplayPipelines(const MeshFormat &primary, const MeshFormat &secondary); + void CopyTex2DMSToArray(ID3D12Resource *destArray, ID3D12Resource *srcMS); + void CopyArrayToTex2DMS(ID3D12Resource *destMS, ID3D12Resource *srcArray, UINT selectedSlice); + private: WrappedID3D12Device *m_pDevice = NULL; @@ -168,6 +186,18 @@ private: ID3D12Resource *m_ReadbackBuffer = NULL; + // Array <-> MSAA copying + ID3D12RootSignature *m_ArrayMSAARootSig = NULL; + ID3DBlob *m_FullscreenVS = NULL; + + ID3DBlob *m_IntMS2Array = NULL; + ID3DBlob *m_FloatMS2Array = NULL; + ID3DBlob *m_DepthMS2Array = NULL; + + ID3DBlob *m_IntArray2MS = NULL; + ID3DBlob *m_FloatArray2MS = NULL; + ID3DBlob *m_DepthArray2MS = NULL; + // Debug lists ID3D12GraphicsCommandList2 *m_DebugList = NULL; ID3D12CommandAllocator *m_DebugAlloc = NULL; diff --git a/renderdoc/driver/d3d12/d3d12_device.cpp b/renderdoc/driver/d3d12/d3d12_device.cpp index e958c09e9..f1139d0d2 100644 --- a/renderdoc/driver/d3d12/d3d12_device.cpp +++ b/renderdoc/driver/d3d12/d3d12_device.cpp @@ -2295,8 +2295,7 @@ void WrappedID3D12Device::CreateInternalResources() if(m_TextRenderer == NULL) m_TextRenderer = new D3D12TextRenderer(this); - if(IsReplayMode(m_State)) - m_Replay.CreateResources(); + m_Replay.CreateResources(); WrappedID3D12Shader::InternalResources(false); } diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index bb1d0496f..0ceecad82 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -46,10 +46,7 @@ struct D3D12InitParams D3D_FEATURE_LEVEL MinimumFeatureLevel; // check if a frame capture section version is supported - static const uint64_t CurrentVersion = 0x5; - - // 0x4 -> 0x5 - CPU_DESCRIPTOR_HANDLE serialised inline as D3D12Descriptor in appropriate - // list-recording functions + static const uint64_t CurrentVersion = 0x6; static bool IsSupportedVersion(uint64_t ver); }; @@ -61,6 +58,7 @@ class WrappedID3D12Resource; class D3D12TextRenderer; class D3D12ShaderCache; +class D3D12DebugManager; // give every impression of working but do nothing. // Just allow the user to call functions so that they don't @@ -405,6 +403,7 @@ public: static std::string GetChunkName(uint32_t idx); D3D12ResourceManager *GetResourceManager() { return m_ResourceManager; } D3D12ShaderCache *GetShaderCache() { return m_ShaderCache; } + D3D12DebugManager *GetDebugManager() { return m_Replay.GetDebugManager(); } ResourceId GetResourceID() { return m_ResourceID; } Threading::RWLock &GetCapTransitionLock() { return m_CapTransitionLock; } void ReleaseSwapchainResources(IDXGISwapChain *swap, IUnknown **backbuffers, int numBackbuffers); diff --git a/renderdoc/driver/d3d12/d3d12_initstate.cpp b/renderdoc/driver/d3d12/d3d12_initstate.cpp index 1478fa957..81de2c387 100644 --- a/renderdoc/driver/d3d12/d3d12_initstate.cpp +++ b/renderdoc/driver/d3d12/d3d12_initstate.cpp @@ -25,6 +25,7 @@ #include "driver/dxgi/dxgi_common.h" #include "d3d12_command_list.h" #include "d3d12_command_queue.h" +#include "d3d12_debug.h" #include "d3d12_device.h" #include "d3d12_manager.h" #include "d3d12_resources.h" @@ -67,14 +68,7 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) D3D12_RESOURCE_DESC desc = r->GetDesc(); - if(desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D && desc.SampleDesc.Count > 1) - { - D3D12NOTIMP("Multisampled initial contents"); - - SetInitialContents(GetResID(r), D3D12InitialContents(D3D12InitialContents::Multisampled)); - return true; - } - else if(desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) + if(desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { D3D12_HEAP_PROPERTIES heapProps; r->GetHeapProperties(&heapProps, NULL); @@ -128,6 +122,99 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) } else { + if(nonresident) + m_Device->MakeResident(1, &pageable); + + ID3D12Resource *arrayTexture = NULL; + D3D12_RESOURCE_STATES destState = D3D12_RESOURCE_STATE_COPY_SOURCE; + ID3D12Resource *unwrappedCopySource = r->GetReal(); + + if(desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D && desc.SampleDesc.Count > 1) + { + bool isDepth = IsDepthFormat(desc.Format); + + desc.Alignment = 0; + desc.DepthOrArraySize *= (UINT16)desc.SampleDesc.Count; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + + if(isDepth) + desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + else + desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + + D3D12_HEAP_PROPERTIES defaultHeap; + defaultHeap.Type = D3D12_HEAP_TYPE_DEFAULT; + defaultHeap.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + defaultHeap.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + defaultHeap.CreationNodeMask = 1; + defaultHeap.VisibleNodeMask = 1; + + // we don't want to serialise this resource's creation, so wrap it manually + HRESULT hr = m_Device->GetReal()->CreateCommittedResource( + &defaultHeap, D3D12_HEAP_FLAG_NONE, &desc, + isDepth ? D3D12_RESOURCE_STATE_DEPTH_WRITE : D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, + __uuidof(ID3D12Resource), (void **)&arrayTexture); + RDCASSERTEQUAL(hr, S_OK); + + destState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + } + + ID3D12GraphicsCommandList *list = Unwrap(m_Device->GetInitialStateList()); + + vector barriers; + + { + const vector &states = m_Device->GetSubresourceStates(GetResID(r)); + + barriers.reserve(states.size()); + + for(size_t i = 0; i < states.size(); i++) + { + if(states[i] & D3D12_RESOURCE_STATE_COPY_SOURCE) + continue; + + D3D12_RESOURCE_BARRIER barrier; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier.Transition.pResource = r->GetReal(); + barrier.Transition.Subresource = (UINT)i; + barrier.Transition.StateBefore = states[i]; + barrier.Transition.StateAfter = destState; + + barriers.push_back(barrier); + } + + // transition to copy dest + if(!barriers.empty()) + list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); + } + + if(arrayTexture) + { + // execute the above barriers + m_Device->CloseInitialStateList(); + + m_Device->ExecuteLists(NULL, true); + m_Device->FlushLists(); + + // expand multisamples out to array + m_Device->GetDebugManager()->CopyTex2DMSToArray(arrayTexture, r->GetReal()); + + // open the initial state list again for the remainder of the work + list = Unwrap(m_Device->GetInitialStateList()); + + D3D12_RESOURCE_BARRIER b = {}; + b.Transition.pResource = arrayTexture; + b.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + b.Transition.StateBefore = IsDepthFormat(desc.Format) ? D3D12_RESOURCE_STATE_DEPTH_WRITE + : D3D12_RESOURCE_STATE_RENDER_TARGET; + b.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; + list->ResourceBarrier(1, &b); + + unwrappedCopySource = arrayTexture; + } + D3D12_HEAP_PROPERTIES heapProps; heapProps.Type = D3D12_HEAP_TYPE_READBACK; heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; @@ -153,6 +240,17 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) if(desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D) numSubresources *= desc.DepthOrArraySize; + // account for multiple planes (i.e. depth and stencil) + { + D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = {}; + formatInfo.Format = desc.Format; + m_Device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, sizeof(formatInfo)); + + UINT planes = RDCMAX((UINT8)1, formatInfo.PlaneCount); + + numSubresources *= planes; + } + D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts = new D3D12_PLACED_SUBRESOURCE_FOOTPRINT[numSubresources]; @@ -164,45 +262,14 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) &heapProps, D3D12_HEAP_FLAG_NONE, &bufDesc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, __uuidof(ID3D12Resource), (void **)©Dst); - if(nonresident) - m_Device->MakeResident(1, &pageable); - if(SUCCEEDED(hr)) { - ID3D12GraphicsCommandList *list = Unwrap(m_Device->GetInitialStateList()); - - vector barriers; - - const vector &states = m_Device->GetSubresourceStates(GetResID(r)); - - barriers.reserve(states.size()); - - for(size_t i = 0; i < states.size(); i++) - { - if(states[i] & D3D12_RESOURCE_STATE_COPY_SOURCE) - continue; - - D3D12_RESOURCE_BARRIER barrier; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier.Transition.pResource = r->GetReal(); - barrier.Transition.Subresource = (UINT)i; - barrier.Transition.StateBefore = states[i]; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; - - barriers.push_back(barrier); - } - - // transition to copy dest - if(!barriers.empty()) - list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); - for(UINT i = 0; i < numSubresources; i++) { D3D12_TEXTURE_COPY_LOCATION dst, src; src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - src.pResource = r->GetReal(); + src.pResource = unwrappedCopySource; src.SubresourceIndex = i; dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; @@ -211,29 +278,31 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); } - - // transition back - for(size_t i = 0; i < barriers.size(); i++) - std::swap(barriers[i].Transition.StateBefore, barriers[i].Transition.StateAfter); - - if(!barriers.empty()) - list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); } else { RDCERR("Couldn't create readback buffer: HRESULT: %s", ToStr(hr).c_str()); } - if(nonresident) + // transition back + for(size_t i = 0; i < barriers.size(); i++) + std::swap(barriers[i].Transition.StateBefore, barriers[i].Transition.StateAfter); + + if(!barriers.empty()) + list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); + + if(nonresident || arrayTexture) { m_Device->CloseInitialStateList(); m_Device->ExecuteLists(NULL, true); m_Device->FlushLists(); - m_Device->Evict(1, &pageable); + if(nonresident) + m_Device->Evict(1, &pageable); } + SAFE_RELEASE(arrayTexture); SAFE_DELETE_ARRAY(layouts); SetInitialContents(GetResID(r), D3D12InitialContents(copyDst)); @@ -269,11 +338,6 @@ uint32_t D3D12ResourceManager::GetSize_InitialState(ResourceId id, ID3D12DeviceC { buf = (ID3D12Resource *)res; } - else if(initContents.tag == D3D12InitialContents::Multisampled) - { - D3D12NOTIMP("Multisampled initial contents"); - buf = NULL; - } return (uint32_t)WriteSerialiser::GetChunkAlignment() + 16 + uint32_t(buf ? buf->GetDesc().Width : 0); @@ -383,11 +447,6 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI { mappedBuffer = (ID3D12Resource *)liveRes; } - else if(initContents.tag == D3D12InitialContents::Multisampled) - { - D3D12NOTIMP("Multisampled initial contents"); - mappedBuffer = NULL; - } if(mappedBuffer) { @@ -417,12 +476,7 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI D3D12_HEAP_PROPERTIES heapProps = {}; ((ID3D12Resource *)liveRes)->GetHeapProperties(&heapProps, NULL); - if(resDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D && resDesc.SampleDesc.Count > 1) - { - initContents.tag = D3D12InitialContents::Multisampled; - D3D12NOTIMP("Multisampled initial contents"); - } - else if(heapProps.Type == D3D12_HEAP_TYPE_UPLOAD) + if(heapProps.Type == D3D12_HEAP_TYPE_UPLOAD) { // if destination is on the upload heap, it's impossible to copy via the device, // so we have to CPU copy. To save time and make a more optimal copy, we just keep the data @@ -457,9 +511,9 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI desc.Width = RDCMAX(ContentsLength, 64ULL); ID3D12Resource *copySrc = NULL; - HRESULT hr = m_Device->GetReal()->CreateCommittedResource( - &heapProps, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, - __uuidof(ID3D12Resource), (void **)©Src); + HRESULT hr = m_Device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc, + D3D12_RESOURCE_STATE_GENERIC_READ, NULL, + __uuidof(ID3D12Resource), (void **)©Src); if(SUCCEEDED(hr)) { @@ -506,10 +560,149 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI { initContents.resourceType = Resource_Resource; initContents.resource = mappedBuffer; - SetInitialContents(id, initContents); - } - return true; + D3D12_RESOURCE_DESC resDesc = ((ID3D12Resource *)liveRes)->GetDesc(); + + // for MSAA textures we upload to an MSAA texture here so we're ready to copy the image in + // Apply_InitState + if(resDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D && resDesc.SampleDesc.Count > 1) + { + if(ContentsLength == 0) + { + // backwards compatibility - older captures will have no data for MSAA textures. + initContents.resource = NULL; + SAFE_RELEASE(mappedBuffer); + } + else + { + D3D12_HEAP_PROPERTIES heapProps = {}; + ((ID3D12Resource *)liveRes)->GetHeapProperties(&heapProps, NULL); + + ID3D12GraphicsCommandList *list = Unwrap(m_Device->GetInitialStateList()); + + D3D12_RESOURCE_DESC arrayDesc = resDesc; + arrayDesc.Alignment = 0; + arrayDesc.DepthOrArraySize *= (UINT16)arrayDesc.SampleDesc.Count; + arrayDesc.SampleDesc.Count = 1; + arrayDesc.SampleDesc.Quality = 0; + arrayDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + + bool isDepth = IsDepthFormat(resDesc.Format); + + D3D12_RESOURCE_DESC msaaDesc = resDesc; + arrayDesc.Alignment = 0; + arrayDesc.Flags = isDepth ? D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL + : D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + + ID3D12Resource *arrayTex = NULL; + HRESULT hr = m_Device->CreateCommittedResource( + &heapProps, D3D12_HEAP_FLAG_NONE, &arrayDesc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, + __uuidof(ID3D12Resource), (void **)&arrayTex); + if(FAILED(hr)) + { + RDCERR("Couldn't create temporary array texture: %s", ToStr(hr).c_str()); + ret = false; + } + + ID3D12Resource *msaaTex = NULL; + hr = m_Device->CreateCommittedResource( + &heapProps, D3D12_HEAP_FLAG_NONE, &msaaDesc, + isDepth ? D3D12_RESOURCE_STATE_DEPTH_WRITE : D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, + __uuidof(ID3D12Resource), (void **)&msaaTex); + RDCASSERTEQUAL(hr, S_OK); + if(FAILED(hr)) + { + RDCERR("Couldn't create init state MSAA texture: %s", ToStr(hr).c_str()); + ret = false; + } + + // copy buffer to array texture + if(arrayTex) + { + uint32_t numSubresources = arrayDesc.DepthOrArraySize; + + { + D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = {}; + formatInfo.Format = arrayDesc.Format; + m_Device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, + sizeof(formatInfo)); + + UINT planes = RDCMAX((UINT8)1, formatInfo.PlaneCount); + + numSubresources *= planes; + } + + D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts = + new D3D12_PLACED_SUBRESOURCE_FOOTPRINT[numSubresources]; + + m_Device->GetCopyableFootprints(&arrayDesc, 0, numSubresources, 0, layouts, NULL, NULL, + NULL); + + for(UINT i = 0; i < numSubresources; i++) + { + D3D12_TEXTURE_COPY_LOCATION dst, src; + + dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dst.pResource = Unwrap(arrayTex); + dst.SubresourceIndex = i; + + src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + src.pResource = Unwrap(mappedBuffer); + src.PlacedFootprint = layouts[i]; + + // copy buffer into this array slice + list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); + + // this slice now needs to be in shader-read to copy to the MSAA texture + D3D12_RESOURCE_BARRIER b = {}; + b.Transition.pResource = Unwrap(arrayTex); + b.Transition.Subresource = i; + b.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + b.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + list->ResourceBarrier(1, &b); + } + + delete[] layouts; + } + + m_Device->CloseInitialStateList(); + m_Device->ExecuteLists(NULL, true); + m_Device->FlushLists(true); + + // compact array into MSAA texture + if(msaaTex && arrayTex) + m_Device->GetDebugManager()->CopyArrayToTex2DMS(msaaTex, arrayTex, ~0U); + + // move MSAA texture permanently to copy source state + if(msaaTex) + { + list = Unwrap(m_Device->GetInitialStateList()); + + D3D12_RESOURCE_BARRIER b = {}; + b.Transition.pResource = Unwrap(msaaTex); + b.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + b.Transition.StateBefore = + isDepth ? D3D12_RESOURCE_STATE_DEPTH_WRITE : D3D12_RESOURCE_STATE_RENDER_TARGET; + b.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; + list->ResourceBarrier(1, &b); + + m_Device->CloseInitialStateList(); + m_Device->ExecuteLists(NULL, true); + m_Device->FlushLists(true); + } + + // subsequent copy comes from msaa texture + initContents.resource = msaaTex; + + // we can release the buffer now, and the temporary array texture + SAFE_RELEASE(mappedBuffer); + SAFE_RELEASE(arrayTex); + } + } + + if(initContents.resource) + SetInitialContents(id, initContents); + } } else { @@ -566,11 +759,7 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init } else if(type == Resource_Resource) { - if(data.tag == D3D12InitialContents::Multisampled) - { - D3D12NOTIMP("Multisampled initial contents"); - } - else if(data.tag == D3D12InitialContents::Copy) + if(data.tag == D3D12InitialContents::Copy) { ID3D12Resource *copyDst = Unwrap((ID3D12Resource *)live); @@ -709,7 +898,13 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init D3D12_RESOURCE_DESC srcDesc = copySrc->GetDesc(); D3D12_RESOURCE_DESC dstDesc = copyDst->GetDesc(); - list->CopyBufferRegion(copyDst, 0, copySrc, 0, RDCMIN(srcDesc.Width, dstDesc.Width)); + list->CopyBufferRegion(copyDst, 0, Unwrap(copySrc), 0, + RDCMIN(srcDesc.Width, dstDesc.Width)); + } + else if(copyDst->GetDesc().SampleDesc.Count > 1) + { + // MSAA texture was pre-uploaded and decoded, just copy the texture + list->CopyResource(copyDst, Unwrap(copySrc)); } else { @@ -719,6 +914,19 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init if(desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D) numSubresources *= desc.DepthOrArraySize; + // we only accounted for planes in version 0x6, before then we only copied the first plane + // so the buffer won't have enough data + if(m_Device->GetLogVersion() >= 0x6) + { + D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = {}; + formatInfo.Format = desc.Format; + m_Device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, sizeof(formatInfo)); + + UINT planes = RDCMAX((UINT8)1, formatInfo.PlaneCount); + + numSubresources *= planes; + } + D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts = new D3D12_PLACED_SUBRESOURCE_FOOTPRINT[numSubresources]; @@ -733,7 +941,7 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init dst.SubresourceIndex = i; src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - src.pResource = copySrc; + src.pResource = Unwrap(copySrc); src.PlacedFootprint = layouts[i]; list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); diff --git a/renderdoc/driver/d3d12/d3d12_manager.cpp b/renderdoc/driver/d3d12/d3d12_manager.cpp index 5d6a7b0b8..027396a26 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.cpp +++ b/renderdoc/driver/d3d12/d3d12_manager.cpp @@ -696,7 +696,7 @@ template void D3D12ResourceManager::SerialiseResourceStates( void D3D12ResourceManager::SetInternalResource(ID3D12DeviceChild *res) { - if(!RenderDoc::Inst().IsReplayApp()) + if(!RenderDoc::Inst().IsReplayApp() && res) { D3D12ResourceRecord *record = GetResourceRecord(GetResID(res)); if(record) diff --git a/renderdoc/driver/d3d12/d3d12_manager.h b/renderdoc/driver/d3d12/d3d12_manager.h index 925bcaa66..d3ed08c44 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.h +++ b/renderdoc/driver/d3d12/d3d12_manager.h @@ -593,7 +593,6 @@ struct D3D12InitialContents // this is only valid during capture - it indicates we didn't create a staging texture, we're // going to read directly from the resource (only valid for resources that are already READBACK) MapDirect, - Multisampled, }; D3D12InitialContents(D3D12Descriptor *d, uint32_t n) : tag(Copy), diff --git a/renderdoc/driver/d3d12/d3d12_msaa_array_conv.cpp b/renderdoc/driver/d3d12/d3d12_msaa_array_conv.cpp new file mode 100644 index 000000000..950f56c3f --- /dev/null +++ b/renderdoc/driver/d3d12/d3d12_msaa_array_conv.cpp @@ -0,0 +1,541 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2018 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/dx/official/d3dcompiler.h" +#include "driver/dxgi/dxgi_common.h" +#include "d3d12_command_list.h" +#include "d3d12_command_queue.h" +#include "d3d12_debug.h" +#include "d3d12_device.h" + +void D3D12DebugManager::CopyTex2DMSToArray(ID3D12Resource *destArray, ID3D12Resource *srcMS) +{ + // this function operates during capture so we work on unwrapped objects + + D3D12_RESOURCE_DESC descMS = srcMS->GetDesc(); + D3D12_RESOURCE_DESC descArr = destArray->GetDesc(); + + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY; + srvDesc.Texture2DMSArray.FirstArraySlice = 0; + srvDesc.Texture2DMSArray.ArraySize = descMS.DepthOrArraySize; + srvDesc.Format = GetTypedFormat(descMS.Format, CompType::UInt); + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + + D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Format = srvDesc.Format; + rtvDesc.Texture2DArray.ArraySize = 1; + rtvDesc.Texture2DArray.FirstArraySlice = 0; + rtvDesc.Texture2DArray.MipSlice = 0; + rtvDesc.Texture2DArray.PlaneSlice = 0; + + D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Flags = D3D12_DSV_FLAG_NONE; + dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY; + dsvDesc.Format = srvDesc.Format; + dsvDesc.Texture2DArray.ArraySize = 1; + dsvDesc.Texture2DArray.FirstArraySlice = 0; + dsvDesc.Texture2DArray.MipSlice = 0; + + bool depthFormat = IsDepthFormat(rtvDesc.Format); + bool intFormat = IsUIntFormat(rtvDesc.Format) || IsIntFormat(rtvDesc.Format); + + bool stencil = false; + DXGI_FORMAT stencilFormat = DXGI_FORMAT_UNKNOWN; + + if(depthFormat) + { + switch(descMS.Format) + { + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_TYPELESS: srvDesc.Format = DXGI_FORMAT_R32_FLOAT; break; + + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + stencilFormat = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; + stencil = true; + break; + + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + stencilFormat = DXGI_FORMAT_X24_TYPELESS_G8_UINT; + stencil = true; + break; + + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_TYPELESS: srvDesc.Format = DXGI_FORMAT_R16_FLOAT; break; + } + } + + for(CBVUAVSRVSlot slot : {MSAA_SRV2x, MSAA_SRV4x, MSAA_SRV8x, MSAA_SRV16x, MSAA_SRV32x}) + { + D3D12_CPU_DESCRIPTOR_HANDLE srv = Unwrap(GetCPUHandle(slot)); + m_pDevice->GetReal()->CreateShaderResourceView(srcMS, &srvDesc, srv); + } + + if(stencil) + { + srvDesc.Format = stencilFormat; + + for(CBVUAVSRVSlot slot : {STENCIL_MSAA_SRV2x, STENCIL_MSAA_SRV4x, STENCIL_MSAA_SRV8x, + STENCIL_MSAA_SRV16x, STENCIL_MSAA_SRV32x}) + { + D3D12_CPU_DESCRIPTOR_HANDLE srv = Unwrap(GetCPUHandle(slot)); + m_pDevice->GetReal()->CreateShaderResourceView(srcMS, &srvDesc, srv); + } + } + + D3D12_CPU_DESCRIPTOR_HANDLE rtv = Unwrap(GetCPUHandle(MSAA_RTV)); + D3D12_CPU_DESCRIPTOR_HANDLE dsv = Unwrap(GetCPUHandle(MSAA_DSV)); + + D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeDesc = {}; + + pipeDesc.pRootSignature = Unwrap(m_ArrayMSAARootSig); + pipeDesc.VS.BytecodeLength = m_FullscreenVS->GetBufferSize(); + pipeDesc.VS.pShaderBytecode = m_FullscreenVS->GetBufferPointer(); + + pipeDesc.PS.BytecodeLength = m_FloatMS2Array->GetBufferSize(); + pipeDesc.PS.pShaderBytecode = m_FloatMS2Array->GetBufferPointer(); + pipeDesc.NumRenderTargets = 1; + pipeDesc.RTVFormats[0] = rtvDesc.Format; + pipeDesc.DSVFormat = DXGI_FORMAT_UNKNOWN; + + if(depthFormat) + { + pipeDesc.PS.BytecodeLength = m_DepthMS2Array->GetBufferSize(); + pipeDesc.PS.pShaderBytecode = m_DepthMS2Array->GetBufferPointer(); + pipeDesc.NumRenderTargets = 0; + pipeDesc.RTVFormats[0] = DXGI_FORMAT_UNKNOWN; + pipeDesc.DSVFormat = rtvDesc.Format; + pipeDesc.DepthStencilState.DepthEnable = TRUE; + pipeDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; + pipeDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS; + } + else if(intFormat) + { + pipeDesc.PS.BytecodeLength = m_IntMS2Array->GetBufferSize(); + pipeDesc.PS.pShaderBytecode = m_IntMS2Array->GetBufferPointer(); + } + + pipeDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; + pipeDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; + pipeDesc.SampleMask = 0xFFFFFFFF; + pipeDesc.SampleDesc.Count = 1; + pipeDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; + pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + pipeDesc.BlendState.RenderTarget[0].BlendEnable = FALSE; + pipeDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; + pipeDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + pipeDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + + ID3D12PipelineState *pso = NULL, *psoStencil = NULL; + HRESULT hr = m_pDevice->GetReal()->CreateGraphicsPipelineState( + &pipeDesc, __uuidof(ID3D12PipelineState), (void **)&pso); + + if(FAILED(hr)) + { + RDCERR("Couldn't create MSAA conversion pipeline! HRESULT: %s", ToStr(hr).c_str()); + return; + } + + ID3D12GraphicsCommandList *list = Unwrap(m_DebugList); + + list->Reset(Unwrap(m_DebugAlloc), NULL); + + D3D12_VIEWPORT viewport = {0, 0, (float)descArr.Width, (float)descArr.Height, 0.0f, 1.0f}; + D3D12_RECT scissor = {0, 0, (LONG)descArr.Width, (LONG)descArr.Height}; + list->RSSetViewports(1, &viewport); + list->RSSetScissorRects(1, &scissor); + list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + ID3D12DescriptorHeap *heap = Unwrap(cbvsrvuavHeap); + list->SetDescriptorHeaps(1, &heap); + list->SetPipelineState(pso); + list->SetGraphicsRootSignature(Unwrap(m_ArrayMSAARootSig)); + list->SetGraphicsRootDescriptorTable(1, Unwrap(GetGPUHandle(MSAA_SRV2x))); + if(stencil) + list->SetGraphicsRootDescriptorTable(2, Unwrap(GetGPUHandle(STENCIL_MSAA_SRV2x))); + + // loop over every array slice in MS texture + for(UINT slice = 0; slice < descMS.DepthOrArraySize; slice++) + { + // loop over every multi sample + for(UINT sample = 0; sample < descMS.SampleDesc.Count; sample++) + { + uint32_t cdata[4] = {descMS.SampleDesc.Count, 1000, sample, slice}; + + list->SetGraphicsRootConstantBufferView(0, UploadConstants(cdata, sizeof(cdata))); + + dsvDesc.Texture2DArray.FirstArraySlice = slice * descMS.SampleDesc.Count + sample; + rtvDesc.Texture2DArray.FirstArraySlice = slice * descMS.SampleDesc.Count + sample; + + if(depthFormat) + { + m_pDevice->GetReal()->CreateDepthStencilView(destArray, &dsvDesc, dsv); + list->OMSetRenderTargets(0, NULL, FALSE, &dsv); + } + else + { + m_pDevice->GetReal()->CreateRenderTargetView(destArray, &rtvDesc, rtv); + list->OMSetRenderTargets(1, &rtv, FALSE, NULL); + } + + list->DrawInstanced(3, 1, 0, 0); + } + } + + if(stencil) + { + pipeDesc.DepthStencilState.DepthEnable = FALSE; + pipeDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + pipeDesc.DepthStencilState.StencilEnable = TRUE; + pipeDesc.DepthStencilState.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS; + pipeDesc.DepthStencilState.FrontFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE; + pipeDesc.DepthStencilState.FrontFace.StencilFailOp = D3D12_STENCIL_OP_REPLACE; + pipeDesc.DepthStencilState.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_REPLACE; + pipeDesc.DepthStencilState.BackFace = pipeDesc.DepthStencilState.FrontFace; + pipeDesc.DepthStencilState.StencilReadMask = 0xff; + pipeDesc.DepthStencilState.StencilWriteMask = 0xff; + + hr = m_pDevice->GetReal()->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState), + (void **)&psoStencil); + RDCASSERTEQUAL(hr, S_OK); + + list->SetPipelineState(psoStencil); + + dsvDesc.Flags = D3D12_DSV_FLAG_READ_ONLY_DEPTH; + dsvDesc.Texture2DArray.ArraySize = 1; + + // loop over every array slice in MS texture + for(UINT slice = 0; slice < descMS.DepthOrArraySize; slice++) + { + // loop over every multi sample + for(UINT sample = 0; sample < descMS.SampleDesc.Count; sample++) + { + dsvDesc.Texture2DArray.FirstArraySlice = slice * descMS.SampleDesc.Count + sample; + m_pDevice->GetReal()->CreateDepthStencilView(destArray, &dsvDesc, dsv); + list->OMSetRenderTargets(0, NULL, FALSE, &dsv); + + // loop over every stencil value (in theory we could use SV_StencilRef, but it's optional + // and would mean a different shader) + for(UINT stencilval = 0; stencilval < 256; stencilval++) + { + uint32_t cdata[4] = {descMS.SampleDesc.Count, stencilval, sample, slice}; + + list->SetGraphicsRootConstantBufferView(0, UploadConstants(cdata, sizeof(cdata))); + + list->OMSetStencilRef(stencilval); + + list->DrawInstanced(3, 1, 0, 0); + } + } + } + } + + list->Close(); + + ID3D12Fence *tmpFence = NULL; + m_pDevice->GetReal()->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence), + (void **)&tmpFence); + + ID3D12CommandList *l = list; + m_pDevice->GetQueue()->GetReal()->ExecuteCommandLists(1, &l); + m_pDevice->GPUSync(m_pDevice->GetQueue()->GetReal(), tmpFence); + m_DebugAlloc->Reset(); + + SAFE_RELEASE(tmpFence); + SAFE_RELEASE(pso); + SAFE_RELEASE(psoStencil); +} + +void D3D12DebugManager::CopyArrayToTex2DMS(ID3D12Resource *destMS, ID3D12Resource *srcArray, + UINT selectedSlice) +{ + bool singleSliceMode = (selectedSlice != ~0U); + + D3D12_RESOURCE_DESC descArr = srcArray->GetDesc(); + D3D12_RESOURCE_DESC descMS = destMS->GetDesc(); + + UINT sampleMask = ~0U; + + if(singleSliceMode) + { + sampleMask = 1U << (selectedSlice % descMS.SampleDesc.Count); + selectedSlice /= descMS.SampleDesc.Count; + } + + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.ArraySize = descArr.DepthOrArraySize; + srvDesc.Format = GetTypedFormat(descMS.Format, CompType::UInt); + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + + D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY; + rtvDesc.Format = srvDesc.Format; + rtvDesc.Texture2DMSArray.ArraySize = 1; + + D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Flags = D3D12_DSV_FLAG_NONE; + dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY; + dsvDesc.Format = srvDesc.Format; + dsvDesc.Texture2DMSArray.ArraySize = 1; + + bool depthFormat = IsDepthFormat(rtvDesc.Format); + bool intFormat = IsUIntFormat(rtvDesc.Format) || IsIntFormat(rtvDesc.Format); + + bool stencil = false; + DXGI_FORMAT stencilFormat = DXGI_FORMAT_UNKNOWN; + + if(depthFormat) + { + switch(descMS.Format) + { + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_TYPELESS: srvDesc.Format = DXGI_FORMAT_R32_FLOAT; break; + + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + stencilFormat = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; + stencil = true; + break; + + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + stencilFormat = DXGI_FORMAT_X24_TYPELESS_G8_UINT; + stencil = true; + break; + + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_TYPELESS: srvDesc.Format = DXGI_FORMAT_R16_FLOAT; break; + } + } + + for(CBVUAVSRVSlot slot : {MSAA_SRV2x, MSAA_SRV4x, MSAA_SRV8x, MSAA_SRV16x, MSAA_SRV32x}) + { + D3D12_CPU_DESCRIPTOR_HANDLE srv = GetCPUHandle(slot); + m_pDevice->CreateShaderResourceView(srcArray, &srvDesc, srv); + } + + if(stencil) + { + srvDesc.Format = stencilFormat; + + { + D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = {}; + formatInfo.Format = srvDesc.Format; + m_pDevice->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, sizeof(formatInfo)); + + UINT planes = RDCMAX((UINT8)1, formatInfo.PlaneCount); + + if(planes > 1) + srvDesc.Texture2DArray.PlaneSlice = 1; + } + + for(CBVUAVSRVSlot slot : {STENCIL_MSAA_SRV2x, STENCIL_MSAA_SRV4x, STENCIL_MSAA_SRV8x, + STENCIL_MSAA_SRV16x, STENCIL_MSAA_SRV32x}) + { + D3D12_CPU_DESCRIPTOR_HANDLE srv = GetCPUHandle(slot); + m_pDevice->CreateShaderResourceView(srcArray, &srvDesc, srv); + } + } + + D3D12_CPU_DESCRIPTOR_HANDLE rtv = GetCPUHandle(MSAA_RTV); + D3D12_CPU_DESCRIPTOR_HANDLE dsv = GetCPUHandle(MSAA_DSV); + + D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeDesc = {}; + + pipeDesc.pRootSignature = m_ArrayMSAARootSig; + pipeDesc.VS.BytecodeLength = m_FullscreenVS->GetBufferSize(); + pipeDesc.VS.pShaderBytecode = m_FullscreenVS->GetBufferPointer(); + + pipeDesc.PS.BytecodeLength = m_FloatArray2MS->GetBufferSize(); + pipeDesc.PS.pShaderBytecode = m_FloatArray2MS->GetBufferPointer(); + pipeDesc.NumRenderTargets = 1; + pipeDesc.RTVFormats[0] = rtvDesc.Format; + pipeDesc.DSVFormat = DXGI_FORMAT_UNKNOWN; + + if(depthFormat) + { + pipeDesc.PS.BytecodeLength = m_DepthArray2MS->GetBufferSize(); + pipeDesc.PS.pShaderBytecode = m_DepthArray2MS->GetBufferPointer(); + pipeDesc.NumRenderTargets = 0; + pipeDesc.RTVFormats[0] = DXGI_FORMAT_UNKNOWN; + pipeDesc.DSVFormat = rtvDesc.Format; + pipeDesc.DepthStencilState.DepthEnable = TRUE; + pipeDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; + pipeDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS; + } + else if(intFormat) + { + pipeDesc.PS.BytecodeLength = m_IntArray2MS->GetBufferSize(); + pipeDesc.PS.pShaderBytecode = m_IntArray2MS->GetBufferPointer(); + } + + pipeDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; + pipeDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; + pipeDesc.SampleMask = sampleMask; + pipeDesc.SampleDesc = descMS.SampleDesc; + pipeDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; + pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + pipeDesc.BlendState.RenderTarget[0].BlendEnable = FALSE; + pipeDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; + pipeDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + pipeDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + + ID3D12PipelineState *pso = NULL, *psoStencil = NULL; + HRESULT hr = m_pDevice->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState), + (void **)&pso); + + if(FAILED(hr)) + { + RDCERR("Couldn't create MSAA conversion pipeline! HRESULT: %s", ToStr(hr).c_str()); + return; + } + + ID3D12GraphicsCommandList *list = m_DebugList; + + list->Reset(m_DebugAlloc, NULL); + + D3D12_VIEWPORT viewport = {0, 0, (float)descArr.Width, (float)descArr.Height, 0.0f, 1.0f}; + D3D12_RECT scissor = {0, 0, (LONG)descArr.Width, (LONG)descArr.Height}; + list->RSSetViewports(1, &viewport); + list->RSSetScissorRects(1, &scissor); + list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + list->SetDescriptorHeaps(1, &cbvsrvuavHeap); + list->SetPipelineState(pso); + list->SetGraphicsRootSignature(m_ArrayMSAARootSig); + list->SetGraphicsRootDescriptorTable(1, GetGPUHandle(MSAA_SRV2x)); + if(stencil) + list->SetGraphicsRootDescriptorTable(2, GetGPUHandle(STENCIL_MSAA_SRV2x)); + + // loop over every array slice in MS texture + for(UINT slice = 0; slice < descMS.DepthOrArraySize; slice++) + { + if(singleSliceMode) + slice = selectedSlice; + + uint32_t cdata[4] = {descMS.SampleDesc.Count, 1000, 0, slice}; + + list->SetGraphicsRootConstantBufferView(0, UploadConstants(cdata, sizeof(cdata))); + + rtvDesc.Texture2DMSArray.FirstArraySlice = slice; + dsvDesc.Texture2DMSArray.FirstArraySlice = slice; + + if(depthFormat) + { + m_pDevice->CreateDepthStencilView(destMS, &dsvDesc, dsv); + list->OMSetRenderTargets(0, NULL, FALSE, &dsv); + } + else + { + m_pDevice->CreateRenderTargetView(destMS, &rtvDesc, rtv); + list->OMSetRenderTargets(1, &rtv, FALSE, NULL); + } + + list->DrawInstanced(3, 1, 0, 0); + + if(singleSliceMode) + break; + } + + if(stencil) + { + pipeDesc.DepthStencilState.DepthEnable = FALSE; + pipeDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + pipeDesc.DepthStencilState.StencilEnable = TRUE; + pipeDesc.DepthStencilState.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS; + pipeDesc.DepthStencilState.FrontFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE; + pipeDesc.DepthStencilState.FrontFace.StencilFailOp = D3D12_STENCIL_OP_REPLACE; + pipeDesc.DepthStencilState.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_REPLACE; + pipeDesc.DepthStencilState.BackFace = pipeDesc.DepthStencilState.FrontFace; + pipeDesc.DepthStencilState.StencilReadMask = 0xff; + pipeDesc.DepthStencilState.StencilWriteMask = 0xff; + + hr = m_pDevice->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState), + (void **)&psoStencil); + RDCASSERTEQUAL(hr, S_OK); + + dsvDesc.Flags = D3D12_DSV_FLAG_READ_ONLY_DEPTH; + dsvDesc.Texture2DMSArray.ArraySize = 1; + m_pDevice->CreateDepthStencilView(destMS, &dsvDesc, dsv); + list->OMSetRenderTargets(0, NULL, FALSE, &dsv); + list->SetPipelineState(psoStencil); + + // loop over every array slice in MS texture + for(UINT slice = 0; slice < descMS.DepthOrArraySize; slice++) + { + if(singleSliceMode) + slice = selectedSlice; + + dsvDesc.Texture2DArray.FirstArraySlice = slice; + + // loop over every stencil value (in theory we could use SV_StencilRef, but it's optional + // and would mean a different shader) + for(UINT stencilval = 0; stencilval < 256; stencilval++) + { + uint32_t cdata[4] = {descMS.SampleDesc.Count, stencilval, 0, slice}; + + list->SetGraphicsRootConstantBufferView(0, UploadConstants(cdata, sizeof(cdata))); + + list->OMSetStencilRef(stencilval); + + list->DrawInstanced(3, 1, 0, 0); + } + } + } + + list->Close(); + + ID3D12CommandList *l = m_DebugList; + m_pDevice->GetQueue()->ExecuteCommandLists(1, &l); + m_pDevice->GPUSync(); + m_DebugAlloc->Reset(); + + SAFE_RELEASE(pso); + SAFE_RELEASE(psoStencil); +} \ No newline at end of file diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index c413aae68..532e921c2 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -100,6 +100,8 @@ void D3D12Replay::Shutdown() void D3D12Replay::CreateResources() { + m_DebugManager = new D3D12DebugManager(m_pDevice); + if(RenderDoc::Inst().IsReplayApp()) { typedef HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY)(REFIID, void **); @@ -136,8 +138,6 @@ void D3D12Replay::CreateResources() } } - m_DebugManager = new D3D12DebugManager(m_pDevice); - CreateSOBuffers(); m_General.Init(m_pDevice, m_DebugManager); @@ -146,10 +146,7 @@ void D3D12Replay::CreateResources() m_VertexPick.Init(m_pDevice, m_DebugManager); m_PixelPick.Init(m_pDevice, m_DebugManager); m_Histogram.Init(m_pDevice, m_DebugManager); - } - if(RenderDoc::Inst().IsReplayApp()) - { AMDCounters *counters = NULL; if(m_Vendor == GPUVendor::AMD) @@ -2926,6 +2923,7 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip copyDesc.DepthOrArraySize *= (UINT16)copyDesc.SampleDesc.Count; copyDesc.SampleDesc.Count = 1; copyDesc.SampleDesc.Quality = 0; + copyDesc.MipLevels = 1; wasms = true; } @@ -3082,7 +3080,74 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip else if(wasms) { // copy/expand multisampled live texture to array readback texture - RDCUNIMPLEMENTED("CopyTex2DMSToArray on D3D12"); + if(isDepth) + copyDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + else + copyDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + copyDesc.Format = GetTypelessFormat(copyDesc.Format); + + ID3D12Resource *arrayTexture; + hr = m_pDevice->CreateCommittedResource( + &defaultHeap, D3D12_HEAP_FLAG_NONE, ©Desc, + isDepth ? D3D12_RESOURCE_STATE_DEPTH_WRITE : D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, + __uuidof(ID3D12Resource), (void **)&arrayTexture); + RDCASSERTEQUAL(hr, S_OK); + + list = m_pDevice->GetNewList(); + + // put source texture into shader read state + const vector &states = m_pDevice->GetSubresourceStates(tex); + + std::vector barriers; + barriers.reserve(states.size()); + for(size_t i = 0; i < states.size(); i++) + { + D3D12_RESOURCE_BARRIER b; + + // skip unneeded barriers + if(states[i] & D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) + continue; + + b.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + b.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + b.Transition.pResource = resource; + b.Transition.Subresource = (UINT)i; + b.Transition.StateBefore = states[i]; + b.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + + barriers.push_back(b); + } + + if(!barriers.empty()) + list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); + + list->Close(); + list = NULL; + + m_pDevice->ExecuteLists(); + m_pDevice->FlushLists(); + + // expand multisamples out to array + GetDebugManager()->CopyTex2DMSToArray(arrayTexture, srcTexture); + + tmpTexture = srcTexture = arrayTexture; + + list = m_pDevice->GetNewList(); + + // real resource back to normal + for(size_t i = 0; i < barriers.size(); i++) + std::swap(barriers[i].Transition.StateBefore, barriers[i].Transition.StateAfter); + + if(!barriers.empty()) + list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); + + D3D12_RESOURCE_BARRIER b = {}; + b.Transition.pResource = arrayTexture; + b.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + b.Transition.StateBefore = + isDepth ? D3D12_RESOURCE_STATE_DEPTH_WRITE : D3D12_RESOURCE_STATE_RENDER_TARGET; + b.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; + list->ResourceBarrier(1, &b); } if(list == NULL) diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj index bf8c1dfe4..7544f7353 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj @@ -110,6 +110,7 @@ + diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters index a0602a282..fee9daa3d 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters @@ -146,5 +146,8 @@ Wrapped + + Replay + \ No newline at end of file