Decouple editor windowing from D3D12 runtime
This commit is contained in:
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user