checkpoint(new_editor): native d3d12 ui path

Key node 1: move main-window UI presentation onto the D3D12 render loop with native UI renderer, text system, and texture host.

Key node 2: wire frame timing/FPS display, window runtime, swapchain presentation, and native screenshot capture around the new path.

Key node 3: carry editor shell/workspace/viewport/panel interaction updates needed by the new renderer and detached window flow.

Key node 4: pump async resource loads and scene bridge follow-up needed for scene content visibility in new_editor.
This commit is contained in:
2026-04-21 20:49:18 +08:00
parent a779b04dba
commit 6e9265e92e
53 changed files with 5330 additions and 858 deletions

View File

@@ -3,28 +3,22 @@
namespace XCEngine::UI::Editor::Host {
D3D12WindowRenderLoopAttachResult D3D12WindowRenderLoop::Attach(
NativeRenderer& uiRenderer,
D3D12UiRenderer& uiRenderer,
D3D12WindowRenderer& windowRenderer) {
m_uiRenderer = &uiRenderer;
m_windowRenderer = &windowRenderer;
D3D12WindowRenderLoopAttachResult result = {};
result.hasViewportSurfacePresentation = m_uiRenderer->AttachWindowRenderer(*m_windowRenderer);
result.hasViewportSurfacePresentation =
m_windowRenderer->GetSwapChain() != nullptr &&
m_windowRenderer->GetRHIDevice() != nullptr;
if (!result.hasViewportSurfacePresentation) {
const std::string& interopError = m_uiRenderer->GetLastRenderError();
result.interopWarning = interopError.empty()
? "native renderer d3d12 interop unavailable; falling back to hwnd renderer."
: "native renderer d3d12 interop unavailable; falling back to hwnd renderer: " +
interopError;
result.warning = "window render loop attach requires an initialized D3D12 window renderer.";
}
return result;
}
void D3D12WindowRenderLoop::Detach() {
if (m_uiRenderer != nullptr) {
m_uiRenderer->DetachWindowRenderer();
}
m_uiRenderer = nullptr;
m_windowRenderer = nullptr;
}
@@ -51,16 +45,10 @@ D3D12WindowRenderLoopFrameContext D3D12WindowRenderLoop::BeginFrame() const {
D3D12WindowRenderLoopResizeResult D3D12WindowRenderLoop::ApplyResize(UINT width, UINT height) {
D3D12WindowRenderLoopResizeResult result = {};
if (m_uiRenderer == nullptr || m_windowRenderer == nullptr) {
result.interopWarning = "window render loop is detached.";
result.windowRendererWarning = "window render loop is detached.";
return result;
}
m_uiRenderer->Resize(width, height);
const bool hadViewportSurfacePresentation = m_uiRenderer->HasAttachedWindowRenderer();
if (hadViewportSurfacePresentation) {
m_uiRenderer->ReleaseWindowRendererBackBufferTargets();
}
const bool resizedWindowRenderer =
m_windowRenderer->Resize(static_cast<int>(width), static_cast<int>(height));
if (!resizedWindowRenderer || !m_windowRenderer->GetLastError().empty()) {
@@ -70,36 +58,10 @@ D3D12WindowRenderLoopResizeResult D3D12WindowRenderLoop::ApplyResize(UINT width,
: "window renderer resize warning: " + resizeError;
}
if (!resizedWindowRenderer) {
if (hadViewportSurfacePresentation) {
result.hasViewportSurfacePresentation =
m_uiRenderer->RebuildWindowRendererBackBufferTargets();
if (!result.hasViewportSurfacePresentation) {
const D3D12WindowRenderLoopAttachResult attachResult =
Attach(*m_uiRenderer, *m_windowRenderer);
result.hasViewportSurfacePresentation = attachResult.hasViewportSurfacePresentation;
result.interopWarning = attachResult.interopWarning;
}
}
return result;
}
if (hadViewportSurfacePresentation) {
result.hasViewportSurfacePresentation =
m_uiRenderer->RebuildWindowRendererBackBufferTargets();
if (!result.hasViewportSurfacePresentation) {
const D3D12WindowRenderLoopAttachResult attachResult =
Attach(*m_uiRenderer, *m_windowRenderer);
result.hasViewportSurfacePresentation = attachResult.hasViewportSurfacePresentation;
result.interopWarning = attachResult.interopWarning;
}
return result;
}
const D3D12WindowRenderLoopAttachResult attachResult =
Attach(*m_uiRenderer, *m_windowRenderer);
result.hasViewportSurfacePresentation = attachResult.hasViewportSurfacePresentation;
result.interopWarning = attachResult.interopWarning;
result.hasViewportSurfacePresentation =
resizedWindowRenderer &&
m_windowRenderer->GetSwapChain() != nullptr &&
m_windowRenderer->GetCurrentRenderSurface() != nullptr;
return result;
}
@@ -111,31 +73,77 @@ D3D12WindowRenderLoopPresentResult D3D12WindowRenderLoop::Present(
return result;
}
if (HasViewportSurfacePresentation()) {
result.framePresented = m_uiRenderer->RenderToWindowRenderer(drawData);
if (!result.framePresented) {
const std::string& composeError = m_uiRenderer->GetLastRenderError();
result.warning = composeError.empty()
? "d3d12 window composition failed, falling back to hwnd renderer."
: "d3d12 window composition failed, falling back to hwnd renderer: " +
composeError;
}
if (!HasViewportSurfacePresentation()) {
result.warning = "window render loop has no active D3D12 presentation path.";
return result;
}
if (!result.framePresented) {
result.framePresented = m_uiRenderer->Render(drawData);
if (!result.framePresented && result.warning.empty()) {
result.warning = m_uiRenderer->GetLastRenderError();
}
if (!m_windowRenderer->PrepareCurrentBackBufferForUiRender()) {
const std::string& error = m_windowRenderer->GetLastError();
result.warning = error.empty()
? "failed to prepare the current back buffer for UI rendering."
: error;
return result;
}
const ::XCEngine::Rendering::RenderContext renderContext =
m_windowRenderer->GetRenderContext();
const ::XCEngine::Rendering::RenderSurface* surface =
m_windowRenderer->GetCurrentRenderSurface();
if (surface == nullptr) {
result.warning = "window render loop could not resolve the current back buffer surface.";
return result;
}
if (!m_uiRenderer->Render(drawData, renderContext, *surface)) {
const std::string& error = m_uiRenderer->GetLastError();
result.warning = error.empty()
? "d3d12 ui renderer failed to render the current frame."
: error;
return result;
}
if (!m_windowRenderer->FinalizeCurrentBackBufferForPresent()) {
const std::string& error = m_windowRenderer->GetLastError();
result.warning = error.empty()
? "failed to finalize the current back buffer for present."
: error;
return result;
}
if (!m_windowRenderer->SubmitFrame()) {
const std::string& error = m_windowRenderer->GetLastError();
result.warning = error.empty()
? "failed to submit the current D3D12 frame."
: error;
return result;
}
if (!m_windowRenderer->SignalFrameCompletion()) {
const std::string& error = m_windowRenderer->GetLastError();
result.warning = error.empty()
? "failed to signal current frame completion."
: error;
return result;
}
if (!m_windowRenderer->PresentFrame()) {
const std::string& error = m_windowRenderer->GetLastError();
result.warning = error.empty()
? "failed to present the swap chain."
: error;
return result;
}
result.framePresented = true;
return result;
}
bool D3D12WindowRenderLoop::HasViewportSurfacePresentation() const {
return m_uiRenderer != nullptr &&
m_windowRenderer != nullptr &&
m_uiRenderer->HasAttachedWindowRenderer();
m_windowRenderer->GetSwapChain() != nullptr &&
m_windowRenderer->GetCurrentRenderSurface() != nullptr;
}
} // namespace XCEngine::UI::Editor::Host