Decouple editor windowing from D3D12 runtime

This commit is contained in:
2026-04-26 18:54:43 +08:00
parent 244bdd78c2
commit 60b2949de2
14 changed files with 456 additions and 117 deletions

View File

@@ -15,8 +15,6 @@
#include <string_view>
#include <utility>
#include <windows.h>
namespace XCEngine::UI::Editor::App {
using App::LoadEmbeddedPngTexture;
@@ -35,14 +33,16 @@ void LogRuntimeTrace(std::string_view channel, std::string_view message) {
EditorWindowRuntimeController::EditorWindowRuntimeController(
EditorContext& editorContext,
std::unique_ptr<EditorWindowContentController> contentController)
std::unique_ptr<EditorWindowContentController> contentController,
std::unique_ptr<Rendering::Host::EditorWindowRenderRuntime> renderRuntime)
: m_editorContext(editorContext)
, m_renderRuntime(std::move(renderRuntime))
, m_contentController(std::move(contentController)) {}
EditorWindowRuntimeController::~EditorWindowRuntimeController() = default;
bool EditorWindowRuntimeController::IsReady() const {
return m_ready;
return m_ready && m_renderRuntime != nullptr && m_renderRuntime->IsReady();
}
EditorWindowContentCapabilities EditorWindowRuntimeController::GetCapabilities() const {
@@ -106,17 +106,20 @@ const UIEditorShellInteractionState& EditorWindowRuntimeController::GetShellInte
void EditorWindowRuntimeController::SetDpiScale(float dpiScale) {
m_dpiScale = dpiScale > 0.0f ? dpiScale : 1.0f;
m_textSystem.SetDpiScale(m_dpiScale);
m_uiRenderer.SetDpiScale(m_dpiScale);
if (m_renderRuntime != nullptr) {
m_renderRuntime->SetDpiScale(m_dpiScale);
}
}
::XCEngine::UI::Editor::UIEditorTextMeasurer& EditorWindowRuntimeController::GetTextMeasurer() {
return m_textSystem;
assert(m_renderRuntime != nullptr);
return m_renderRuntime->GetTextMeasurer();
}
const ::XCEngine::UI::Editor::UIEditorTextMeasurer&
EditorWindowRuntimeController::GetTextMeasurer() const {
return m_textSystem;
assert(m_renderRuntime != nullptr);
return m_renderRuntime->GetTextMeasurer();
}
const ::XCEngine::UI::UITextureHandle& EditorWindowRuntimeController::GetTitleBarLogoIcon() const {
@@ -124,69 +127,44 @@ const ::XCEngine::UI::UITextureHandle& EditorWindowRuntimeController::GetTitleBa
}
bool EditorWindowRuntimeController::Initialize(
void* nativeWindowHandle,
const Rendering::Host::EditorWindowRenderRuntimeSurface& renderSurface,
const std::filesystem::path& repoRoot,
const std::filesystem::path& captureRoot,
bool autoCaptureOnStartup) {
HWND hwnd = static_cast<HWND>(nativeWindowHandle);
if (hwnd == nullptr) {
LogRuntimeTrace("app", "window initialize skipped: hwnd is null");
if (m_renderRuntime == nullptr) {
LogRuntimeTrace("app", "window initialize failed: render runtime is null");
return false;
}
RECT clientRect = {};
GetClientRect(hwnd, &clientRect);
const int clientWidth = (std::max)(clientRect.right - clientRect.left, 1L);
const int clientHeight = (std::max)(clientRect.bottom - clientRect.top, 1L);
if (!m_windowRenderer.Initialize(hwnd, clientWidth, clientHeight)) {
LogRuntimeTrace("app", "d3d12 window renderer initialization failed");
const Rendering::Host::EditorWindowRenderRuntimeInitializeResult initializeResult =
m_renderRuntime->Initialize(renderSurface);
if (!initializeResult.success) {
LogRuntimeTrace("app", initializeResult.errorMessage.empty()
? "window render runtime initialization failed"
: initializeResult.errorMessage);
return false;
}
if (!m_textureHost.Initialize(m_windowRenderer)) {
LogRuntimeTrace("app", "d3d12 ui texture host initialization failed");
m_windowRenderer.Shutdown();
return false;
}
if (!m_textSystem.Initialize()) {
LogRuntimeTrace("app", "d3d12 ui text system initialization failed");
m_textureHost.Shutdown();
m_windowRenderer.Shutdown();
return false;
}
m_textSystem.SetDpiScale(m_dpiScale);
if (!m_uiRenderer.Initialize(m_windowRenderer, m_textureHost, m_textSystem)) {
LogRuntimeTrace("app", "d3d12 ui renderer initialization failed");
m_textSystem.Shutdown();
m_textureHost.Shutdown();
m_windowRenderer.Shutdown();
return false;
}
m_uiRenderer.SetDpiScale(m_dpiScale);
const Host::D3D12WindowRenderLoopAttachResult attachResult =
m_windowRenderLoop.Attach(m_uiRenderer, m_windowRenderer);
if (!attachResult.warning.empty()) {
LogRuntimeTrace("app", attachResult.warning);
if (!initializeResult.warning.empty()) {
LogRuntimeTrace("app", initializeResult.warning);
}
assert(m_contentController != nullptr);
m_contentController->PrepareEditorContext(m_editorContext, m_textSystem);
m_contentController->PrepareEditorContext(
m_editorContext,
m_renderRuntime->GetTextMeasurer());
m_contentController->Initialize(EditorWindowContentInitializationContext{
.repoRoot = repoRoot,
.editorContext = m_editorContext,
.textureHost = m_textureHost,
.textMeasurer = m_textSystem,
.viewportRenderer = m_windowRenderer,
.textureHost = m_renderRuntime->GetTextureHost(),
.textMeasurer = m_renderRuntime->GetTextMeasurer(),
.viewportRenderer = m_renderRuntime->GetViewportRenderHost(),
});
m_contentController->SetViewportSurfacePresentationEnabled(
attachResult.hasViewportSurfacePresentation);
initializeResult.hasViewportSurfacePresentation);
std::string titleBarLogoError = {};
if (!LoadEmbeddedPngTexture(
m_textureHost,
m_renderRuntime->GetTextureHost(),
IDR_PNG_LOGO_ICON,
m_titleBarLogoIcon,
titleBarLogoError)) {
@@ -218,7 +196,9 @@ void EditorWindowRuntimeController::Shutdown() {
m_ready = false;
ResetFrameTiming();
LogRuntimeTrace("window-close", "EditorWindowRuntimeController::Shutdown stage=WaitForGpuIdle");
m_windowRenderer.WaitForGpuIdle();
if (m_renderRuntime != nullptr) {
m_renderRuntime->WaitForGpuIdle();
}
LogRuntimeTrace(
"window-close",
"EditorWindowRuntimeController::Shutdown stage=ScreenshotController");
@@ -227,18 +207,12 @@ void EditorWindowRuntimeController::Shutdown() {
if (m_contentController != nullptr) {
m_contentController->Shutdown();
}
LogRuntimeTrace("window-close", "EditorWindowRuntimeController::Shutdown stage=RenderLoopDetach");
m_windowRenderLoop.Detach();
LogRuntimeTrace("window-close", "EditorWindowRuntimeController::Shutdown stage=UiRenderer");
m_uiRenderer.Shutdown();
LogRuntimeTrace("window-close", "EditorWindowRuntimeController::Shutdown stage=TextSystem");
m_textSystem.Shutdown();
LogRuntimeTrace("window-close", "EditorWindowRuntimeController::Shutdown stage=TitleBarLogo");
m_textureHost.ReleaseTexture(m_titleBarLogoIcon);
LogRuntimeTrace("window-close", "EditorWindowRuntimeController::Shutdown stage=TextureHost");
m_textureHost.Shutdown();
LogRuntimeTrace("window-close", "EditorWindowRuntimeController::Shutdown stage=WindowRenderer");
m_windowRenderer.Shutdown();
if (m_renderRuntime != nullptr) {
m_renderRuntime->GetTextureHost().ReleaseTexture(m_titleBarLogoIcon);
LogRuntimeTrace("window-close", "EditorWindowRuntimeController::Shutdown stage=RenderRuntime");
m_renderRuntime->Shutdown();
}
m_dpiScale = 1.0f;
LogRuntimeTrace("window-close", "EditorWindowRuntimeController::Shutdown end");
}
@@ -251,27 +225,29 @@ void EditorWindowRuntimeController::ResetInteractionState() {
}
bool EditorWindowRuntimeController::ApplyResize(std::uint32_t width, std::uint32_t height) {
if (!m_ready || width == 0u || height == 0u) {
if (!IsReady() || width == 0u || height == 0u) {
return false;
}
const Host::D3D12WindowRenderLoopResizeResult resizeResult =
m_windowRenderLoop.ApplyResize(width, height);
const Rendering::Host::EditorWindowRenderRuntimeResizeResult resizeResult =
m_renderRuntime->ApplyResize(width, height);
if (m_contentController != nullptr) {
m_contentController->SetViewportSurfacePresentationEnabled(
resizeResult.hasViewportSurfacePresentation);
}
if (!resizeResult.windowRendererWarning.empty()) {
LogRuntimeTrace("present", resizeResult.windowRendererWarning);
if (!resizeResult.warning.empty()) {
LogRuntimeTrace("present", resizeResult.warning);
}
return resizeResult.hasViewportSurfacePresentation;
}
void EditorWindowRuntimeController::PrepareEditorContext() {
if (m_contentController != nullptr) {
m_contentController->PrepareEditorContext(m_editorContext, m_textSystem);
if (m_contentController != nullptr && m_renderRuntime != nullptr) {
m_contentController->PrepareEditorContext(
m_editorContext,
m_renderRuntime->GetTextMeasurer());
}
}
@@ -287,18 +263,26 @@ void EditorWindowRuntimeController::AppendInvalidFrame(
}
}
Host::D3D12WindowRenderLoopFrameContext EditorWindowRuntimeController::BeginFrame() {
Rendering::Host::EditorWindowRenderRuntimeFrameContext EditorWindowRuntimeController::BeginFrame() {
UpdateFrameTiming();
return m_windowRenderLoop.BeginFrame();
return m_renderRuntime != nullptr
? m_renderRuntime->BeginFrame()
: Rendering::Host::EditorWindowRenderRuntimeFrameContext{};
}
Host::D3D12WindowRenderLoopPresentResult EditorWindowRuntimeController::Present(
Rendering::Host::EditorWindowRenderRuntimePresentResult EditorWindowRuntimeController::Present(
const ::XCEngine::UI::UIDrawData& drawData) {
if (m_renderRuntime == nullptr) {
Rendering::Host::EditorWindowRenderRuntimePresentResult result = {};
result.warning = "window render runtime is null.";
return result;
}
std::filesystem::path capturePath = {};
const bool captureRequested = m_screenshotController.TryBeginCapture(capturePath);
Host::D3D12WindowRenderLoopPresentResult result =
m_windowRenderLoop.Present(
Rendering::Host::EditorWindowRenderRuntimePresentResult result =
m_renderRuntime->Present(
drawData,
captureRequested ? &capturePath : nullptr);
@@ -306,7 +290,7 @@ Host::D3D12WindowRenderLoopPresentResult EditorWindowRuntimeController::Present(
const bool captureSucceeded = result.framePresented && result.captureSucceeded;
if (captureSucceeded) {
m_screenshotController.CompleteCaptureSuccess(capturePath);
LogRuntimeTrace("capture", "native d3d12 capture succeeded: " + capturePath.string());
LogRuntimeTrace("capture", "native capture succeeded: " + capturePath.string());
} else {
std::string captureError = result.captureError;
if (captureError.empty()) {
@@ -317,7 +301,7 @@ Host::D3D12WindowRenderLoopPresentResult EditorWindowRuntimeController::Present(
m_screenshotController.CompleteCaptureFailure(std::move(captureError));
LogRuntimeTrace(
"capture",
"native d3d12 capture failed: " + m_screenshotController.GetLastCaptureError());
"native capture failed: " + m_screenshotController.GetLastCaptureError());
}
}