diff --git a/src/xenia/ui/d3d12/d3d12_context.cc b/src/xenia/ui/d3d12/d3d12_context.cc index f897a5516..7764afa44 100644 --- a/src/xenia/ui/d3d12/d3d12_context.cc +++ b/src/xenia/ui/d3d12/d3d12_context.cc @@ -9,9 +9,6 @@ #include "xenia/ui/d3d12/d3d12_context.h" -#include - -#include "xenia/base/cvar.h" #include "xenia/base/logging.h" #include "xenia/base/math.h" #include "xenia/ui/d3d12/d3d12_immediate_drawer.h" @@ -19,9 +16,6 @@ #include "xenia/ui/d3d12/d3d12_util.h" #include "xenia/ui/window.h" -DEFINE_bool(d3d12_random_clear_color, false, - "Randomize presentation back buffer clear color.", "D3D12"); - namespace xe { namespace ui { namespace d3d12 { @@ -32,110 +26,112 @@ D3D12Context::D3D12Context(D3D12Provider* provider, Window* target_window) D3D12Context::~D3D12Context() { Shutdown(); } bool D3D12Context::Initialize() { + context_lost_ = false; + + if (!target_window_) { + return true; + } + auto& provider = GetD3D12Provider(); auto dxgi_factory = provider.GetDXGIFactory(); auto device = provider.GetDevice(); auto direct_queue = provider.GetDirectQueue(); - context_lost_ = false; + swap_fence_current_value_ = 1; + swap_fence_completed_value_ = 0; + swap_fence_completion_event_ = CreateEvent(nullptr, false, false, nullptr); + if (swap_fence_completion_event_ == nullptr) { + XELOGE("Failed to create the composition fence completion event"); + Shutdown(); + return false; + } + // Create a fence for transient resources of compositing. + if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, + IID_PPV_ARGS(&swap_fence_)))) { + XELOGE("Failed to create the composition fence"); + Shutdown(); + return false; + } - if (target_window_) { - swap_fence_current_value_ = 1; - swap_fence_completed_value_ = 0; - swap_fence_completion_event_ = CreateEvent(nullptr, false, false, nullptr); - if (swap_fence_completion_event_ == nullptr) { - XELOGE("Failed to create the composition fence completion event"); - Shutdown(); - return false; - } - // Create a fence for transient resources of compositing. - if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, - IID_PPV_ARGS(&swap_fence_)))) { - XELOGE("Failed to create the composition fence"); - Shutdown(); - return false; - } - - // Create the swap chain. - swap_chain_width_ = target_window_->scaled_width(); - swap_chain_height_ = target_window_->scaled_height(); - DXGI_SWAP_CHAIN_DESC1 swap_chain_desc; - swap_chain_desc.Width = swap_chain_width_; - swap_chain_desc.Height = swap_chain_height_; - swap_chain_desc.Format = kSwapChainFormat; - swap_chain_desc.Stereo = FALSE; - swap_chain_desc.SampleDesc.Count = 1; - swap_chain_desc.SampleDesc.Quality = 0; - swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swap_chain_desc.BufferCount = kSwapChainBufferCount; - swap_chain_desc.Scaling = DXGI_SCALING_STRETCH; - swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; - swap_chain_desc.Flags = 0; - IDXGISwapChain1* swap_chain_1; - if (FAILED(dxgi_factory->CreateSwapChainForHwnd( - provider.GetDirectQueue(), - static_cast(target_window_->native_handle()), - &swap_chain_desc, nullptr, nullptr, &swap_chain_1))) { - XELOGE("Failed to create a DXGI swap chain"); - Shutdown(); - return false; - } - if (FAILED(swap_chain_1->QueryInterface(IID_PPV_ARGS(&swap_chain_)))) { - XELOGE("Failed to get version 3 of the DXGI swap chain interface"); - swap_chain_1->Release(); - Shutdown(); - return false; - } + // Create the swap chain. + swap_chain_width_ = target_window_->scaled_width(); + swap_chain_height_ = target_window_->scaled_height(); + DXGI_SWAP_CHAIN_DESC1 swap_chain_desc; + swap_chain_desc.Width = swap_chain_width_; + swap_chain_desc.Height = swap_chain_height_; + swap_chain_desc.Format = kSwapChainFormat; + swap_chain_desc.Stereo = FALSE; + swap_chain_desc.SampleDesc.Count = 1; + swap_chain_desc.SampleDesc.Quality = 0; + swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swap_chain_desc.BufferCount = kSwapChainBufferCount; + swap_chain_desc.Scaling = DXGI_SCALING_STRETCH; + swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + swap_chain_desc.Flags = 0; + IDXGISwapChain1* swap_chain_1; + if (FAILED(dxgi_factory->CreateSwapChainForHwnd( + provider.GetDirectQueue(), + reinterpret_cast(target_window_->native_handle()), + &swap_chain_desc, nullptr, nullptr, &swap_chain_1))) { + XELOGE("Failed to create a DXGI swap chain"); + Shutdown(); + return false; + } + if (FAILED(swap_chain_1->QueryInterface(IID_PPV_ARGS(&swap_chain_)))) { + XELOGE("Failed to get version 3 of the DXGI swap chain interface"); swap_chain_1->Release(); + Shutdown(); + return false; + } + swap_chain_1->Release(); - // Create a heap for RTV descriptors of swap chain buffers. - D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc; - rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; - rtv_heap_desc.NumDescriptors = kSwapChainBufferCount; - rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; - rtv_heap_desc.NodeMask = 0; - if (FAILED(device->CreateDescriptorHeap( - &rtv_heap_desc, IID_PPV_ARGS(&swap_chain_rtv_heap_)))) { - XELOGE("Failed to create swap chain RTV descriptor heap"); + // Create a heap for RTV descriptors of swap chain buffers. + D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc; + rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + rtv_heap_desc.NumDescriptors = kSwapChainBufferCount; + rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + rtv_heap_desc.NodeMask = 0; + if (FAILED(device->CreateDescriptorHeap( + &rtv_heap_desc, IID_PPV_ARGS(&swap_chain_rtv_heap_)))) { + XELOGE("Failed to create swap chain RTV descriptor heap"); + Shutdown(); + return false; + } + swap_chain_rtv_heap_start_ = + swap_chain_rtv_heap_->GetCPUDescriptorHandleForHeapStart(); + + // Get the buffers and create their RTV descriptors. + if (!InitializeSwapChainBuffers()) { + Shutdown(); + return false; + } + + // Create the command list for compositing. + for (uint32_t i = 0; i < kSwapCommandAllocatorCount; ++i) { + if (FAILED(device->CreateCommandAllocator( + D3D12_COMMAND_LIST_TYPE_DIRECT, + IID_PPV_ARGS(&swap_command_allocators_[i])))) { + XELOGE("Failed to create a composition command allocator"); Shutdown(); return false; } - swap_chain_rtv_heap_start_ = - swap_chain_rtv_heap_->GetCPUDescriptorHandleForHeapStart(); + } + if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, + swap_command_allocators_[0], nullptr, + IID_PPV_ARGS(&swap_command_list_)))) { + XELOGE("Failed to create the composition graphics command list"); + Shutdown(); + return false; + } + // Initially in open state, wait until BeginSwap. + swap_command_list_->Close(); - // Get the buffers and create their RTV descriptors. - if (!InitializeSwapChainBuffers()) { - Shutdown(); - return false; - } - - // Create the command list for compositing. - for (uint32_t i = 0; i < kSwapCommandAllocatorCount; ++i) { - if (FAILED(device->CreateCommandAllocator( - D3D12_COMMAND_LIST_TYPE_DIRECT, - IID_PPV_ARGS(&swap_command_allocators_[i])))) { - XELOGE("Failed to create a composition command allocator"); - Shutdown(); - return false; - } - } - if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, - swap_command_allocators_[0], nullptr, - IID_PPV_ARGS(&swap_command_list_)))) { - XELOGE("Failed to create the composition graphics command list"); - Shutdown(); - return false; - } - // Initially in open state, wait until BeginSwap. - swap_command_list_->Close(); - - // Initialize the immediate mode drawer if not offscreen. - immediate_drawer_ = std::make_unique(*this); - if (!immediate_drawer_->Initialize()) { - Shutdown(); - return false; - } + // Initialize the immediate mode drawer if not offscreen. + immediate_drawer_ = std::make_unique(*this); + if (!immediate_drawer_->Initialize()) { + Shutdown(); + return false; } return true; @@ -223,9 +219,11 @@ ImmediateDrawer* D3D12Context::immediate_drawer() { return immediate_drawer_.get(); } -void D3D12Context::BeginSwap() { +bool D3D12Context::WasLost() { return context_lost_; } + +bool D3D12Context::BeginSwap() { if (!target_window_ || context_lost_) { - return; + return false; } // Resize the swap chain if the window is resized. @@ -252,13 +250,13 @@ void D3D12Context::BeginSwap() { kSwapChainBufferCount, target_window_width, target_window_height, kSwapChainFormat, 0))) { context_lost_ = true; - return; + return false; } swap_chain_width_ = target_window_width; swap_chain_height_ = target_window_height; if (!InitializeSwapChainBuffers()) { context_lost_ = true; - return; + return false; } } @@ -295,18 +293,11 @@ void D3D12Context::BeginSwap() { D3D12_CPU_DESCRIPTOR_HANDLE back_buffer_rtv = GetSwapChainBackBufferRTV(); swap_command_list_->OMSetRenderTargets(1, &back_buffer_rtv, TRUE, nullptr); float clear_color[4]; - if (cvars::d3d12_random_clear_color) { - clear_color[0] = rand() / float(RAND_MAX); // NOLINT(runtime/threadsafe_fn) - clear_color[1] = 1.0f; - clear_color[2] = 0.0f; - } else { - clear_color[0] = 0.0f; - clear_color[1] = 0.0f; - clear_color[2] = 0.0f; - } - clear_color[3] = 1.0f; + GetClearColor(clear_color); swap_command_list_->ClearRenderTargetView(back_buffer_rtv, clear_color, 0, nullptr); + + return true; } void D3D12Context::EndSwap() { diff --git a/src/xenia/ui/d3d12/d3d12_context.h b/src/xenia/ui/d3d12/d3d12_context.h index 4cf13d87e..c9f235b97 100644 --- a/src/xenia/ui/d3d12/d3d12_context.h +++ b/src/xenia/ui/d3d12/d3d12_context.h @@ -28,9 +28,9 @@ class D3D12Context : public GraphicsContext { ImmediateDrawer* immediate_drawer() override; - bool WasLost() override { return context_lost_; } + bool WasLost() override; - void BeginSwap() override; + bool BeginSwap() override; void EndSwap() override; std::unique_ptr Capture() override; @@ -69,11 +69,10 @@ class D3D12Context : public GraphicsContext { private: friend class D3D12Provider; - explicit D3D12Context(D3D12Provider* provider, Window* target_window); + bool Initialize(); private: - bool Initialize(); bool InitializeSwapChainBuffers(); void Shutdown(); diff --git a/src/xenia/ui/d3d12/d3d12_provider.cc b/src/xenia/ui/d3d12/d3d12_provider.cc index cb5287e14..d1f6594ca 100644 --- a/src/xenia/ui/d3d12/d3d12_provider.cc +++ b/src/xenia/ui/d3d12/d3d12_provider.cc @@ -383,6 +383,14 @@ bool D3D12Provider::Initialize() { device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV); // Check if optional features are supported. + // D3D12_HEAP_FLAG_CREATE_NOT_ZEROED requires Windows 10 2004 (indicated by + // the availability of ID3D12Device8 or D3D12_FEATURE_D3D12_OPTIONS7). + heap_flag_create_not_zeroed_ = D3D12_HEAP_FLAG_NONE; + D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7; + if (SUCCEEDED(device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, + &options7, sizeof(options7)))) { + heap_flag_create_not_zeroed_ = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED; + } rasterizer_ordered_views_supported_ = false; resource_binding_tier_ = D3D12_RESOURCE_BINDING_TIER_1; tiled_resources_tier_ = D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED; @@ -409,14 +417,6 @@ bool D3D12Provider::Initialize() { virtual_address_bits_per_resource_ = virtual_address_support.MaxGPUVirtualAddressBitsPerResource; } - // D3D12_HEAP_FLAG_CREATE_NOT_ZEROED requires Windows 10 2004 (indicated by - // the availability of ID3D12Device8 or D3D12_FEATURE_D3D12_OPTIONS7). - heap_flag_create_not_zeroed_ = D3D12_HEAP_FLAG_NONE; - D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7; - if (SUCCEEDED(device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, - &options7, sizeof(options7)))) { - heap_flag_create_not_zeroed_ = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED; - } XELOGD3D( "Direct3D 12 device and OS features:\n" "* Max GPU virtual address bits per resource: {}\n" diff --git a/src/xenia/ui/d3d12/d3d12_provider.h b/src/xenia/ui/d3d12/d3d12_provider.h index 1c8694fd0..c8332801c 100644 --- a/src/xenia/ui/d3d12/d3d12_provider.h +++ b/src/xenia/ui/d3d12/d3d12_provider.h @@ -68,6 +68,9 @@ class D3D12Provider : public GraphicsProvider { uint32_t GetAdapterVendorID() const { return adapter_vendor_id_; } // Device features. + D3D12_HEAP_FLAGS GetHeapFlagCreateNotZeroed() const { + return heap_flag_create_not_zeroed_; + } D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER GetProgrammableSamplePositionsTier() const { return programmable_sample_positions_tier_; @@ -84,9 +87,6 @@ class D3D12Provider : public GraphicsProvider { uint32_t GetVirtualAddressBitsPerResource() const { return virtual_address_bits_per_resource_; } - D3D12_HEAP_FLAGS GetHeapFlagCreateNotZeroed() const { - return heap_flag_create_not_zeroed_; - } // Proxies for Direct3D 12 functions since they are loaded dynamically. inline HRESULT SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, @@ -162,12 +162,12 @@ class D3D12Provider : public GraphicsProvider { uint32_t adapter_vendor_id_; + D3D12_HEAP_FLAGS heap_flag_create_not_zeroed_; D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER programmable_sample_positions_tier_; bool rasterizer_ordered_views_supported_; D3D12_RESOURCE_BINDING_TIER resource_binding_tier_; D3D12_TILED_RESOURCES_TIER tiled_resources_tier_; uint32_t virtual_address_bits_per_resource_; - D3D12_HEAP_FLAGS heap_flag_create_not_zeroed_; }; } // namespace d3d12 diff --git a/src/xenia/ui/graphics_context.cc b/src/xenia/ui/graphics_context.cc index 73980cd37..7f5ab07b6 100644 --- a/src/xenia/ui/graphics_context.cc +++ b/src/xenia/ui/graphics_context.cc @@ -9,8 +9,13 @@ #include "xenia/ui/graphics_context.h" +#include + +#include "xenia/base/cvar.h" #include "xenia/ui/graphics_provider.h" +DEFINE_bool(random_clear_color, false, "Randomize window clear color.", "UI"); + namespace xe { namespace ui { @@ -26,5 +31,18 @@ bool GraphicsContext::MakeCurrent() { return true; } void GraphicsContext::ClearCurrent() {} +void GraphicsContext::GetClearColor(float* rgba) { + if (cvars::random_clear_color) { + rgba[0] = rand() / float(RAND_MAX); // NOLINT(runtime/threadsafe_fn) + rgba[1] = 1.0f; + rgba[2] = 0.0f; + } else { + rgba[0] = 0.0f; + rgba[1] = 0.0f; + rgba[2] = 0.0f; + } + rgba[3] = 1.0f; +} + } // namespace ui } // namespace xe diff --git a/src/xenia/ui/graphics_context.h b/src/xenia/ui/graphics_context.h index 383338770..0ed5bd881 100644 --- a/src/xenia/ui/graphics_context.h +++ b/src/xenia/ui/graphics_context.h @@ -51,7 +51,8 @@ class GraphicsContext { // This context must be made current in order for this call to work properly. virtual bool WasLost() = 0; - virtual void BeginSwap() = 0; + // Returns true if able to draw now (the target surface is available). + virtual bool BeginSwap() = 0; virtual void EndSwap() = 0; virtual std::unique_ptr Capture() = 0; @@ -59,6 +60,8 @@ class GraphicsContext { protected: explicit GraphicsContext(GraphicsProvider* provider, Window* target_window); + static void GetClearColor(float* rgba); + GraphicsProvider* provider_ = nullptr; Window* target_window_ = nullptr; }; diff --git a/src/xenia/ui/vulkan/vulkan_context.cc b/src/xenia/ui/vulkan/vulkan_context.cc index 339f099ef..50f51ad74 100644 --- a/src/xenia/ui/vulkan/vulkan_context.cc +++ b/src/xenia/ui/vulkan/vulkan_context.cc @@ -141,7 +141,7 @@ bool VulkanContext::MakeCurrent() { void VulkanContext::ClearCurrent() {} -void VulkanContext::BeginSwap() { +bool VulkanContext::BeginSwap() { SCOPE_profile_cpu_f("gpu"); auto provider = static_cast(provider_); auto device = provider->device(); @@ -170,6 +170,8 @@ void VulkanContext::BeginSwap() { // TODO(benvanik): use a fence instead? May not be possible with target image. std::lock_guard queue_lock(device->primary_queue_mutex()); status = vkQueueWaitIdle(device->primary_queue()); + + return true; } void VulkanContext::EndSwap() { diff --git a/src/xenia/ui/vulkan/vulkan_context.h b/src/xenia/ui/vulkan/vulkan_context.h index 3665ffd78..f5658bdd1 100644 --- a/src/xenia/ui/vulkan/vulkan_context.h +++ b/src/xenia/ui/vulkan/vulkan_context.h @@ -40,7 +40,7 @@ class VulkanContext : public GraphicsContext { bool WasLost() override { return context_lost_; } - void BeginSwap() override; + bool BeginSwap() override; void EndSwap() override; std::unique_ptr Capture() override; diff --git a/src/xenia/ui/window.cc b/src/xenia/ui/window.cc index 8be8900c8..1273b61f0 100644 --- a/src/xenia/ui/window.cc +++ b/src/xenia/ui/window.cc @@ -200,11 +200,15 @@ void Window::OnPaint(UIEvent* e) { io.DisplaySize = ImVec2(static_cast(scaled_width()), static_cast(scaled_height())); - context_->BeginSwap(); + bool can_swap = context_->BeginSwap(); if (context_->WasLost()) { on_context_lost(e); return; } + if (!can_swap) { + // Surface not available. + return; + } ImGui::NewFrame();