#include "D3D12WindowRenderer.h" namespace XCEngine::UI::Editor::Host { using ::XCEngine::RHI::RHIDevice; using ::XCEngine::RHI::RHISwapChain; using ::XCEngine::RHI::D3D12Texture; bool D3D12WindowRenderer::Initialize(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 (!m_hostDevice.Initialize()) { m_lastError = m_hostDevice.GetLastError(); return false; } if (!m_presenter.Initialize(m_hostDevice, hwnd, width, height)) { m_lastError = m_presenter.GetLastError(); Shutdown(); return false; } auto* device = m_hostDevice.GetRHIDevice(); if (device == nullptr || !m_viewportTextureAllocator.Initialize(*device)) { m_lastError = "Failed to initialize the viewport texture allocator."; Shutdown(); return false; } m_lastError.clear(); return true; } void D3D12WindowRenderer::Shutdown() { m_viewportTextureCpuHandles.clear(); m_viewportTextureAllocator.Shutdown(); m_presenter.Shutdown(); m_hostDevice.Shutdown(); m_activeBackBufferIndex = 0u; m_lastError.clear(); } bool D3D12WindowRenderer::Resize(int width, int height) { if (!m_presenter.Resize(width, height)) { m_lastError = m_presenter.GetLastError(); return false; } m_activeBackBufferIndex = m_presenter.GetCurrentBackBufferIndex(); m_lastError = m_presenter.GetLastError(); if (!m_lastError.empty()) { return true; } m_lastError.clear(); return true; } bool D3D12WindowRenderer::BeginFrame() { if (m_presenter.GetSwapChain() == nullptr) { m_lastError = "BeginFrame requires an initialized swap chain."; return false; } m_activeBackBufferIndex = m_presenter.GetCurrentBackBufferIndex(); if (!m_hostDevice.BeginFrame(m_activeBackBufferIndex)) { m_lastError = m_hostDevice.GetLastError(); return false; } m_lastError.clear(); return true; } bool D3D12WindowRenderer::PreparePresentSurface() { ::XCEngine::Rendering::RenderContext renderContext = GetRenderContext(); if (!renderContext.IsValid() || renderContext.commandList == nullptr) { m_lastError = "PreparePresentSurface requires a valid render context."; return false; } const bool prepared = m_presenter.PreparePresentSurface(renderContext); m_lastError = prepared ? std::string() : m_presenter.GetLastError(); return prepared; } bool D3D12WindowRenderer::SubmitFrame(bool presentSwapChain) { if (presentSwapChain && m_presenter.GetSwapChain() == nullptr) { m_lastError = "SubmitFrame requested present without a swap chain."; return false; } if (!m_hostDevice.SubmitFrame(m_activeBackBufferIndex)) { m_lastError = m_hostDevice.GetLastError(); return false; } if (presentSwapChain) { if (!m_presenter.PresentFrame()) { m_lastError = m_presenter.GetLastError(); return false; } } m_lastError.clear(); return true; } bool D3D12WindowRenderer::SignalFrameCompletion() { if (!m_hostDevice.SignalFrameCompletion(m_activeBackBufferIndex)) { m_lastError = m_hostDevice.GetLastError(); return false; } m_lastError.clear(); return true; } bool D3D12WindowRenderer::PresentFrame() { const bool presented = m_presenter.PresentFrame(); m_lastError = presented ? std::string() : m_presenter.GetLastError(); return presented; } ID3D12Device* D3D12WindowRenderer::GetDevice() const { return m_hostDevice.GetDevice(); } ID3D12CommandQueue* D3D12WindowRenderer::GetCommandQueue() const { return m_hostDevice.GetCommandQueue(); } const std::string& D3D12WindowRenderer::GetLastError() const { return m_lastError; } RHIDevice* D3D12WindowRenderer::GetRHIDevice() const { return m_hostDevice.GetRHIDevice(); } bool D3D12WindowRenderer::CreateViewportTextureHandle( ::XCEngine::RHI::RHITexture& texture, std::uint32_t width, std::uint32_t height, ::XCEngine::UI::UITextureHandle& outTexture) { outTexture = {}; if (width == 0u || height == 0u || !m_viewportTextureAllocator.IsInitialized()) { return false; } D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = {}; D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = {}; if (!m_viewportTextureAllocator.CreateTextureDescriptor( &texture, &cpuHandle, &gpuHandle) || cpuHandle.ptr == 0u || gpuHandle.ptr == 0u) { return false; } outTexture.nativeHandle = static_cast(gpuHandle.ptr); outTexture.width = width; outTexture.height = height; outTexture.kind = ::XCEngine::UI::UITextureHandleKind::ShaderResourceView; outTexture.resourceHandle = reinterpret_cast(&texture); m_viewportTextureCpuHandles[outTexture.nativeHandle] = cpuHandle; return true; } void D3D12WindowRenderer::ReleaseViewportTextureHandle( ::XCEngine::UI::UITextureHandle& texture) { if (!texture.IsValid()) { texture = {}; return; } const auto found = m_viewportTextureCpuHandles.find(texture.nativeHandle); if (found != m_viewportTextureCpuHandles.end()) { D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = {}; gpuHandle.ptr = static_cast(texture.nativeHandle); m_viewportTextureAllocator.Free(found->second, gpuHandle); m_viewportTextureCpuHandles.erase(found); } texture = {}; } RHISwapChain* D3D12WindowRenderer::GetSwapChain() const { return m_presenter.GetSwapChain(); } const ::XCEngine::Rendering::RenderSurface* D3D12WindowRenderer::GetCurrentRenderSurface() const { return m_presenter.GetCurrentRenderSurface(); } const D3D12Texture* D3D12WindowRenderer::GetCurrentBackBufferTexture() const { return m_presenter.GetCurrentBackBufferTexture(); } const D3D12Texture* D3D12WindowRenderer::GetBackBufferTexture(std::uint32_t index) const { return m_presenter.GetBackBufferTexture(index); } std::uint32_t D3D12WindowRenderer::GetBackBufferCount() const { return m_presenter.GetBackBufferCount(); } ::XCEngine::Rendering::RenderContext D3D12WindowRenderer::GetRenderContext() const { return m_hostDevice.GetRenderContext(m_activeBackBufferIndex); } } // namespace XCEngine::UI::Editor::Host