Refactor new editor host orchestration

This commit is contained in:
2026-04-13 19:37:10 +08:00
parent d2140bf5cc
commit f3fc34898a
9 changed files with 648 additions and 223 deletions

View File

@@ -2,57 +2,115 @@
namespace XCEngine::UI::Editor::Host {
bool RenderD3D12WindowFrame(
D3D12WindowRenderer& windowRenderer,
const float clearColor[4],
const D3D12WindowRenderCallback& beforePresent,
const D3D12WindowRenderCallback& afterPresent) {
const ::XCEngine::Rendering::RenderSurface* renderSurface =
windowRenderer.GetCurrentRenderSurface();
::XCEngine::Rendering::RenderContext renderContext =
windowRenderer.GetRenderContext();
if (!renderContext.IsValid() ||
renderContext.commandList == nullptr ||
renderContext.commandQueue == nullptr ||
windowRenderer.GetSwapChain() == nullptr ||
renderSurface == nullptr) {
return false;
D3D12WindowRenderLoopAttachResult D3D12WindowRenderLoop::Attach(
NativeRenderer& uiRenderer,
D3D12WindowRenderer& windowRenderer) {
m_uiRenderer = &uiRenderer;
m_windowRenderer = &windowRenderer;
D3D12WindowRenderLoopAttachResult result = {};
result.hasViewportSurfacePresentation = m_uiRenderer->AttachWindowRenderer(*m_windowRenderer);
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;
}
return result;
}
void D3D12WindowRenderLoop::Detach() {
if (m_uiRenderer != nullptr) {
m_uiRenderer->DetachWindowRenderer();
}
auto* d3d12CommandList =
static_cast<::XCEngine::RHI::D3D12CommandList*>(renderContext.commandList);
if (d3d12CommandList == nullptr) {
return false;
m_uiRenderer = nullptr;
m_windowRenderer = nullptr;
}
D3D12WindowRenderLoopFrameContext D3D12WindowRenderLoop::BeginFrame() const {
D3D12WindowRenderLoopFrameContext context = {};
if (!HasViewportSurfacePresentation()) {
return context;
}
const auto& colorAttachments = renderSurface->GetColorAttachments();
if (colorAttachments.empty() || colorAttachments[0] == nullptr) {
return false;
if (!m_windowRenderer->BeginFrame()) {
const std::string& frameError = m_windowRenderer->GetLastError();
context.warning = frameError.empty()
? "d3d12 frame begin failed"
: "d3d12 frame begin failed: " + frameError;
return context;
}
::XCEngine::RHI::RHIResourceView* renderTargetView = colorAttachments[0];
renderContext.commandList->TransitionBarrier(
renderTargetView,
::XCEngine::RHI::ResourceStates::Present,
::XCEngine::RHI::ResourceStates::RenderTarget);
renderContext.commandList->SetRenderTargets(1, &renderTargetView, nullptr);
renderContext.commandList->ClearRenderTarget(renderTargetView, clearColor);
context.canRenderViewports = true;
context.renderContext = m_windowRenderer->GetRenderContext();
return context;
}
if (beforePresent) {
beforePresent(renderContext, *renderSurface);
renderContext.commandList->SetRenderTargets(1, &renderTargetView, nullptr);
D3D12WindowRenderLoopResizeResult D3D12WindowRenderLoop::ApplyResize(UINT width, UINT height) {
D3D12WindowRenderLoopResizeResult result = {};
if (m_uiRenderer == nullptr || m_windowRenderer == nullptr) {
result.interopWarning = "window render loop is detached.";
return result;
}
if (afterPresent) {
afterPresent(renderContext, *renderSurface);
renderContext.commandList->SetRenderTargets(1, &renderTargetView, nullptr);
m_uiRenderer->Resize(width, height);
m_uiRenderer->DetachWindowRenderer();
const bool resizedWindowRenderer =
m_windowRenderer->Resize(static_cast<int>(width), static_cast<int>(height));
if (!resizedWindowRenderer || !m_windowRenderer->GetLastError().empty()) {
const std::string& resizeError = m_windowRenderer->GetLastError();
result.windowRendererWarning = resizeError.empty()
? "window renderer resize warning."
: "window renderer resize warning: " + resizeError;
}
renderContext.commandList->TransitionBarrier(
renderTargetView,
::XCEngine::RHI::ResourceStates::RenderTarget,
::XCEngine::RHI::ResourceStates::Present);
return windowRenderer.SubmitFrame(true);
if (!resizedWindowRenderer) {
return result;
}
const D3D12WindowRenderLoopAttachResult attachResult =
Attach(*m_uiRenderer, *m_windowRenderer);
result.hasViewportSurfacePresentation = attachResult.hasViewportSurfacePresentation;
result.interopWarning = attachResult.interopWarning;
return result;
}
D3D12WindowRenderLoopPresentResult D3D12WindowRenderLoop::Present(
const ::XCEngine::UI::UIDrawData& drawData) const {
D3D12WindowRenderLoopPresentResult result = {};
if (m_uiRenderer == nullptr) {
result.warning = "window render loop has no ui renderer.";
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 (!result.framePresented) {
result.framePresented = m_uiRenderer->Render(drawData);
if (!result.framePresented && result.warning.empty()) {
result.warning = m_uiRenderer->GetLastRenderError();
}
}
return result;
}
bool D3D12WindowRenderLoop::HasViewportSurfacePresentation() const {
return m_uiRenderer != nullptr &&
m_windowRenderer != nullptr &&
m_uiRenderer->HasAttachedWindowRenderer();
}
} // namespace XCEngine::UI::Editor::Host