diff --git a/new_editor/CMakeLists.txt b/new_editor/CMakeLists.txt index 27af0914..a6e614c0 100644 --- a/new_editor/CMakeLists.txt +++ b/new_editor/CMakeLists.txt @@ -179,10 +179,12 @@ set(XCUI_EDITOR_HOST_RENDERING_SOURCES app/Rendering/Native/NativeRendererCapture.cpp app/Rendering/Native/NativeRendererDraw.cpp app/Rendering/Native/NativeRendererLifecycle.cpp + app/Rendering/Native/NativeRendererRenderTarget.cpp app/Rendering/Native/NativeRendererRendering.cpp app/Rendering/Native/NativeRendererText.cpp app/Rendering/Native/NativeRendererTextureDecoding.cpp app/Rendering/Native/NativeRendererTextures.cpp + app/Rendering/Native/NativeRendererWindowInterop.cpp ) add_library(XCUIEditorHost STATIC diff --git a/new_editor/app/Rendering/Native/NativeRendererLifecycle.cpp b/new_editor/app/Rendering/Native/NativeRendererLifecycle.cpp index 8744e0ca..197bfa2d 100644 --- a/new_editor/app/Rendering/Native/NativeRendererLifecycle.cpp +++ b/new_editor/app/Rendering/Native/NativeRendererLifecycle.cpp @@ -73,95 +73,10 @@ float NativeRenderer::GetDpiScale() const { return m_dpiScale; } -void NativeRenderer::Resize(UINT width, UINT height) { - if (!m_renderTarget || width == 0 || height == 0) { - return; - } - - const HRESULT hr = m_renderTarget->Resize(D2D1::SizeU(width, height)); - if (hr == D2DERR_RECREATE_TARGET) { - DiscardRenderTarget(); - } -} - -bool NativeRenderer::AttachWindowRenderer(D3D12WindowRenderer& windowRenderer) { - if (m_windowRenderer != &windowRenderer) { - ReleaseWindowRendererInterop(); - m_windowRenderer = &windowRenderer; - } - - if (!EnsureWindowRendererInterop()) { - return false; - } - - DiscardRenderTarget(); - - if (m_windowInterop.HasBackBufferTargets()) { - return true; - } - - return m_windowInterop.RebuildBackBufferTargets(); -} - -void NativeRenderer::DetachWindowRenderer() { - ReleaseWindowRendererInterop(); - m_windowRenderer = nullptr; -} - -void NativeRenderer::ReleaseWindowRendererBackBufferTargets() { - m_windowInterop.ReleaseBackBufferTargets(); -} - -bool NativeRenderer::RebuildWindowRendererBackBufferTargets() { - if (!EnsureWindowRendererInterop()) { - return false; - } - - DiscardRenderTarget(); - ReleaseWindowRendererBackBufferTargets(); - return m_windowInterop.RebuildBackBufferTargets(); -} - -bool NativeRenderer::HasAttachedWindowRenderer() const { - return m_windowInterop.HasAttachedWindowRenderer(); -} - const std::string& NativeRenderer::GetLastRenderError() const { return m_lastRenderError; } -bool NativeRenderer::EnsureWindowRendererInterop() { - if (m_windowRenderer == nullptr) { - m_lastRenderError = "EnsureWindowRendererInterop requires an attached D3D12 window renderer."; - return false; - } - if (m_d2dFactory == nullptr || m_dwriteFactory == nullptr) { - m_lastRenderError = "EnsureWindowRendererInterop requires initialized D2D and DWrite factories."; - return false; - } - - const bool attached = m_windowInterop.Attach(*m_windowRenderer, *m_d2dFactory.Get()); - if (!attached) { - m_lastRenderError = m_windowInterop.GetLastError(); - } else { - m_lastRenderError.clear(); - } - return attached; -} - -void NativeRenderer::ReleaseWindowRendererInterop() { - m_windowInterop.Detach(); -} - -bool NativeRenderer::EnsureRenderTarget() { - if (!m_hwnd || !m_d2dFactory || !m_dwriteFactory) { - m_lastRenderError = "EnsureRenderTarget requires hwnd, D2D factory, and DWrite factory."; - return false; - } - - return CreateDeviceResources(); -} - bool NativeRenderer::EnsureWicFactory(std::string& outError) { outError.clear(); if (m_wicFactory) { @@ -190,66 +105,4 @@ bool NativeRenderer::EnsureWicFactory(std::string& outError) { return true; } -void NativeRenderer::DiscardRenderTarget() { - InvalidateCachedTextureBitmaps(m_renderTarget.Get()); - m_solidBrush.Reset(); - m_renderTarget.Reset(); -} - -bool NativeRenderer::CreateDeviceResources() { - if (m_renderTarget) { - return true; - } - - RECT clientRect = {}; - GetClientRect(m_hwnd, &clientRect); - const UINT width = static_cast((std::max)(clientRect.right - clientRect.left, 1L)); - const UINT height = static_cast((std::max)(clientRect.bottom - clientRect.top, 1L)); - - const D2D1_RENDER_TARGET_PROPERTIES renderTargetProps = D2D1::RenderTargetProperties( - D2D1_RENDER_TARGET_TYPE_DEFAULT, - D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), - kBaseDpi, - kBaseDpi); - const D2D1_HWND_RENDER_TARGET_PROPERTIES hwndProps = D2D1::HwndRenderTargetProperties( - m_hwnd, - D2D1::SizeU(width, height)); - - const HRESULT renderTargetHr = m_d2dFactory->CreateHwndRenderTarget( - renderTargetProps, - hwndProps, - m_renderTarget.ReleaseAndGetAddressOf()); - if (FAILED(renderTargetHr)) { - m_lastRenderError = HrToString("ID2D1Factory::CreateHwndRenderTarget", renderTargetHr); - return false; - } - - const HRESULT brushHr = m_renderTarget->CreateSolidColorBrush( - D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), - m_solidBrush.ReleaseAndGetAddressOf()); - if (FAILED(brushHr)) { - m_lastRenderError = HrToString("ID2D1HwndRenderTarget::CreateSolidColorBrush", brushHr); - DiscardRenderTarget(); - return false; - } - - m_renderTarget->SetDpi(kBaseDpi, kBaseDpi); - m_renderTarget->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE); - m_lastRenderError.clear(); - return true; -} - -void NativeRenderer::InvalidateCachedTextureBitmaps(const ID2D1RenderTarget* renderTarget) { - for (NativeTextureResource* texture : m_liveTextures) { - if (texture == nullptr) { - continue; - } - - if (renderTarget == nullptr || texture->cachedTarget == renderTarget) { - texture->cachedBitmap.Reset(); - texture->cachedTarget = nullptr; - } - } -} - } // namespace XCEngine::UI::Editor::Host diff --git a/new_editor/app/Rendering/Native/NativeRendererRenderTarget.cpp b/new_editor/app/Rendering/Native/NativeRendererRenderTarget.cpp new file mode 100644 index 00000000..0597e7b7 --- /dev/null +++ b/new_editor/app/Rendering/Native/NativeRendererRenderTarget.cpp @@ -0,0 +1,89 @@ +#include "NativeRendererSupport.h" + +namespace XCEngine::UI::Editor::Host { + +using namespace NativeRendererSupport; + +void NativeRenderer::Resize(UINT width, UINT height) { + if (!m_renderTarget || width == 0 || height == 0) { + return; + } + + const HRESULT hr = m_renderTarget->Resize(D2D1::SizeU(width, height)); + if (hr == D2DERR_RECREATE_TARGET) { + DiscardRenderTarget(); + } +} + +bool NativeRenderer::EnsureRenderTarget() { + if (!m_hwnd || !m_d2dFactory || !m_dwriteFactory) { + m_lastRenderError = "EnsureRenderTarget requires hwnd, D2D factory, and DWrite factory."; + return false; + } + + return CreateDeviceResources(); +} + +void NativeRenderer::DiscardRenderTarget() { + InvalidateCachedTextureBitmaps(m_renderTarget.Get()); + m_solidBrush.Reset(); + m_renderTarget.Reset(); +} + +bool NativeRenderer::CreateDeviceResources() { + if (m_renderTarget) { + return true; + } + + RECT clientRect = {}; + GetClientRect(m_hwnd, &clientRect); + const UINT width = static_cast((std::max)(clientRect.right - clientRect.left, 1L)); + const UINT height = static_cast((std::max)(clientRect.bottom - clientRect.top, 1L)); + + const D2D1_RENDER_TARGET_PROPERTIES renderTargetProps = D2D1::RenderTargetProperties( + D2D1_RENDER_TARGET_TYPE_DEFAULT, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), + kBaseDpi, + kBaseDpi); + const D2D1_HWND_RENDER_TARGET_PROPERTIES hwndProps = D2D1::HwndRenderTargetProperties( + m_hwnd, + D2D1::SizeU(width, height)); + + const HRESULT renderTargetHr = m_d2dFactory->CreateHwndRenderTarget( + renderTargetProps, + hwndProps, + m_renderTarget.ReleaseAndGetAddressOf()); + if (FAILED(renderTargetHr)) { + m_lastRenderError = HrToString("ID2D1Factory::CreateHwndRenderTarget", renderTargetHr); + return false; + } + + const HRESULT brushHr = m_renderTarget->CreateSolidColorBrush( + D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), + m_solidBrush.ReleaseAndGetAddressOf()); + if (FAILED(brushHr)) { + m_lastRenderError = HrToString("ID2D1HwndRenderTarget::CreateSolidColorBrush", brushHr); + DiscardRenderTarget(); + return false; + } + + m_renderTarget->SetDpi(kBaseDpi, kBaseDpi); + m_renderTarget->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE); + m_lastRenderError.clear(); + return true; +} + +void NativeRenderer::InvalidateCachedTextureBitmaps(const ID2D1RenderTarget* renderTarget) { + for (NativeTextureResource* texture : m_liveTextures) { + if (texture == nullptr) { + continue; + } + + if (renderTarget == nullptr || texture->cachedTarget == renderTarget) { + texture->cachedBitmap.Reset(); + texture->cachedTarget = nullptr; + } + } +} + +} // namespace XCEngine::UI::Editor::Host diff --git a/new_editor/app/Rendering/Native/NativeRendererWindowInterop.cpp b/new_editor/app/Rendering/Native/NativeRendererWindowInterop.cpp new file mode 100644 index 00000000..9b722a7f --- /dev/null +++ b/new_editor/app/Rendering/Native/NativeRendererWindowInterop.cpp @@ -0,0 +1,72 @@ +#include "NativeRendererSupport.h" + +namespace XCEngine::UI::Editor::Host { + +using namespace NativeRendererSupport; + +bool NativeRenderer::AttachWindowRenderer(D3D12WindowRenderer& windowRenderer) { + if (m_windowRenderer != &windowRenderer) { + ReleaseWindowRendererInterop(); + m_windowRenderer = &windowRenderer; + } + + if (!EnsureWindowRendererInterop()) { + return false; + } + + DiscardRenderTarget(); + + if (m_windowInterop.HasBackBufferTargets()) { + return true; + } + + return m_windowInterop.RebuildBackBufferTargets(); +} + +void NativeRenderer::DetachWindowRenderer() { + ReleaseWindowRendererInterop(); + m_windowRenderer = nullptr; +} + +void NativeRenderer::ReleaseWindowRendererBackBufferTargets() { + m_windowInterop.ReleaseBackBufferTargets(); +} + +bool NativeRenderer::RebuildWindowRendererBackBufferTargets() { + if (!EnsureWindowRendererInterop()) { + return false; + } + + DiscardRenderTarget(); + ReleaseWindowRendererBackBufferTargets(); + return m_windowInterop.RebuildBackBufferTargets(); +} + +bool NativeRenderer::HasAttachedWindowRenderer() const { + return m_windowInterop.HasAttachedWindowRenderer(); +} + +bool NativeRenderer::EnsureWindowRendererInterop() { + if (m_windowRenderer == nullptr) { + m_lastRenderError = "EnsureWindowRendererInterop requires an attached D3D12 window renderer."; + return false; + } + if (m_d2dFactory == nullptr || m_dwriteFactory == nullptr) { + m_lastRenderError = "EnsureWindowRendererInterop requires initialized D2D and DWrite factories."; + return false; + } + + const bool attached = m_windowInterop.Attach(*m_windowRenderer, *m_d2dFactory.Get()); + if (!attached) { + m_lastRenderError = m_windowInterop.GetLastError(); + } else { + m_lastRenderError.clear(); + } + return attached; +} + +void NativeRenderer::ReleaseWindowRendererInterop() { + m_windowInterop.Detach(); +} + +} // namespace XCEngine::UI::Editor::Host