[D3D12] DirectComposition basic initialization

This commit is contained in:
Triang3l 2021-06-09 22:56:36 +03:00
parent 50bb35b4b4
commit 14bac72f0d
5 changed files with 109 additions and 57 deletions

View File

@ -17,6 +17,7 @@
#include <d3d12.h>
#include <d3d12sdklayers.h>
#include <d3dcompiler.h>
#include <dcomp.h>
#include <dxgi1_4.h>
#include <dxgidebug.h>
// For Microsoft::WRL::ComPtr.

View File

@ -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<HWND>(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<HWND>(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<D3D12ImmediateDrawer>(*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();

View File

@ -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<IDXGISwapChain3> swap_chain_;
uint32_t swap_chain_width_ = 0, swap_chain_height_ = 0;
ID3D12Resource* swap_chain_buffers_[kSwapChainBufferCount] = {};
Microsoft::WRL::ComPtr<ID3D12Resource>
swap_chain_buffers_[kSwapChainBufferCount];
uint32_t swap_chain_back_buffer_index_ = 0;
ID3D12DescriptorHeap* swap_chain_rtv_heap_ = nullptr;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> 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<ID3D12Fence> swap_fence_;
static constexpr uint32_t kSwapCommandAllocatorCount = 3;
ID3D12CommandAllocator* swap_command_allocators_[kSwapCommandAllocatorCount] =
{};
Microsoft::WRL::ComPtr<ID3D12CommandAllocator>
swap_command_allocators_[kSwapCommandAllocatorCount];
// Current command allocator is:
// ((swap_fence_current_value_ + (kSwapCommandAllocatorCount - 1))) %
// kSwapCommandAllocatorCount.
ID3D12GraphicsCommandList* swap_command_list_ = nullptr;
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> swap_command_list_;
Microsoft::WRL::ComPtr<IDCompositionDevice> dcomp_device_;
Microsoft::WRL::ComPtr<IDCompositionTarget> dcomp_target_;
Microsoft::WRL::ComPtr<IDCompositionVisual> dcomp_visual_;
std::unique_ptr<D3D12ImmediateDrawer> immediate_drawer_;
};

View File

@ -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;
}

View File

@ -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;