From 8ad12480a45815a72c757cd065a695a58b88818e Mon Sep 17 00:00:00 2001 From: Triang3l Date: Wed, 9 Jan 2019 13:19:49 +0300 Subject: [PATCH] [D3D12] Copy index buffer to a scratch buffer for memexporting draws --- .../gpu/d3d12/d3d12_command_processor.cc | 40 ++++++++++++++----- src/xenia/gpu/d3d12/shared_memory.cc | 11 ----- src/xenia/gpu/d3d12/shared_memory.h | 15 ++++++- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index f6b53311d..1a2e07475 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -1456,16 +1456,8 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type, render_target_cache_->UseEDRAMAsUAV(); } - // TODO(Triang3l): Copy the index buffer to a scratch buffer if using - // memexport with an index buffer, because a resource can't be an index buffer - // (read-only) and a UAV (read/write) at once. - // Actually draw. if (indexed) { - if (memexport_used) { - // TODO(Triang3l): Index buffer copying for memexport. - return false; - } uint32_t index_size = index_buffer_info->format == IndexFormat::kInt32 ? sizeof(uint32_t) : sizeof(uint16_t); @@ -1489,6 +1481,7 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type, PrimitiveConverter::ConversionResult::kPrimitiveEmpty) { return true; } + ID3D12Resource* scratch_index_buffer = nullptr; if (conversion_result == PrimitiveConverter::ConversionResult::kConverted) { index_buffer_view.SizeInBytes = converted_index_count * index_size; index_count = converted_index_count; @@ -1501,8 +1494,29 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type, index_base, index_buffer_size); return false; } - index_buffer_view.BufferLocation = - shared_memory_->GetGPUAddress() + index_base; + if (memexport_used && !adaptive_tessellation) { + // If the shared memory is a UAV, it can't be used as an index buffer + // (UAV is a read/write state, index buffer is a read-only state). Need + // to copy the indices to a buffer in the index buffer state. + scratch_index_buffer = RequestScratchGPUBuffer( + index_buffer_size, D3D12_RESOURCE_STATE_COPY_DEST); + if (scratch_index_buffer == nullptr) { + return false; + } + shared_memory_->UseAsCopySource(); + SubmitBarriers(); + deferred_command_list_->D3DCopyBufferRegion( + scratch_index_buffer, 0, shared_memory_->GetBuffer(), index_base, + index_buffer_size); + PushTransitionBarrier(scratch_index_buffer, + D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_INDEX_BUFFER); + index_buffer_view.BufferLocation = + scratch_index_buffer->GetGPUVirtualAddress(); + } else { + index_buffer_view.BufferLocation = + shared_memory_->GetGPUAddress() + index_base; + } index_buffer_view.SizeInBytes = index_buffer_size; } if (memexport_used) { @@ -1510,14 +1524,18 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type, } else { shared_memory_->UseForReading(); } - deferred_command_list_->D3DIASetIndexBuffer(&index_buffer_view); SubmitBarriers(); if (adaptive_tessellation) { // Index buffer used for per-edge factors. deferred_command_list_->D3DDrawInstanced(index_count, 1, 0, 0); } else { + deferred_command_list_->D3DIASetIndexBuffer(&index_buffer_view); deferred_command_list_->D3DDrawIndexedInstanced(index_count, 1, 0, 0, 0); } + if (scratch_index_buffer != nullptr) { + ReleaseScratchGPUBuffer(scratch_index_buffer, + D3D12_RESOURCE_STATE_INDEX_BUFFER); + } } else { // Check if need to draw using a conversion index buffer. uint32_t converted_index_count; diff --git a/src/xenia/gpu/d3d12/shared_memory.cc b/src/xenia/gpu/d3d12/shared_memory.cc index 6e2a3e21e..6e01381d5 100644 --- a/src/xenia/gpu/d3d12/shared_memory.cc +++ b/src/xenia/gpu/d3d12/shared_memory.cc @@ -573,17 +573,6 @@ void SharedMemory::TransitionBuffer(D3D12_RESOURCE_STATES new_state) { buffer_state_ = new_state; } -void SharedMemory::UseForReading() { - // Vertex fetch also seems to be allowed in pixel shaders. - TransitionBuffer(D3D12_RESOURCE_STATE_INDEX_BUFFER | - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | - D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); -} - -void SharedMemory::UseForWriting() { - TransitionBuffer(D3D12_RESOURCE_STATE_UNORDERED_ACCESS); -} - void SharedMemory::CreateSRV(D3D12_CPU_DESCRIPTOR_HANDLE handle) { ui::d3d12::util::CreateRawBufferSRV( command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice(), diff --git a/src/xenia/gpu/d3d12/shared_memory.h b/src/xenia/gpu/d3d12/shared_memory.h index fa43a6734..4732d0fce 100644 --- a/src/xenia/gpu/d3d12/shared_memory.h +++ b/src/xenia/gpu/d3d12/shared_memory.h @@ -104,9 +104,20 @@ class SharedMemory { void RangeWrittenByGPU(uint32_t start, uint32_t length); // Makes the buffer usable for vertices, indices and texture untiling. - void UseForReading(); + inline void UseForReading() { + // Vertex fetch is also allowed in pixel shaders. + TransitionBuffer(D3D12_RESOURCE_STATE_INDEX_BUFFER | + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + } // Makes the buffer usable for texture tiling after a resolve. - void UseForWriting(); + inline void UseForWriting() { + TransitionBuffer(D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + } + // Makes the buffer usable as a source for copy commands. + inline void UseAsCopySource() { + TransitionBuffer(D3D12_RESOURCE_STATE_COPY_SOURCE); + } void CreateSRV(D3D12_CPU_DESCRIPTOR_HANDLE handle); void CreateRawUAV(D3D12_CPU_DESCRIPTOR_HANDLE handle);