Checkpoint current new editor host iteration

This commit is contained in:
2026-04-13 18:52:30 +08:00
parent a0d5e84516
commit d2140bf5cc
11 changed files with 243 additions and 184 deletions

View File

@@ -141,6 +141,7 @@ xcui_editor_apply_common_target_settings(XCUIEditorHost PUBLIC)
target_link_libraries(XCUIEditorHost PUBLIC
XCEngine
d2d1.lib
d3d11.lib
d3d12.lib
d3dcompiler.lib
dwrite.lib

View File

@@ -36,6 +36,7 @@ constexpr const wchar_t* kWindowClassName = L"XCEditorShellHost";
constexpr const wchar_t* kWindowTitle = L"Main Scene * - Main.xx - XCEngine Editor";
constexpr UINT kDefaultDpi = 96u;
constexpr float kBaseDpiScale = 96.0f;
constexpr UINT kDeferredRenderMessage = WM_APP + 1u;
bool ResolveVerboseRuntimeTraceEnabled() {
wchar_t buffer[8] = {};
@@ -541,6 +542,8 @@ void Application::RenderFrame() {
return;
}
ApplyPendingWindowResize();
RECT clientRect = {};
GetClientRect(m_hwnd, &clientRect);
const unsigned int pixelWidth =
@@ -607,7 +610,7 @@ void Application::RenderFrame() {
ApplyHostedContentCaptureRequests();
ApplyCurrentCursor();
m_editorWorkspace.Append(drawList);
if (d3d12FrameBegun && !m_inInteractiveResize) {
if (d3d12FrameBegun) {
m_editorWorkspace.RenderRequestedViewports(m_windowRenderer.GetRenderContext());
}
} else {
@@ -760,36 +763,51 @@ std::string Application::DescribeInputEvents(
}
void Application::OnResize() {
QueueCurrentClientResize();
}
void Application::OnEnterSizeMove() {
m_inInteractiveResize = true;
}
void Application::OnExitSizeMove() {
m_inInteractiveResize = false;
QueueCurrentClientResize();
}
void Application::QueueWindowResize(UINT width, UINT height) {
if (width == 0u || height == 0u) {
return;
}
m_pendingWindowResizeWidth = width;
m_pendingWindowResizeHeight = height;
m_hasPendingWindowResize = true;
}
void Application::QueueCurrentClientResize() {
UINT width = 0u;
UINT height = 0u;
if (!QueryCurrentClientPixelSize(width, height)) {
return;
}
m_renderer.Resize(width, height);
CommitWindowResize();
if (m_inInteractiveResize) {
m_editorWorkspace.SetViewportSurfacePresentationEnabled(false);
QueueWindowResize(width, height);
}
bool Application::ApplyPendingWindowResize() {
if (!m_hasPendingWindowResize) {
return true;
}
}
void Application::OnEnterSizeMove() {
m_inInteractiveResize = true;
m_editorWorkspace.SetViewportSurfacePresentationEnabled(false);
}
void Application::OnExitSizeMove() {
m_inInteractiveResize = false;
CommitWindowResize();
}
bool Application::CommitWindowResize() {
UINT width = 0u;
UINT height = 0u;
if (!QueryCurrentClientPixelSize(width, height)) {
const UINT width = m_pendingWindowResizeWidth;
const UINT height = m_pendingWindowResizeHeight;
m_hasPendingWindowResize = false;
if (width == 0u || height == 0u) {
return false;
}
m_renderer.Resize(width, height);
m_renderer.DetachWindowRenderer();
const bool resizedWindowRenderer =
m_windowRenderer.Resize(static_cast<int>(width), static_cast<int>(height));
@@ -816,6 +834,15 @@ bool Application::CommitWindowResize() {
return hasHealthyD3D12WindowInterop;
}
void Application::RequestDeferredRenderFrame() {
if (m_hwnd == nullptr || !IsWindow(m_hwnd) || m_renderFrameQueued) {
return;
}
m_renderFrameQueued = true;
PostMessageW(m_hwnd, kDeferredRenderMessage, 0, 0);
}
bool Application::QueryCurrentClientPixelSize(UINT& outWidth, UINT& outHeight) const {
outWidth = 0u;
outHeight = 0u;
@@ -844,16 +871,18 @@ void Application::OnDpiChanged(UINT dpi, const RECT& suggestedRect) {
m_dpiScale = GetDpiScale();
m_renderer.SetDpiScale(m_dpiScale);
if (m_hwnd != nullptr) {
const LONG windowWidth = suggestedRect.right - suggestedRect.left;
const LONG windowHeight = suggestedRect.bottom - suggestedRect.top;
SetWindowPos(
m_hwnd,
nullptr,
suggestedRect.left,
suggestedRect.top,
suggestedRect.right - suggestedRect.left,
suggestedRect.bottom - suggestedRect.top,
windowWidth,
windowHeight,
SWP_NOZORDER | SWP_NOACTIVATE);
CommitWindowResize();
InvalidateRect(m_hwnd, nullptr, FALSE);
QueueCurrentClientResize();
RequestDeferredRenderFrame();
}
std::ostringstream trace = {};
@@ -1011,16 +1040,23 @@ LRESULT CALLBACK Application::WndProc(HWND hwnd, UINT message, WPARAM wParam, LP
case WM_EXITSIZEMOVE:
if (application != nullptr) {
application->OnExitSizeMove();
application->RenderFrame();
application->RequestDeferredRenderFrame();
return 0;
}
break;
case WM_SIZE:
if (application != nullptr && wParam != SIZE_MINIMIZED) {
application->OnResize();
application->RenderFrame();
application->RequestDeferredRenderFrame();
}
return 0;
case kDeferredRenderMessage:
if (application != nullptr) {
application->m_renderFrameQueued = false;
application->RenderFrame();
return 0;
}
break;
case WM_PAINT:
if (application != nullptr) {
PAINTSTRUCT paintStruct = {};

View File

@@ -37,8 +37,15 @@ private:
bool Initialize(HINSTANCE hInstance, int nCmdShow);
void Shutdown();
void RenderFrame();
void OnResize(UINT width, UINT height);
void OnResize();
void OnEnterSizeMove();
void OnExitSizeMove();
void OnDpiChanged(UINT dpi, const RECT& suggestedRect);
void QueueWindowResize(UINT width, UINT height);
void QueueCurrentClientResize();
bool ApplyPendingWindowResize();
void RequestDeferredRenderFrame();
bool QueryCurrentClientPixelSize(UINT& outWidth, UINT& outHeight) const;
bool IsPointerInsideClientArea() const;
bool ApplyCurrentCursor() const;
LPCWSTR ResolveCurrentCursorResource() const;
@@ -64,6 +71,7 @@ private:
void QueueWindowFocusEvent(::XCEngine::UI::UIInputEventType type);
static std::filesystem::path ResolveRepoRootPath();
static LONG WINAPI HandleUnhandledException(EXCEPTION_POINTERS* exceptionInfo);
static bool IsVerboseRuntimeTraceEnabled();
HWND m_hwnd = nullptr;
HINSTANCE m_hInstance = nullptr;
@@ -78,6 +86,11 @@ private:
bool m_trackingMouseLeave = false;
UINT m_windowDpi = 96u;
float m_dpiScale = 1.0f;
bool m_inInteractiveResize = false;
bool m_renderFrameQueued = false;
bool m_hasPendingWindowResize = false;
UINT m_pendingWindowResizeWidth = 0u;
UINT m_pendingWindowResizeHeight = 0u;
};
int RunXCUIEditorApp(HINSTANCE hInstance, int nCmdShow);

View File

@@ -22,7 +22,10 @@
#include <d3d12.h>
#include <windows.h>
#include <wrl/client.h>
#include <array>
#include <string>
#include <vector>
namespace XCEngine::UI::Editor::Host {
@@ -34,13 +37,17 @@ public:
bool Initialize(HWND hwnd, int width, int height);
void Shutdown();
void Resize(int width, int height);
bool Resize(int width, int height);
bool BeginFrame();
bool PreparePresentSurface();
bool SubmitFrame(bool presentSwapChain);
bool SignalFrameCompletion();
bool PresentFrame();
ID3D12Device* GetDevice() const;
ID3D12DescriptorHeap* GetSrvHeap() const;
ID3D12CommandQueue* GetCommandQueue() const;
const std::string& GetLastError() const;
void AllocateShaderResourceDescriptor(
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle);
@@ -57,6 +64,9 @@ public:
::XCEngine::RHI::RHIDevice* GetRHIDevice() const;
::XCEngine::RHI::RHISwapChain* GetSwapChain() const;
const ::XCEngine::Rendering::RenderSurface* GetCurrentRenderSurface() const;
const ::XCEngine::RHI::D3D12Texture* GetCurrentBackBufferTexture() const;
const ::XCEngine::RHI::D3D12Texture* GetBackBufferTexture(std::uint32_t index) const;
std::uint32_t GetBackBufferCount() const;
::XCEngine::Rendering::RenderContext GetRenderContext() const;
private:
@@ -64,13 +74,18 @@ private:
::XCEngine::RHI::D3D12CommandQueue* GetD3D12CommandQueue() const;
::XCEngine::RHI::D3D12CommandList* GetD3D12CommandList() const;
::XCEngine::RHI::D3D12SwapChain* GetD3D12SwapChain() const;
::XCEngine::RHI::RHICommandList* GetCurrentCommandList() const;
void AllocateShaderResourceDescriptorInternal(
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle);
void FreeShaderResourceDescriptorInternal(
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle);
bool InitializeFrameCompletionFence();
void ReleaseFrameCompletionFence();
void WaitForBackBufferFrame(std::uint32_t backBufferIndex);
void WaitForGpuIdle();
void ReleaseBackBufferCommandReferences();
void ReleaseBackBufferViews();
bool RecreateBackBufferViews();
@@ -80,13 +95,19 @@ private:
::XCEngine::RHI::RHIDevice* m_device = nullptr;
::XCEngine::RHI::RHICommandQueue* m_commandQueue = nullptr;
::XCEngine::RHI::RHICommandList* m_commandList = nullptr;
std::array<::XCEngine::RHI::RHICommandList*, kSwapChainBufferCount> m_commandLists = {};
::XCEngine::RHI::RHISwapChain* m_swapChain = nullptr;
::XCEngine::RHI::RHIDescriptorPool* m_srvPool = nullptr;
::XCEngine::RHI::D3D12DescriptorHeap* m_srvHeap = nullptr;
std::vector<bool> m_srvUsage = {};
std::vector<::XCEngine::RHI::RHIResourceView*> m_backBufferViews = {};
std::vector<::XCEngine::Rendering::RenderSurface> m_backBufferSurfaces = {};
Microsoft::WRL::ComPtr<ID3D12Fence> m_frameCompletionFence = {};
HANDLE m_frameCompletionEvent = nullptr;
std::array<std::uint64_t, kSwapChainBufferCount> m_backBufferFenceValues = {};
std::uint32_t m_activeBackBufferIndex = 0u;
std::uint64_t m_lastSubmittedFrameValue = 0;
std::string m_lastError = {};
UINT m_srvDescriptorSize = 0;
};

View File

@@ -4,12 +4,17 @@
#define NOMINMAX
#endif
#include "D3D12WindowRenderer.h"
#include <XCEditor/Foundation/UIEditorTextMeasurement.h>
#include <XCEngine/UI/DrawData.h>
#include <d2d1.h>
#include <d2d1_1.h>
#include <d3d11_4.h>
#include <d3d11on12.h>
#include <dwrite.h>
#include <dxgi1_2.h>
#include <wincodec.h>
#include <windows.h>
#include <wrl/client.h>
@@ -30,7 +35,13 @@ public:
void SetDpiScale(float dpiScale);
float GetDpiScale() const;
void Resize(UINT width, UINT height);
bool AttachWindowRenderer(D3D12WindowRenderer& windowRenderer);
void DetachWindowRenderer();
void ReleaseWindowRendererBackBufferTargets();
bool RebuildWindowRendererBackBufferTargets();
bool HasAttachedWindowRenderer() const;
bool Render(const ::XCEngine::UI::UIDrawData& drawData);
bool RenderToWindowRenderer(const ::XCEngine::UI::UIDrawData& drawData);
const std::string& GetLastRenderError() const;
bool LoadTextureFromFile(
const std::filesystem::path& path,
@@ -47,15 +58,6 @@ public:
std::string& outError);
private:
bool EnsureRenderTarget();
bool EnsureWicFactory(std::string& outError);
void DiscardRenderTarget();
bool CreateDeviceResources();
void InvalidateCachedTextureBitmaps(const ID2D1RenderTarget* renderTarget);
bool RenderToTarget(
ID2D1RenderTarget& renderTarget,
ID2D1SolidColorBrush& solidBrush,
const ::XCEngine::UI::UIDrawData& drawData);
struct NativeTextureResource {
std::vector<std::uint8_t> pixels = {};
Microsoft::WRL::ComPtr<ID2D1Bitmap> cachedBitmap = {};
@@ -63,6 +65,30 @@ private:
UINT width = 0u;
UINT height = 0u;
};
struct D3D12BackBufferInteropTarget {
Microsoft::WRL::ComPtr<ID3D11Resource> wrappedResource = {};
Microsoft::WRL::ComPtr<ID2D1Bitmap1> targetBitmap = {};
};
struct D3D12SourceTextureInteropResource {
std::uintptr_t key = 0u;
Microsoft::WRL::ComPtr<ID3D11Resource> wrappedResource = {};
Microsoft::WRL::ComPtr<ID2D1Bitmap1> bitmap = {};
};
bool EnsureRenderTarget();
bool EnsureWindowRendererInterop();
bool EnsureWicFactory(std::string& outError);
void DiscardRenderTarget();
bool CreateDeviceResources();
void ReleaseWindowRendererInterop();
bool RebuildBackBufferInteropTargets();
void ClearActiveInteropSourceTextures();
bool PrepareActiveInteropSourceTextures(const ::XCEngine::UI::UIDrawData& drawData);
void InvalidateCachedTextureBitmaps(const ID2D1RenderTarget* renderTarget);
bool RenderToTarget(
ID2D1RenderTarget& renderTarget,
ID2D1SolidColorBrush& solidBrush,
const ::XCEngine::UI::UIDrawData& drawData);
bool DecodeTextureFile(
const std::filesystem::path& path,
NativeTextureResource& outTexture,
@@ -71,6 +97,9 @@ private:
ID2D1RenderTarget& renderTarget,
NativeTextureResource& texture,
Microsoft::WRL::ComPtr<ID2D1Bitmap>& outBitmap);
bool ResolveInteropBitmap(
const ::XCEngine::UI::UITextureHandle& texture,
Microsoft::WRL::ComPtr<ID2D1Bitmap>& outBitmap) const;
void RenderCommand(
ID2D1RenderTarget& renderTarget,
ID2D1SolidColorBrush& solidBrush,
@@ -82,11 +111,21 @@ private:
static std::wstring Utf8ToWide(std::string_view text);
HWND m_hwnd = nullptr;
Microsoft::WRL::ComPtr<ID2D1Factory> m_d2dFactory;
D3D12WindowRenderer* m_windowRenderer = nullptr;
Microsoft::WRL::ComPtr<ID2D1Factory1> m_d2dFactory;
Microsoft::WRL::ComPtr<IDWriteFactory> m_dwriteFactory;
Microsoft::WRL::ComPtr<IWICImagingFactory> m_wicFactory;
Microsoft::WRL::ComPtr<ID3D11Device> m_d3d11Device;
Microsoft::WRL::ComPtr<ID3D11DeviceContext> m_d3d11DeviceContext;
Microsoft::WRL::ComPtr<ID3D11On12Device> m_d3d11On12Device;
Microsoft::WRL::ComPtr<ID2D1Device> m_d2dDevice;
Microsoft::WRL::ComPtr<ID2D1DeviceContext> m_d2dDeviceContext;
Microsoft::WRL::ComPtr<ID2D1HwndRenderTarget> m_renderTarget;
Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> m_solidBrush;
Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> m_interopBrush;
std::vector<D3D12BackBufferInteropTarget> m_backBufferInteropTargets = {};
std::vector<D3D12SourceTextureInteropResource> m_activeInteropSourceTextures = {};
std::unordered_map<std::uintptr_t, Microsoft::WRL::ComPtr<ID2D1Bitmap1>> m_activeInteropBitmaps;
mutable std::unordered_map<int, Microsoft::WRL::ComPtr<IDWriteTextFormat>> m_textFormats;
std::unordered_set<NativeTextureResource*> m_liveTextures;
std::string m_lastRenderError = {};

View File

@@ -429,11 +429,10 @@ UIEditorWorkspacePanelPresentationModel BuildViewportPresentation(
presentation.panelId = std::move(panelId);
presentation.kind = UIEditorPanelPresentationKind::ViewportShell;
presentation.viewportShellModel.spec.chrome.title = std::move(title);
presentation.viewportShellModel.spec.chrome.subtitle = std::move(subtitle);
presentation.viewportShellModel.spec.chrome.showTopBar = true;
presentation.viewportShellModel.spec.chrome.showBottomBar = true;
presentation.viewportShellModel.frame.statusText =
"Viewport request chain is active.";
presentation.viewportShellModel.spec.chrome.subtitle = {};
presentation.viewportShellModel.spec.chrome.showTopBar = false;
presentation.viewportShellModel.spec.chrome.showBottomBar = false;
presentation.viewportShellModel.frame.statusText.clear();
return presentation;
}
@@ -448,8 +447,8 @@ UIEditorShellInteractionDefinition BuildBaseShellDefinition() {
definition.statusSegments = {};
definition.workspacePresentations = {
BuildHostedContentPresentation("hierarchy"),
BuildViewportPresentation("scene", "Scene", "New Editor viewport shell"),
BuildViewportPresentation("game", "Game", "New Editor viewport shell"),
BuildViewportPresentation("scene", "Scene", {}),
BuildViewportPresentation("game", "Game", {}),
BuildHostedContentPresentation("inspector"),
BuildHostedContentPresentation("console"),
BuildHostedContentPresentation("project")

View File

@@ -8,24 +8,6 @@ namespace {
using ::XCEngine::RHI::ResourceStates;
std::string BuildViewportPendingStatus(ProductViewportKind kind) {
return kind == ProductViewportKind::Scene
? "Scene viewport host pending D3D12 presenter integration."
: "Game viewport host pending D3D12 presenter integration.";
}
std::string BuildViewportReadyStatus(ProductViewportKind kind) {
return kind == ProductViewportKind::Scene
? "Scene viewport render target ready; presenter still uses NativeRenderer."
: "Game viewport render target ready; presenter still uses NativeRenderer.";
}
std::string BuildViewportPresentedStatus(ProductViewportKind kind) {
return kind == ProductViewportKind::Scene
? "Scene viewport frame ready."
: "Game viewport frame ready.";
}
} // namespace
void ProductViewportHostService::AttachWindowRenderer(
@@ -81,23 +63,17 @@ ProductViewportFrame ProductViewportHostService::RequestViewport(
: 0u;
if (!entry.requestedThisFrame) {
entry.statusText = "Viewport is waiting for a visible surface.";
return BuildFrame(entry, requestedSize);
}
if (m_windowRenderer == nullptr || m_device == nullptr) {
entry.statusText = BuildViewportPendingStatus(kind);
return BuildFrame(entry, requestedSize);
}
if (!EnsureViewportResources(entry)) {
entry.statusText = "Failed to create viewport render targets.";
return BuildFrame(entry, requestedSize);
}
entry.statusText = m_surfacePresentationEnabled
? BuildViewportPresentedStatus(kind)
: BuildViewportReadyStatus(kind);
return BuildFrame(entry, requestedSize);
}
@@ -119,9 +95,6 @@ void ProductViewportHostService::RenderRequestedViewports(
}
entry.renderedThisFrame = true;
entry.statusText = m_surfacePresentationEnabled
? BuildViewportPresentedStatus(entry.kind)
: BuildViewportReadyStatus(entry.kind);
}
}

View File

@@ -36,33 +36,62 @@ void ApplyViewportFrameToPresentation(
presentation.viewportShellModel.frame.statusText = viewportFrame.statusText;
}
std::vector<UIEditorWorkspacePanelPresentationModel> BuildWorkspacePresentations(
const UIEditorShellInteractionDefinition& definition,
const UIEditorShellInteractionRequest& shellRequest,
ProductViewportHostService& viewportHostService) {
std::vector<UIEditorWorkspacePanelPresentationModel> presentations =
definition.workspacePresentations;
void ApplyViewportFrameToShellModel(
const ProductViewportFrame& viewportFrame,
UIEditorViewportShellModel& shellModel) {
shellModel.frame.texture = viewportFrame.texture;
shellModel.frame.requestedSize = viewportFrame.requestedSize;
shellModel.frame.presentedSize = viewportFrame.renderSize;
shellModel.frame.hasTexture = viewportFrame.hasTexture;
shellModel.frame.statusText = viewportFrame.statusText;
}
UIEditorWorkspacePanelPresentationModel* FindMutableWorkspacePresentation(
std::vector<UIEditorWorkspacePanelPresentationModel>& presentations,
std::string_view panelId) {
for (UIEditorWorkspacePanelPresentationModel& presentation : presentations) {
if (presentation.kind != UIEditorPanelPresentationKind::ViewportShell ||
!IsProductViewportPanel(presentation.panelId)) {
if (presentation.panelId == panelId) {
return &presentation;
}
}
return nullptr;
}
void ApplyViewportFramesToShellFrame(
UIEditorShellInteractionFrame& shellFrame,
ProductViewportHostService& viewportHostService) {
auto applyToViewportFrames =
[&](std::vector<UIEditorWorkspaceViewportComposeFrame>& viewportFrames) {
for (UIEditorWorkspaceViewportComposeFrame& viewportComposeFrame : viewportFrames) {
if (!IsProductViewportPanel(viewportComposeFrame.panelId)) {
continue;
}
const UIEditorWorkspaceViewportComposeRequest* viewportRequest =
FindUIEditorWorkspaceViewportPresentationRequest(
shellRequest.shellRequest.workspaceRequest,
presentation.panelId);
const ::XCEngine::UI::UISize requestedSize =
viewportRequest != nullptr
? viewportRequest->viewportShellRequest.requestedViewportSize
: ::XCEngine::UI::UISize();
ApplyViewportFrameToPresentation(
const ProductViewportFrame viewportFrame =
viewportHostService.RequestViewport(
ResolveProductViewportKind(presentation.panelId),
requestedSize),
presentation);
ResolveProductViewportKind(viewportComposeFrame.panelId),
viewportComposeFrame.viewportShellFrame.requestedViewportSize);
ApplyViewportFrameToShellModel(
viewportFrame,
viewportComposeFrame.viewportShellModel);
if (UIEditorWorkspacePanelPresentationModel* presentation =
FindMutableWorkspacePresentation(
shellFrame.model.workspacePresentations,
viewportComposeFrame.panelId);
presentation != nullptr) {
ApplyViewportFrameToPresentation(viewportFrame, *presentation);
}
return presentations;
}
};
applyToViewportFrames(shellFrame.workspaceInteractionFrame.composeFrame.viewportFrames);
applyToViewportFrames(shellFrame.shellFrame.workspaceFrame.viewportFrames);
}
std::vector<UIEditorWorkspacePanelPresentationModel> BuildWorkspacePresentations(
const UIEditorShellInteractionDefinition& definition) {
return definition.workspacePresentations;
}
UIEditorShellComposeModel BuildShellComposeModelFromFrame(
@@ -168,18 +197,7 @@ void ProductEditorWorkspace::Update(
UIEditorShellInteractionDefinition definition =
context.BuildShellDefinition(captureText);
m_viewportHostService.BeginFrame();
const UIEditorShellInteractionRequest shellRequest =
ResolveUIEditorShellInteractionRequest(
bounds,
context.GetWorkspaceController(),
definition,
m_shellInteractionState,
metrics,
context.GetShellServices());
definition.workspacePresentations = BuildWorkspacePresentations(
definition,
shellRequest,
m_viewportHostService);
definition.workspacePresentations = BuildWorkspacePresentations(definition);
const std::vector<UIInputEvent> hostedContentEvents = inputEvents;
const std::vector<UIInputEvent> shellEvents =
HasHostedContentCapture()
@@ -194,6 +212,7 @@ void ProductEditorWorkspace::Update(
shellEvents,
context.GetShellServices(),
metrics);
ApplyViewportFramesToShellFrame(m_shellFrame, m_viewportHostService);
context.SyncSessionFromWorkspace();
context.UpdateStatusFromShellResult(m_shellFrame.result);

View File

@@ -19,5 +19,6 @@ void AppendUIEditorCrashTrace(
std::filesystem::path GetUIEditorRuntimeTracePath();
std::filesystem::path GetUIEditorCrashTracePath();
bool IsUIEditorRuntimeTraceInitialized();
} // namespace XCEngine::UI::Editor

View File

@@ -17,6 +17,8 @@ std::mutex g_traceMutex = {};
std::filesystem::path g_logRoot = {};
std::filesystem::path g_runtimeTracePath = {};
std::filesystem::path g_crashTracePath = {};
std::ofstream g_runtimeTraceStream = {};
std::ofstream g_crashTraceStream = {};
bool g_traceInitialized = false;
std::string BuildTimestampString() {
@@ -40,16 +42,9 @@ std::string BuildTimestampString() {
}
void AppendTraceLine(
const std::filesystem::path& path,
std::ofstream& stream,
std::string_view channel,
std::string_view message) {
if (path.empty()) {
return;
}
std::error_code errorCode = {};
std::filesystem::create_directories(path.parent_path(), errorCode);
std::ofstream stream(path, std::ios::out | std::ios::app);
if (!stream.is_open()) {
return;
}
@@ -70,11 +65,20 @@ void InitializeUIEditorRuntimeTrace(const std::filesystem::path& logRoot) {
g_logRoot = logRoot.lexically_normal();
g_runtimeTracePath = (g_logRoot / "runtime.log").lexically_normal();
g_crashTracePath = (g_logRoot / "crash.log").lexically_normal();
g_traceInitialized = true;
std::error_code errorCode = {};
std::filesystem::create_directories(g_logRoot, errorCode);
AppendTraceLine(g_runtimeTracePath, "trace", "trace session started");
g_runtimeTraceStream.close();
g_crashTraceStream.close();
g_runtimeTraceStream.open(g_runtimeTracePath, std::ios::out | std::ios::app);
g_crashTraceStream.open(g_crashTracePath, std::ios::out | std::ios::app);
g_traceInitialized = g_runtimeTraceStream.is_open() && g_crashTraceStream.is_open();
if (!g_traceInitialized) {
return;
}
AppendTraceLine(g_runtimeTraceStream, "trace", "trace session started");
g_runtimeTraceStream.flush();
}
void ShutdownUIEditorRuntimeTrace() {
@@ -83,7 +87,11 @@ void ShutdownUIEditorRuntimeTrace() {
return;
}
AppendTraceLine(g_runtimeTracePath, "trace", "trace session ended");
AppendTraceLine(g_runtimeTraceStream, "trace", "trace session ended");
g_runtimeTraceStream.flush();
g_crashTraceStream.flush();
g_runtimeTraceStream.close();
g_crashTraceStream.close();
g_traceInitialized = false;
}
@@ -95,7 +103,7 @@ void AppendUIEditorRuntimeTrace(
return;
}
AppendTraceLine(g_runtimeTracePath, channel, message);
AppendTraceLine(g_runtimeTraceStream, channel, message);
}
void AppendUIEditorCrashTrace(
@@ -113,8 +121,10 @@ void AppendUIEditorCrashTrace(
"Unhandled exception code=0x%08X address=%p",
exceptionCode,
exceptionAddress);
AppendTraceLine(g_crashTracePath, "crash", buffer);
AppendTraceLine(g_runtimeTracePath, "crash", buffer);
AppendTraceLine(g_crashTraceStream, "crash", buffer);
AppendTraceLine(g_runtimeTraceStream, "crash", buffer);
g_crashTraceStream.flush();
g_runtimeTraceStream.flush();
}
std::filesystem::path GetUIEditorRuntimeTracePath() {
@@ -127,4 +137,9 @@ std::filesystem::path GetUIEditorCrashTracePath() {
return g_crashTracePath;
}
bool IsUIEditorRuntimeTraceInitialized() {
std::lock_guard lock(g_traceMutex);
return g_traceInitialized;
}
} // namespace XCEngine::UI::Editor

View File

@@ -55,34 +55,6 @@ UISize ResolveFrameAspectSize(const UIEditorViewportSlotFrame& frame, const UISi
return fallback;
}
UIRect FitRectToAspect(const UIRect& container, const UISize& size) {
if (!HasArea(container) || size.width <= 0.0f || size.height <= 0.0f) {
return container;
}
const float containerAspect = container.width / container.height;
const float frameAspect = size.width / size.height;
if (frameAspect <= 0.0f) {
return container;
}
if (frameAspect >= containerAspect) {
const float fittedHeight = container.width / frameAspect;
return UIRect(
container.x,
container.y + (container.height - fittedHeight) * 0.5f,
container.width,
fittedHeight);
}
const float fittedWidth = container.height * frameAspect;
return UIRect(
container.x + (container.width - fittedWidth) * 0.5f,
container.y,
fittedWidth,
container.height);
}
UIColor ResolveToolFillColor(
const UIEditorViewportSlotToolItem& item,
bool hovered,
@@ -199,11 +171,7 @@ UIEditorViewportSlotLayout BuildUIEditorViewportSlotLayout(
layout.inputRect = InsetRect(layout.surfaceRect, metrics.surfaceInset);
layout.requestedSurfaceSize =
UISize(layout.inputRect.width, layout.inputRect.height);
layout.textureRect = frame.hasTexture
? FitRectToAspect(
layout.inputRect,
ResolveFrameAspectSize(frame, layout.requestedSurfaceSize))
: layout.inputRect;
layout.textureRect = layout.inputRect;
if (!layout.hasTopBar) {
return layout;
@@ -437,34 +405,8 @@ void AppendUIEditorViewportSlotForeground(
}
}
const UISize frameSize = ResolveFrameAspectSize(frame, layout.requestedSurfaceSize);
if (frame.hasTexture && frame.texture.IsValid()) {
drawList.AddImage(layout.textureRect, frame.texture, palette.imageTint);
drawList.AddText(
UIPoint(layout.inputRect.x + 14.0f, layout.inputRect.y + 14.0f),
"Texture " +
std::to_string(static_cast<int>(frameSize.width)) +
"x" +
std::to_string(static_cast<int>(frameSize.height)),
palette.textMuted,
12.0f);
} else {
const std::string statusText = frame.statusText.empty()
? std::string("Viewport is waiting for frame")
: frame.statusText;
drawList.AddText(
UIPoint(layout.inputRect.x + 16.0f, layout.inputRect.y + 18.0f),
statusText,
palette.textPrimary,
14.0f);
drawList.AddText(
UIPoint(layout.inputRect.x + 16.0f, layout.inputRect.y + 42.0f),
"Requested surface: " +
std::to_string(static_cast<int>(layout.requestedSurfaceSize.width)) +
"x" +
std::to_string(static_cast<int>(layout.requestedSurfaceSize.height)),
palette.textMuted,
12.0f);
}
if (layout.hasBottomBar) {