Checkpoint current new editor host iteration
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 = {};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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 = {};
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -19,5 +19,6 @@ void AppendUIEditorCrashTrace(
|
||||
|
||||
std::filesystem::path GetUIEditorRuntimeTracePath();
|
||||
std::filesystem::path GetUIEditorCrashTracePath();
|
||||
bool IsUIEditorRuntimeTraceInitialized();
|
||||
|
||||
} // namespace XCEngine::UI::Editor
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user