#include "D3D12WindowInteropInternal.h" #include namespace XCEngine::UI::Editor::Host { using namespace D3D12WindowInteropInternal; bool D3D12WindowInteropContext::EnsureInterop() { if (m_windowRenderer == nullptr) { m_lastError = "EnsureInterop requires an attached D3D12 window renderer."; return false; } if (m_d2dFactory == nullptr) { m_lastError = "EnsureInterop requires an initialized D2D factory."; return false; } if (m_d3d11On12Device != nullptr && m_d2dDeviceContext != nullptr && m_interopBrush != nullptr) { return true; } ReleaseInteropState(); ID3D12Device* d3d12Device = m_windowRenderer->GetDevice(); ID3D12CommandQueue* d3d12CommandQueue = m_windowRenderer->GetCommandQueue(); if (d3d12Device == nullptr || d3d12CommandQueue == nullptr) { m_lastError = "The attached D3D12 window renderer does not expose a native device/queue."; return false; } const std::array featureLevels = { D3D_FEATURE_LEVEL_12_1, D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0 }; const std::array commandQueues = { reinterpret_cast(d3d12CommandQueue) }; UINT createFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; #ifdef _DEBUG createFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif D3D_FEATURE_LEVEL actualFeatureLevel = D3D_FEATURE_LEVEL_11_0; HRESULT hr = D3D11On12CreateDevice( d3d12Device, createFlags, featureLevels.data(), static_cast(featureLevels.size()), commandQueues.data(), static_cast(commandQueues.size()), 0u, m_d3d11Device.ReleaseAndGetAddressOf(), m_d3d11DeviceContext.ReleaseAndGetAddressOf(), &actualFeatureLevel); #ifdef _DEBUG if (FAILED(hr)) { createFlags &= ~D3D11_CREATE_DEVICE_DEBUG; hr = D3D11On12CreateDevice( d3d12Device, createFlags, featureLevels.data(), static_cast(featureLevels.size()), commandQueues.data(), static_cast(commandQueues.size()), 0u, m_d3d11Device.ReleaseAndGetAddressOf(), m_d3d11DeviceContext.ReleaseAndGetAddressOf(), &actualFeatureLevel); } #endif if (FAILED(hr) || m_d3d11Device == nullptr || m_d3d11DeviceContext == nullptr) { m_lastError = HrToInteropString("D3D11On12CreateDevice", hr); ReleaseInteropState(); return false; } hr = m_d3d11Device.As(&m_d3d11On12Device); if (FAILED(hr) || m_d3d11On12Device == nullptr) { m_lastError = HrToInteropString("ID3D11Device::QueryInterface(ID3D11On12Device)", hr); ReleaseInteropState(); return false; } Microsoft::WRL::ComPtr dxgiDevice = {}; hr = m_d3d11Device.As(&dxgiDevice); if (FAILED(hr) || dxgiDevice == nullptr) { m_lastError = HrToInteropString("ID3D11Device::QueryInterface(IDXGIDevice)", hr); ReleaseInteropState(); return false; } hr = m_d2dFactory->CreateDevice(dxgiDevice.Get(), m_d2dDevice.ReleaseAndGetAddressOf()); if (FAILED(hr) || m_d2dDevice == nullptr) { m_lastError = HrToInteropString("ID2D1Factory1::CreateDevice", hr); ReleaseInteropState(); return false; } hr = m_d2dDevice->CreateDeviceContext( D2D1_DEVICE_CONTEXT_OPTIONS_NONE, m_d2dDeviceContext.ReleaseAndGetAddressOf()); if (FAILED(hr) || m_d2dDeviceContext == nullptr) { m_lastError = HrToInteropString("ID2D1Device::CreateDeviceContext", hr); ReleaseInteropState(); return false; } hr = m_d2dDeviceContext->CreateSolidColorBrush( D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), m_interopBrush.ReleaseAndGetAddressOf()); if (FAILED(hr) || m_interopBrush == nullptr) { m_lastError = HrToInteropString("ID2D1DeviceContext::CreateSolidColorBrush", hr); ReleaseInteropState(); return false; } m_d2dDeviceContext->SetDpi(96.0f, 96.0f); m_d2dDeviceContext->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE); m_lastError.clear(); return true; } void D3D12WindowInteropContext::ReleaseInteropState() { ReleaseBackBufferTargets(); m_interopBrush.Reset(); m_d2dDeviceContext.Reset(); m_d2dDevice.Reset(); m_d3d11On12Device.Reset(); m_d3d11DeviceContext.Reset(); m_d3d11Device.Reset(); } } // namespace XCEngine::UI::Editor::Host