From 0d2c4c24b4dd7ad8ca49cf4dd64b7a4b162832c4 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Wed, 25 Nov 2015 17:54:58 +0100 Subject: [PATCH] d3d12: Use a single big buffer to store readback data --- rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp | 8 +- rpcs3/Emu/RSX/D3D12/D3D12GSRender.h | 2 +- rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h | 11 +- rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp | 119 ++++++------------ 4 files changed, 50 insertions(+), 90 deletions(-) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index dc66e8f33e..eb772ca656 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -197,14 +197,14 @@ D3D12GSRender::D3D12GSRender() IID_PPV_ARGS(&m_dummy_texture)) ); - m_readback_resources.init(m_device.Get(), 1024 * 1024 * 128, D3D12_HEAP_TYPE_READBACK, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS); + m_readback_resources.init(m_device.Get(), 1024 * 1024 * 128, D3D12_HEAP_TYPE_READBACK, D3D12_RESOURCE_STATE_COPY_DEST); m_uav_heap.init(m_device.Get(), 1024 * 1024 * 128, D3D12_HEAP_TYPE_DEFAULT, D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES); m_rtts.init(m_device.Get()); - m_constants_data.init(m_device.Get(), 1024 * 1024 * 64, D3D12_HEAP_TYPE_UPLOAD, D3D12_HEAP_FLAG_NONE); - m_vertex_index_data.init(m_device.Get(), 1024 * 1024 * 384, D3D12_HEAP_TYPE_UPLOAD, D3D12_HEAP_FLAG_NONE); - m_texture_upload_data.init(m_device.Get(), 1024 * 1024 * 512, D3D12_HEAP_TYPE_UPLOAD, D3D12_HEAP_FLAG_NONE); + m_constants_data.init(m_device.Get(), 1024 * 1024 * 64, D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_STATE_GENERIC_READ); + m_vertex_index_data.init(m_device.Get(), 1024 * 1024 * 384, D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_STATE_GENERIC_READ); + m_texture_upload_data.init(m_device.Get(), 1024 * 1024 * 512, D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_STATE_GENERIC_READ); if (rpcs3::config.rsx.d3d12.overlay.value()) init_d2d_structures(); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h index c306d9ee56..614472f346 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -121,7 +121,7 @@ private: // Texture storage data_heap m_texture_upload_data; data_heap m_uav_heap; - data_heap m_readback_resources; + data_heap m_readback_resources; struct { diff --git a/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h b/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h index 33c026a93c..0704ca89ea 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h @@ -27,15 +27,15 @@ struct init_heap template<> struct init_heap { - static ID3D12Resource* init(ID3D12Device *device, size_t heap_size, D3D12_HEAP_TYPE type, D3D12_HEAP_FLAGS flags) + static ID3D12Resource* init(ID3D12Device *device, size_t heap_size, D3D12_HEAP_TYPE type, D3D12_RESOURCE_STATES state) { ID3D12Resource *result; D3D12_HEAP_PROPERTIES heap_properties = {}; heap_properties.Type = type; ThrowIfFailed(device->CreateCommittedResource(&heap_properties, - flags, + D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(heap_size), - D3D12_RESOURCE_STATE_GENERIC_READ, + state, nullptr, IID_PPV_ARGS(&result)) ); @@ -60,10 +60,11 @@ struct data_heap size_t m_put_pos; // Start of free space size_t m_get_pos; // End of free space - void init(ID3D12Device *device, size_t heap_size, D3D12_HEAP_TYPE type, D3D12_HEAP_FLAGS flags) + template + void init(ID3D12Device *device, size_t heap_size, D3D12_HEAP_TYPE type, arg_type... args) { m_size = heap_size; - m_heap = init_heap::init(device, heap_size, type, flags); + m_heap = init_heap::init(device, heap_size, type, args...); m_put_pos = 0; m_get_pos = heap_size - 1; } diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp index 373b2d1a87..c99ddffb4b 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp @@ -348,13 +348,12 @@ void render_targets::init(ID3D12Device *device)//, u8 surfaceDepthFormat, size_t namespace { /** - * Create a write back buffer resource and populate command_list with copy command to fill it - * with color_surface data. - */ - ComPtr create_readback_buffer_and_download( + * Populate command_list with copy command with color_surface data and return offset in readback buffer + */ + size_t download_to_readback_buffer( ID3D12Device *device, ID3D12GraphicsCommandList * command_list, - data_heap &readback_heap, + data_heap &readback_heap, ID3D12Resource * color_surface, int color_surface_format ) @@ -376,31 +375,22 @@ namespace size_t buffer_size = row_pitch * clip_h; assert(readback_heap.can_alloc(buffer_size)); - size_t heapOffset = readback_heap.alloc(buffer_size); - ComPtr Result; - ThrowIfFailed( - device->CreatePlacedResource( - readback_heap.m_heap, - heapOffset, - &CD3DX12_RESOURCE_DESC::Buffer(row_pitch * clip_h), - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(Result.GetAddressOf()) - ) - ); + size_t heap_offset = readback_heap.alloc(buffer_size); command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(color_surface, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE)); - command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(Result.Get(), { 0,{ dxgi_format, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0, + command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(readback_heap.m_heap, { heap_offset, { dxgi_format, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0, &CD3DX12_TEXTURE_COPY_LOCATION(color_surface, 0), nullptr); command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(color_surface, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET)); - return Result; + return heap_offset; } - void copy_readback_buffer_to_dest(void *dest, ID3D12Resource *res, size_t dst_pitch, size_t src_pitch, size_t height) + void copy_readback_buffer_to_dest(void *dest, data_heap &readback_heap, size_t offset_in_heap, size_t dst_pitch, size_t src_pitch, size_t height) { - void *mapped_buffer; - ThrowIfFailed(res->Map(0, nullptr, &mapped_buffer)); + void *buffer; + // TODO: Use exact range + ThrowIfFailed(readback_heap.m_heap->Map(0, nullptr, &buffer)); + void *mapped_buffer = (char*)buffer + offset_in_heap; for (unsigned row = 0; row < height; row++) { u32 *casted_dest = (u32*)((char*)dest + row * dst_pitch); @@ -408,7 +398,7 @@ namespace for (unsigned col = 0; col < src_pitch / 4; col++) *casted_dest++ = _byteswap_ulong(*casted_src++); } - res->Unmap(0, nullptr); + readback_heap.m_heap->Unmap(0, nullptr); } void wait_for_command_queue(ID3D12Device *device, ID3D12CommandQueue *command_queue) @@ -431,9 +421,10 @@ void D3D12GSRender::copy_render_target_to_dma_location() int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16; int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16; - ComPtr depth_buffer_write_dest, depth_format_conversion_buffer; + ComPtr depth_format_conversion_buffer; ComPtr descriptor_heap; size_t depth_row_pitch = align(clip_w, 256); + size_t depth_buffer_offset_in_heap = 0; u32 context_dma_color[] = { @@ -463,21 +454,6 @@ void D3D12GSRender::copy_render_target_to_dma_location() ) ); - size_t buffer_size = depth_row_pitch * clip_h; - assert(m_readback_resources.can_alloc(buffer_size)); - heap_offset = m_readback_resources.alloc(buffer_size); - - ThrowIfFailed( - m_device->CreatePlacedResource( - m_readback_resources.m_heap, - heap_offset, - &CD3DX12_RESOURCE_DESC::Buffer(buffer_size), - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(depth_buffer_write_dest.GetAddressOf()) - ) - ); - D3D12_DESCRIPTOR_HEAP_DESC descriptor_heap_desc = { D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV , 2, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE }; ThrowIfFailed( m_device->CreateDescriptorHeap(&descriptor_heap_desc, IID_PPV_ARGS(descriptor_heap.GetAddressOf())) @@ -511,22 +487,22 @@ void D3D12GSRender::copy_render_target_to_dma_location() }; get_current_resource_storage().command_list->ResourceBarrier(2, barriers); get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(depth_format_conversion_buffer.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE)); - get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(depth_buffer_write_dest.Get(), { 0,{ DXGI_FORMAT_R8_UNORM, (UINT)clip_w, (UINT)clip_h, 1, (UINT)depth_row_pitch } }), 0, 0, 0, - &CD3DX12_TEXTURE_COPY_LOCATION(depth_buffer_write_dest.Get(), 0), nullptr); + get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.m_heap, { depth_buffer_offset_in_heap,{ DXGI_FORMAT_R8_UNORM, (UINT)clip_w, (UINT)clip_h, 1, (UINT)depth_row_pitch } }), 0, 0, 0, + &CD3DX12_TEXTURE_COPY_LOCATION(depth_format_conversion_buffer.Get(), 0), nullptr); invalidate_address(rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], m_context_dma_z - 0xfeed0000)); need_transfer = true; } - ComPtr readback_buffers[4]; + size_t color_buffer_offset_in_heap[4]; if (rpcs3::state.config.rsx.opengl.write_color_buffers) { for (u8 i : get_rtt_indexes(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])) { if (!context_dma_color[i]) continue; - readback_buffers[i] = create_readback_buffer_and_download(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, m_rtts.bound_render_targets[0], m_surface.color_format); + color_buffer_offset_in_heap[i] = download_to_readback_buffer(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, m_rtts.bound_render_targets[i], m_surface.color_format); invalidate_address(rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_COLOR_AOFFSET], context_dma_color[i] - 0xfeed0000)); need_transfer = true; } @@ -546,8 +522,10 @@ void D3D12GSRender::copy_render_target_to_dma_location() u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], m_context_dma_z - 0xfeed0000); auto ptr = vm::base(address); char *depth_buffer = (char*)ptr; - unsigned char *mapped_buffer; - ThrowIfFailed(depth_buffer_write_dest->Map(0, nullptr, (void**)&mapped_buffer)); + void *buffer; + // TODO: Use exact range + ThrowIfFailed(m_readback_resources.m_heap->Map(0, nullptr, &buffer)); + unsigned char *mapped_buffer = (unsigned char*)buffer + depth_buffer_offset_in_heap; for (unsigned row = 0; row < (unsigned)clip_h; row++) { @@ -560,6 +538,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() depth_buffer[4 * (row * clip_w + i) + 3] = c; } } + m_readback_resources.m_heap->Unmap(0, nullptr); } size_t srcPitch, dstPitch; @@ -589,7 +568,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() { if (!context_dma_color[i]) continue; - copy_readback_buffer_to_dest(dest_buffer[i], readback_buffers[i].Get(), srcPitch, dstPitch, clip_h); + copy_readback_buffer_to_dest(dest_buffer[i], m_readback_resources, color_buffer_offset_in_heap[i], srcPitch, dstPitch, clip_h); } } } @@ -597,7 +576,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() void D3D12GSRender::copy_render_targets_to_memory(void *buffer, u8 rtt) { - ComPtr readback_buffer = create_readback_buffer_and_download(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, m_rtts.bound_render_targets[rtt], m_surface.color_format); + size_t heap_offset = download_to_readback_buffer(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, m_rtts.bound_render_targets[rtt], m_surface.color_format); ThrowIfFailed(get_current_resource_storage().command_list->Close()); m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf()); @@ -620,7 +599,7 @@ void D3D12GSRender::copy_render_targets_to_memory(void *buffer, u8 rtt) dstPitch = clip_w * 8; break; } - copy_readback_buffer_to_dest(buffer, readback_buffer.Get(), srcPitch, dstPitch, clip_h); + copy_readback_buffer_to_dest(buffer, m_readback_resources, heap_offset, srcPitch, dstPitch, clip_h); } void D3D12GSRender::copy_depth_buffer_to_memory(void *buffer) @@ -630,24 +609,13 @@ void D3D12GSRender::copy_depth_buffer_to_memory(void *buffer) size_t row_pitch = align(clip_w * 4, 256); - ComPtr readback_buffer; size_t buffer_size = row_pitch * clip_h; assert(m_readback_resources.can_alloc(buffer_size)); - size_t heapOffset = m_readback_resources.alloc(buffer_size); - ThrowIfFailed( - m_device->CreatePlacedResource( - m_readback_resources.m_heap, - heapOffset, - &CD3DX12_RESOURCE_DESC::Buffer(buffer_size), - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(readback_buffer.GetAddressOf()) - ) - ); + size_t heap_offset = m_readback_resources.alloc(buffer_size); get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE)); - get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(readback_buffer.Get(), { 0,{ DXGI_FORMAT_R32_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0, + get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.m_heap, { heap_offset,{ DXGI_FORMAT_R32_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0, &CD3DX12_TEXTURE_COPY_LOCATION(m_rtts.bound_depth_stencil, 0), nullptr); get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE)); @@ -658,8 +626,9 @@ void D3D12GSRender::copy_depth_buffer_to_memory(void *buffer) wait_for_command_queue(m_device.Get(), m_command_queue.Get()); m_readback_resources.m_get_pos = m_readback_resources.get_current_put_pos_minus_one(); - void *mapped_buffer; - ThrowIfFailed(readback_buffer->Map(0, nullptr, &mapped_buffer)); + void *temp_buffer; + ThrowIfFailed(m_readback_resources.m_heap->Map(0, nullptr, &temp_buffer)); + void *mapped_buffer = (char*)temp_buffer + heap_offset; for (unsigned row = 0; row < clip_h; row++) { u32 *casted_dest = (u32*)((char*)buffer + row * clip_w * 4); @@ -667,7 +636,7 @@ void D3D12GSRender::copy_depth_buffer_to_memory(void *buffer) for (unsigned col = 0; col < row_pitch / 4; col++) *casted_dest++ = *casted_src++; } - readback_buffer->Unmap(0, nullptr); + m_readback_resources.m_heap->Unmap(0, nullptr); } @@ -678,24 +647,13 @@ void D3D12GSRender::copy_stencil_buffer_to_memory(void *buffer) size_t row_pitch = align(clip_w * 4, 256); - ComPtr readback_buffer; size_t buffer_size = row_pitch * clip_h; assert(m_readback_resources.can_alloc(buffer_size)); - size_t heapOffset = m_readback_resources.alloc(buffer_size); - ThrowIfFailed( - m_device->CreatePlacedResource( - m_readback_resources.m_heap, - heapOffset, - &CD3DX12_RESOURCE_DESC::Buffer(buffer_size), - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(readback_buffer.GetAddressOf()) - ) - ); + size_t heap_offset = m_readback_resources.alloc(buffer_size); get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE)); - get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(readback_buffer.Get(), { 0,{ DXGI_FORMAT_R8_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0, + get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.m_heap, { heap_offset, { DXGI_FORMAT_R8_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0, &CD3DX12_TEXTURE_COPY_LOCATION(m_rtts.bound_depth_stencil, 1), nullptr); get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE)); @@ -706,8 +664,9 @@ void D3D12GSRender::copy_stencil_buffer_to_memory(void *buffer) wait_for_command_queue(m_device.Get(), m_command_queue.Get()); m_readback_resources.m_get_pos = m_readback_resources.get_current_put_pos_minus_one(); - void *mapped_buffer; - ThrowIfFailed(readback_buffer->Map(0, nullptr, &mapped_buffer)); + void *temp_buffer; + ThrowIfFailed(m_readback_resources.m_heap->Map(0, nullptr, &temp_buffer)); + void *mapped_buffer = (char*)temp_buffer + heap_offset; for (unsigned row = 0; row < clip_h; row++) { char *casted_dest = (char*)buffer + row * clip_w; @@ -715,7 +674,7 @@ void D3D12GSRender::copy_stencil_buffer_to_memory(void *buffer) for (unsigned col = 0; col < row_pitch; col++) *casted_dest++ = *casted_src++; } - readback_buffer->Unmap(0, nullptr); + m_readback_resources.m_heap->Unmap(0, nullptr); } #endif