#include "Rendering/D3D12/D3D12WindowSwapChainPresenter.h" namespace XCEngine::UI::Editor::Host { using ::XCEngine::RHI::D3D12SwapChain; using ::XCEngine::RHI::D3D12Texture; using ::XCEngine::RHI::RHISwapChain; using ::XCEngine::RHI::SwapChainDesc; bool D3D12WindowSwapChainPresenter::Initialize( D3D12HostDevice& hostDevice, HWND hwnd, int width, int height) { Shutdown(); if (hwnd == nullptr || width <= 0 || height <= 0) { m_lastError = "Initialize rejected an invalid hwnd or size."; return false; } if (hostDevice.GetRHIDevice() == nullptr || hostDevice.GetRHICommandQueue() == nullptr) { m_lastError = "Initialize requires an initialized host D3D12 device."; return false; } m_hwnd = hwnd; m_width = width; m_height = height; m_hostDevice = &hostDevice; if (!CreateSwapChain(width, height)) { Shutdown(); return false; } m_lastError.clear(); return true; } bool D3D12WindowSwapChainPresenter::CreateSwapChain(int width, int height) { if (m_hostDevice == nullptr || m_hostDevice->GetRHIDevice() == nullptr || m_hostDevice->GetRHICommandQueue() == nullptr) { m_lastError = "CreateSwapChain requires an initialized host D3D12 device."; return false; } SwapChainDesc swapChainDesc = {}; swapChainDesc.windowHandle = m_hwnd; swapChainDesc.width = static_cast(width); swapChainDesc.height = static_cast(height); swapChainDesc.bufferCount = kSwapChainBufferCount; m_swapChain = m_hostDevice->GetRHIDevice()->CreateSwapChain( swapChainDesc, m_hostDevice->GetRHICommandQueue()); if (m_swapChain == nullptr || GetD3D12SwapChain() == nullptr) { m_lastError = "Failed to create the D3D12 swap chain."; return false; } ConfigureFrameLatency(); if (!RecreateBackBufferViews()) { m_lastError = "Failed to create swap chain back buffer views."; return false; } m_width = width; m_height = height; return true; } void D3D12WindowSwapChainPresenter::ConfigureFrameLatency() { D3D12SwapChain* d3d12SwapChain = GetD3D12SwapChain(); if (d3d12SwapChain == nullptr) { return; } auto* nativeSwapChain = static_cast(d3d12SwapChain->GetNativeHandle()); if (nativeSwapChain == nullptr) { return; } nativeSwapChain->SetMaximumFrameLatency(1u); } void D3D12WindowSwapChainPresenter::DestroySwapChain() { ReleaseBackBufferViews(); if (m_swapChain != nullptr) { m_swapChain->Shutdown(); delete m_swapChain; m_swapChain = nullptr; } } bool D3D12WindowSwapChainPresenter::RecreateSwapChain(int width, int height) { DestroySwapChain(); m_hostDevice->ResetFrameTracking(); return CreateSwapChain(width, height); } void D3D12WindowSwapChainPresenter::Shutdown() { if (m_hostDevice != nullptr) { m_hostDevice->WaitForGpuIdle(); } DestroySwapChain(); m_hwnd = nullptr; m_width = 0; m_height = 0; m_hostDevice = nullptr; m_lastError.clear(); } const std::string& D3D12WindowSwapChainPresenter::GetLastError() const { return m_lastError; } RHISwapChain* D3D12WindowSwapChainPresenter::GetSwapChain() const { return m_swapChain; } const ::XCEngine::Rendering::RenderSurface* D3D12WindowSwapChainPresenter::GetCurrentRenderSurface() const { if (m_swapChain == nullptr) { return nullptr; } const std::uint32_t backBufferIndex = m_swapChain->GetCurrentBackBufferIndex(); if (backBufferIndex >= m_backBufferSurfaces.size()) { return nullptr; } return &m_backBufferSurfaces[backBufferIndex]; } const D3D12Texture* D3D12WindowSwapChainPresenter::GetCurrentBackBufferTexture() const { if (m_swapChain == nullptr) { return nullptr; } return GetBackBufferTexture(m_swapChain->GetCurrentBackBufferIndex()); } const D3D12Texture* D3D12WindowSwapChainPresenter::GetBackBufferTexture(std::uint32_t index) const { const D3D12SwapChain* d3d12SwapChain = GetD3D12SwapChain(); if (d3d12SwapChain == nullptr) { return nullptr; } return d3d12SwapChain->TryGetBackBuffer(index); } std::uint32_t D3D12WindowSwapChainPresenter::GetBackBufferCount() const { return kSwapChainBufferCount; } std::uint32_t D3D12WindowSwapChainPresenter::GetCurrentBackBufferIndex() const { return m_swapChain != nullptr ? m_swapChain->GetCurrentBackBufferIndex() : 0u; } D3D12SwapChain* D3D12WindowSwapChainPresenter::GetD3D12SwapChain() const { return m_swapChain != nullptr ? static_cast(m_swapChain) : nullptr; } } // namespace XCEngine::UI::Editor::Host