From 14bac72f0daeae5b8de0b213c5df97d8b59f8c04 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Wed, 9 Jun 2021 22:56:36 +0300 Subject: [PATCH] [D3D12] DirectComposition basic initialization --- src/xenia/ui/d3d12/d3d12_api.h | 1 + src/xenia/ui/d3d12/d3d12_context.cc | 115 +++++++++++++++++---------- src/xenia/ui/d3d12/d3d12_context.h | 23 +++--- src/xenia/ui/d3d12/d3d12_provider.cc | 14 +++- src/xenia/ui/d3d12/d3d12_provider.h | 13 ++- 5 files changed, 109 insertions(+), 57 deletions(-) diff --git a/src/xenia/ui/d3d12/d3d12_api.h b/src/xenia/ui/d3d12/d3d12_api.h index 1f22fcaf7..e474d9391 100644 --- a/src/xenia/ui/d3d12/d3d12_api.h +++ b/src/xenia/ui/d3d12/d3d12_api.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include // For Microsoft::WRL::ComPtr. diff --git a/src/xenia/ui/d3d12/d3d12_context.cc b/src/xenia/ui/d3d12/d3d12_context.cc index 7764afa44..a37c61b72 100644 --- a/src/xenia/ui/d3d12/d3d12_context.cc +++ b/src/xenia/ui/d3d12/d3d12_context.cc @@ -32,10 +32,10 @@ bool D3D12Context::Initialize() { return true; } - auto& provider = GetD3D12Provider(); - auto dxgi_factory = provider.GetDXGIFactory(); - auto device = provider.GetDevice(); - auto direct_queue = provider.GetDirectQueue(); + const D3D12Provider& provider = GetD3D12Provider(); + IDXGIFactory2* dxgi_factory = provider.GetDXGIFactory(); + ID3D12Device* device = provider.GetDevice(); + ID3D12CommandQueue* direct_queue = provider.GetDirectQueue(); swap_fence_current_value_ = 1; swap_fence_completed_value_ = 0; @@ -70,11 +70,10 @@ bool D3D12Context::Initialize() { 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"); + if (FAILED(dxgi_factory->CreateSwapChainForComposition( + provider.GetDirectQueue(), &swap_chain_desc, nullptr, + &swap_chain_1))) { + XELOGE("Failed to create a DXGI swap chain for composition"); Shutdown(); return false; } @@ -117,9 +116,9 @@ bool D3D12Context::Initialize() { return false; } } - if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, - swap_command_allocators_[0], nullptr, - IID_PPV_ARGS(&swap_command_list_)))) { + if (FAILED(device->CreateCommandList( + 0, D3D12_COMMAND_LIST_TYPE_DIRECT, swap_command_allocators_[0].Get(), + nullptr, IID_PPV_ARGS(&swap_command_list_)))) { XELOGE("Failed to create the composition graphics command list"); Shutdown(); return false; @@ -127,6 +126,45 @@ bool D3D12Context::Initialize() { // Initially in open state, wait until BeginSwap. swap_command_list_->Close(); + // Associate the swap chain with the window via DirectComposition. + if (FAILED(provider.CreateDCompositionDevice(nullptr, + IID_PPV_ARGS(&dcomp_device_)))) { + XELOGE("Failed to create a DirectComposition device"); + Shutdown(); + return false; + } + if (FAILED(dcomp_device_->CreateTargetForHwnd( + reinterpret_cast(target_window_->native_handle()), TRUE, + &dcomp_target_))) { + XELOGE("Failed to create a DirectComposition target for the window"); + Shutdown(); + return false; + } + if (FAILED(dcomp_device_->CreateVisual(&dcomp_visual_))) { + XELOGE("Failed to create a DirectComposition visual"); + Shutdown(); + return false; + } + if (FAILED(dcomp_visual_->SetContent(swap_chain_.Get()))) { + XELOGE( + "Failed to set the content of the DirectComposition visual to the swap " + "chain"); + Shutdown(); + return false; + } + if (FAILED(dcomp_target_->SetRoot(dcomp_visual_.Get()))) { + XELOGE( + "Failed to set the root of the DirectComposition target to the swap " + "chain visual"); + Shutdown(); + return false; + } + if (FAILED(dcomp_device_->Commit())) { + XELOGE("Failed to commit DirectComposition commands"); + Shutdown(); + return false; + } + // Initialize the immediate mode drawer if not offscreen. immediate_drawer_ = std::make_unique(*this); if (!immediate_drawer_->Initialize()) { @@ -151,14 +189,14 @@ bool D3D12Context::InitializeSwapChainBuffers() { swap_chain_back_buffer_index_ = swap_chain_->GetCurrentBackBufferIndex(); // Create RTV descriptors for the swap chain buffers. - auto device = GetD3D12Provider().GetDevice(); + ID3D12Device* device = GetD3D12Provider().GetDevice(); D3D12_RENDER_TARGET_VIEW_DESC rtv_desc; rtv_desc.Format = kSwapChainFormat; rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; rtv_desc.Texture2D.MipSlice = 0; rtv_desc.Texture2D.PlaneSlice = 0; for (uint32_t i = 0; i < kSwapChainBufferCount; ++i) { - device->CreateRenderTargetView(swap_chain_buffers_[i], &rtv_desc, + device->CreateRenderTargetView(swap_chain_buffers_[i].Get(), &rtv_desc, GetSwapChainBufferRTV(i)); } @@ -179,34 +217,23 @@ void D3D12Context::Shutdown() { immediate_drawer_.reset(); - util::ReleaseAndNull(swap_command_list_); + dcomp_visual_.Reset(); + dcomp_target_.Reset(); + dcomp_device_.Reset(); + + swap_command_list_.Reset(); for (uint32_t i = 0; i < kSwapCommandAllocatorCount; ++i) { - auto& swap_command_allocator = swap_command_allocators_[i]; - if (!swap_command_allocator) { - break; - } - swap_command_allocator->Release(); - swap_command_allocator = nullptr; + swap_command_allocators_[i].Reset(); } - if (swap_chain_) { - for (uint32_t i = 0; i < kSwapChainBufferCount; ++i) { - auto& swap_chain_buffer = swap_chain_buffers_[i]; - if (!swap_chain_buffer) { - break; - } - swap_chain_buffer->Release(); - swap_chain_buffer = nullptr; - } - - util::ReleaseAndNull(swap_chain_rtv_heap_); - - swap_chain_->Release(); - swap_chain_ = nullptr; + for (uint32_t i = 0; i < kSwapChainBufferCount; ++i) { + swap_chain_buffers_[i].Reset(); } + swap_chain_rtv_heap_.Reset(); + swap_chain_.Reset(); // First release the fence since it may reference the event. - util::ReleaseAndNull(swap_fence_); + swap_fence_.Reset(); if (swap_fence_completion_event_) { CloseHandle(swap_fence_completion_event_); swap_fence_completion_event_ = nullptr; @@ -243,8 +270,7 @@ bool D3D12Context::BeginSwap() { } // All buffer references must be released before resizing. for (uint32_t i = 0; i < kSwapChainBufferCount; ++i) { - swap_chain_buffers_[i]->Release(); - swap_chain_buffers_[i] = nullptr; + swap_chain_buffers_[i].Reset(); } if (FAILED(swap_chain_->ResizeBuffers( kSwapChainBufferCount, target_window_width, target_window_height, @@ -276,7 +302,8 @@ bool D3D12Context::BeginSwap() { uint32_t command_allocator_index = uint32_t((swap_fence_current_value_ + (kSwapCommandAllocatorCount - 1)) % kSwapCommandAllocatorCount); - auto command_allocator = swap_command_allocators_[command_allocator_index]; + ID3D12CommandAllocator* command_allocator = + swap_command_allocators_[command_allocator_index].Get(); command_allocator->Reset(); swap_command_list_->Reset(command_allocator, nullptr); @@ -285,7 +312,7 @@ bool D3D12Context::BeginSwap() { barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = - swap_chain_buffers_[swap_chain_back_buffer_index_]; + swap_chain_buffers_[swap_chain_back_buffer_index_].Get(); barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; @@ -305,14 +332,14 @@ void D3D12Context::EndSwap() { return; } - auto direct_queue = GetD3D12Provider().GetDirectQueue(); + ID3D12CommandQueue* direct_queue = GetD3D12Provider().GetDirectQueue(); // Switch the back buffer to presentation state. D3D12_RESOURCE_BARRIER barrier; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = - swap_chain_buffers_[swap_chain_back_buffer_index_]; + swap_chain_buffers_[swap_chain_back_buffer_index_].Get(); barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; @@ -320,7 +347,7 @@ void D3D12Context::EndSwap() { // Submit the command list. swap_command_list_->Close(); - ID3D12CommandList* execute_command_lists[] = {swap_command_list_}; + ID3D12CommandList* execute_command_lists[] = {swap_command_list_.Get()}; direct_queue->ExecuteCommandLists(1, execute_command_lists); // Present and check if the context was lost. @@ -330,7 +357,7 @@ void D3D12Context::EndSwap() { } // Signal the fence to wait for frame resources to become free again. - direct_queue->Signal(swap_fence_, swap_fence_current_value_++); + direct_queue->Signal(swap_fence_.Get(), swap_fence_current_value_++); // Get the back buffer index for the next frame. swap_chain_back_buffer_index_ = swap_chain_->GetCurrentBackBufferIndex(); diff --git a/src/xenia/ui/d3d12/d3d12_context.h b/src/xenia/ui/d3d12/d3d12_context.h index b9bcb11c5..308d3aa6f 100644 --- a/src/xenia/ui/d3d12/d3d12_context.h +++ b/src/xenia/ui/d3d12/d3d12_context.h @@ -40,7 +40,7 @@ class D3D12Context : public GraphicsContext { // The format used by DWM. static constexpr DXGI_FORMAT kSwapChainFormat = DXGI_FORMAT_B8G8R8A8_UNORM; ID3D12Resource* GetSwapChainBuffer(uint32_t buffer_index) const { - return swap_chain_buffers_[buffer_index]; + return swap_chain_buffers_[buffer_index].Get(); } uint32_t GetSwapChainBackBufferIndex() const { return swap_chain_back_buffer_index_; @@ -62,7 +62,7 @@ class D3D12Context : public GraphicsContext { return swap_fence_completed_value_; } ID3D12GraphicsCommandList* GetSwapCommandList() const { - return swap_command_list_; + return swap_command_list_.Get(); } private: @@ -77,25 +77,30 @@ class D3D12Context : public GraphicsContext { bool context_lost_ = false; static constexpr uint32_t kSwapChainBufferCount = 3; - IDXGISwapChain3* swap_chain_ = nullptr; + Microsoft::WRL::ComPtr swap_chain_; uint32_t swap_chain_width_ = 0, swap_chain_height_ = 0; - ID3D12Resource* swap_chain_buffers_[kSwapChainBufferCount] = {}; + Microsoft::WRL::ComPtr + swap_chain_buffers_[kSwapChainBufferCount]; uint32_t swap_chain_back_buffer_index_ = 0; - ID3D12DescriptorHeap* swap_chain_rtv_heap_ = nullptr; + Microsoft::WRL::ComPtr swap_chain_rtv_heap_; D3D12_CPU_DESCRIPTOR_HANDLE swap_chain_rtv_heap_start_; uint64_t swap_fence_current_value_ = 1; uint64_t swap_fence_completed_value_ = 0; HANDLE swap_fence_completion_event_ = nullptr; - ID3D12Fence* swap_fence_ = nullptr; + Microsoft::WRL::ComPtr swap_fence_; static constexpr uint32_t kSwapCommandAllocatorCount = 3; - ID3D12CommandAllocator* swap_command_allocators_[kSwapCommandAllocatorCount] = - {}; + Microsoft::WRL::ComPtr + swap_command_allocators_[kSwapCommandAllocatorCount]; // Current command allocator is: // ((swap_fence_current_value_ + (kSwapCommandAllocatorCount - 1))) % // kSwapCommandAllocatorCount. - ID3D12GraphicsCommandList* swap_command_list_ = nullptr; + Microsoft::WRL::ComPtr swap_command_list_; + + Microsoft::WRL::ComPtr dcomp_device_; + Microsoft::WRL::ComPtr dcomp_target_; + Microsoft::WRL::ComPtr dcomp_visual_; std::unique_ptr immediate_drawer_; }; diff --git a/src/xenia/ui/d3d12/d3d12_provider.cc b/src/xenia/ui/d3d12/d3d12_provider.cc index 37686b1ff..9560cfa97 100644 --- a/src/xenia/ui/d3d12/d3d12_provider.cc +++ b/src/xenia/ui/d3d12/d3d12_provider.cc @@ -89,6 +89,9 @@ D3D12Provider::~D3D12Provider() { if (library_d3dcompiler_ != nullptr) { FreeLibrary(library_d3dcompiler_); } + if (library_dcomp_ != nullptr) { + FreeLibrary(library_dcomp_); + } if (library_d3d12_ != nullptr) { FreeLibrary(library_d3d12_); } @@ -120,8 +123,9 @@ bool D3D12Provider::Initialize() { // Load the core libraries. library_dxgi_ = LoadLibraryW(L"dxgi.dll"); library_d3d12_ = LoadLibraryW(L"D3D12.dll"); - if (library_dxgi_ == nullptr || library_d3d12_ == nullptr) { - XELOGE("Failed to load dxgi.dll or D3D12.dll"); + library_dcomp_ = LoadLibraryW(L"dcomp.dll"); + if (!library_dxgi_ || !library_d3d12_ || !library_dcomp_) { + XELOGE("Failed to load dxgi.dll, D3D12.dll or dcomp.dll"); return false; } bool libraries_loaded = true; @@ -142,8 +146,12 @@ bool D3D12Provider::Initialize() { (pfn_d3d12_serialize_root_signature_ = PFN_D3D12_SERIALIZE_ROOT_SIGNATURE( GetProcAddress(library_d3d12_, "D3D12SerializeRootSignature"))) != nullptr; + libraries_loaded &= + (pfn_dcomposition_create_device_ = PFNDCompositionCreateDevice( + GetProcAddress(library_dcomp_, "DCompositionCreateDevice"))) != + nullptr; if (!libraries_loaded) { - XELOGE("Failed to get DXGI or Direct3D 12 functions"); + XELOGE("Failed to get DXGI, Direct3D 12 or DirectComposition functions"); return false; } diff --git a/src/xenia/ui/d3d12/d3d12_provider.h b/src/xenia/ui/d3d12/d3d12_provider.h index 089712b78..25c159dcd 100644 --- a/src/xenia/ui/d3d12/d3d12_provider.h +++ b/src/xenia/ui/d3d12/d3d12_provider.h @@ -110,7 +110,7 @@ class D3D12Provider : public GraphicsProvider { return virtual_address_bits_per_resource_; } - // Proxies for Direct3D 12 functions since they are loaded dynamically. + // Proxies for DirectX functions since they are loaded dynamically. HRESULT SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, D3D_ROOT_SIGNATURE_VERSION version, ID3DBlob** blob_out, @@ -118,6 +118,11 @@ class D3D12Provider : public GraphicsProvider { return pfn_d3d12_serialize_root_signature_(desc, version, blob_out, error_blob_out); } + HRESULT CreateDCompositionDevice(IDXGIDevice* dxgi_device, const IID& iid, + void** dcomposition_device_out) const { + return pfn_dcomposition_create_device_(dxgi_device, iid, + dcomposition_device_out); + } HRESULT Disassemble(const void* src_data, size_t src_data_size, UINT flags, const char* comments, ID3DBlob** disassembly_out) const { if (!pfn_d3d_disassemble_) { @@ -151,6 +156,9 @@ class D3D12Provider : public GraphicsProvider { _COM_Outptr_ void** ppFactory); typedef HRESULT(WINAPI* PFNDXGIGetDebugInterface1)( UINT Flags, REFIID riid, _COM_Outptr_ void** pDebug); + typedef HRESULT(WINAPI* PFNDCompositionCreateDevice)( + _In_opt_ IDXGIDevice* dxgiDevice, _In_ REFIID iid, + _Outptr_ void** dcompositionDevice); HMODULE library_dxgi_ = nullptr; PFNCreateDXGIFactory2 pfn_create_dxgi_factory2_; @@ -161,6 +169,9 @@ class D3D12Provider : public GraphicsProvider { PFN_D3D12_CREATE_DEVICE pfn_d3d12_create_device_; PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfn_d3d12_serialize_root_signature_; + HMODULE library_dcomp_ = nullptr; + PFNDCompositionCreateDevice pfn_dcomposition_create_device_; + HMODULE library_d3dcompiler_ = nullptr; pD3DDisassemble pfn_d3d_disassemble_ = nullptr;