From b7a5c24bb1bc48afa2c5741758b6cbec144757a7 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Sun, 17 May 2020 00:26:04 +0300 Subject: [PATCH] [D3D12] d3d12_break_on_error + fix PerformSwap descriptor heap wrap --- .../gpu/d3d12/d3d12_command_processor.cc | 28 +++++++---- src/xenia/gpu/d3d12/render_target_cache.h | 5 +- src/xenia/gpu/d3d12/texture_cache.cc | 28 +++++------ src/xenia/gpu/d3d12/texture_cache.h | 9 ++-- src/xenia/ui/d3d12/d3d12_api.h | 2 + src/xenia/ui/d3d12/d3d12_context.cc | 4 +- src/xenia/ui/d3d12/d3d12_provider.cc | 46 +++++++++++++++++++ 7 files changed, 88 insertions(+), 34 deletions(-) diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index ce1d48316..ddfe29585 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -1153,16 +1153,23 @@ void D3D12CommandProcessor::PerformSwap(uint32_t frontbuffer_ptr, dirty_gamma_ramp_pwl_ = false; } - D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start; - D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start; - 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)) { - render_target_cache_->FlushAndUnbindRenderTargets(); + D3D12_SHADER_RESOURCE_VIEW_DESC swap_texture_srv_desc; + TextureFormat frontbuffer_format; + ID3D12Resource* swap_texture_resource = texture_cache_->RequestSwapTexture( + swap_texture_srv_desc, frontbuffer_format); + if (swap_texture_resource) { + render_target_cache_->FlushAndUnbindRenderTargets(); + D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start; + D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start; + if (RequestViewDescriptors(ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, + 2, 2, descriptor_cpu_start, + descriptor_gpu_start) != + ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) { + // Must not call anything that can change the descriptor heap from now on! + + // Create the swap texture descriptor. + device->CreateShaderResourceView( + swap_texture_resource, &swap_texture_srv_desc, descriptor_cpu_start); // Create the gamma ramp texture descriptor. // This is according to D3D::InitializePresentationParameters from a game @@ -1453,6 +1460,7 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type, if (!UpdateBindings(vertex_shader, pixel_shader, root_signature)) { return false; } + // Must not call anything that can change the descriptor heap from now on! // Ensure vertex and index buffers are resident and draw. // TODO(Triang3l): Cache residency for ranges in a way similar to how texture diff --git a/src/xenia/gpu/d3d12/render_target_cache.h b/src/xenia/gpu/d3d12/render_target_cache.h index 360977f7f..888938eb7 100644 --- a/src/xenia/gpu/d3d12/render_target_cache.h +++ b/src/xenia/gpu/d3d12/render_target_cache.h @@ -261,7 +261,8 @@ class RenderTargetCache { void CompletedSubmissionUpdated(); void BeginSubmission(); void EndFrame(); - // Called in the beginning of a draw call - may bind pipelines. + // Called in the beginning of a draw call - may bind pipelines and change the + // view descriptor heap. bool UpdateRenderTargets(const D3D12Shader* pixel_shader); // Returns the host-to-guest mappings and host formats of currently bound // render targets for pipeline creation and remapping in shaders. They are @@ -281,7 +282,7 @@ class RenderTargetCache { void ForceApplyOnNextUpdate() { apply_to_command_list_ = true; } // Flushes the render targets to EDRAM and unbinds them, for instance, when // the command processor takes over framebuffer bindings to draw something - // special. + // special. May change the CBV/SRV/UAV descriptor heap. void FlushAndUnbindRenderTargets(); void WriteEDRAMUint32UAVDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE handle); diff --git a/src/xenia/gpu/d3d12/texture_cache.cc b/src/xenia/gpu/d3d12/texture_cache.cc index 7740f9ec1..daae4239b 100644 --- a/src/xenia/gpu/d3d12/texture_cache.cc +++ b/src/xenia/gpu/d3d12/texture_cache.cc @@ -2011,8 +2011,8 @@ void TextureCache::CreateScaledResolveBufferRawUAV( first_unscaled_4kb_page << 14); } -bool TextureCache::RequestSwapTexture(D3D12_CPU_DESCRIPTOR_HANDLE handle, - TextureFormat& format_out) { +ID3D12Resource* TextureCache::RequestSwapTexture( + D3D12_SHADER_RESOURCE_VIEW_DESC& srv_desc_out, TextureFormat& format_out) { auto& regs = *register_file_; const auto& fetch = regs.Get( XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0); @@ -2020,11 +2020,11 @@ bool TextureCache::RequestSwapTexture(D3D12_CPU_DESCRIPTOR_HANDLE handle, uint32_t swizzle; BindingInfoFromFetchConstant(fetch, key, &swizzle, nullptr, nullptr); if (key.base_page == 0 || key.dimension != Dimension::k2D) { - return false; + return nullptr; } Texture* texture = FindOrCreateTexture(key); if (texture == nullptr || !LoadTextureData(texture)) { - return false; + return nullptr; } MarkTextureUsed(texture); // The swap texture is likely to be used only for the presentation pixel @@ -2034,21 +2034,17 @@ bool TextureCache::RequestSwapTexture(D3D12_CPU_DESCRIPTOR_HANDLE handle, texture->resource, texture->state, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); texture->state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; - D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc; - srv_desc.Format = GetDXGIUnormFormat(key); - srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; - srv_desc.Shader4ComponentMapping = + srv_desc_out.Format = GetDXGIUnormFormat(key); + srv_desc_out.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srv_desc_out.Shader4ComponentMapping = swizzle | D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES; - srv_desc.Texture2D.MostDetailedMip = 0; - srv_desc.Texture2D.MipLevels = 1; - srv_desc.Texture2D.PlaneSlice = 0; - srv_desc.Texture2D.ResourceMinLODClamp = 0.0f; - auto device = - command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice(); - device->CreateShaderResourceView(texture->resource, &srv_desc, handle); + srv_desc_out.Texture2D.MostDetailedMip = 0; + srv_desc_out.Texture2D.MipLevels = 1; + srv_desc_out.Texture2D.PlaneSlice = 0; + srv_desc_out.Texture2D.ResourceMinLODClamp = 0.0f; format_out = key.format; - return true; + return texture->resource; } bool TextureCache::IsDecompressionNeeded(TextureFormat format, uint32_t width, diff --git a/src/xenia/gpu/d3d12/texture_cache.h b/src/xenia/gpu/d3d12/texture_cache.h index dbeb0cc2d..4aced6424 100644 --- a/src/xenia/gpu/d3d12/texture_cache.h +++ b/src/xenia/gpu/d3d12/texture_cache.h @@ -159,9 +159,12 @@ class TextureCache { uint32_t first_unscaled_4kb_page, uint32_t unscaled_4kb_page_count); - // Returns a descriptor of the front buffer in PIXEL_SHADER_RESOURCE state. - bool RequestSwapTexture(D3D12_CPU_DESCRIPTOR_HANDLE handle, - TextureFormat& format_out); + // Returns the ID3D12Resource of the front buffer texture (in + // PIXEL_SHADER_RESOURCE state), or nullptr in case of failure, and writes the + // description of its SRV. May call LoadTextureData, so the same restrictions + // (such as about descriptor heap change possibility) apply. + ID3D12Resource* RequestSwapTexture( + D3D12_SHADER_RESOURCE_VIEW_DESC& srv_desc_out, TextureFormat& format_out); private: enum class LoadMode { diff --git a/src/xenia/ui/d3d12/d3d12_api.h b/src/xenia/ui/d3d12/d3d12_api.h index 45eb02e07..3d6b693eb 100644 --- a/src/xenia/ui/d3d12/d3d12_api.h +++ b/src/xenia/ui/d3d12/d3d12_api.h @@ -15,8 +15,10 @@ #include #include +#include #include #include +#include #define XELOGD3D XELOGI diff --git a/src/xenia/ui/d3d12/d3d12_context.cc b/src/xenia/ui/d3d12/d3d12_context.cc index 261c82628..029d3c7bf 100644 --- a/src/xenia/ui/d3d12/d3d12_context.cc +++ b/src/xenia/ui/d3d12/d3d12_context.cc @@ -342,9 +342,7 @@ void D3D12Context::EndSwap() { direct_queue->ExecuteCommandLists(1, execute_command_lists); // Present and check if the context was lost. - HRESULT result = swap_chain_->Present(0, 0); - if (result == DXGI_ERROR_DEVICE_RESET || - result == DXGI_ERROR_DEVICE_REMOVED) { + if (FAILED(swap_chain_->Present(0, 0))) { context_lost_ = true; return; } diff --git a/src/xenia/ui/d3d12/d3d12_provider.cc b/src/xenia/ui/d3d12/d3d12_provider.cc index fd53d6ce9..14e690ba5 100644 --- a/src/xenia/ui/d3d12/d3d12_provider.cc +++ b/src/xenia/ui/d3d12/d3d12_provider.cc @@ -14,10 +14,13 @@ #include "xenia/base/cvar.h" #include "xenia/base/logging.h" +#include "xenia/base/math.h" #include "xenia/ui/d3d12/d3d12_context.h" DEFINE_bool(d3d12_debug, false, "Enable Direct3D 12 and DXGI debug layer.", "D3D12"); +DEFINE_bool(d3d12_break_on_error, false, + "Break on Direct3D 12 validation errors.", "D3D12"); DEFINE_int32(d3d12_adapter, -1, "Index of the DXGI adapter to use. " "-1 for any physical adapter, -2 for WARP software rendering.", @@ -139,6 +142,19 @@ bool D3D12Provider::Initialize() { return false; } + // Configure the DXGI debug info queue. + if (cvars::d3d12_break_on_error) { + IDXGIInfoQueue* dxgi_info_queue; + if (SUCCEEDED(pfn_dxgi_get_debug_interface1_( + 0, IID_PPV_ARGS(&dxgi_info_queue)))) { + dxgi_info_queue->SetBreakOnSeverity( + DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE); + dxgi_info_queue->SetBreakOnSeverity( + DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE); + dxgi_info_queue->Release(); + } + } + // Enable the debug layer. bool debug = cvars::d3d12_debug; if (debug) { @@ -225,6 +241,36 @@ bool D3D12Provider::Initialize() { } adapter->Release(); + // Configure the Direct3D 12 debug info queue. + ID3D12InfoQueue* d3d12_info_queue; + if (SUCCEEDED(device->QueryInterface(IID_PPV_ARGS(&d3d12_info_queue)))) { + D3D12_MESSAGE_SEVERITY d3d12_info_queue_denied_severities[] = { + D3D12_MESSAGE_SEVERITY_INFO, + }; + D3D12_MESSAGE_ID d3d12_info_queue_denied_messages[] = { + // Xbox 360 vertex fetch is explicit in shaders. + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_EMPTY_LAYOUT, + // Render targets and shader exports don't have to match on the Xbox + // 360. + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_PS_OUTPUT_RT_OUTPUT_MISMATCH, + }; + D3D12_INFO_QUEUE_FILTER d3d12_info_queue_filter = {}; + d3d12_info_queue_filter.DenyList.NumSeverities = + UINT(xe::countof(d3d12_info_queue_denied_severities)); + d3d12_info_queue_filter.DenyList.pSeverityList = + d3d12_info_queue_denied_severities; + d3d12_info_queue_filter.DenyList.NumIDs = + UINT(xe::countof(d3d12_info_queue_denied_messages)); + d3d12_info_queue_filter.DenyList.pIDList = d3d12_info_queue_denied_messages; + d3d12_info_queue->PushStorageFilter(&d3d12_info_queue_filter); + if (cvars::d3d12_break_on_error) { + d3d12_info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, + TRUE); + d3d12_info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE); + } + d3d12_info_queue->Release(); + } + // Create the command queue for graphics. D3D12_COMMAND_QUEUE_DESC queue_desc; queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;