diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index 8cd8f98f8..cc06fc612 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -435,16 +435,16 @@ uint32_t D3D12CommandProcessor::GetRootExtraParameterIndices( } uint64_t D3D12CommandProcessor::RequestViewDescriptors( - uint64_t previous_full_update, uint32_t count_for_partial_update, + uint64_t previous_heap_index, uint32_t count_for_partial_update, uint32_t count_for_full_update, D3D12_CPU_DESCRIPTOR_HANDLE& cpu_handle_out, D3D12_GPU_DESCRIPTOR_HANDLE& gpu_handle_out) { uint32_t descriptor_index; - uint64_t current_full_update = - view_heap_pool_->Request(previous_full_update, count_for_partial_update, - count_for_full_update, descriptor_index); - if (current_full_update == 0) { + uint64_t current_heap_index = view_heap_pool_->Request( + GetD3D12Context()->GetCurrentFrame(), previous_heap_index, + count_for_partial_update, count_for_full_update, descriptor_index); + if (current_heap_index == ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { // There was an error. - return 0; + return ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid; } ID3D12DescriptorHeap* heap = view_heap_pool_->GetLastRequestHeap(); if (current_view_heap_ != heap) { @@ -457,20 +457,20 @@ uint64_t D3D12CommandProcessor::RequestViewDescriptors( view_heap_pool_->GetLastRequestHeapCPUStart(), descriptor_index); gpu_handle_out = provider->OffsetViewDescriptor( view_heap_pool_->GetLastRequestHeapGPUStart(), descriptor_index); - return current_full_update; + return current_heap_index; } uint64_t D3D12CommandProcessor::RequestSamplerDescriptors( - uint64_t previous_full_update, uint32_t count_for_partial_update, + uint64_t previous_heap_index, uint32_t count_for_partial_update, uint32_t count_for_full_update, D3D12_CPU_DESCRIPTOR_HANDLE& cpu_handle_out, D3D12_GPU_DESCRIPTOR_HANDLE& gpu_handle_out) { uint32_t descriptor_index; - uint64_t current_full_update = sampler_heap_pool_->Request( - previous_full_update, count_for_partial_update, count_for_full_update, - descriptor_index); - if (current_full_update == 0) { + uint64_t current_heap_index = sampler_heap_pool_->Request( + GetD3D12Context()->GetCurrentFrame(), previous_heap_index, + count_for_partial_update, count_for_full_update, descriptor_index); + if (current_heap_index == ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { // There was an error. - return 0; + return ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid; } ID3D12DescriptorHeap* heap = sampler_heap_pool_->GetLastRequestHeap(); if (current_sampler_heap_ != heap) { @@ -485,7 +485,7 @@ uint64_t D3D12CommandProcessor::RequestSamplerDescriptors( sampler_heap_pool_->GetLastRequestHeapCPUStart().ptr + descriptor_offset; gpu_handle_out.ptr = sampler_heap_pool_->GetLastRequestHeapGPUStart().ptr + descriptor_offset; - return current_full_update; + return current_heap_index; } ID3D12Resource* D3D12CommandProcessor::RequestScratchGPUBuffer( @@ -705,8 +705,7 @@ bool D3D12CommandProcessor::SetupContext() { return false; } - auto context = GetD3D12Context(); - auto provider = context->GetD3D12Provider(); + auto provider = GetD3D12Context()->GetD3D12Provider(); auto device = provider->GetDevice(); auto direct_queue = provider->GetDirectQueue(); @@ -721,12 +720,12 @@ bool D3D12CommandProcessor::SetupContext() { deferred_command_list_ = std::make_unique(this); constant_buffer_pool_ = - std::make_unique(context, 1024 * 1024); + std::make_unique(device, 1024 * 1024); view_heap_pool_ = std::make_unique( - context, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 32768); + device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 32768); // Can't create a shader-visible heap with more than 2048 samplers. sampler_heap_pool_ = std::make_unique( - context, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 2048); + device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 2048); shared_memory_ = std::make_unique(this, memory_, &trace_writer_); @@ -1068,8 +1067,10 @@ void D3D12CommandProcessor::PerformSwap(uint32_t frontbuffer_ptr, D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start; D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start; - if (RequestViewDescriptors(0, 2, 2, descriptor_cpu_start, - descriptor_gpu_start) != 0) { + if (RequestViewDescriptors(ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, + 2, 2, descriptor_cpu_start, + descriptor_gpu_start) != + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { TextureFormat frontbuffer_format; if (texture_cache_->RequestSwapTexture(descriptor_cpu_start, frontbuffer_format)) { @@ -1818,8 +1819,8 @@ bool D3D12CommandProcessor::BeginFrame() { cbuffer_bindings_float_pixel_.up_to_date = false; cbuffer_bindings_bool_loop_.up_to_date = false; cbuffer_bindings_fetch_.up_to_date = false; - draw_view_full_update_ = 0; - draw_sampler_full_update_ = 0; + draw_view_heap_index_ = ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid; + draw_sampler_heap_index_ = ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid; texture_bindings_written_vertex_ = false; texture_bindings_written_pixel_ = false; samplers_written_vertex_ = false; @@ -1836,9 +1837,9 @@ bool D3D12CommandProcessor::BeginFrame() { } deferred_command_list_->Reset(); - constant_buffer_pool_->BeginFrame(); - view_heap_pool_->BeginFrame(); - sampler_heap_pool_->BeginFrame(); + constant_buffer_pool_->Reclaim(last_completed_frame); + view_heap_pool_->Reclaim(last_completed_frame); + sampler_heap_pool_->Reclaim(last_completed_frame); shared_memory_->BeginFrame(); @@ -1858,16 +1859,12 @@ bool D3D12CommandProcessor::EndFrame() { assert_false(scratch_buffer_used_); - primitive_converter_->EndFrame(); - pipeline_cache_->EndFrame(); render_target_cache_->EndFrame(); texture_cache_->EndFrame(); - shared_memory_->EndFrame(); - // Submit barriers now because resources the queued barriers are for may be // destroyed between frames. SubmitBarriers(); @@ -1888,10 +1885,6 @@ bool D3D12CommandProcessor::EndFrame() { pix_capturing_ = false; } - sampler_heap_pool_->EndFrame(); - view_heap_pool_->EndFrame(); - constant_buffer_pool_->EndFrame(); - auto context = GetD3D12Context(); context->EndSwap(); current_queue_frame_ = UINT32_MAX; @@ -2633,8 +2626,10 @@ void D3D12CommandProcessor::UpdateSystemConstantValues( bool D3D12CommandProcessor::UpdateBindings( const D3D12Shader* vertex_shader, const D3D12Shader* pixel_shader, ID3D12RootSignature* root_signature) { - auto provider = GetD3D12Context()->GetD3D12Provider(); + auto context = GetD3D12Context(); + auto provider = context->GetD3D12Provider(); auto device = provider->GetDevice(); + auto current_frame = context->GetCurrentFrame(); auto& regs = *register_file_; #if FINE_GRAINED_DRAW_SCOPES @@ -2769,9 +2764,9 @@ bool D3D12CommandProcessor::UpdateBindings( // Update constant buffers. if (!cbuffer_bindings_system_.up_to_date) { - uint8_t* system_constants = constant_buffer_pool_->RequestFull( - xe::align(uint32_t(sizeof(system_constants_)), 256u), nullptr, nullptr, - &cbuffer_bindings_system_.buffer_address); + uint8_t* system_constants = constant_buffer_pool_->Request( + current_frame, xe::align(uint32_t(sizeof(system_constants_)), 256u), + nullptr, nullptr, &cbuffer_bindings_system_.buffer_address); if (system_constants == nullptr) { return false; } @@ -2781,8 +2776,8 @@ bool D3D12CommandProcessor::UpdateBindings( write_system_constant_view = true; } if (!cbuffer_bindings_float_vertex_.up_to_date) { - uint8_t* float_constants = constant_buffer_pool_->RequestFull( - float_constant_size_vertex, nullptr, nullptr, + uint8_t* float_constants = constant_buffer_pool_->Request( + current_frame, float_constant_size_vertex, nullptr, nullptr, &cbuffer_bindings_float_vertex_.buffer_address); if (float_constants == nullptr) { return false; @@ -2806,8 +2801,8 @@ bool D3D12CommandProcessor::UpdateBindings( write_float_constant_view_vertex = true; } if (!cbuffer_bindings_float_pixel_.up_to_date) { - uint8_t* float_constants = constant_buffer_pool_->RequestFull( - float_constant_size_pixel, nullptr, nullptr, + uint8_t* float_constants = constant_buffer_pool_->Request( + current_frame, float_constant_size_pixel, nullptr, nullptr, &cbuffer_bindings_float_pixel_.buffer_address); if (float_constants == nullptr) { return false; @@ -2836,8 +2831,8 @@ bool D3D12CommandProcessor::UpdateBindings( } if (!cbuffer_bindings_bool_loop_.up_to_date) { uint32_t* bool_loop_constants = - reinterpret_cast(constant_buffer_pool_->RequestFull( - 768, nullptr, nullptr, + reinterpret_cast(constant_buffer_pool_->Request( + current_frame, 768, nullptr, nullptr, &cbuffer_bindings_bool_loop_.buffer_address)); if (bool_loop_constants == nullptr) { return false; @@ -2856,8 +2851,9 @@ bool D3D12CommandProcessor::UpdateBindings( write_bool_loop_constant_view = true; } if (!cbuffer_bindings_fetch_.up_to_date) { - uint8_t* fetch_constants = constant_buffer_pool_->RequestFull( - 768, nullptr, nullptr, &cbuffer_bindings_fetch_.buffer_address); + uint8_t* fetch_constants = + constant_buffer_pool_->Request(current_frame, 768, nullptr, nullptr, + &cbuffer_bindings_fetch_.buffer_address); if (fetch_constants == nullptr) { return false; } @@ -2901,10 +2897,10 @@ bool D3D12CommandProcessor::UpdateBindings( D3D12_CPU_DESCRIPTOR_HANDLE view_cpu_handle; D3D12_GPU_DESCRIPTOR_HANDLE view_gpu_handle; uint32_t descriptor_size_view = provider->GetViewDescriptorSize(); - uint64_t view_full_update_index = RequestViewDescriptors( - draw_view_full_update_, view_count_partial_update, view_count_full_update, + uint64_t view_heap_index = RequestViewDescriptors( + draw_view_heap_index_, view_count_partial_update, view_count_full_update, view_cpu_handle, view_gpu_handle); - if (view_full_update_index == 0) { + if (view_heap_index == ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { XELOGE("Failed to allocate view descriptors!"); return false; } @@ -2918,18 +2914,20 @@ bool D3D12CommandProcessor::UpdateBindings( D3D12_CPU_DESCRIPTOR_HANDLE sampler_cpu_handle = {}; D3D12_GPU_DESCRIPTOR_HANDLE sampler_gpu_handle = {}; uint32_t descriptor_size_sampler = provider->GetSamplerDescriptorSize(); - uint64_t sampler_full_update_index = 0; + uint64_t sampler_heap_index = + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid; if (sampler_count_vertex != 0 || sampler_count_pixel != 0) { - sampler_full_update_index = RequestSamplerDescriptors( - draw_sampler_full_update_, sampler_count_partial_update, + sampler_heap_index = RequestSamplerDescriptors( + draw_sampler_heap_index_, sampler_count_partial_update, sampler_count_vertex + sampler_count_pixel, sampler_cpu_handle, sampler_gpu_handle); - if (sampler_full_update_index == 0) { + if (sampler_heap_index == + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { XELOGE("Failed to allocate sampler descriptors!"); return false; } } - if (draw_view_full_update_ != view_full_update_index) { + if (draw_view_heap_index_ != view_heap_index) { // Need to update all view descriptors. write_system_constant_view = true; write_fetch_constant_view = true; @@ -2957,7 +2955,8 @@ bool D3D12CommandProcessor::UpdateBindings( current_graphics_root_up_to_date_ &= ~(1u << kRootParameter_SharedMemoryAndEDRAM); } - if (draw_sampler_full_update_ != sampler_full_update_index) { + if (sampler_heap_index != ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid && + draw_sampler_heap_index_ != sampler_heap_index) { write_samplers_vertex = sampler_count_vertex != 0; write_samplers_pixel = sampler_count_pixel != 0; samplers_written_vertex_ = false; @@ -3085,8 +3084,10 @@ bool D3D12CommandProcessor::UpdateBindings( } // Wrote new descriptors on the current page. - draw_view_full_update_ = view_full_update_index; - draw_sampler_full_update_ = sampler_full_update_index; + draw_view_heap_index_ = view_heap_index; + if (sampler_heap_index != ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { + draw_sampler_heap_index_ = sampler_heap_index; + } // Update the root parameters. if (!(current_graphics_root_up_to_date_ & diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.h b/src/xenia/gpu/d3d12/d3d12_command_processor.h index 006eb1062..070607d89 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.h +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.h @@ -92,13 +92,13 @@ class D3D12CommandProcessor : public CommandProcessor { } // Request and automatically rebind descriptors on the draw command list. // Refer to DescriptorHeapPool::Request for partial/full update explanation. - uint64_t RequestViewDescriptors(uint64_t previous_full_update, + uint64_t RequestViewDescriptors(uint64_t previous_heap_index, uint32_t count_for_partial_update, uint32_t count_for_full_update, D3D12_CPU_DESCRIPTOR_HANDLE& cpu_handle_out, D3D12_GPU_DESCRIPTOR_HANDLE& gpu_handle_out); uint64_t RequestSamplerDescriptors( - uint64_t previous_full_update, uint32_t count_for_partial_update, + uint64_t previous_heap_index, uint32_t count_for_partial_update, uint32_t count_for_full_update, D3D12_CPU_DESCRIPTOR_HANDLE& cpu_handle_out, D3D12_GPU_DESCRIPTOR_HANDLE& gpu_handle_out); @@ -362,8 +362,8 @@ class D3D12CommandProcessor : public CommandProcessor { ConstantBufferBinding cbuffer_bindings_fetch_; // Pages with the descriptors currently used for handling Xenos draw calls. - uint64_t draw_view_full_update_; - uint64_t draw_sampler_full_update_; + uint64_t draw_view_heap_index_; + uint64_t draw_sampler_heap_index_; // Whether the last used texture bindings have been written to the current // view descriptor heap. diff --git a/src/xenia/gpu/d3d12/primitive_converter.cc b/src/xenia/gpu/d3d12/primitive_converter.cc index 80db854de..8842d7618 100644 --- a/src/xenia/gpu/d3d12/primitive_converter.cc +++ b/src/xenia/gpu/d3d12/primitive_converter.cc @@ -53,14 +53,14 @@ PrimitiveConverter::PrimitiveConverter(D3D12CommandProcessor* command_processor, PrimitiveConverter::~PrimitiveConverter() { Shutdown(); } bool PrimitiveConverter::Initialize() { - auto context = command_processor_->GetD3D12Context(); - auto device = context->GetD3D12Provider()->GetDevice(); + auto device = + command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice(); // There can be at most 65535 indices in a Xenos draw call, but they can be up // to 4 bytes large, and conversion can add more indices (almost triple the // count for triangle strips, for instance). buffer_pool_ = - std::make_unique(context, 4 * 1024 * 1024); + std::make_unique(device, 4 * 1024 * 1024); // Create the static index buffer for non-indexed drawing. D3D12_RESOURCE_DESC static_ib_desc; @@ -162,14 +162,13 @@ void PrimitiveConverter::BeginFrame() { } } - buffer_pool_->BeginFrame(); + buffer_pool_->Reclaim( + command_processor_->GetD3D12Context()->GetLastCompletedFrame()); converted_indices_cache_.clear(); memory_regions_used_ = 0; } -void PrimitiveConverter::EndFrame() { buffer_pool_->EndFrame(); } - PrimitiveType PrimitiveConverter::GetReplacementPrimitiveType( PrimitiveType type) { switch (type) { @@ -695,8 +694,9 @@ void* PrimitiveConverter::AllocateIndices( size += 16; } D3D12_GPU_VIRTUAL_ADDRESS gpu_address; - uint8_t* mapping = - buffer_pool_->RequestFull(size, nullptr, nullptr, &gpu_address); + uint8_t* mapping = buffer_pool_->Request( + command_processor_->GetD3D12Context()->GetCurrentFrame(), size, nullptr, + nullptr, &gpu_address); if (mapping == nullptr) { XELOGE("Failed to allocate space for %u converted %u-bit vertex indices", count, format == IndexFormat::kInt32 ? 32 : 16); diff --git a/src/xenia/gpu/d3d12/primitive_converter.h b/src/xenia/gpu/d3d12/primitive_converter.h index ea06a1b32..eafc456bd 100644 --- a/src/xenia/gpu/d3d12/primitive_converter.h +++ b/src/xenia/gpu/d3d12/primitive_converter.h @@ -47,7 +47,6 @@ class PrimitiveConverter { void ClearCache(); void BeginFrame(); - void EndFrame(); // Returns the primitive type that the original type will be converted to. static PrimitiveType GetReplacementPrimitiveType(PrimitiveType type); diff --git a/src/xenia/gpu/d3d12/render_target_cache.cc b/src/xenia/gpu/d3d12/render_target_cache.cc index 7e429fa50..bc6830335 100644 --- a/src/xenia/gpu/d3d12/render_target_cache.cc +++ b/src/xenia/gpu/d3d12/render_target_cache.cc @@ -23,6 +23,7 @@ #include "xenia/gpu/texture_info.h" #include "xenia/gpu/texture_util.h" #include "xenia/ui/d3d12/d3d12_util.h" +#include "xenia/ui/d3d12/pools.h" DEFINE_bool(d3d12_16bit_rtv_full_range, true, "Use full -32...32 range for RG16 and RGBA16 render targets " @@ -1379,7 +1380,9 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory, D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start; D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start; if (command_processor_->RequestViewDescriptors( - 0, 2, 2, descriptor_cpu_start, descriptor_gpu_start) == 0) { + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 2, 2, + descriptor_cpu_start, descriptor_gpu_start) == + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { return false; } TransitionEDRAMBuffer(D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); @@ -1527,7 +1530,9 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory, D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start; D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start; if (command_processor_->RequestViewDescriptors( - 0, 3, 3, descriptor_cpu_start, descriptor_gpu_start) == 0) { + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 3, 3, + descriptor_cpu_start, descriptor_gpu_start) == + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { return false; } // Buffer for copying. @@ -1833,8 +1838,10 @@ bool RenderTargetCache::ResolveClear(uint32_t edram_base, command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice(); D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start; D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start; - if (command_processor_->RequestViewDescriptors(0, 1, 1, descriptor_cpu_start, - descriptor_gpu_start) == 0) { + if (command_processor_->RequestViewDescriptors( + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 1, 1, + descriptor_cpu_start, descriptor_gpu_start) == + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { return false; } @@ -2549,8 +2556,10 @@ void RenderTargetCache::StoreRenderTargetsToEDRAM() { // Allocate descriptors for the buffers. D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start; D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start; - if (command_processor_->RequestViewDescriptors(0, 2, 2, descriptor_cpu_start, - descriptor_gpu_start) == 0) { + if (command_processor_->RequestViewDescriptors( + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 2, 2, + descriptor_cpu_start, descriptor_gpu_start) == + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { return; } @@ -2694,8 +2703,10 @@ void RenderTargetCache::LoadRenderTargetsFromEDRAM( // Allocate descriptors for the buffers. D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start; D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start; - if (command_processor_->RequestViewDescriptors(0, 2, 2, descriptor_cpu_start, - descriptor_gpu_start) == 0) { + if (command_processor_->RequestViewDescriptors( + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 2, 2, + descriptor_cpu_start, descriptor_gpu_start) == + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { return; } diff --git a/src/xenia/gpu/d3d12/shared_memory.cc b/src/xenia/gpu/d3d12/shared_memory.cc index 39dcb679a..84e0ce637 100644 --- a/src/xenia/gpu/d3d12/shared_memory.cc +++ b/src/xenia/gpu/d3d12/shared_memory.cc @@ -59,8 +59,7 @@ SharedMemory::SharedMemory(D3D12CommandProcessor* command_processor, SharedMemory::~SharedMemory() { Shutdown(); } bool SharedMemory::Initialize() { - auto context = command_processor_->GetD3D12Context(); - auto provider = context->GetD3D12Provider(); + auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider(); auto device = provider->GetDevice(); D3D12_RESOURCE_DESC buffer_desc; @@ -131,7 +130,7 @@ bool SharedMemory::Initialize() { valid_and_gpu_written_pages_.size() * sizeof(uint64_t)); upload_buffer_pool_ = - std::make_unique(context, 4 * 1024 * 1024); + std::make_unique(device, 4 * 1024 * 1024); physical_write_watch_handle_ = memory_->RegisterPhysicalWriteWatch(MemoryWriteCallbackThunk, this); @@ -168,12 +167,11 @@ void SharedMemory::Shutdown() { } void SharedMemory::BeginFrame() { - upload_buffer_pool_->BeginFrame(); + upload_buffer_pool_->Reclaim( + command_processor_->GetD3D12Context()->GetLastCompletedFrame()); heap_creation_failed_ = false; } -void SharedMemory::EndFrame() { upload_buffer_pool_->EndFrame(); } - SharedMemory::GlobalWatchHandle SharedMemory::RegisterGlobalWatch( GlobalWatchCallback callback, void* callback_context) { GlobalWatch* watch = new GlobalWatch; @@ -378,6 +376,7 @@ bool SharedMemory::RequestRange(uint32_t start, uint32_t length) { ID3D12Resource* upload_buffer; uint32_t upload_buffer_offset, upload_buffer_size; uint8_t* upload_buffer_mapping = upload_buffer_pool_->RequestPartial( + command_processor_->GetD3D12Context()->GetCurrentFrame(), upload_range_length << page_size_log2_, &upload_buffer, &upload_buffer_offset, &upload_buffer_size, nullptr); if (upload_buffer_mapping == nullptr) { diff --git a/src/xenia/gpu/d3d12/shared_memory.h b/src/xenia/gpu/d3d12/shared_memory.h index dc1119878..f4b3fa815 100644 --- a/src/xenia/gpu/d3d12/shared_memory.h +++ b/src/xenia/gpu/d3d12/shared_memory.h @@ -45,7 +45,6 @@ class SharedMemory { } void BeginFrame(); - void EndFrame(); typedef void (*GlobalWatchCallback)(void* context, uint32_t address_first, uint32_t address_last, diff --git a/src/xenia/gpu/d3d12/texture_cache.cc b/src/xenia/gpu/d3d12/texture_cache.cc index 347ebe2d8..f9ee6a705 100644 --- a/src/xenia/gpu/d3d12/texture_cache.cc +++ b/src/xenia/gpu/d3d12/texture_cache.cc @@ -24,6 +24,7 @@ #include "xenia/gpu/texture_info.h" #include "xenia/gpu/texture_util.h" #include "xenia/ui/d3d12/d3d12_util.h" +#include "xenia/ui/d3d12/pools.h" DEFINE_int32(d3d12_resolution_scale, 1, "Scale of rendering width and height (currently only 1 and 2 " @@ -1813,8 +1814,10 @@ bool TextureCache::TileResolvedTexture( // Tile the texture. D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start; D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start; - if (command_processor_->RequestViewDescriptors(0, 2, 2, descriptor_cpu_start, - descriptor_gpu_start) == 0) { + if (command_processor_->RequestViewDescriptors( + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 2, 2, + descriptor_cpu_start, descriptor_gpu_start) == + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { return false; } if (resolution_scale_log2) { @@ -2403,7 +2406,8 @@ bool TextureCache::LoadTextureData(Texture* texture) { } auto command_list = command_processor_->GetDeferredCommandList(); - auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider(); + auto context = command_processor_->GetD3D12Context(); + auto provider = context->GetD3D12Provider(); auto device = provider->GetDevice(); // Get the pipeline. @@ -2496,8 +2500,9 @@ bool TextureCache::LoadTextureData(Texture* texture) { D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start; D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start; if (command_processor_->RequestViewDescriptors( - 0, descriptor_count, descriptor_count, descriptor_cpu_start, - descriptor_gpu_start) == 0) { + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, descriptor_count, + descriptor_count, descriptor_cpu_start, descriptor_gpu_start) == + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { command_processor_->ReleaseScratchGPUBuffer(copy_buffer, copy_buffer_state); return false; } @@ -2602,7 +2607,8 @@ bool TextureCache::LoadTextureData(Texture* texture) { load_constants.guest_mip_offset[2]); } D3D12_GPU_VIRTUAL_ADDRESS cbuffer_gpu_address; - uint8_t* cbuffer_mapping = cbuffer_pool->RequestFull( + uint8_t* cbuffer_mapping = cbuffer_pool->Request( + context->GetCurrentFrame(), xe::align(uint32_t(sizeof(load_constants)), 256u), nullptr, nullptr, &cbuffer_gpu_address); if (cbuffer_mapping == nullptr) { diff --git a/src/xenia/ui/d3d12/d3d12_immediate_drawer.cc b/src/xenia/ui/d3d12/d3d12_immediate_drawer.cc index 6d6823796..e89017157 100644 --- a/src/xenia/ui/d3d12/d3d12_immediate_drawer.cc +++ b/src/xenia/ui/d3d12/d3d12_immediate_drawer.cc @@ -287,9 +287,10 @@ bool D3D12ImmediateDrawer::Initialize() { // Create pools for draws. vertex_buffer_pool_ = - std::make_unique(context_, 2 * 1024 * 1024); + std::make_unique(device, 2 * 1024 * 1024); texture_descriptor_pool_ = std::make_unique( - context_, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2048); + device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2048); + texture_descriptor_pool_heap_index_ = DescriptorHeapPool::kHeapIndexInvalid; // Reset the current state. current_command_list_ = nullptr; @@ -460,9 +461,9 @@ void D3D12ImmediateDrawer::Begin(int render_target_width, texture_uploads_pending_.pop_back(); } - vertex_buffer_pool_->BeginFrame(); - texture_descriptor_pool_->BeginFrame(); - texture_descriptor_pool_full_update_ = 0; + vertex_buffer_pool_->Reclaim(last_completed_frame); + texture_descriptor_pool_->Reclaim(last_completed_frame); + texture_descriptor_pool_heap_index_ = DescriptorHeapPool::kHeapIndexInvalid; current_render_target_width_ = render_target_width; current_render_target_height_ = render_target_height; @@ -500,9 +501,9 @@ void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { vertex_buffer_view.StrideInBytes = UINT(sizeof(ImmediateVertex)); vertex_buffer_view.SizeInBytes = batch.vertex_count * uint32_t(sizeof(ImmediateVertex)); - void* vertex_buffer_mapping = vertex_buffer_pool_->RequestFull( - vertex_buffer_view.SizeInBytes, nullptr, nullptr, - &vertex_buffer_view.BufferLocation); + void* vertex_buffer_mapping = vertex_buffer_pool_->Request( + context_->GetCurrentFrame(), vertex_buffer_view.SizeInBytes, nullptr, + nullptr, &vertex_buffer_view.BufferLocation); if (vertex_buffer_mapping == nullptr) { XELOGE("Failed to get a buffer for %u vertices in the immediate drawer", batch.vertex_count); @@ -518,7 +519,8 @@ void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { D3D12_INDEX_BUFFER_VIEW index_buffer_view; index_buffer_view.SizeInBytes = batch.index_count * sizeof(uint16_t); index_buffer_view.Format = DXGI_FORMAT_R16_UINT; - void* index_buffer_mapping = vertex_buffer_pool_->RequestFull( + void* index_buffer_mapping = vertex_buffer_pool_->Request( + context_->GetCurrentFrame(), xe::align(index_buffer_view.SizeInBytes, UINT(sizeof(uint32_t))), nullptr, nullptr, &index_buffer_view.BufferLocation); if (index_buffer_mapping == nullptr) { @@ -560,15 +562,15 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) { } bool bind_texture = current_texture_ != texture; uint32_t texture_descriptor_index; - uint64_t texture_full_update = texture_descriptor_pool_->Request( - texture_descriptor_pool_full_update_, bind_texture ? 1 : 0, 1, - texture_descriptor_index); - if (texture_full_update == 0) { + uint64_t texture_heap_index = texture_descriptor_pool_->Request( + context_->GetCurrentFrame(), texture_descriptor_pool_heap_index_, + bind_texture ? 1 : 0, 1, texture_descriptor_index); + if (texture_heap_index == DescriptorHeapPool::kHeapIndexInvalid) { return; } - if (texture_descriptor_pool_full_update_ != texture_full_update) { + if (texture_descriptor_pool_heap_index_ != texture_heap_index) { bind_texture = true; - texture_descriptor_pool_full_update_ = texture_full_update; + texture_descriptor_pool_heap_index_ = texture_heap_index; ID3D12DescriptorHeap* descriptor_heaps[] = { texture_descriptor_pool_->GetLastRequestHeap(), sampler_heap_}; current_command_list_->SetDescriptorHeaps(2, descriptor_heaps); @@ -673,9 +675,6 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) { void D3D12ImmediateDrawer::EndDrawBatch() { batch_open_ = false; } void D3D12ImmediateDrawer::End() { - texture_descriptor_pool_->EndFrame(); - vertex_buffer_pool_->EndFrame(); - current_command_list_ = nullptr; } diff --git a/src/xenia/ui/d3d12/d3d12_immediate_drawer.h b/src/xenia/ui/d3d12/d3d12_immediate_drawer.h index 67bcc4fec..6003f611e 100644 --- a/src/xenia/ui/d3d12/d3d12_immediate_drawer.h +++ b/src/xenia/ui/d3d12/d3d12_immediate_drawer.h @@ -77,6 +77,7 @@ class D3D12ImmediateDrawer : public ImmediateDrawer { std::unique_ptr vertex_buffer_pool_ = nullptr; std::unique_ptr texture_descriptor_pool_ = nullptr; + uint64_t texture_descriptor_pool_heap_index_; struct PendingTextureUpload { ImmediateTexture* texture; @@ -94,7 +95,6 @@ class D3D12ImmediateDrawer : public ImmediateDrawer { int current_render_target_width_, current_render_target_height_; bool batch_open_ = false; bool batch_has_index_buffer_; - uint64_t texture_descriptor_pool_full_update_; D3D_PRIMITIVE_TOPOLOGY current_primitive_topology_; ImmediateTexture* current_texture_; SamplerIndex current_sampler_index_; diff --git a/src/xenia/ui/d3d12/pools.cc b/src/xenia/ui/d3d12/pools.cc index 436d2ed68..2b2a608dd 100644 --- a/src/xenia/ui/d3d12/pools.cc +++ b/src/xenia/ui/d3d12/pools.cc @@ -13,251 +13,212 @@ #include "xenia/base/assert.h" #include "xenia/base/logging.h" -#include "xenia/ui/d3d12/d3d12_context.h" #include "xenia/ui/d3d12/d3d12_util.h" namespace xe { namespace ui { namespace d3d12 { -UploadBufferPool::UploadBufferPool(D3D12Context* context, uint32_t page_size) - : context_(context), page_size_(page_size) {} +UploadBufferPool::UploadBufferPool(ID3D12Device* device, uint32_t page_size) + : device_(device), page_size_(page_size) {} UploadBufferPool::~UploadBufferPool() { - // Allow mid-frame destruction in cases like device loss. - if (current_mapping_ != nullptr) { - // Don't care about the written range - destroying anyway. - D3D12_RANGE written_range; - written_range.Begin = 0; - written_range.End = 0; - unsent_->buffer->Unmap(0, &written_range); - current_mapping_ = nullptr; - } - current_size_ = 0; ClearCache(); } -void UploadBufferPool::BeginFrame() { - // Recycle submitted pages not used by the GPU anymore. - uint64_t last_completed_frame = context_->GetLastCompletedFrame(); - while (sent_first_ != nullptr) { - auto page = sent_first_; - if (page->frame_sent > last_completed_frame) { +void UploadBufferPool::Reclaim(uint64_t completed_fence_value) { + while (submitted_first_) { + if (submitted_first_->last_usage_fence_value > completed_fence_value) { break; } - sent_first_ = page->next; - page->next = unsent_; - unsent_ = page; + if (writable_last_) { + writable_last_->next = submitted_first_; + } else { + writable_first_ = submitted_first_; + } + writable_last_ = submitted_first_; + submitted_first_ = submitted_first_->next; + writable_last_->next = nullptr; } - if (sent_first_ == nullptr) { - sent_last_ = nullptr; + if (!submitted_first_) { + submitted_last_ = nullptr; } - - // Try to create new pages again in this frame if failed in the previous. - page_creation_failed_ = false; -} - -void UploadBufferPool::EndFrame() { - // If something is written to the current page, mark it as submitted. - EndPage(); } void UploadBufferPool::ClearCache() { - assert(current_size_ == 0); - while (unsent_ != nullptr) { - auto next = unsent_->next; - unsent_->buffer->Release(); - delete unsent_; - unsent_ = next; + current_page_used_ = 0; + // Deleting anyway, so assuming data not needed anymore. + D3D12_RANGE written_range; + written_range.Begin = 0; + written_range.End = 0; + while (submitted_first_) { + auto next = submitted_first_->next; + submitted_first_->buffer->Unmap(0, &written_range); + submitted_first_->buffer->Release(); + delete submitted_first_; + submitted_first_ = next; } - while (sent_first_ != nullptr) { - auto next = sent_first_->next; - sent_first_->buffer->Release(); - delete sent_first_; - sent_first_ = next; + submitted_last_ = nullptr; + while (writable_first_) { + auto next = writable_first_->next; + writable_first_->buffer->Unmap(0, &written_range); + writable_first_->buffer->Release(); + delete writable_first_; + writable_first_ = next; } - sent_last_ = nullptr; + writable_last_ = nullptr; } -uint8_t* UploadBufferPool::RequestFull( - uint32_t size, ID3D12Resource** buffer_out, uint32_t* offset_out, - D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out) { +uint8_t* UploadBufferPool::Request(uint64_t usage_fence_value, uint32_t size, + ID3D12Resource** buffer_out, + uint32_t* offset_out, + D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out) { assert_true(size <= page_size_); if (size > page_size_) { return nullptr; } - if (page_size_ - current_size_ < size || current_mapping_ == nullptr) { + assert_true(!current_page_used_ || + usage_fence_value >= writable_first_->last_usage_fence_value); + assert_true(!submitted_last_ || + usage_fence_value >= submitted_last_->last_usage_fence_value); + if (page_size_ - current_page_used_ < size || !writable_first_) { // Start a new page if can't fit all the bytes or don't have an open page. - if (!BeginNextPage()) { - return nullptr; + if (writable_first_) { + // Close the page that was current. + if (submitted_last_) { + submitted_last_->next = writable_first_; + } else { + submitted_first_ = writable_first_; + } + submitted_last_ = writable_first_; + writable_first_ = writable_first_->next; + submitted_last_->next = nullptr; + if (!writable_first_) { + writable_last_ = nullptr; + } } - } - if (buffer_out != nullptr) { - *buffer_out = unsent_->buffer; - } - if (offset_out != nullptr) { - *offset_out = current_size_; - } - if (gpu_address_out != nullptr) { - if (current_gpu_address_ == 0) { - current_gpu_address_ = unsent_->buffer->GetGPUVirtualAddress(); + if (!writable_first_) { + // Create a new page if none available. + D3D12_RESOURCE_DESC new_buffer_desc; + util::FillBufferResourceDesc(new_buffer_desc, page_size_, + D3D12_RESOURCE_FLAG_NONE); + ID3D12Resource* new_buffer; + if (FAILED(device_->CreateCommittedResource( + &util::kHeapPropertiesUpload, D3D12_HEAP_FLAG_NONE, + &new_buffer_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, + IID_PPV_ARGS(&new_buffer)))) { + XELOGE("Failed to create a D3D upload buffer with %u bytes", + page_size_); + return nullptr; + } + D3D12_RANGE read_range; + read_range.Begin = 0; + read_range.End = 0; + void* new_buffer_mapping; + if (FAILED(new_buffer->Map(0, &read_range, &new_buffer_mapping))) { + XELOGE("Failed to map a D3D upload buffer with %u bytes", page_size_); + new_buffer->Release(); + return nullptr; + } + writable_first_ = new Page; + writable_first_->buffer = new_buffer; + writable_first_->gpu_address = new_buffer->GetGPUVirtualAddress(); + writable_first_->mapping = new_buffer_mapping; + writable_first_->last_usage_fence_value = usage_fence_value; + writable_first_->next = nullptr; + writable_last_ = writable_first_; } - *gpu_address_out = current_gpu_address_ + current_size_; + current_page_used_ = 0; } - uint8_t* mapping = current_mapping_ + current_size_; - current_size_ += size; + writable_first_->last_usage_fence_value = usage_fence_value; + if (buffer_out) { + *buffer_out = writable_first_->buffer; + } + if (offset_out) { + *offset_out = current_page_used_; + } + if (gpu_address_out) { + *gpu_address_out = writable_first_->gpu_address + current_page_used_; + } + uint8_t* mapping = + reinterpret_cast(writable_first_->mapping) + current_page_used_; + current_page_used_ += size; return mapping; } uint8_t* UploadBufferPool::RequestPartial( - uint32_t size, ID3D12Resource** buffer_out, uint32_t* offset_out, - uint32_t* size_out, D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out) { - if (current_size_ == page_size_ || current_mapping_ == nullptr) { - // Start a new page if can't fit any bytes or don't have an open page. - if (!BeginNextPage()) { - return nullptr; - } + uint64_t usage_fence_value, uint32_t size, ID3D12Resource** buffer_out, + uint32_t* offset_out, uint32_t* size_out, + D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out) { + size = std::min(size, page_size_); + if (current_page_used_ < page_size_) { + size = std::min(size, page_size_ - current_page_used_); } - size = std::min(size, page_size_ - current_size_); - if (buffer_out != nullptr) { - *buffer_out = unsent_->buffer; + uint8_t* mapping = + Request(usage_fence_value, size, buffer_out, offset_out, gpu_address_out); + if (!mapping) { + return nullptr; } - if (offset_out != nullptr) { - *offset_out = current_size_; - } - if (size_out != nullptr) { + if (size_out) { *size_out = size; } - if (gpu_address_out != nullptr) { - if (current_gpu_address_ == 0) { - current_gpu_address_ = unsent_->buffer->GetGPUVirtualAddress(); - } - *gpu_address_out = current_gpu_address_ + current_size_; - } - uint8_t* mapping = current_mapping_ + current_size_; - current_size_ += size; return mapping; } -void UploadBufferPool::EndPage() { - if (current_mapping_ != nullptr) { - D3D12_RANGE written_range; - written_range.Begin = 0; - written_range.End = current_size_; - unsent_->buffer->Unmap(0, &written_range); - current_mapping_ = nullptr; - } - if (current_size_ != 0) { - auto page = unsent_; - page->frame_sent = context_->GetCurrentFrame(); - unsent_ = page->next; - page->next = nullptr; - if (sent_last_ != nullptr) { - sent_last_->next = page; - } else { - sent_first_ = page; - } - sent_last_ = page; - current_size_ = 0; - } -} +constexpr uint64_t DescriptorHeapPool::kHeapIndexInvalid; -bool UploadBufferPool::BeginNextPage() { - EndPage(); - - if (page_creation_failed_) { - return false; - } - - if (unsent_ == nullptr) { - auto device = context_->GetD3D12Provider()->GetDevice(); - D3D12_RESOURCE_DESC buffer_desc; - util::FillBufferResourceDesc(buffer_desc, page_size_, - D3D12_RESOURCE_FLAG_NONE); - ID3D12Resource* buffer_resource; - if (FAILED(device->CreateCommittedResource( - &util::kHeapPropertiesUpload, D3D12_HEAP_FLAG_NONE, &buffer_desc, - D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, - IID_PPV_ARGS(&buffer_resource)))) { - XELOGE("Failed to create a D3D upload buffer with %u bytes", page_size_); - page_creation_failed_ = true; - return false; - } - unsent_ = new UploadBuffer; - unsent_->buffer = buffer_resource; - unsent_->next = nullptr; - } - - D3D12_RANGE read_range; - read_range.Begin = 0; - read_range.End = 0; - void* mapping; - if (FAILED(unsent_->buffer->Map(0, &read_range, &mapping))) { - XELOGE("Failed to map a D3D upload buffer with %u bytes", page_size_); - page_creation_failed_ = true; - return false; - } - current_mapping_ = reinterpret_cast(mapping); - current_gpu_address_ = 0; - - return true; -} - -DescriptorHeapPool::DescriptorHeapPool(D3D12Context* context, +DescriptorHeapPool::DescriptorHeapPool(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32_t page_size) - : context_(context), type_(type), page_size_(page_size) {} + : device_(device), type_(type), page_size_(page_size) {} DescriptorHeapPool::~DescriptorHeapPool() { - // Allow mid-frame destruction in cases like device loss. - current_size_ = 0; ClearCache(); } -void DescriptorHeapPool::BeginFrame() { - // Don't hold old pages if few descriptors are written, also make 0 usable as - // an invalid page index. - ++current_page_; - - // Recycle submitted pages not used by the GPU anymore. - uint64_t last_completed_frame = context_->GetLastCompletedFrame(); - while (sent_first_ != nullptr) { - auto page = sent_first_; - if (page->frame_sent > last_completed_frame) { +void DescriptorHeapPool::Reclaim(uint64_t completed_fence_value) { + while (submitted_first_) { + if (submitted_first_->last_usage_fence_value > completed_fence_value) { break; } - sent_first_ = page->next; - page->next = unsent_; - unsent_ = page; + if (writable_last_) { + writable_last_->next = submitted_first_; + } else { + writable_first_ = submitted_first_; + } + writable_last_ = submitted_first_; + submitted_first_ = submitted_first_->next; + writable_last_->next = nullptr; } - if (sent_first_ == nullptr) { - sent_last_ = nullptr; + if (!submitted_first_) { + submitted_last_ = nullptr; } - - // Try to create new pages again in this frame if failed in the previous. - page_creation_failed_ = false; } -void DescriptorHeapPool::EndFrame() { EndPage(); } - void DescriptorHeapPool::ClearCache() { - assert_true(current_size_ == 0); - while (unsent_ != nullptr) { - auto next = unsent_->next; - unsent_->heap->Release(); - delete unsent_; - unsent_ = next; + // Not checking current_page_used_ != 0 because asking for 0 descriptors + // returns a valid heap also - but actually the new heap will be different now + // and the old one must be unbound since it doesn't exist anymore. + ++current_heap_index_; + current_page_used_ = 0; + while (submitted_first_) { + auto next = submitted_first_->next; + submitted_first_->heap->Release(); + delete submitted_first_; + submitted_first_ = next; } - while (sent_first_ != nullptr) { - auto next = sent_first_->next; - sent_first_->heap->Release(); - delete sent_first_; - sent_first_ = next; + submitted_last_ = nullptr; + while (writable_first_) { + auto next = writable_first_->next; + writable_first_->heap->Release(); + delete writable_first_; + writable_first_ = next; } - sent_last_ = nullptr; + writable_last_ = nullptr; } -uint64_t DescriptorHeapPool::Request(uint64_t previous_full_update, +uint64_t DescriptorHeapPool::Request(uint64_t usage_fence_value, + uint64_t previous_heap_index, uint32_t count_for_partial_update, uint32_t count_for_full_update, uint32_t& index_out) { @@ -265,75 +226,63 @@ uint64_t DescriptorHeapPool::Request(uint64_t previous_full_update, assert_true(count_for_full_update <= page_size_); if (count_for_partial_update > count_for_full_update || count_for_full_update > page_size_) { - return 0; + return kHeapIndexInvalid; } - - if (page_creation_failed_) { - // Don't touch the page index every call if there was a failure as well. - return 0; - } - + assert_true(!current_page_used_ || + usage_fence_value >= writable_first_->last_usage_fence_value); + assert_true(!submitted_last_ || + usage_fence_value >= submitted_last_->last_usage_fence_value); // If the last full update happened on the current page, a partial update is // possible. - uint32_t count = previous_full_update == current_page_ + uint32_t count = previous_heap_index == current_heap_index_ ? count_for_partial_update : count_for_full_update; - // Go to the next page if there's not enough free space on the current one, // or because the previous page may be outdated. In this case, a full update // is necessary. - if (page_size_ - current_size_ < count) { - EndPage(); - ++current_page_; + if (page_size_ - current_page_used_ < count) { + // Close the page that was current. + if (submitted_last_) { + submitted_last_->next = writable_first_; + } else { + submitted_first_ = writable_first_; + } + submitted_last_ = writable_first_; + writable_first_ = writable_first_->next; + submitted_last_->next = nullptr; + if (!writable_first_) { + writable_last_ = nullptr; + } + ++current_heap_index_; + current_page_used_ = 0; count = count_for_full_update; } - // Create the page if needed (may be the first call for the page). - if (unsent_ == nullptr) { - auto device = context_->GetD3D12Provider()->GetDevice(); - D3D12_DESCRIPTOR_HEAP_DESC heap_desc; - heap_desc.Type = type_; - heap_desc.NumDescriptors = page_size_; - heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - heap_desc.NodeMask = 0; - ID3D12DescriptorHeap* heap; - if (FAILED(device->CreateDescriptorHeap(&heap_desc, IID_PPV_ARGS(&heap)))) { + if (!writable_first_) { + D3D12_DESCRIPTOR_HEAP_DESC new_heap_desc; + new_heap_desc.Type = type_; + new_heap_desc.NumDescriptors = page_size_; + new_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + new_heap_desc.NodeMask = 0; + ID3D12DescriptorHeap* new_heap; + if (FAILED(device_->CreateDescriptorHeap(&new_heap_desc, + IID_PPV_ARGS(&new_heap)))) { XELOGE("Failed to create a heap for %u shader-visible descriptors", page_size_); - page_creation_failed_ = true; - return 0; + return kHeapIndexInvalid; } - unsent_ = new DescriptorHeap; - unsent_->heap = heap; - unsent_->next = nullptr; - } - - // If starting a new page, get the handles to the beginning of it. - if (current_size_ == 0) { - current_heap_cpu_start_ = - unsent_->heap->GetCPUDescriptorHandleForHeapStart(); - current_heap_gpu_start_ = - unsent_->heap->GetGPUDescriptorHandleForHeapStart(); - } - index_out = current_size_; - current_size_ += count; - return current_page_; -} - -void DescriptorHeapPool::EndPage() { - if (current_size_ != 0) { - auto page = unsent_; - page->frame_sent = context_->GetCurrentFrame(); - unsent_ = page->next; - page->next = nullptr; - if (sent_last_ != nullptr) { - sent_last_->next = page; - } else { - sent_first_ = page; - } - sent_last_ = page; - current_size_ = 0; + writable_first_ = new Page; + writable_first_->heap = new_heap; + writable_first_->cpu_start = new_heap->GetCPUDescriptorHandleForHeapStart(); + writable_first_->gpu_start = new_heap->GetGPUDescriptorHandleForHeapStart(); + writable_first_->last_usage_fence_value = usage_fence_value; + writable_first_->next = nullptr; + writable_last_ = writable_first_; } + writable_first_->last_usage_fence_value = usage_fence_value; + index_out = current_page_used_; + current_page_used_ += count; + return current_heap_index_; } } // namespace d3d12 diff --git a/src/xenia/ui/d3d12/pools.h b/src/xenia/ui/d3d12/pools.h index 5b1a00c3d..6e6f65512 100644 --- a/src/xenia/ui/d3d12/pools.h +++ b/src/xenia/ui/d3d12/pools.h @@ -18,64 +18,57 @@ namespace xe { namespace ui { namespace d3d12 { -class D3D12Context; - class UploadBufferPool { public: - UploadBufferPool(D3D12Context* context, uint32_t page_size); + UploadBufferPool(ID3D12Device* device, uint32_t page_size); ~UploadBufferPool(); - void BeginFrame(); - void EndFrame(); + void Reclaim(uint64_t completed_fence_value); void ClearCache(); // Request to write data in a single piece, creating a new page if the current // one doesn't have enough free space. - uint8_t* RequestFull(uint32_t size, ID3D12Resource** buffer_out, - uint32_t* offset_out, - D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out); + uint8_t* Request(uint64_t usage_fence_value, uint32_t size, + ID3D12Resource** buffer_out, uint32_t* offset_out, + D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out); // Request to write data in multiple parts, filling the buffer entirely. - uint8_t* RequestPartial(uint32_t size, ID3D12Resource** buffer_out, - uint32_t* offset_out, uint32_t* size_out, + uint8_t* RequestPartial(uint64_t usage_fence_value, uint32_t size, + ID3D12Resource** buffer_out, uint32_t* offset_out, + uint32_t* size_out, D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out); private: - D3D12Context* context_; + ID3D12Device* device_; uint32_t page_size_; - void EndPage(); - bool BeginNextPage(); - - struct UploadBuffer { + struct Page { ID3D12Resource* buffer; - UploadBuffer* next; - uint64_t frame_sent; + D3D12_GPU_VIRTUAL_ADDRESS gpu_address; + void* mapping; + uint64_t last_usage_fence_value; + Page* next; }; - // A list of unsent buffers, with the first one being the current. - UploadBuffer* unsent_ = nullptr; - // A list of sent buffers, moved to unsent in the beginning of a frame. - UploadBuffer* sent_first_ = nullptr; - UploadBuffer* sent_last_ = nullptr; - - uint32_t current_size_ = 0; - uint8_t* current_mapping_ = nullptr; - // Not updated until actually requested. - D3D12_GPU_VIRTUAL_ADDRESS current_gpu_address_ = 0; - - // Reset in the beginning of a frame - don't try and fail to create a new page - // if failed to create one in the current frame. - bool page_creation_failed_ = false; + // A list of buffers with free space, with the first buffer being the one + // currently being filled. + Page* writable_first_ = nullptr; + Page* writable_last_ = nullptr; + // A list of full buffers that can be reclaimed when the GPU doesn't use them + // anymore. + Page* submitted_first_ = nullptr; + Page* submitted_last_ = nullptr; + uint32_t current_page_used_ = 0; }; class DescriptorHeapPool { public: - DescriptorHeapPool(D3D12Context* context, D3D12_DESCRIPTOR_HEAP_TYPE type, + static constexpr uint64_t kHeapIndexInvalid = UINT64_MAX; + + DescriptorHeapPool(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32_t page_size); ~DescriptorHeapPool(); - void BeginFrame(); - void EndFrame(); + void Reclaim(uint64_t completed_fence_value); void ClearCache(); // Because all descriptors for a single draw call must be in the same heap, @@ -88,64 +81,64 @@ class DescriptorHeapPool { // // If something uses this pool to do partial updates, it must let this // function determine whether a partial update is possible. For this purpose, - // this function returns a full update number - and it must be called with its + // this function returns the heap reset index - and it must be called with its // previous return value for the set of descriptors it's updating. // - // If this function returns a value that is the same as previous_full_update, - // a partial update needs to be done - and space for count_for_partial_update - // is allocated. + // If this function returns a value that is the same as previous_heap_index, a + // partial update needs to be done - and space for count_for_partial_update is + // allocated. // // If it's different, all descriptors must be written again - and space for // count_for_full_update is allocated. // - // If 0 is returned, there was an error. + // If kHeapIndexInvalid is returned, there was an error. // // This MUST be called even if there's nothing to write in a partial update // (with count_for_partial_update being 0), because a full update may still be // required. - uint64_t Request(uint64_t previous_full_update, + uint64_t Request(uint64_t usage_fence_value, uint64_t previous_heap_index, uint32_t count_for_partial_update, uint32_t count_for_full_update, uint32_t& index_out); // The current heap, for binding and actually writing - may be called only // after a successful request because before a request, the heap may not exist // yet. - ID3D12DescriptorHeap* GetLastRequestHeap() const { return unsent_->heap; } + ID3D12DescriptorHeap* GetLastRequestHeap() const { + return writable_first_->heap; + } D3D12_CPU_DESCRIPTOR_HANDLE GetLastRequestHeapCPUStart() const { - return current_heap_cpu_start_; + return writable_first_->cpu_start; } D3D12_GPU_DESCRIPTOR_HANDLE GetLastRequestHeapGPUStart() const { - return current_heap_gpu_start_; + return writable_first_->gpu_start; } private: - D3D12Context* context_; + ID3D12Device* device_; D3D12_DESCRIPTOR_HEAP_TYPE type_; uint32_t page_size_; - void EndPage(); - bool BeginNextPage(); - - struct DescriptorHeap { + struct Page { ID3D12DescriptorHeap* heap; - DescriptorHeap* next; - uint64_t frame_sent; + D3D12_CPU_DESCRIPTOR_HANDLE cpu_start; + D3D12_GPU_DESCRIPTOR_HANDLE gpu_start; + uint64_t last_usage_fence_value; + Page* next; }; - // A list of unsent heaps, with the first one being the current. - DescriptorHeap* unsent_ = nullptr; - // A list of sent heaps, moved to unsent in the beginning of a frame. - DescriptorHeap* sent_first_ = nullptr; - DescriptorHeap* sent_last_ = nullptr; - - uint64_t current_page_ = 0; - D3D12_CPU_DESCRIPTOR_HANDLE current_heap_cpu_start_ = {}; - D3D12_GPU_DESCRIPTOR_HANDLE current_heap_gpu_start_ = {}; - uint32_t current_size_ = 0; - - // Reset in the beginning of a frame - don't try and fail to create a new page - // if failed to create one in the current frame. - bool page_creation_failed_ = false; + // A list of heap with free space, with the first buffer being the one + // currently being filled. + Page* writable_first_ = nullptr; + Page* writable_last_ = nullptr; + // A list of full heaps that can be reclaimed when the GPU doesn't use them + // anymore. + Page* submitted_first_ = nullptr; + Page* submitted_last_ = nullptr; + // Monotonically increased when a new request is going to a different + // ID3D12DescriptorHeap than the one that may be bound currently. See Request + // for more information. + uint64_t current_heap_index_ = 0; + uint32_t current_page_used_ = 0; }; } // namespace d3d12