Align SRP boundaries and editor windowing
This commit is contained in:
@@ -160,6 +160,11 @@ logic.
|
||||
- First decide whether the change belongs to XCEditor framework, app semantics,
|
||||
app windowing, Win32 host, or rendering host.
|
||||
- Keep public framework headers free of `App::*`, Win32, and D3D12 host types.
|
||||
- Do not add `editor/app` as an include directory for `XCUIEditorLib`.
|
||||
App-only services must cross into framework code through framework-owned
|
||||
interfaces and app-side adapters.
|
||||
- Do not compile `${XCUI_EDITOR_SHARED_SOURCES}` directly into `XCUIEditorApp`;
|
||||
the executable should consume shared framework code through `XCUIEditorLib`.
|
||||
- Use `editor/include/XCEditor/Windowing` and `editor/src/Windowing` for
|
||||
generic window authority, synchronization, validation, and presentation
|
||||
projection.
|
||||
@@ -186,6 +191,12 @@ owns the app-internal content controller factory, coordinators, frame transfer
|
||||
flow, host contracts, and manager. The Win32 host is the concrete native
|
||||
adapter and creates native host windows from content supplied by app windowing.
|
||||
|
||||
The framework/app compile boundary is also enforced. `XCUIEditorLib` does not
|
||||
receive `editor/app` includes, and `XCUIEditorApp` does not directly compile
|
||||
the shared framework sources. When framework UI code needs app-provided data
|
||||
such as loaded icons, expose a framework-owned interface and adapt it in app
|
||||
composition code.
|
||||
|
||||
The main remaining debt is promotion discipline around the app runtime surface.
|
||||
`XCUIEditorAppWindowing` is still app-internal and may depend on app semantics
|
||||
such as `EditorContext`, `EditorShellRuntime`, utility window descriptors, and
|
||||
@@ -194,25 +205,17 @@ content controllers to `XCEditor` until they are generic enough to expose.
|
||||
|
||||
## Validation
|
||||
|
||||
Useful local targets for editor/windowing changes:
|
||||
|
||||
- `cmake --build build --config Debug --target XCUIEditorApp`
|
||||
- `cmake --build build --config Debug --target editor_windowing_phase1_tests`
|
||||
- `cmake --build build --config Debug --target editor_ui_tests`
|
||||
|
||||
Useful test executables when they are present in the configured build tree:
|
||||
|
||||
- `build/tests/UI/Editor/unit/Debug/editor_windowing_phase1_tests.exe`
|
||||
- `build/tests/UI/Editor/unit/Debug/editor_ui_tests.exe`
|
||||
|
||||
`xcui_editor_app_smoke` is a useful supplemental smoke test when the app target
|
||||
and smoke test are configured, but it is not the default windowing unit-test
|
||||
entry point. In the current Debug build, the direct 12-second smoke command is:
|
||||
Default editor validation is only the app build plus the 12-second smoke run:
|
||||
|
||||
```powershell
|
||||
cmake --build build --config Debug --target editor_ui_smoke_targets
|
||||
build\tests\UI\Editor\smoke\Debug\editor_ui_smoke_runner.exe build\editor\Debug\XCEngine.exe
|
||||
```
|
||||
|
||||
Do not run `editor_windowing_phase1_tests`, `editor_ui_tests`, or broader test
|
||||
targets by default. Run them only when the user explicitly asks for them or a
|
||||
separate targeted change makes them necessary.
|
||||
|
||||
The runner sets `XCUIEDITOR_SMOKE_TEST_DURATION_SECONDS=12`, waits for the
|
||||
editor to launch, lets the app auto-exit, and treats a clean editor exit as
|
||||
success.
|
||||
@@ -248,38 +251,24 @@ Start with these files for editor/windowing work:
|
||||
- `editor/app/Platform/Win32/Windowing/EditorWindow.*`
|
||||
- `editor/app/Platform/Win32/Windowing/EditorWindowHostRuntime.*`
|
||||
- `editor/app/Platform/Win32/Windowing/EditorWindowMessageDispatcher.*`
|
||||
- `tests/UI/Editor/unit/test_editor_window_synchronization_planner.cpp`
|
||||
- `tests/UI/Editor/unit/CMakeLists.txt`
|
||||
- `tests/UI/Editor/smoke/CMakeLists.txt`
|
||||
|
||||
## 上一刀
|
||||
## 前面几刀
|
||||
|
||||
上一刀把窗口权威核心从 app-internal 层真正切到 framework 层。具体来说:
|
||||
`EditorWindowSystem`、`EditorWindowSynchronizationPlan`、
|
||||
`EditorWindowSynchronizationPlanner`、`EditorWorkspaceWindowProjection` 和
|
||||
`EditorWindowPresentationPolicy` 的公共头移到
|
||||
`editor/include/XCEditor/Windowing`;对应实现移到 `editor/src/Windowing`。
|
||||
`EditorWindowWorkspaceStore` 只作为 framework 私有实现保留在
|
||||
`editor/src/Windowing/System`,没有暴露到 public include 面。
|
||||
|
||||
构建边界也同步收紧:这些 window authority / synchronization / presentation
|
||||
sources 现在编进 `XCUIEditorLib`,不再属于 `XCUIEditorAppWindowing`;
|
||||
`XCUIEditorAppWindowing` 的 `editor/app` include 从 `PUBLIC` 改成 `PRIVATE`。
|
||||
这意味着下游不能再因为链接 app windowing 目标而顺手拿到整个 app include 面。
|
||||
|
||||
app 层只改成依赖新的 framework include,例如
|
||||
`<XCEditor/Windowing/System/EditorWindowSystem.h>` 和
|
||||
`<XCEditor/Windowing/Presentation/EditorWindowPresentationPolicy.h>`。
|
||||
`editor/app/Windowing` 仍然保留 app-specific 的 content controllers、
|
||||
coordinators、frame transfer、host contracts 和 `EditorWindowManager`;
|
||||
`editor/app/Platform/Win32` 仍然只做 native host/window/message/runtime 适配。
|
||||
|
||||
测试边界也跟着改了:`editor_windowing_phase1_tests` 现在只链接
|
||||
`XCUIEditorLib`,不再链接 `XCUIEditorAppWindowing`,也不再把 `editor/app`
|
||||
和 `editor/src` 作为测试 include 目录。这个测试因此只验证公开的
|
||||
`XCEditor/Windowing` 权威模型,而不是穿透 app 内部目录。
|
||||
|
||||
这一刀没有把整个 `app/Windowing` 提升到 `XCEditor`。故意没有提升的部分包括
|
||||
`EditorContext`、`EditorShellRuntime`、utility window descriptor/panel、
|
||||
frame transfer request、host interface、content controller、coordinator 和 Win32 host。
|
||||
这些仍然是产品运行时/宿主编排职责,不是 framework windowing kernel。
|
||||
- 最近一刀封死 framework -> app 的反向依赖:`UIEditorShellCompose`
|
||||
不再认识 `App::BuiltInIcons`,改由 `UIEditorShellIconResolver` 抽象取图标,
|
||||
app 在 `EditorShellDrawComposer` 里用 adapter 连接 `BuiltInIcons`。
|
||||
- 同一刀收紧构建边界:`XCUIEditorLib` 不再拥有 `editor/app` include,
|
||||
`XCUIEditorApp` 不再直接编译 `${XCUI_EDITOR_SHARED_SOURCES}`,也不再把
|
||||
`editor/src` 加进 include;app 通过 `XCUIEditorLib` 消费 framework。
|
||||
- 前一刀把窗口权威核心切到 framework:`EditorWindowSystem`、同步计划/规划器、
|
||||
workspace store 和 presentation projection 位于 `editor/include/XCEditor/Windowing`
|
||||
与 `editor/src/Windowing`。
|
||||
- `editor/app/Windowing` 保留 app-specific 的 content controllers、coordinators、
|
||||
frame transfer、host contracts 和 `EditorWindowManager`;Win32 host 仍只做
|
||||
native adapter。
|
||||
- 未提升到 `XCEditor` 的内容包括 `EditorContext`、`EditorShellRuntime`、utility
|
||||
descriptors/panels、host interfaces、content controllers、coordinators、
|
||||
frame transfer 和 Win32/D3D12 host。
|
||||
- 默认验证也收口:只构建 `XCUIEditorApp` 相关 smoke 目标并跑 12 秒 smoke;
|
||||
需要专项覆盖时再单独运行 windowing/unit targets。
|
||||
|
||||
@@ -167,7 +167,6 @@ target_include_directories(XCUIEditorLib PUBLIC
|
||||
)
|
||||
|
||||
target_include_directories(XCUIEditorLib PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/app
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
)
|
||||
|
||||
@@ -187,6 +186,8 @@ set(XCUI_EDITOR_APP_WINDOWING_SOURCES
|
||||
app/Windowing/Content/EditorUtilityWindowContentController.cpp
|
||||
app/Windowing/Content/EditorWorkspaceWindowContentController.cpp
|
||||
app/Windowing/Frame/EditorWindowFrameOrchestrator.cpp
|
||||
app/Windowing/Runtime/EditorWindowRuntimeController.cpp
|
||||
app/Windowing/Runtime/EditorWindowScreenshotController.cpp
|
||||
)
|
||||
|
||||
add_library(XCUIEditorAppWindowing STATIC
|
||||
@@ -209,7 +210,6 @@ set(XCUI_EDITOR_HOST_PLATFORM_SOURCES
|
||||
)
|
||||
|
||||
set(XCUI_EDITOR_HOST_RENDERING_SOURCES
|
||||
app/Platform/Win32/Runtime/EditorWindowScreenshotController.cpp
|
||||
app/Rendering/D3D12/D3D12HostDevice.cpp
|
||||
app/Rendering/D3D12/D3D12WindowCapture.cpp
|
||||
app/Rendering/D3D12/D3D12UiRenderer.cpp
|
||||
@@ -297,9 +297,7 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP)
|
||||
app/Platform/Win32/Windowing/EditorFloatingWindowPlacement.cpp
|
||||
app/Platform/Win32/Windowing/EditorWindowSession.cpp
|
||||
app/Platform/Win32/Chrome/EditorWindowChromeController.cpp
|
||||
app/Platform/Win32/Runtime/EditorWindowFrameDriver.cpp
|
||||
app/Platform/Win32/Runtime/EditorWindowInputController.cpp
|
||||
app/Platform/Win32/Runtime/EditorWindowRuntimeController.cpp
|
||||
app/Platform/Win32/System/Win32SystemInteractionHost.cpp
|
||||
app/Platform/Win32/Windowing/EditorWindowHostRuntime.cpp
|
||||
app/Platform/Win32/Windowing/EditorWindowMessageDispatcher.cpp
|
||||
@@ -315,7 +313,6 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP)
|
||||
)
|
||||
|
||||
set(XCUI_EDITOR_APP_INTERNAL_SOURCES
|
||||
${XCUI_EDITOR_SHARED_SOURCES}
|
||||
${XCUI_EDITOR_HOST_PLATFORM_SOURCES}
|
||||
${XCUI_EDITOR_HOST_RENDERING_SOURCES}
|
||||
${XCUI_EDITOR_APP_CORE_SOURCES}
|
||||
@@ -330,7 +327,6 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP)
|
||||
target_include_directories(XCUIEditorApp PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/app
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_SOURCE_DIR}/engine/include
|
||||
${CMAKE_SOURCE_DIR}/engine/third_party/stb
|
||||
)
|
||||
|
||||
@@ -20,6 +20,20 @@ namespace {
|
||||
using ::XCEngine::UI::UIDrawData;
|
||||
using ::XCEngine::UI::UIDrawList;
|
||||
|
||||
class BuiltInIconResolver final : public UIEditorShellIconResolver {
|
||||
public:
|
||||
explicit BuiltInIconResolver(const BuiltInIcons& icons)
|
||||
: m_icons(icons) {}
|
||||
|
||||
const ::XCEngine::UI::UITextureHandle* TryResolveIcon(
|
||||
std::uint8_t iconKind) const override {
|
||||
return &m_icons.Resolve(static_cast<BuiltInIconKind>(iconKind));
|
||||
}
|
||||
|
||||
private:
|
||||
const BuiltInIcons& m_icons;
|
||||
};
|
||||
|
||||
UIEditorShellComposeModel BuildShellComposeModelFromFrame(
|
||||
const UIEditorShellInteractionFrame& frame) {
|
||||
UIEditorShellComposeModel model = {};
|
||||
@@ -80,6 +94,7 @@ void EditorShellDrawComposer::Append(
|
||||
const auto& palette = ResolveUIEditorShellInteractionPalette();
|
||||
const UIEditorShellComposeModel shellComposeModel =
|
||||
BuildShellComposeModelFromFrame(context.shellFrame);
|
||||
const BuiltInIconResolver iconResolver(context.builtInIcons);
|
||||
|
||||
AppendDrawPacket(
|
||||
drawData,
|
||||
@@ -92,7 +107,7 @@ void EditorShellDrawComposer::Append(
|
||||
context.shellInteractionState.composeState,
|
||||
palette.shellPalette,
|
||||
metrics.shellMetrics,
|
||||
&context.builtInIcons);
|
||||
&iconResolver);
|
||||
});
|
||||
AppendDrawPacket(
|
||||
drawData,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "Platform/Win32/Chrome/EditorWindowChromeController.h"
|
||||
|
||||
#include "Platform/Win32/Windowing/EditorWindow.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowFrameDriver.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowRuntimeController.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowSupport.h"
|
||||
#include "Windowing/Host/EditorWindowHostCoordinator.h"
|
||||
#include "Windowing/Runtime/EditorWindowRuntimeController.h"
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorTheme.h>
|
||||
#include <XCEngine/UI/DrawData.h>
|
||||
@@ -250,17 +250,16 @@ void EditorWindowChromeController::InitializeWindowChrome(EditorWindow& window)
|
||||
|
||||
bool EditorWindowChromeController::HandleSystemCommand(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
EditorWindowHostCoordinator& hostCoordinator,
|
||||
WPARAM wParam) {
|
||||
const HWND hwnd = window.GetHwnd();
|
||||
switch (wParam & 0xFFF0u) {
|
||||
case SC_MAXIMIZE:
|
||||
ToggleMaximizeRestore(window, editorContext, globalTabDragActive);
|
||||
ToggleMaximizeRestore(window, hostCoordinator);
|
||||
return true;
|
||||
case SC_RESTORE:
|
||||
if (hwnd != nullptr && !IsIconic(hwnd)) {
|
||||
ToggleMaximizeRestore(window, editorContext, globalTabDragActive);
|
||||
ToggleMaximizeRestore(window, hostCoordinator);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -338,8 +337,7 @@ bool EditorWindowChromeController::HandleResizeButtonUp(EditorWindow& window) {
|
||||
|
||||
bool EditorWindowChromeController::HandleResizePointerMove(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive) {
|
||||
EditorWindowHostCoordinator& hostCoordinator) {
|
||||
const HWND hwnd = window.GetHwnd();
|
||||
if (!IsBorderlessResizeActive() || hwnd == nullptr) {
|
||||
return false;
|
||||
@@ -372,10 +370,7 @@ bool EditorWindowChromeController::HandleResizePointerMove(
|
||||
if (window.ApplyWindowResize(static_cast<UINT>(width), static_cast<UINT>(height))) {
|
||||
const auto immediateFrameBegin = std::chrono::steady_clock::now();
|
||||
window.QueueCompletedImmediateFrame(
|
||||
EditorWindowFrameDriver::DriveImmediateFrame(
|
||||
window,
|
||||
editorContext,
|
||||
globalTabDragActive));
|
||||
hostCoordinator.DriveImmediateWindowFrame(window));
|
||||
const auto immediateFrameEnd = std::chrono::steady_clock::now();
|
||||
MarkPredictedClientPixelSizePresented();
|
||||
if (IsVerboseResizeTraceEnabled()) {
|
||||
@@ -535,8 +530,7 @@ bool EditorWindowChromeController::HandleChromeButtonDown(EditorWindow& window,
|
||||
|
||||
bool EditorWindowChromeController::HandleChromeButtonUp(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
EditorWindowHostCoordinator& hostCoordinator,
|
||||
LPARAM lParam) {
|
||||
if (IsBorderlessWindowDragRestoreArmed()) {
|
||||
ClearChromeDragRestoreState(window);
|
||||
@@ -554,15 +548,14 @@ bool EditorWindowChromeController::HandleChromeButtonUp(
|
||||
window.InvalidateHostWindow();
|
||||
|
||||
if (pressedTarget == releasedTarget) {
|
||||
ExecuteChromeAction(window, editorContext, globalTabDragActive, pressedTarget);
|
||||
ExecuteChromeAction(window, hostCoordinator, pressedTarget);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditorWindowChromeController::HandleChromeDoubleClick(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
EditorWindowHostCoordinator& hostCoordinator,
|
||||
LPARAM lParam) {
|
||||
if (IsBorderlessWindowDragRestoreArmed()) {
|
||||
ClearChromeDragRestoreState(window);
|
||||
@@ -574,16 +567,14 @@ bool EditorWindowChromeController::HandleChromeDoubleClick(
|
||||
|
||||
ExecuteChromeAction(
|
||||
window,
|
||||
editorContext,
|
||||
globalTabDragActive,
|
||||
hostCoordinator,
|
||||
Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditorWindowChromeController::HandleChromeDragRestorePointerMove(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive) {
|
||||
EditorWindowHostCoordinator& hostCoordinator) {
|
||||
const HWND hwnd = window.GetHwnd();
|
||||
if (!IsBorderlessWindowDragRestoreArmed() || hwnd == nullptr) {
|
||||
return false;
|
||||
@@ -647,7 +638,7 @@ bool EditorWindowChromeController::HandleChromeDragRestorePointerMove(
|
||||
};
|
||||
|
||||
SetBorderlessWindowMaximized(false);
|
||||
ApplyPredictedWindowRectTransition(window, editorContext, globalTabDragActive, targetRect);
|
||||
ApplyPredictedWindowRectTransition(window, hostCoordinator, targetRect);
|
||||
ClearChromeDragRestoreState(window);
|
||||
SendMessageW(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
|
||||
return true;
|
||||
@@ -891,8 +882,7 @@ bool EditorWindowChromeController::QueryBorderlessWindowWorkAreaRect(
|
||||
|
||||
bool EditorWindowChromeController::ApplyPredictedWindowRectTransition(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
EditorWindowHostCoordinator& hostCoordinator,
|
||||
const RECT& targetRect) {
|
||||
const HWND hwnd = window.GetHwnd();
|
||||
if (hwnd == nullptr) {
|
||||
@@ -908,10 +898,7 @@ bool EditorWindowChromeController::ApplyPredictedWindowRectTransition(
|
||||
SetPredictedClientPixelSize(static_cast<UINT>(width), static_cast<UINT>(height));
|
||||
if (window.ApplyWindowResize(static_cast<UINT>(width), static_cast<UINT>(height))) {
|
||||
window.QueueCompletedImmediateFrame(
|
||||
EditorWindowFrameDriver::DriveImmediateFrame(
|
||||
window,
|
||||
editorContext,
|
||||
globalTabDragActive));
|
||||
hostCoordinator.DriveImmediateWindowFrame(window));
|
||||
MarkPredictedClientPixelSizePresented();
|
||||
}
|
||||
SetWindowPos(
|
||||
@@ -957,8 +944,7 @@ bool EditorWindowChromeController::ApplyWindowTopmost(EditorWindow& window, bool
|
||||
|
||||
void EditorWindowChromeController::ToggleMaximizeRestore(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive) {
|
||||
EditorWindowHostCoordinator& hostCoordinator) {
|
||||
if (window.GetHwnd() == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -973,7 +959,7 @@ void EditorWindowChromeController::ToggleMaximizeRestore(
|
||||
|
||||
SetBorderlessWindowRestoreRect(currentRect);
|
||||
SetBorderlessWindowMaximized(true);
|
||||
ApplyPredictedWindowRectTransition(window, editorContext, globalTabDragActive, workAreaRect);
|
||||
ApplyPredictedWindowRectTransition(window, hostCoordinator, workAreaRect);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -983,13 +969,12 @@ void EditorWindowChromeController::ToggleMaximizeRestore(
|
||||
}
|
||||
|
||||
SetBorderlessWindowMaximized(false);
|
||||
ApplyPredictedWindowRectTransition(window, editorContext, globalTabDragActive, restoreRect);
|
||||
ApplyPredictedWindowRectTransition(window, hostCoordinator, restoreRect);
|
||||
}
|
||||
|
||||
void EditorWindowChromeController::ExecuteChromeAction(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
EditorWindowHostCoordinator& hostCoordinator,
|
||||
Host::BorderlessWindowChromeHitTarget target) {
|
||||
const HWND hwnd = window.GetHwnd();
|
||||
if (hwnd == nullptr) {
|
||||
@@ -1004,7 +989,7 @@ void EditorWindowChromeController::ExecuteChromeAction(
|
||||
ShowWindow(hwnd, SW_MINIMIZE);
|
||||
break;
|
||||
case Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton:
|
||||
ToggleMaximizeRestore(window, editorContext, globalTabDragActive);
|
||||
ToggleMaximizeRestore(window, hostCoordinator);
|
||||
break;
|
||||
case Host::BorderlessWindowChromeHitTarget::CloseButton:
|
||||
PostMessageW(hwnd, WM_CLOSE, 0, 0);
|
||||
|
||||
@@ -11,8 +11,8 @@ class UIDrawList;
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class EditorContext;
|
||||
class EditorWindow;
|
||||
class EditorWindowHostCoordinator;
|
||||
|
||||
} // namespace XCEngine::UI::Editor::App
|
||||
|
||||
@@ -78,8 +78,7 @@ public:
|
||||
|
||||
bool HandleSystemCommand(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
EditorWindowHostCoordinator& hostCoordinator,
|
||||
WPARAM wParam);
|
||||
bool HandleGetMinMaxInfo(const EditorWindow& window, LPARAM lParam) const;
|
||||
LRESULT HandleNcCalcSize(const EditorWindow& window, WPARAM wParam, LPARAM lParam) const;
|
||||
@@ -89,8 +88,7 @@ public:
|
||||
bool HandleResizeButtonUp(EditorWindow& window);
|
||||
bool HandleResizePointerMove(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive);
|
||||
EditorWindowHostCoordinator& hostCoordinator);
|
||||
void ClearResizeState(EditorWindow& window);
|
||||
void ForceClearResizeState(EditorWindow& window);
|
||||
Host::BorderlessWindowResizeEdge HitTestResizeEdge(
|
||||
@@ -101,18 +99,15 @@ public:
|
||||
bool HandleChromeButtonDown(EditorWindow& window, LPARAM lParam);
|
||||
bool HandleChromeButtonUp(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
EditorWindowHostCoordinator& hostCoordinator,
|
||||
LPARAM lParam);
|
||||
bool HandleChromeDoubleClick(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
EditorWindowHostCoordinator& hostCoordinator,
|
||||
LPARAM lParam);
|
||||
bool HandleChromeDragRestorePointerMove(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive);
|
||||
EditorWindowHostCoordinator& hostCoordinator);
|
||||
void ClearChromeDragRestoreState(EditorWindow& window);
|
||||
void ClearChromeState(EditorWindow& window);
|
||||
Host::BorderlessWindowChromeHitTarget HitTestChrome(
|
||||
@@ -131,20 +126,17 @@ public:
|
||||
bool QueryBorderlessWindowWorkAreaRect(const EditorWindow& window, RECT& outRect) const;
|
||||
bool ApplyPredictedWindowRectTransition(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
EditorWindowHostCoordinator& hostCoordinator,
|
||||
const RECT& targetRect);
|
||||
void SetWindowTopmost(bool topmost);
|
||||
bool IsWindowTopmost() const;
|
||||
bool ApplyWindowTopmost(EditorWindow& window, bool topmost);
|
||||
void ToggleMaximizeRestore(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive);
|
||||
EditorWindowHostCoordinator& hostCoordinator);
|
||||
void ExecuteChromeAction(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
EditorWindowHostCoordinator& hostCoordinator,
|
||||
Host::BorderlessWindowChromeHitTarget target);
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
#include "Platform/Win32/Runtime/EditorWindowFrameDriver.h"
|
||||
|
||||
#include "Platform/Win32/Chrome/EditorWindowChromeController.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindow.h"
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
EditorWindowFrameTransferRequests EditorWindowFrameDriver::DriveFrameInternal(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
bool requestSkipNextSteadyStateFrame) {
|
||||
if (!window.IsRenderReady() ||
|
||||
window.GetHwnd() == nullptr ||
|
||||
window.GetLifecycleState() != EditorWindowLifecycleState::Running) {
|
||||
return {};
|
||||
}
|
||||
|
||||
EditorWindowFrameTransferRequests transferRequests =
|
||||
window.RenderFrame(editorContext, globalTabDragActive);
|
||||
if (const HWND hwnd = window.GetHwnd();
|
||||
hwnd != nullptr && IsWindow(hwnd)) {
|
||||
ValidateRect(hwnd, nullptr);
|
||||
}
|
||||
if (requestSkipNextSteadyStateFrame) {
|
||||
window.RequestSkipNextSteadyStateFrame();
|
||||
}
|
||||
|
||||
return transferRequests;
|
||||
}
|
||||
|
||||
EditorWindowFrameTransferRequests EditorWindowFrameDriver::DriveFrame(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive) {
|
||||
return DriveFrameInternal(window, editorContext, globalTabDragActive, false);
|
||||
}
|
||||
|
||||
EditorWindowFrameTransferRequests EditorWindowFrameDriver::DriveImmediateFrame(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive) {
|
||||
return DriveFrameInternal(window, editorContext, globalTabDragActive, true);
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor::App
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Windowing/Frame/EditorWindowTransferRequests.h"
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class EditorContext;
|
||||
class EditorWindow;
|
||||
|
||||
class EditorWindowFrameDriver final {
|
||||
public:
|
||||
static EditorWindowFrameTransferRequests DriveFrame(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive);
|
||||
static EditorWindowFrameTransferRequests DriveImmediateFrame(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive);
|
||||
|
||||
private:
|
||||
static EditorWindowFrameTransferRequests DriveFrameInternal(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
bool requestSkipNextSteadyStateFrame);
|
||||
};
|
||||
|
||||
} // namespace XCEngine::UI::Editor::App
|
||||
@@ -1,12 +1,10 @@
|
||||
#include "Platform/Win32/Windowing/EditorWindow.h"
|
||||
#include "Bootstrap/EditorResources.h"
|
||||
#include "Platform/Win32/Chrome/EditorWindowChromeController.h"
|
||||
#include "Windowing/Content/EditorWindowContentController.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowFrameDriver.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowSession.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowSupport.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowInputController.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowRuntimeController.h"
|
||||
#include "Windowing/Runtime/EditorWindowRuntimeController.h"
|
||||
#include <XCEditor/Docking/UIEditorDockHostTransfer.h>
|
||||
#include <XCEditor/Foundation/UIEditorRuntimeTrace.h>
|
||||
#include <XCEditor/Shell/UIEditorShellInteraction.h>
|
||||
@@ -88,7 +86,7 @@ EditorWindow::EditorWindow(
|
||||
EditorWindowCategory category,
|
||||
EditorWindowChromePolicy chromePolicy,
|
||||
bool primary,
|
||||
std::unique_ptr<EditorWindowContentController> contentController)
|
||||
std::unique_ptr<EditorWindowRuntimeController> runtimeController)
|
||||
: m_session(std::make_unique<EditorWindowSession>(
|
||||
std::move(windowId),
|
||||
std::move(title),
|
||||
@@ -97,8 +95,7 @@ EditorWindow::EditorWindow(
|
||||
primary))
|
||||
, m_chromeController(std::make_unique<EditorWindowChromeController>())
|
||||
, m_inputController(std::make_unique<EditorWindowInputController>())
|
||||
, m_runtime(std::make_unique<EditorWindowRuntimeController>(
|
||||
std::move(contentController))) {}
|
||||
, m_runtime(std::move(runtimeController)) {}
|
||||
|
||||
EditorWindow::~EditorWindow() = default;
|
||||
|
||||
@@ -226,11 +223,8 @@ void EditorWindow::InvalidateHostWindow() const {
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorWindow::Initialize(
|
||||
const std::filesystem::path& repoRoot,
|
||||
EditorContext& editorContext,
|
||||
const std::filesystem::path& captureRoot,
|
||||
bool autoCaptureOnStartup) {
|
||||
bool EditorWindow::InitializeRuntime(
|
||||
const EditorHostWindowRuntimeInitializationParams& params) {
|
||||
if (m_session->GetHwnd() == nullptr) {
|
||||
LogRuntimeTrace("app", "window initialize skipped: hwnd is null");
|
||||
return false;
|
||||
@@ -250,10 +244,9 @@ bool EditorWindow::Initialize(
|
||||
MarkInitializing();
|
||||
const bool initialized = m_runtime->Initialize(
|
||||
m_session->GetHwnd(),
|
||||
repoRoot,
|
||||
editorContext,
|
||||
captureRoot,
|
||||
autoCaptureOnStartup);
|
||||
params.repoRoot,
|
||||
params.captureRoot,
|
||||
params.autoCaptureOnStartup);
|
||||
if (initialized) {
|
||||
MarkRunning();
|
||||
} else {
|
||||
@@ -614,8 +607,7 @@ std::uint8_t ResolveExpectedShellCaptureButtons(
|
||||
|
||||
} // namespace
|
||||
|
||||
EditorWindowFrameTransferRequests EditorWindow::RenderFrame(
|
||||
EditorContext& editorContext,
|
||||
EditorWindowFrameTransferRequests EditorWindow::RenderHostFrame(
|
||||
bool globalTabDragActive) {
|
||||
if (!m_runtime->IsReady() || m_session->GetHwnd() == nullptr) {
|
||||
return {};
|
||||
@@ -638,12 +630,12 @@ EditorWindowFrameTransferRequests EditorWindow::RenderFrame(
|
||||
kShellSurfaceColor);
|
||||
|
||||
EditorWindowFrameTransferRequests transferRequests = {};
|
||||
if (m_runtime->IsEditorContextValid(editorContext)) {
|
||||
if (m_runtime->IsEditorContextValid()) {
|
||||
transferRequests =
|
||||
RenderRuntimeFrame(editorContext, globalTabDragActive, workspaceBounds, drawData);
|
||||
RenderRuntimeFrame(globalTabDragActive, workspaceBounds, drawData);
|
||||
} else {
|
||||
UIDrawList& invalidDrawList = drawData.EmplaceDrawList("XCEditorWindow.Invalid");
|
||||
m_runtime->AppendInvalidFrame(editorContext, invalidDrawList);
|
||||
m_runtime->AppendInvalidFrame(invalidDrawList);
|
||||
}
|
||||
|
||||
UIDrawList& windowChromeDrawList = drawData.EmplaceDrawList("XCEditorWindow.Chrome");
|
||||
@@ -656,22 +648,11 @@ EditorWindowFrameTransferRequests EditorWindow::RenderFrame(
|
||||
return transferRequests;
|
||||
}
|
||||
|
||||
EditorWindowFrameTransferRequests EditorWindow::OnPaintMessage(
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive) {
|
||||
if (!m_runtime->IsReady() || m_session->GetHwnd() == nullptr) {
|
||||
return {};
|
||||
void EditorWindow::ValidateHostFrame() const {
|
||||
if (const HWND hwnd = m_session->GetHwnd();
|
||||
hwnd != nullptr && IsWindow(hwnd)) {
|
||||
ValidateRect(hwnd, nullptr);
|
||||
}
|
||||
|
||||
PAINTSTRUCT paintStruct = {};
|
||||
BeginPaint(m_session->GetHwnd(), &paintStruct);
|
||||
const EditorWindowFrameTransferRequests transferRequests =
|
||||
EditorWindowFrameDriver::DriveImmediateFrame(
|
||||
*this,
|
||||
editorContext,
|
||||
globalTabDragActive);
|
||||
EndPaint(m_session->GetHwnd(), &paintStruct);
|
||||
return transferRequests;
|
||||
}
|
||||
|
||||
void EditorWindow::QueueCompletedImmediateFrame(
|
||||
@@ -710,7 +691,6 @@ UIRect EditorWindow::ResolveWorkspaceBounds(float clientWidthDips, float clientH
|
||||
}
|
||||
|
||||
EditorWindowFrameTransferRequests EditorWindow::RenderRuntimeFrame(
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
const UIRect& workspaceBounds,
|
||||
UIDrawData& drawData) {
|
||||
@@ -718,7 +698,7 @@ EditorWindowFrameTransferRequests EditorWindow::RenderRuntimeFrame(
|
||||
std::vector<UIInputEvent> frameEvents = m_inputController->TakePendingEvents();
|
||||
const bool useDetachedTitleBarTabStrip =
|
||||
m_chromeController->ShouldUseDetachedTitleBarTabStrip(*this);
|
||||
m_runtime->PrepareEditorContext(editorContext);
|
||||
m_runtime->PrepareEditorContext();
|
||||
const Host::D3D12WindowRenderLoopFrameContext frameContext = m_runtime->BeginFrame();
|
||||
if (!frameContext.warning.empty()) {
|
||||
LogRuntimeTrace("viewport", frameContext.warning);
|
||||
@@ -726,16 +706,12 @@ EditorWindowFrameTransferRequests EditorWindow::RenderRuntimeFrame(
|
||||
|
||||
const EditorWindowFrameTransferRequests transferRequests =
|
||||
m_runtime->UpdateAndAppend(
|
||||
EditorWindowContentFrameContext{
|
||||
.editorContext = editorContext,
|
||||
.bounds = workspaceBounds,
|
||||
.inputEvents = frameEvents,
|
||||
.cursorScreenPoint = QueryCursorScreenPoint(),
|
||||
.captureStatusText = m_runtime->BuildCaptureStatusText(),
|
||||
.primary = m_session->IsPrimary(),
|
||||
.globalTabDragActive = globalTabDragActive,
|
||||
.useDetachedTitleBarTabStrip = useDetachedTitleBarTabStrip,
|
||||
},
|
||||
workspaceBounds,
|
||||
frameEvents,
|
||||
QueryCursorScreenPoint(),
|
||||
m_session->IsPrimary(),
|
||||
globalTabDragActive,
|
||||
useDetachedTitleBarTabStrip,
|
||||
drawData);
|
||||
if (frameContext.canRenderViewports) {
|
||||
m_runtime->RenderRequestedViewports(frameContext.renderContext);
|
||||
|
||||
@@ -49,11 +49,8 @@ struct UIEditorDockHostDropPreviewState;
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class EditorContext;
|
||||
class EditorWindowContentController;
|
||||
class EditorWindowChromeController;
|
||||
class EditorWindowDockHostBinding;
|
||||
class EditorWindowFrameDriver;
|
||||
class EditorWindowHostRuntime;
|
||||
class EditorWindowInputController;
|
||||
class EditorWindowLifecycleCoordinator;
|
||||
@@ -70,7 +67,7 @@ public:
|
||||
EditorWindowCategory category,
|
||||
EditorWindowChromePolicy chromePolicy,
|
||||
bool primary,
|
||||
std::unique_ptr<EditorWindowContentController> contentController);
|
||||
std::unique_ptr<EditorWindowRuntimeController> runtimeController);
|
||||
~EditorWindow();
|
||||
|
||||
EditorWindow(const EditorWindow&) = delete;
|
||||
@@ -100,7 +97,6 @@ public:
|
||||
|
||||
private:
|
||||
friend class EditorWindowChromeController;
|
||||
friend class EditorWindowFrameDriver;
|
||||
friend class EditorWindowHostRuntime;
|
||||
friend class EditorWindowMessageDispatcher;
|
||||
friend class EditorWindowLifecycleCoordinator;
|
||||
@@ -127,11 +123,8 @@ private:
|
||||
void ApplyHostWindowTitle() override;
|
||||
void RefreshWorkspaceProjection(EditorWorkspaceWindowProjection projection) override;
|
||||
|
||||
bool Initialize(
|
||||
const std::filesystem::path& repoRoot,
|
||||
EditorContext& editorContext,
|
||||
const std::filesystem::path& captureRoot,
|
||||
bool autoCaptureOnStartup);
|
||||
bool InitializeRuntime(
|
||||
const EditorHostWindowRuntimeInitializationParams& params) override;
|
||||
void Shutdown() override;
|
||||
void ResetInteractionState() override;
|
||||
bool TryGetHostScreenRect(EditorWindowScreenRect& outRect) const override;
|
||||
@@ -140,18 +133,15 @@ private:
|
||||
void PostCloseToHost() override;
|
||||
void DestroyHostWindow() override;
|
||||
|
||||
EditorWindowFrameTransferRequests RenderFrame(
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive);
|
||||
EditorWindowFrameTransferRequests OnPaintMessage(
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive);
|
||||
EditorWindowFrameTransferRequests RenderHostFrame(
|
||||
bool globalTabDragActive) override;
|
||||
void ValidateHostFrame() const override;
|
||||
void QueueCompletedImmediateFrame(
|
||||
EditorWindowFrameTransferRequests transferRequests);
|
||||
bool HasQueuedCompletedImmediateFrame() const;
|
||||
EditorWindowFrameTransferRequests ConsumeQueuedCompletedImmediateFrameTransferRequests();
|
||||
void RequestSkipNextSteadyStateFrame();
|
||||
bool ConsumeSkipNextSteadyStateFrame();
|
||||
void RequestSkipNextSteadyStateFrame() override;
|
||||
bool ConsumeSkipNextSteadyStateFrame() override;
|
||||
bool OnResize(UINT width, UINT height);
|
||||
void OnEnterSizeMove();
|
||||
bool OnExitSizeMove();
|
||||
@@ -186,7 +176,6 @@ private:
|
||||
static POINT ToNativePoint(const EditorWindowScreenPoint& screenPoint);
|
||||
static EditorWindowScreenPoint FromNativePoint(const POINT& screenPoint);
|
||||
EditorWindowFrameTransferRequests RenderRuntimeFrame(
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
const ::XCEngine::UI::UIRect& workspaceBounds,
|
||||
::XCEngine::UI::UIDrawData& drawData);
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
#include "Platform/Win32/Chrome/EditorWindowChromeController.h"
|
||||
#include "Platform/Win32/Windowing/EditorFloatingWindowPlacement.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindow.h"
|
||||
#include "Windowing/Content/EditorWindowContentController.h"
|
||||
#include "Windowing/Host/EditorWindowHostCoordinator.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowFrameDriver.h"
|
||||
#include "Windowing/Runtime/EditorWindowRuntimeController.h"
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorRuntimeTrace.h>
|
||||
|
||||
@@ -63,15 +62,15 @@ EditorWindowHostRuntime::EditorWindowHostRuntime(
|
||||
EditorWindowHostRuntime::~EditorWindowHostRuntime() = default;
|
||||
|
||||
EditorWindow* EditorWindowHostRuntime::CreateHostWindow(
|
||||
std::unique_ptr<EditorWindowContentController> contentController,
|
||||
std::unique_ptr<EditorWindowRuntimeController> runtimeController,
|
||||
const EditorWindowCreateParams& params) {
|
||||
if (contentController == nullptr) {
|
||||
LogRuntimeTrace("window", "window creation failed: content controller is null");
|
||||
if (runtimeController == nullptr) {
|
||||
LogRuntimeTrace("window", "window creation failed: runtime controller is null");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const EditorWindowContentCapabilities capabilities =
|
||||
contentController->GetCapabilities();
|
||||
runtimeController->GetCapabilities();
|
||||
if (params.category == EditorWindowCategory::Workspace && !capabilities.workspace) {
|
||||
LogRuntimeTrace("window", "workspace window creation rejected: content is not workspace");
|
||||
return nullptr;
|
||||
@@ -87,7 +86,7 @@ EditorWindow* EditorWindowHostRuntime::CreateHostWindow(
|
||||
params.category,
|
||||
params.chromePolicy,
|
||||
params.primary,
|
||||
std::move(contentController));
|
||||
std::move(runtimeController));
|
||||
EditorWindow* const rawWindow = windowPtr.get();
|
||||
m_windows.push_back(std::move(windowPtr));
|
||||
|
||||
@@ -177,11 +176,13 @@ EditorWindow* EditorWindowHostRuntime::CreateHostWindow(
|
||||
return failWindowInitialization("managed window initialization failed: coordinator missing");
|
||||
}
|
||||
|
||||
if (!rawWindow->Initialize(
|
||||
m_repoRoot,
|
||||
m_hostCoordinator->GetEditorContext(),
|
||||
m_captureRoot,
|
||||
params.autoCaptureOnStartup)) {
|
||||
if (!m_hostCoordinator->InitializeHostWindow(
|
||||
*rawWindow,
|
||||
EditorHostWindowRuntimeInitializationParams{
|
||||
.repoRoot = m_repoRoot,
|
||||
.captureRoot = m_captureRoot,
|
||||
.autoCaptureOnStartup = params.autoCaptureOnStartup,
|
||||
})) {
|
||||
return failWindowInitialization("managed window initialization failed");
|
||||
}
|
||||
|
||||
@@ -313,60 +314,6 @@ std::string EditorWindowHostRuntime::DescribeWindows() const {
|
||||
return DescribeHostWindows(m_windows);
|
||||
}
|
||||
|
||||
void EditorWindowHostRuntime::RenderAllWindows() {
|
||||
if (m_hostCoordinator == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct WindowFrameTransferBatch {
|
||||
EditorWindow* sourceWindow = nullptr;
|
||||
EditorWindowFrameTransferRequests requests = {};
|
||||
};
|
||||
|
||||
std::vector<WindowFrameTransferBatch> transferBatches = {};
|
||||
transferBatches.reserve(m_windows.size());
|
||||
|
||||
for (const std::unique_ptr<EditorWindow>& window : m_windows) {
|
||||
if (window == nullptr ||
|
||||
!window->HasLiveHostWindow() ||
|
||||
window->GetLifecycleState() != EditorWindowLifecycleState::Running) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (window->ConsumeSkipNextSteadyStateFrame()) {
|
||||
m_hostCoordinator->RefreshWindowPresentation(*window);
|
||||
continue;
|
||||
}
|
||||
|
||||
EditorWindowFrameTransferRequests transferRequests =
|
||||
EditorWindowFrameDriver::DriveFrame(
|
||||
*window,
|
||||
m_hostCoordinator->GetEditorContext(),
|
||||
m_hostCoordinator->IsGlobalTabDragActive());
|
||||
m_hostCoordinator->RefreshWindowPresentation(*window);
|
||||
if (!transferRequests.HasPendingRequests()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
transferBatches.push_back(WindowFrameTransferBatch{
|
||||
window.get(),
|
||||
std::move(transferRequests),
|
||||
});
|
||||
}
|
||||
|
||||
for (WindowFrameTransferBatch& batch : transferBatches) {
|
||||
if (batch.sourceWindow == nullptr ||
|
||||
!batch.sourceWindow->HasLiveHostWindow() ||
|
||||
batch.sourceWindow->GetLifecycleState() != EditorWindowLifecycleState::Running) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_hostCoordinator->DispatchWindowFrameTransferRequests(
|
||||
*batch.sourceWindow,
|
||||
batch.requests);
|
||||
}
|
||||
}
|
||||
|
||||
EditorWindow* EditorWindowHostRuntime::FindWindow(HWND hwnd) {
|
||||
if (hwnd == nullptr) {
|
||||
return nullptr;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class EditorWindow;
|
||||
class EditorWindowContentController;
|
||||
class EditorWindowRuntimeController;
|
||||
|
||||
class EditorWindowHostRuntime final : public EditorWindowHostRuntimeServices {
|
||||
public:
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
~EditorWindowHostRuntime();
|
||||
|
||||
EditorWindow* CreateHostWindow(
|
||||
std::unique_ptr<EditorWindowContentController> contentController,
|
||||
std::unique_ptr<EditorWindowRuntimeController> runtimeController,
|
||||
const EditorWindowCreateParams& params) override;
|
||||
void BindHostCoordinator(EditorWindowHostCoordinator& hostCoordinator) override;
|
||||
void HandlePendingNativeWindowCreated(HWND hwnd);
|
||||
@@ -51,7 +51,6 @@ public:
|
||||
const EditorWindowScreenPoint& screenPoint) const override;
|
||||
void ReapDestroyedWindows() override;
|
||||
std::string DescribeWindows() const override;
|
||||
void RenderAllWindows() override;
|
||||
|
||||
const EditorWindowHostConfig& GetHostConfig() const {
|
||||
return m_hostConfig;
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include "Platform/Win32/Chrome/EditorWindowChromeController.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowInputController.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindow.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowFrameDriver.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowRuntimeController.h"
|
||||
#include "Windowing/Runtime/EditorWindowRuntimeController.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowPointerCapture.h"
|
||||
#include "Windowing/Host/EditorWindowHostCoordinator.h"
|
||||
|
||||
@@ -61,10 +60,7 @@ void EditorWindowMessageDispatcher::FlushQueuedCompletedImmediateFrame(
|
||||
void EditorWindowMessageDispatcher::RenderAndHandleWindowFrame(const DispatchContext& context) {
|
||||
FinalizeImmediateFrame(
|
||||
context,
|
||||
EditorWindowFrameDriver::DriveImmediateFrame(
|
||||
context.window,
|
||||
context.hostCoordinator.GetEditorContext(),
|
||||
context.hostCoordinator.IsGlobalTabDragActive()));
|
||||
context.hostCoordinator.DriveImmediateWindowFrame(context.window));
|
||||
}
|
||||
|
||||
bool EditorWindowMessageDispatcher::EnsureTrackingMouseLeave(const DispatchContext& context) {
|
||||
@@ -152,8 +148,7 @@ bool EditorWindowMessageDispatcher::TryDispatchWindowPointerMessage(
|
||||
inputController.GetPointerCaptureOwner()) &&
|
||||
chromeController.HandleResizePointerMove(
|
||||
context.window,
|
||||
context.hostCoordinator.GetEditorContext(),
|
||||
context.hostCoordinator.IsGlobalTabDragActive())) {
|
||||
context.hostCoordinator)) {
|
||||
outResult = 0;
|
||||
return true;
|
||||
}
|
||||
@@ -161,8 +156,7 @@ bool EditorWindowMessageDispatcher::TryDispatchWindowPointerMessage(
|
||||
inputController.GetPointerCaptureOwner()) &&
|
||||
chromeController.HandleChromeDragRestorePointerMove(
|
||||
context.window,
|
||||
context.hostCoordinator.GetEditorContext(),
|
||||
context.hostCoordinator.IsGlobalTabDragActive())) {
|
||||
context.hostCoordinator)) {
|
||||
outResult = 0;
|
||||
return true;
|
||||
}
|
||||
@@ -247,8 +241,7 @@ bool EditorWindowMessageDispatcher::TryDispatchWindowPointerMessage(
|
||||
inputController.GetPointerCaptureOwner()) &&
|
||||
chromeController.HandleChromeButtonUp(
|
||||
context.window,
|
||||
context.hostCoordinator.GetEditorContext(),
|
||||
context.hostCoordinator.IsGlobalTabDragActive(),
|
||||
context.hostCoordinator,
|
||||
lParam)) {
|
||||
outResult = 0;
|
||||
return true;
|
||||
@@ -279,8 +272,7 @@ bool EditorWindowMessageDispatcher::TryDispatchWindowPointerMessage(
|
||||
case WM_LBUTTONDBLCLK:
|
||||
if (chromeController.HandleChromeDoubleClick(
|
||||
context.window,
|
||||
context.hostCoordinator.GetEditorContext(),
|
||||
context.hostCoordinator.IsGlobalTabDragActive(),
|
||||
context.hostCoordinator,
|
||||
lParam)) {
|
||||
outResult = 0;
|
||||
return true;
|
||||
@@ -437,13 +429,16 @@ bool EditorWindowMessageDispatcher::TryDispatchWindowLifecycleMessage(
|
||||
outResult = 0;
|
||||
return true;
|
||||
case WM_PAINT:
|
||||
FinalizeImmediateFrame(
|
||||
context,
|
||||
context.window.OnPaintMessage(
|
||||
context.hostCoordinator.GetEditorContext(),
|
||||
context.hostCoordinator.IsGlobalTabDragActive()));
|
||||
{
|
||||
PAINTSTRUCT paintStruct = {};
|
||||
BeginPaint(context.hwnd, &paintStruct);
|
||||
const EditorWindowFrameTransferRequests transferRequests =
|
||||
context.hostCoordinator.DriveImmediateWindowFrame(context.window);
|
||||
EndPaint(context.hwnd, &paintStruct);
|
||||
FinalizeImmediateFrame(context, transferRequests);
|
||||
outResult = 0;
|
||||
return true;
|
||||
}
|
||||
case WM_ERASEBKGND:
|
||||
outResult = 1;
|
||||
return true;
|
||||
@@ -488,8 +483,7 @@ bool EditorWindowMessageDispatcher::TryDispatchWindowChromeMessage(
|
||||
case WM_SYSCOMMAND:
|
||||
if (chromeController.HandleSystemCommand(
|
||||
context.window,
|
||||
context.hostCoordinator.GetEditorContext(),
|
||||
context.hostCoordinator.IsGlobalTabDragActive(),
|
||||
context.hostCoordinator,
|
||||
wParam)) {
|
||||
outResult = 0;
|
||||
return true;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Windowing/Content/EditorWindowContentController.h"
|
||||
#include "Windowing/Content/EditorWindowContentFactory.h"
|
||||
#include "Windowing/Coordinator/EditorWindowLifecycleCoordinator.h"
|
||||
#include "Windowing/Runtime/EditorWindowRuntimeController.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
@@ -26,9 +27,11 @@ int ResolveOuterDimension(float value, int fallback) {
|
||||
}
|
||||
|
||||
EditorUtilityWindowCoordinator::EditorUtilityWindowCoordinator(
|
||||
EditorContext& editorContext,
|
||||
EditorWindowHost& hostRuntime,
|
||||
EditorWindowContentFactory& contentFactory)
|
||||
: m_hostRuntime(hostRuntime),
|
||||
m_editorContext(editorContext),
|
||||
m_contentFactory(contentFactory) {}
|
||||
|
||||
EditorUtilityWindowCoordinator::~EditorUtilityWindowCoordinator() = default;
|
||||
@@ -122,7 +125,9 @@ bool EditorUtilityWindowCoordinator::TryProcessOpenUtilityWindowRequest(
|
||||
}
|
||||
|
||||
EditorHostWindow* utilityWindow = m_hostRuntime.CreateHostWindow(
|
||||
m_contentFactory.CreateUtilityContentController(*descriptor),
|
||||
std::make_unique<EditorWindowRuntimeController>(
|
||||
m_editorContext,
|
||||
m_contentFactory.CreateUtilityContentController(*descriptor)),
|
||||
createParams);
|
||||
if (utilityWindow == nullptr) {
|
||||
LogRuntimeTrace("utility", "failed to create utility window");
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class EditorContext;
|
||||
class EditorWindowContentFactory;
|
||||
class EditorWindowLifecycleCoordinator;
|
||||
|
||||
class EditorUtilityWindowCoordinator final {
|
||||
public:
|
||||
EditorUtilityWindowCoordinator(
|
||||
EditorContext& editorContext,
|
||||
EditorWindowHost& hostRuntime,
|
||||
EditorWindowContentFactory& contentFactory);
|
||||
~EditorUtilityWindowCoordinator();
|
||||
@@ -29,6 +31,7 @@ private:
|
||||
void LogRuntimeTrace(std::string_view channel, std::string_view message) const;
|
||||
|
||||
EditorWindowHost& m_hostRuntime;
|
||||
EditorContext& m_editorContext;
|
||||
EditorWindowContentFactory& m_contentFactory;
|
||||
EditorWindowLifecycleCoordinator* m_lifecycleCoordinator = nullptr;
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Windowing/Content/EditorWindowContentFactory.h"
|
||||
#include "Windowing/Content/EditorWindowContentController.h"
|
||||
#include "Windowing/Coordinator/EditorWindowLifecycleCoordinator.h"
|
||||
#include "Windowing/Runtime/EditorWindowRuntimeController.h"
|
||||
|
||||
#include <XCEditor/Docking/UIEditorDockHostTransfer.h>
|
||||
#include <XCEditor/Windowing/Presentation/EditorWindowPresentationPolicy.h>
|
||||
@@ -88,10 +89,12 @@ std::string DescribeWindowSetState(const UIEditorWindowWorkspaceSet& windowSet)
|
||||
} // namespace
|
||||
|
||||
EditorWindowWorkspaceCoordinator::EditorWindowWorkspaceCoordinator(
|
||||
EditorContext& editorContext,
|
||||
EditorWindowHost& hostRuntime,
|
||||
EditorWindowSystem& windowSystem,
|
||||
EditorWindowContentFactory& contentFactory)
|
||||
: m_hostRuntime(hostRuntime),
|
||||
m_editorContext(editorContext),
|
||||
m_windowSystem(windowSystem),
|
||||
m_contentFactory(contentFactory) {}
|
||||
|
||||
@@ -365,7 +368,9 @@ bool EditorWindowWorkspaceCoordinator::ApplySynchronizationPlan(
|
||||
}
|
||||
|
||||
EditorHostWindow* const createdWindow = m_hostRuntime.CreateHostWindow(
|
||||
m_contentFactory.CreateWorkspaceContentController(action.create.windowState),
|
||||
std::make_unique<EditorWindowRuntimeController>(
|
||||
m_editorContext,
|
||||
m_contentFactory.CreateWorkspaceContentController(action.create.windowState)),
|
||||
createParams);
|
||||
if (createdWindow == nullptr) {
|
||||
for (const ExistingWindowSnapshot& snapshot : existingWindowSnapshots) {
|
||||
|
||||
@@ -22,12 +22,14 @@ class EditorWindowSystem;
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class EditorContext;
|
||||
class EditorWindowContentFactory;
|
||||
class EditorWindowLifecycleCoordinator;
|
||||
|
||||
class EditorWindowWorkspaceCoordinator final {
|
||||
public:
|
||||
EditorWindowWorkspaceCoordinator(
|
||||
EditorContext& editorContext,
|
||||
EditorWindowHost& hostRuntime,
|
||||
EditorWindowSystem& windowSystem,
|
||||
EditorWindowContentFactory& contentFactory);
|
||||
@@ -114,6 +116,7 @@ private:
|
||||
void LogRuntimeTrace(std::string_view channel, std::string_view message) const;
|
||||
|
||||
EditorWindowHost& m_hostRuntime;
|
||||
EditorContext& m_editorContext;
|
||||
EditorWindowSystem& m_windowSystem;
|
||||
EditorWindowContentFactory& m_contentFactory;
|
||||
EditorWindowLifecycleCoordinator* m_lifecycleCoordinator = nullptr;
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
#include "Windowing/Coordinator/EditorWindowLifecycleCoordinator.h"
|
||||
#include "Windowing/Coordinator/EditorUtilityWindowCoordinator.h"
|
||||
#include "Windowing/Coordinator/EditorWindowWorkspaceCoordinator.h"
|
||||
#include "Windowing/Runtime/EditorWindowRuntimeController.h"
|
||||
|
||||
#include <XCEditor/Workspace/UIEditorWindowWorkspaceModel.h>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
@@ -21,11 +23,13 @@ EditorWindowManager::EditorWindowManager(
|
||||
m_contentFactory = CreateDefaultEditorWindowContentFactory(windowSystem);
|
||||
m_workspaceCoordinator =
|
||||
std::make_unique<EditorWindowWorkspaceCoordinator>(
|
||||
m_editorContext,
|
||||
m_hostRuntime,
|
||||
windowSystem,
|
||||
*m_contentFactory);
|
||||
m_utilityCoordinator =
|
||||
std::make_unique<EditorUtilityWindowCoordinator>(
|
||||
m_editorContext,
|
||||
m_hostRuntime,
|
||||
*m_contentFactory);
|
||||
m_lifecycleCoordinator = std::make_unique<EditorWindowLifecycleCoordinator>(
|
||||
@@ -52,7 +56,9 @@ EditorHostWindow* EditorWindowManager::CreateWorkspaceWindow(
|
||||
}
|
||||
|
||||
EditorHostWindow* const window = m_hostRuntime.CreateHostWindow(
|
||||
m_contentFactory->CreateWorkspaceContentController(windowState),
|
||||
std::make_unique<EditorWindowRuntimeController>(
|
||||
m_editorContext,
|
||||
m_contentFactory->CreateWorkspaceContentController(windowState)),
|
||||
params);
|
||||
if (window != nullptr) {
|
||||
m_workspaceCoordinator->RegisterExistingWindow(*window);
|
||||
@@ -68,7 +74,9 @@ EditorHostWindow* EditorWindowManager::CreateUtilityWindow(
|
||||
}
|
||||
|
||||
EditorHostWindow* const window = m_hostRuntime.CreateHostWindow(
|
||||
m_contentFactory->CreateUtilityContentController(descriptor),
|
||||
std::make_unique<EditorWindowRuntimeController>(
|
||||
m_editorContext,
|
||||
m_contentFactory->CreateUtilityContentController(descriptor)),
|
||||
params);
|
||||
if (window != nullptr) {
|
||||
m_workspaceCoordinator->RegisterExistingWindow(*window);
|
||||
@@ -107,15 +115,85 @@ void EditorWindowManager::DestroyClosedWindows() {
|
||||
}
|
||||
|
||||
void EditorWindowManager::RenderAllWindows() {
|
||||
m_hostRuntime.RenderAllWindows();
|
||||
struct WindowFrameTransferBatch {
|
||||
EditorHostWindow* sourceWindow = nullptr;
|
||||
EditorWindowFrameTransferRequests requests = {};
|
||||
};
|
||||
|
||||
std::vector<WindowFrameTransferBatch> transferBatches = {};
|
||||
const std::vector<EditorHostWindow*> windows = m_hostRuntime.GetWindows();
|
||||
transferBatches.reserve(windows.size());
|
||||
|
||||
for (EditorHostWindow* window : windows) {
|
||||
if (window == nullptr ||
|
||||
!window->HasLiveHostWindow() ||
|
||||
window->GetLifecycleState() != EditorWindowLifecycleState::Running) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (window->ConsumeSkipNextSteadyStateFrame()) {
|
||||
RefreshWindowPresentation(*window);
|
||||
continue;
|
||||
}
|
||||
|
||||
EditorWindowFrameTransferRequests transferRequests = DriveWindowFrame(*window);
|
||||
RefreshWindowPresentation(*window);
|
||||
if (!transferRequests.HasPendingRequests()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
transferBatches.push_back(WindowFrameTransferBatch{
|
||||
window,
|
||||
std::move(transferRequests),
|
||||
});
|
||||
}
|
||||
|
||||
for (WindowFrameTransferBatch& batch : transferBatches) {
|
||||
if (batch.sourceWindow == nullptr ||
|
||||
!batch.sourceWindow->HasLiveHostWindow() ||
|
||||
batch.sourceWindow->GetLifecycleState() != EditorWindowLifecycleState::Running) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DispatchWindowFrameTransferRequests(
|
||||
*batch.sourceWindow,
|
||||
batch.requests);
|
||||
}
|
||||
}
|
||||
|
||||
EditorContext& EditorWindowManager::GetEditorContext() {
|
||||
return m_editorContext;
|
||||
bool EditorWindowManager::InitializeHostWindow(
|
||||
EditorHostWindow& window,
|
||||
const EditorHostWindowRuntimeInitializationParams& params) {
|
||||
return window.InitializeRuntime(params);
|
||||
}
|
||||
|
||||
const EditorContext& EditorWindowManager::GetEditorContext() const {
|
||||
return m_editorContext;
|
||||
EditorWindowFrameTransferRequests EditorWindowManager::DriveWindowFrame(
|
||||
EditorHostWindow& window) {
|
||||
return DriveWindowFrameInternal(window, false);
|
||||
}
|
||||
|
||||
EditorWindowFrameTransferRequests EditorWindowManager::DriveImmediateWindowFrame(
|
||||
EditorHostWindow& window) {
|
||||
return DriveWindowFrameInternal(window, true);
|
||||
}
|
||||
|
||||
EditorWindowFrameTransferRequests EditorWindowManager::DriveWindowFrameInternal(
|
||||
EditorHostWindow& window,
|
||||
bool requestSkipNextSteadyStateFrame) {
|
||||
if (!window.IsRenderReady() ||
|
||||
!window.HasLiveHostWindow() ||
|
||||
window.GetLifecycleState() != EditorWindowLifecycleState::Running) {
|
||||
return {};
|
||||
}
|
||||
|
||||
EditorWindowFrameTransferRequests transferRequests =
|
||||
window.RenderHostFrame(IsGlobalTabDragActive());
|
||||
window.ValidateHostFrame();
|
||||
if (requestSkipNextSteadyStateFrame) {
|
||||
window.RequestSkipNextSteadyStateFrame();
|
||||
}
|
||||
|
||||
return transferRequests;
|
||||
}
|
||||
|
||||
bool EditorWindowManager::IsGlobalTabDragActive() const {
|
||||
|
||||
@@ -55,8 +55,12 @@ public:
|
||||
void RenderAllWindows();
|
||||
|
||||
private:
|
||||
EditorContext& GetEditorContext() override;
|
||||
const EditorContext& GetEditorContext() const override;
|
||||
bool InitializeHostWindow(
|
||||
EditorHostWindow& window,
|
||||
const EditorHostWindowRuntimeInitializationParams& params) override;
|
||||
EditorWindowFrameTransferRequests DriveWindowFrame(EditorHostWindow& window) override;
|
||||
EditorWindowFrameTransferRequests DriveImmediateWindowFrame(
|
||||
EditorHostWindow& window) override;
|
||||
bool IsGlobalTabDragActive() const override;
|
||||
bool OwnsActiveGlobalTabDrag(std::string_view windowId) const override;
|
||||
bool HandleGlobalTabDragPointerMove(EditorHostWindow& window) override;
|
||||
@@ -71,6 +75,10 @@ private:
|
||||
void AbortUnregisteredWindow(EditorHostWindow& window) override;
|
||||
void ReapDestroyedWindows() override;
|
||||
|
||||
EditorWindowFrameTransferRequests DriveWindowFrameInternal(
|
||||
EditorHostWindow& window,
|
||||
bool requestSkipNextSteadyStateFrame);
|
||||
|
||||
EditorContext& m_editorContext;
|
||||
EditorWindowHostRuntimeServices& m_hostRuntime;
|
||||
std::unique_ptr<EditorWindowContentFactory> m_contentFactory = {};
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
#include "Windowing/Frame/EditorWindowTransferRequests.h"
|
||||
#include "Windowing/Host/EditorWindowHostInterfaces.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class EditorContext;
|
||||
|
||||
class EditorWindowHostCoordinator {
|
||||
public:
|
||||
virtual ~EditorWindowHostCoordinator() = default;
|
||||
|
||||
virtual EditorContext& GetEditorContext() = 0;
|
||||
virtual const EditorContext& GetEditorContext() const = 0;
|
||||
virtual bool InitializeHostWindow(
|
||||
EditorHostWindow& window,
|
||||
const EditorHostWindowRuntimeInitializationParams& params) = 0;
|
||||
virtual EditorWindowFrameTransferRequests DriveWindowFrame(EditorHostWindow& window) = 0;
|
||||
virtual EditorWindowFrameTransferRequests DriveImmediateWindowFrame(
|
||||
EditorHostWindow& window) = 0;
|
||||
|
||||
virtual bool IsGlobalTabDragActive() const = 0;
|
||||
virtual bool OwnsActiveGlobalTabDrag(std::string_view windowId) const = 0;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Windowing/EditorWindowShared.h"
|
||||
#include "Windowing/Frame/EditorWindowTransferRequests.h"
|
||||
#include "Windowing/Host/EditorWindowHostTypes.h"
|
||||
#include "Windowing/Host/EditorWindowPointerCapture.h"
|
||||
#include "Windowing/Host/EditorWindowTypes.h"
|
||||
@@ -8,6 +9,7 @@
|
||||
#include <XCEditor/Windowing/Presentation/EditorWorkspaceWindowProjection.h>
|
||||
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
@@ -27,8 +29,14 @@ struct UIEditorDockHostTabDropTarget;
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class EditorWindowHostCoordinator;
|
||||
class EditorWindowContentController;
|
||||
class EditorWindowDockHostBinding;
|
||||
class EditorWindowRuntimeController;
|
||||
|
||||
struct EditorHostWindowRuntimeInitializationParams {
|
||||
std::filesystem::path repoRoot = {};
|
||||
std::filesystem::path captureRoot = {};
|
||||
bool autoCaptureOnStartup = false;
|
||||
};
|
||||
|
||||
class EditorHostWindow {
|
||||
public:
|
||||
@@ -67,6 +75,13 @@ public:
|
||||
virtual void MarkClosing() = 0;
|
||||
virtual void MarkDestroyed() = 0;
|
||||
virtual bool IsRenderReady() const = 0;
|
||||
virtual bool InitializeRuntime(
|
||||
const EditorHostWindowRuntimeInitializationParams& params) = 0;
|
||||
virtual EditorWindowFrameTransferRequests RenderHostFrame(
|
||||
bool globalTabDragActive) = 0;
|
||||
virtual void ValidateHostFrame() const = 0;
|
||||
virtual void RequestSkipNextSteadyStateFrame() = 0;
|
||||
virtual bool ConsumeSkipNextSteadyStateFrame() = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
virtual bool TryGetHostScreenRect(EditorWindowScreenRect& outRect) const = 0;
|
||||
virtual void SetHostScreenPosition(const EditorWindowScreenPoint& screenPoint) = 0;
|
||||
@@ -80,7 +95,7 @@ public:
|
||||
virtual ~EditorWindowHost() = default;
|
||||
|
||||
virtual EditorHostWindow* CreateHostWindow(
|
||||
std::unique_ptr<EditorWindowContentController> contentController,
|
||||
std::unique_ptr<EditorWindowRuntimeController> runtimeController,
|
||||
const EditorWindowCreateParams& params) = 0;
|
||||
virtual EditorHostWindow* FindWindowById(std::string_view windowId) = 0;
|
||||
virtual const EditorHostWindow* FindWindowById(std::string_view windowId) const = 0;
|
||||
@@ -106,7 +121,6 @@ public:
|
||||
virtual ~EditorWindowHostRuntimeServices() = default;
|
||||
|
||||
virtual void BindHostCoordinator(EditorWindowHostCoordinator& hostCoordinator) = 0;
|
||||
virtual void RenderAllWindows() = 0;
|
||||
};
|
||||
|
||||
} // namespace XCEngine::UI::Editor::App
|
||||
|
||||
@@ -1,33 +1,41 @@
|
||||
#include "Platform/Win32/Runtime/EditorWindowRuntimeController.h"
|
||||
#include "Windowing/Runtime/EditorWindowRuntimeController.h"
|
||||
|
||||
#include "Bootstrap/EditorResources.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowSupport.h"
|
||||
#include "Support/EmbeddedPngLoader.h"
|
||||
#include "Support/TextFormat.h"
|
||||
|
||||
#include <XCEditor/Docking/UIEditorDockHostTransfer.h>
|
||||
#include <XCEditor/Foundation/UIEditorRuntimeTrace.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
using App::LoadEmbeddedPngTexture;
|
||||
using namespace EditorWindowSupport;
|
||||
using App::TruncateText;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr float kFrameTimeSmoothingFactor = 0.12f;
|
||||
constexpr float kFrameStatsDisplayRefreshIntervalSeconds = 0.25f;
|
||||
|
||||
void LogRuntimeTrace(std::string_view channel, std::string_view message) {
|
||||
AppendUIEditorRuntimeTrace(channel, message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EditorWindowRuntimeController::EditorWindowRuntimeController(
|
||||
EditorContext& editorContext,
|
||||
std::unique_ptr<EditorWindowContentController> contentController)
|
||||
: m_contentController(std::move(contentController)) {}
|
||||
: m_editorContext(editorContext)
|
||||
, m_contentController(std::move(contentController)) {}
|
||||
|
||||
EditorWindowRuntimeController::~EditorWindowRuntimeController() = default;
|
||||
|
||||
@@ -35,6 +43,12 @@ bool EditorWindowRuntimeController::IsReady() const {
|
||||
return m_ready;
|
||||
}
|
||||
|
||||
EditorWindowContentCapabilities EditorWindowRuntimeController::GetCapabilities() const {
|
||||
return m_contentController != nullptr
|
||||
? m_contentController->GetCapabilities()
|
||||
: EditorWindowContentCapabilities{};
|
||||
}
|
||||
|
||||
EditorWindowWorkspaceBinding* EditorWindowRuntimeController::TryGetWorkspaceBinding() {
|
||||
return m_contentController != nullptr
|
||||
? m_contentController->TryGetWorkspaceBinding()
|
||||
@@ -110,7 +124,6 @@ const ::XCEngine::UI::UITextureHandle& EditorWindowRuntimeController::GetTitleBa
|
||||
bool EditorWindowRuntimeController::Initialize(
|
||||
HWND hwnd,
|
||||
const std::filesystem::path& repoRoot,
|
||||
EditorContext& editorContext,
|
||||
const std::filesystem::path& captureRoot,
|
||||
bool autoCaptureOnStartup) {
|
||||
if (hwnd == nullptr) {
|
||||
@@ -157,10 +170,10 @@ bool EditorWindowRuntimeController::Initialize(
|
||||
}
|
||||
|
||||
assert(m_contentController != nullptr);
|
||||
m_contentController->PrepareEditorContext(editorContext, m_textSystem);
|
||||
m_contentController->PrepareEditorContext(m_editorContext, m_textSystem);
|
||||
m_contentController->Initialize(EditorWindowContentInitializationContext{
|
||||
.repoRoot = repoRoot,
|
||||
.editorContext = editorContext,
|
||||
.editorContext = m_editorContext,
|
||||
.textureHost = m_textureHost,
|
||||
.textMeasurer = m_textSystem,
|
||||
.viewportRenderer = m_windowRenderer,
|
||||
@@ -192,7 +205,7 @@ bool EditorWindowRuntimeController::Initialize(
|
||||
m_screenshotController.Initialize(captureRoot);
|
||||
if (autoCaptureOnStartup) {
|
||||
m_screenshotController.RequestCapture("startup");
|
||||
m_contentController->NotifyStartupCaptureRequested(editorContext);
|
||||
m_contentController->NotifyStartupCaptureRequested(m_editorContext);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -253,23 +266,21 @@ bool EditorWindowRuntimeController::ApplyResize(UINT width, UINT height) {
|
||||
return resizeResult.hasViewportSurfacePresentation;
|
||||
}
|
||||
|
||||
void EditorWindowRuntimeController::PrepareEditorContext(EditorContext& editorContext) {
|
||||
void EditorWindowRuntimeController::PrepareEditorContext() {
|
||||
if (m_contentController != nullptr) {
|
||||
m_contentController->PrepareEditorContext(editorContext, m_textSystem);
|
||||
m_contentController->PrepareEditorContext(m_editorContext, m_textSystem);
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorWindowRuntimeController::IsEditorContextValid(
|
||||
const EditorContext& editorContext) const {
|
||||
bool EditorWindowRuntimeController::IsEditorContextValid() const {
|
||||
return m_contentController != nullptr &&
|
||||
m_contentController->IsEditorContextValid(editorContext);
|
||||
m_contentController->IsEditorContextValid(m_editorContext);
|
||||
}
|
||||
|
||||
void EditorWindowRuntimeController::AppendInvalidFrame(
|
||||
const EditorContext& editorContext,
|
||||
::XCEngine::UI::UIDrawList& drawList) const {
|
||||
if (m_contentController != nullptr) {
|
||||
m_contentController->AppendInvalidFrame(editorContext, drawList);
|
||||
m_contentController->AppendInvalidFrame(m_editorContext, drawList);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,10 +322,26 @@ Host::D3D12WindowRenderLoopPresentResult EditorWindowRuntimeController::Present(
|
||||
}
|
||||
|
||||
EditorWindowFrameTransferRequests EditorWindowRuntimeController::UpdateAndAppend(
|
||||
const EditorWindowContentFrameContext& context,
|
||||
const ::XCEngine::UI::UIRect& bounds,
|
||||
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
||||
std::optional<EditorWindowScreenPoint> cursorScreenPoint,
|
||||
bool primary,
|
||||
bool globalTabDragActive,
|
||||
bool useDetachedTitleBarTabStrip,
|
||||
::XCEngine::UI::UIDrawData& drawData) {
|
||||
assert(m_contentController != nullptr);
|
||||
return m_contentController->UpdateAndAppend(context, drawData);
|
||||
return m_contentController->UpdateAndAppend(
|
||||
EditorWindowContentFrameContext{
|
||||
.editorContext = m_editorContext,
|
||||
.bounds = bounds,
|
||||
.inputEvents = inputEvents,
|
||||
.cursorScreenPoint = cursorScreenPoint,
|
||||
.captureStatusText = BuildCaptureStatusText(),
|
||||
.primary = primary,
|
||||
.globalTabDragActive = globalTabDragActive,
|
||||
.useDetachedTitleBarTabStrip = useDetachedTitleBarTabStrip,
|
||||
},
|
||||
drawData);
|
||||
}
|
||||
|
||||
void EditorWindowRuntimeController::RenderRequestedViewports(
|
||||
@@ -5,7 +5,7 @@
|
||||
#endif
|
||||
|
||||
#include "Windowing/Content/EditorWindowContentController.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowScreenshotController.h"
|
||||
#include "Windowing/Runtime/EditorWindowScreenshotController.h"
|
||||
|
||||
#include <Rendering/D3D12/D3D12UiRenderer.h>
|
||||
#include <Rendering/D3D12/D3D12UiTextSystem.h>
|
||||
@@ -20,7 +20,9 @@
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine::UI {
|
||||
|
||||
@@ -34,7 +36,8 @@ class EditorContext;
|
||||
|
||||
class EditorWindowRuntimeController final {
|
||||
public:
|
||||
explicit EditorWindowRuntimeController(
|
||||
EditorWindowRuntimeController(
|
||||
EditorContext& editorContext,
|
||||
std::unique_ptr<EditorWindowContentController> contentController);
|
||||
~EditorWindowRuntimeController();
|
||||
|
||||
@@ -44,6 +47,7 @@ public:
|
||||
EditorWindowRuntimeController& operator=(EditorWindowRuntimeController&&) = delete;
|
||||
|
||||
bool IsReady() const;
|
||||
EditorWindowContentCapabilities GetCapabilities() const;
|
||||
|
||||
EditorWindowWorkspaceBinding* TryGetWorkspaceBinding();
|
||||
const EditorWindowWorkspaceBinding* TryGetWorkspaceBinding() const;
|
||||
@@ -64,23 +68,25 @@ public:
|
||||
bool Initialize(
|
||||
HWND hwnd,
|
||||
const std::filesystem::path& repoRoot,
|
||||
EditorContext& editorContext,
|
||||
const std::filesystem::path& captureRoot,
|
||||
bool autoCaptureOnStartup);
|
||||
void Shutdown();
|
||||
void ResetInteractionState();
|
||||
bool ApplyResize(UINT width, UINT height);
|
||||
|
||||
void PrepareEditorContext(EditorContext& editorContext);
|
||||
bool IsEditorContextValid(const EditorContext& editorContext) const;
|
||||
void AppendInvalidFrame(
|
||||
const EditorContext& editorContext,
|
||||
::XCEngine::UI::UIDrawList& drawList) const;
|
||||
void PrepareEditorContext();
|
||||
bool IsEditorContextValid() const;
|
||||
void AppendInvalidFrame(::XCEngine::UI::UIDrawList& drawList) const;
|
||||
Host::D3D12WindowRenderLoopFrameContext BeginFrame();
|
||||
Host::D3D12WindowRenderLoopPresentResult Present(
|
||||
const ::XCEngine::UI::UIDrawData& drawData);
|
||||
EditorWindowFrameTransferRequests UpdateAndAppend(
|
||||
const EditorWindowContentFrameContext& context,
|
||||
const ::XCEngine::UI::UIRect& bounds,
|
||||
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
||||
std::optional<EditorWindowScreenPoint> cursorScreenPoint,
|
||||
bool primary,
|
||||
bool globalTabDragActive,
|
||||
bool useDetachedTitleBarTabStrip,
|
||||
::XCEngine::UI::UIDrawData& drawData);
|
||||
void RenderRequestedViewports(
|
||||
const ::XCEngine::Rendering::RenderContext& renderContext);
|
||||
@@ -94,6 +100,7 @@ private:
|
||||
void UpdateFrameTiming();
|
||||
void RefreshDisplayedFrameStats();
|
||||
|
||||
EditorContext& m_editorContext;
|
||||
Host::D3D12WindowRenderer m_windowRenderer = {};
|
||||
Host::D3D12UiTextureHost m_textureHost = {};
|
||||
Host::D3D12UiTextSystem m_textSystem = {};
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "Platform/Win32/Runtime/EditorWindowScreenshotController.h"
|
||||
#include "Windowing/Runtime/EditorWindowScreenshotController.h"
|
||||
|
||||
#include "Support/ExecutablePath.h"
|
||||
|
||||
@@ -4,12 +4,16 @@
|
||||
#include <XCEditor/Menu/UIEditorMenuBar.h>
|
||||
#include <XCEditor/Shell/UIEditorStatusBar.h>
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
class BuiltInIcons;
|
||||
}
|
||||
|
||||
namespace XCEngine::UI::Editor {
|
||||
|
||||
class UIEditorShellIconResolver {
|
||||
public:
|
||||
virtual ~UIEditorShellIconResolver() = default;
|
||||
|
||||
virtual const ::XCEngine::UI::UITextureHandle* TryResolveIcon(
|
||||
std::uint8_t iconKind) const = 0;
|
||||
};
|
||||
|
||||
struct UIEditorShellToolbarButton {
|
||||
std::string buttonId = {};
|
||||
std::uint8_t iconKind = 0;
|
||||
@@ -143,7 +147,7 @@ void AppendUIEditorShellCompose(
|
||||
const UIEditorShellComposeState& state,
|
||||
const UIEditorShellComposePalette& palette = {},
|
||||
const UIEditorShellComposeMetrics& metrics = {},
|
||||
const App::BuiltInIcons* builtInIcons = nullptr);
|
||||
const UIEditorShellIconResolver* iconResolver = nullptr);
|
||||
|
||||
void AppendUIEditorShellComposeBase(
|
||||
::XCEngine::UI::UIDrawList& drawList,
|
||||
@@ -152,7 +156,7 @@ void AppendUIEditorShellComposeBase(
|
||||
const UIEditorShellComposeState& state,
|
||||
const UIEditorShellComposePalette& palette = {},
|
||||
const UIEditorShellComposeMetrics& metrics = {},
|
||||
const App::BuiltInIcons* builtInIcons = nullptr);
|
||||
const UIEditorShellIconResolver* iconResolver = nullptr);
|
||||
|
||||
void AppendUIEditorShellComposeStatusBar(
|
||||
::XCEngine::UI::UIDrawList& drawList,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include <XCEditor/Shell/UIEditorShellCompose.h>
|
||||
|
||||
#include "Rendering/Assets/BuiltInIcons.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine::UI::Editor {
|
||||
@@ -77,14 +75,15 @@ void AppendToolbarGlyph(
|
||||
::XCEngine::UI::UIDrawList& drawList,
|
||||
const UIRect& rect,
|
||||
std::uint8_t iconKind,
|
||||
const App::BuiltInIcons* icons,
|
||||
const UIEditorShellIconResolver* iconResolver,
|
||||
const UIColor& tintColor) {
|
||||
if (icons == nullptr) {
|
||||
if (iconResolver == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ::XCEngine::UI::UITextureHandle& texture = icons->Resolve(static_cast<App::BuiltInIconKind>(iconKind));
|
||||
if (!texture.IsValid()) {
|
||||
const ::XCEngine::UI::UITextureHandle* const texture =
|
||||
iconResolver->TryResolveIcon(iconKind);
|
||||
if (texture == nullptr || !texture->IsValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -94,7 +93,7 @@ void AppendToolbarGlyph(
|
||||
rect.y + inset,
|
||||
rect.width - inset * 2.0f,
|
||||
rect.height - inset * 2.0f);
|
||||
drawList.AddImage(iconRect, texture, tintColor);
|
||||
drawList.AddImage(iconRect, *texture, tintColor);
|
||||
}
|
||||
|
||||
void AppendUIEditorShellToolbar(
|
||||
@@ -103,7 +102,7 @@ void AppendUIEditorShellToolbar(
|
||||
const std::vector<UIEditorShellToolbarButton>& buttons,
|
||||
const UIEditorShellToolbarPalette& palette,
|
||||
const UIEditorShellToolbarMetrics& metrics,
|
||||
const App::BuiltInIcons* builtInIcons) {
|
||||
const UIEditorShellIconResolver* iconResolver) {
|
||||
if (layout.bounds.width <= 0.0f || layout.bounds.height <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
@@ -135,7 +134,7 @@ void AppendUIEditorShellToolbar(
|
||||
drawList,
|
||||
buttonRect,
|
||||
buttons[index].iconKind,
|
||||
builtInIcons,
|
||||
iconResolver,
|
||||
palette.iconColor);
|
||||
}
|
||||
}
|
||||
@@ -292,7 +291,7 @@ void AppendUIEditorShellCompose(
|
||||
const UIEditorShellComposeState& state,
|
||||
const UIEditorShellComposePalette& palette,
|
||||
const UIEditorShellComposeMetrics& metrics,
|
||||
const App::BuiltInIcons* builtInIcons) {
|
||||
const UIEditorShellIconResolver* iconResolver) {
|
||||
AppendUIEditorShellComposeBase(
|
||||
drawList,
|
||||
frame,
|
||||
@@ -300,7 +299,7 @@ void AppendUIEditorShellCompose(
|
||||
state,
|
||||
palette,
|
||||
metrics,
|
||||
builtInIcons);
|
||||
iconResolver);
|
||||
|
||||
AppendUIEditorWorkspaceCompose(
|
||||
drawList,
|
||||
@@ -327,7 +326,7 @@ void AppendUIEditorShellComposeBase(
|
||||
const UIEditorShellComposeState& state,
|
||||
const UIEditorShellComposePalette& palette,
|
||||
const UIEditorShellComposeMetrics& metrics,
|
||||
const App::BuiltInIcons* builtInIcons) {
|
||||
const UIEditorShellIconResolver* iconResolver) {
|
||||
drawList.AddFilledRect(
|
||||
frame.layout.bounds,
|
||||
palette.surfaceColor,
|
||||
@@ -359,7 +358,7 @@ void AppendUIEditorShellComposeBase(
|
||||
model.toolbarButtons,
|
||||
palette.toolbarPalette,
|
||||
metrics.toolbarMetrics,
|
||||
builtInIcons);
|
||||
iconResolver);
|
||||
}
|
||||
|
||||
void AppendUIEditorShellComposeStatusBar(
|
||||
|
||||
@@ -34,16 +34,25 @@ SceneRenderer
|
||||
`ScriptableRenderPipelineAsset -> ScriptableRendererData -> ScriptableRenderer -> ScriptableRendererFeature/Pass`
|
||||
- builtin 和 SRP 现在都必须是显式可切换的顶层路径,而不是“SRP 隐式优先,builtin 只是兜底”。
|
||||
- `ScriptableRenderPipelineHost` 里的 native backend 是 managed SRP 的绘制后端,不是 SRP stage 录制失败时的顶层兜底。
|
||||
- managed `ScriptableRenderContext` 的公开场景接口只表达绘制能力:`DrawRenderers(...)`、`DrawSkybox()`、`DrawOpaqueRenderers()`、`DrawTransparentRenderers()`。
|
||||
- renderer-backed SRP 的 frame stage 组织权归 `ScriptableRenderer` / `ScriptableRendererFeature`,包括 shadow caster、depth only、post-process、final output 等可选 stage。
|
||||
|
||||
## 5. 当前硬边界
|
||||
- `RenderPipelineFactory` 在无显式 asset、无托管配置、创建失败回退时,都必须先回 builtin,而不是回 `ScriptableRenderPipelineHost`。
|
||||
- `MonoScriptRuntime::OnRuntimeStart()` 不得隐式写入 render pipeline 选择。
|
||||
- builtin 私有 native feature 通道只能留在 native 内部使用。
|
||||
- managed SRP runtime 或 stage recorder 存在时,stage 组织权归 managed SRP;native backend 不得在 host 层隐式接管 `RecordStageRenderGraph`、`Render(...)` 或 scene-pass standalone stage。
|
||||
- `RendererBackedRenderPipelineAsset` 进入 frame planning 时必须先清掉 native 默认请求出来的可选 stage,再由 renderer / feature 显式请求需要的 stage。
|
||||
- 下列能力不得再暴露给 managed / URP 公开层:
|
||||
`NativeSceneFeaturePassId`
|
||||
`ScriptableRenderContext.RecordNativeSceneFeaturePass(...)`
|
||||
`ScriptableRenderContext.RecordScene(...)`
|
||||
`ScriptableRenderContext.RecordScenePhase(...)`
|
||||
`ScriptableRenderContext.RecordSceneInjectionPoint(...)`
|
||||
`ScriptableRenderContext.RecordOpaque/Skybox/TransparentScenePhase(...)`
|
||||
`ScriptableRenderContext.RecordBefore/After*Injection(...)`
|
||||
依赖上述接口的 managed wrapper feature / controller
|
||||
- `CameraRenderRequestContext.hasDirectionalShadow` 和 `CameraRenderRequestContext.ClearDirectionalShadow()` 不得作为 ScriptCore public surface 暴露;core 层只能保留内部桥接,产品层策略放在 URP renderer asset / renderer data / feature。
|
||||
- URP 默认 renderer feature 工厂不得自动注入 builtin 私有 feature wrapper。
|
||||
|
||||
## 6. native / managed 分层
|
||||
@@ -57,7 +66,9 @@ SceneRenderer
|
||||
renderer 选择
|
||||
stage planning
|
||||
renderer feature / pass 组织
|
||||
renderer feature 的 frame-plan / scene-setup / shadow-execution 配置分发
|
||||
camera 级策略
|
||||
shadow caster / depth only 等可选 stage 的显式请求
|
||||
产品层行为差异
|
||||
- 判断原则:
|
||||
如果新增的是“绘制能力”或“后端 contract”,优先放 C++。
|
||||
@@ -66,9 +77,11 @@ SceneRenderer
|
||||
## 7. 禁止回退的实现方式
|
||||
- 不要再引入“项目默认 SRP asset 自动生效”的隐式逻辑。
|
||||
- 不要再把 builtin 私有 native feature 包成 public managed API 方便调用。
|
||||
- 不要让 managed `ScriptableRenderContext.RecordScene(...)` 或任何 managed pass 录制 native scene injection point。
|
||||
- 不要再让 “null 选择” 默认落到 `ScriptableRenderPipelineHost`。
|
||||
- 不要把非通用产品层策略继续直接塞回 `BuiltinForwardPipeline`。
|
||||
- 不要让 `ScriptableRenderPipelineHost` 在 managed SRP 未支持或未录制某个 stage 时自动回退到 native backend;需要绘制时应通过 managed `ScriptableRenderContext` 显式调用 native draw 能力。
|
||||
- 不要让 renderer-backed SRP 继续继承 native planner 默认请求出来的 shadow/depth stage;需要这些 stage 时必须由 managed renderer / feature 显式请求并录制。
|
||||
|
||||
## 8. 关键文件
|
||||
- `engine/src/Rendering/Internal/RenderPipelineFactory.cpp`
|
||||
@@ -89,7 +102,21 @@ SceneRenderer
|
||||
无 managed 选择时默认走 builtin。
|
||||
设置 managed descriptor 后切到 `ScriptableRenderPipelineHost`。
|
||||
清空 managed descriptor 后退回 builtin。
|
||||
- `tests/scripting/test_mono_script_runtime.cpp`
|
||||
`ScriptableRenderContextPublicApiSurfaceUsesDirectContextModel` 保证 public managed surface 不再暴露 native scene injection / phase wrapper。
|
||||
`DefaultSceneRendererUsesManagedUniversalPipelineForPlannedMainSceneAndPostProcessRender` 保证 managed URP 通过显式 renderer/pass 录制主场景和后处理。
|
||||
`ManagedRenderContextExposes*ThroughRenderingData` 保证 managed renderer 可通过 `RenderingData` 观察 camera / lighting / shadow / environment / final color / stage color 数据。
|
||||
`ManagedStageRecorderRecordsMainSceneThroughScriptableRenderContext` 保证主场景通过 `ScriptableRenderContext` 的显式 draw 能力录制。
|
||||
|
||||
## 10. 后续演进方向
|
||||
- 继续补齐 URP 上层组织能力,但不能破坏 builtin / programmable 的显式切换语义。
|
||||
- 如果未来继续向 Unity 收口,优先收口“入口语义”和“分层边界”,不要靠隐式 fallback 和私有桥接维持表面形似。
|
||||
|
||||
## 过去几刀
|
||||
|
||||
- 收回 managed native scene injection 公开面:渲染模块目标向 Unity SRP / URP 对齐,但 managed / URP 层仍公开 native builtin scene injection point 和 phase wrapper,导致产品层像是在组织 URP,实质上仍在调用 builtin 私有时序。
|
||||
- 移除 `ScriptableRenderContext.RecordSceneInjectionPoint(...)`、`RecordBefore/After*Injection(...)`、`RecordOpaque/Skybox/TransparentScenePhase(...)` 等 public managed API;移除对应 Mono internal call;`RecordScene()` / `RecordScenePhase(...)` 收回 internal。
|
||||
- 确立 managed 公开层只通过 `DrawRenderers(...)`、`DrawSkybox()`、`DrawOpaqueRenderers()`、`DrawTransparentRenderers()` 表达 native draw 能力;pass / feature / stage 的组织权归 managed SRP / URP。
|
||||
- `ScriptableRenderer` 统一驱动 renderer feature 的 frame-plan、scene-setup、directional-shadow execution 配置;`RendererBackedRenderPipelineAsset` 清掉 native 默认 optional stage 后再让 renderer / feature 显式请求。
|
||||
- `CameraRenderRequestContext.hasDirectionalShadow` 和 `ClearDirectionalShadow()` 从 ScriptCore public surface 收回 internal,避免 core public API 泄漏 native shadow 规划控制。
|
||||
- 当时验证:`xcengine_managed_assemblies`、`scripting_tests` 构建通过;聚焦 `MonoScriptRuntimeTest` 12 项 SRP / URP / API surface 测试通过。
|
||||
|
||||
@@ -5594,25 +5594,6 @@ InternalCall_Rendering_ScriptableRenderContext_RecordScenePhase(
|
||||
: 0;
|
||||
}
|
||||
|
||||
mono_bool
|
||||
InternalCall_Rendering_ScriptableRenderContext_RecordSceneInjectionPoint(
|
||||
uint64_t nativeHandle,
|
||||
int32_t injectionPoint) {
|
||||
ManagedScriptableRenderContextState* const state =
|
||||
FindManagedScriptableRenderContextState(nativeHandle);
|
||||
if (state == nullptr ||
|
||||
state->graphContext == nullptr ||
|
||||
state->sceneRecorder == nullptr ||
|
||||
state->stage != Rendering::CameraFrameStage::MainScene) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return state->sceneRecorder->RecordInjectionPoint(
|
||||
static_cast<Rendering::SceneRenderInjectionPoint>(injectionPoint))
|
||||
? 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
mono_bool
|
||||
InternalCall_Rendering_ScriptableRenderContext_DrawRenderersByDesc(
|
||||
uint64_t nativeHandle,
|
||||
@@ -6576,7 +6557,6 @@ void RegisterInternalCalls() {
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetFinalColorHasCameraOverrides", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_GetFinalColorHasCameraOverrides));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordScenePhase", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_RecordScenePhase));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_DrawRenderersByDesc", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_DrawRenderersByDesc));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordSceneInjectionPoint", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_RecordSceneInjectionPoint));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetRendererIndex", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetRendererIndex));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_IsStageRequested", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_IsStageRequested));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetStageColorSource", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetStageColorSource));
|
||||
|
||||
@@ -134,16 +134,6 @@ namespace Gameplay
|
||||
}
|
||||
}
|
||||
|
||||
internal enum SceneInjectionKind
|
||||
{
|
||||
BeforeOpaque,
|
||||
AfterOpaque,
|
||||
BeforeSkybox,
|
||||
AfterSkybox,
|
||||
BeforeTransparent,
|
||||
AfterTransparent
|
||||
}
|
||||
|
||||
internal enum ScenePhaseKind
|
||||
{
|
||||
Opaque,
|
||||
@@ -157,51 +147,6 @@ namespace Gameplay
|
||||
ShaderVector
|
||||
}
|
||||
|
||||
internal sealed class SceneInjectionPass : ScriptableRenderPass
|
||||
{
|
||||
private readonly SceneInjectionKind m_injectionKind;
|
||||
|
||||
public SceneInjectionPass(
|
||||
RenderPassEvent passEvent,
|
||||
SceneInjectionKind injectionKind)
|
||||
{
|
||||
renderPassEvent = passEvent;
|
||||
m_injectionKind = injectionKind;
|
||||
}
|
||||
|
||||
protected override bool RecordRenderGraph(
|
||||
ScriptableRenderContext context,
|
||||
RenderingData renderingData)
|
||||
{
|
||||
return context != null &&
|
||||
renderingData != null &&
|
||||
renderingData.isMainSceneStage &&
|
||||
RecordInjection(context);
|
||||
}
|
||||
|
||||
private bool RecordInjection(
|
||||
ScriptableRenderContext context)
|
||||
{
|
||||
switch (m_injectionKind)
|
||||
{
|
||||
case SceneInjectionKind.BeforeOpaque:
|
||||
return context.RecordBeforeOpaqueInjection();
|
||||
case SceneInjectionKind.AfterOpaque:
|
||||
return context.RecordAfterOpaqueInjection();
|
||||
case SceneInjectionKind.BeforeSkybox:
|
||||
return context.RecordBeforeSkyboxInjection();
|
||||
case SceneInjectionKind.AfterSkybox:
|
||||
return context.RecordAfterSkyboxInjection();
|
||||
case SceneInjectionKind.BeforeTransparent:
|
||||
return context.RecordBeforeTransparentInjection();
|
||||
case SceneInjectionKind.AfterTransparent:
|
||||
return context.RecordAfterTransparentInjection();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ScenePhasePass : ScriptableRenderPass
|
||||
{
|
||||
private readonly ScenePhaseKind m_phaseKind;
|
||||
@@ -239,11 +184,11 @@ namespace Gameplay
|
||||
switch (m_phaseKind)
|
||||
{
|
||||
case ScenePhaseKind.Opaque:
|
||||
return context.RecordOpaqueScenePhase();
|
||||
return context.DrawOpaqueRenderers();
|
||||
case ScenePhaseKind.Skybox:
|
||||
return context.RecordSkyboxScenePhase();
|
||||
return context.DrawSkybox();
|
||||
case ScenePhaseKind.Transparent:
|
||||
return context.RecordTransparentScenePhase();
|
||||
return context.DrawTransparentRenderers();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -368,56 +313,26 @@ namespace Gameplay
|
||||
|
||||
internal sealed class DefaultSceneFeature : ScriptableRendererFeature
|
||||
{
|
||||
private readonly SceneInjectionPass m_beforeOpaquePass;
|
||||
private readonly ScenePhasePass m_opaquePass;
|
||||
private readonly SceneInjectionPass m_afterOpaquePass;
|
||||
private readonly SceneInjectionPass m_beforeSkyboxPass;
|
||||
private readonly ScenePhasePass m_skyboxPass;
|
||||
private readonly SceneInjectionPass m_afterSkyboxPass;
|
||||
private readonly SceneInjectionPass m_beforeTransparentPass;
|
||||
private readonly ScenePhasePass m_transparentPass;
|
||||
private readonly SceneInjectionPass m_afterTransparentPass;
|
||||
|
||||
public DefaultSceneFeature(
|
||||
Action onOpaqueRecorded = null)
|
||||
{
|
||||
m_beforeOpaquePass =
|
||||
new SceneInjectionPass(
|
||||
RenderPassEvent.BeforeRenderingOpaques,
|
||||
SceneInjectionKind.BeforeOpaque);
|
||||
m_opaquePass =
|
||||
new ScenePhasePass(
|
||||
RenderPassEvent.RenderOpaques,
|
||||
ScenePhaseKind.Opaque,
|
||||
onOpaqueRecorded);
|
||||
m_afterOpaquePass =
|
||||
new SceneInjectionPass(
|
||||
RenderPassEvent.AfterRenderingOpaques,
|
||||
SceneInjectionKind.AfterOpaque);
|
||||
m_beforeSkyboxPass =
|
||||
new SceneInjectionPass(
|
||||
RenderPassEvent.BeforeRenderingSkybox,
|
||||
SceneInjectionKind.BeforeSkybox);
|
||||
m_skyboxPass =
|
||||
new ScenePhasePass(
|
||||
RenderPassEvent.RenderSkybox,
|
||||
ScenePhaseKind.Skybox);
|
||||
m_afterSkyboxPass =
|
||||
new SceneInjectionPass(
|
||||
RenderPassEvent.AfterRenderingSkybox,
|
||||
SceneInjectionKind.AfterSkybox);
|
||||
m_beforeTransparentPass =
|
||||
new SceneInjectionPass(
|
||||
RenderPassEvent.BeforeRenderingTransparents,
|
||||
SceneInjectionKind.BeforeTransparent);
|
||||
m_transparentPass =
|
||||
new ScenePhasePass(
|
||||
RenderPassEvent.RenderTransparents,
|
||||
ScenePhaseKind.Transparent);
|
||||
m_afterTransparentPass =
|
||||
new SceneInjectionPass(
|
||||
RenderPassEvent.AfterRenderingTransparents,
|
||||
SceneInjectionKind.AfterTransparent);
|
||||
}
|
||||
|
||||
public override void AddRenderPasses(
|
||||
@@ -431,15 +346,60 @@ namespace Gameplay
|
||||
return;
|
||||
}
|
||||
|
||||
renderer.EnqueuePass(m_beforeOpaquePass);
|
||||
renderer.EnqueuePass(m_opaquePass);
|
||||
renderer.EnqueuePass(m_afterOpaquePass);
|
||||
renderer.EnqueuePass(m_beforeSkyboxPass);
|
||||
renderer.EnqueuePass(m_skyboxPass);
|
||||
renderer.EnqueuePass(m_afterSkyboxPass);
|
||||
renderer.EnqueuePass(m_beforeTransparentPass);
|
||||
renderer.EnqueuePass(m_transparentPass);
|
||||
renderer.EnqueuePass(m_afterTransparentPass);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DefaultShadowCasterFeature
|
||||
: ScriptableRendererFeature
|
||||
{
|
||||
private readonly DrawObjectsPass m_shadowCasterPass =
|
||||
new DrawObjectsPass(
|
||||
RenderPassEvent.BeforeRenderingShadows,
|
||||
SceneRenderPhase.Opaque,
|
||||
RendererListDesc.CreateDefault(
|
||||
RendererListType.ShadowCaster));
|
||||
|
||||
public override void ConfigureCameraFramePlan(
|
||||
ScriptableRenderPipelinePlanningContext context)
|
||||
{
|
||||
if (context != null)
|
||||
{
|
||||
context.RequestShadowCasterStage();
|
||||
}
|
||||
}
|
||||
|
||||
public override void ConfigureDirectionalShadowExecutionState(
|
||||
DirectionalShadowExecutionContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.hasPlannedMainDirectionalShadow)
|
||||
{
|
||||
context.UseDefaultMainDirectionalShadowExecution();
|
||||
return;
|
||||
}
|
||||
|
||||
context.ClearDirectionalShadowExecution();
|
||||
}
|
||||
|
||||
public override void AddRenderPasses(
|
||||
ScriptableRenderer renderer,
|
||||
RenderingData renderingData)
|
||||
{
|
||||
if (renderer == null ||
|
||||
renderingData == null ||
|
||||
!renderingData.isShadowCasterStage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
renderer.EnqueuePass(m_shadowCasterPass);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,6 +530,7 @@ namespace Gameplay
|
||||
Vector4 firstVectorPayload,
|
||||
Vector4 secondVectorPayload)
|
||||
{
|
||||
AddFeature(new DefaultSceneFeature());
|
||||
AddFeature(
|
||||
new FullscreenFeature(
|
||||
new FullscreenPass(
|
||||
@@ -1076,7 +1037,9 @@ namespace Gameplay
|
||||
finalColorData.requiresProcessing;
|
||||
}
|
||||
RecordCallCount++;
|
||||
return context.RecordScene();
|
||||
return context.DrawOpaqueRenderers() &&
|
||||
context.DrawSkybox() &&
|
||||
context.DrawTransparentRenderers();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1106,6 +1069,7 @@ namespace Gameplay
|
||||
{
|
||||
public CameraDataObservationRenderer()
|
||||
{
|
||||
AddFeature(new DefaultShadowCasterFeature());
|
||||
AddFeature(new CameraDataObservationFeature());
|
||||
}
|
||||
}
|
||||
@@ -1765,6 +1729,8 @@ namespace Gameplay
|
||||
{
|
||||
public static int CreatePipelineCallCount;
|
||||
public Vector4 postProcessScale = new Vector4(1.03f, 0.98f, 0.94f, 1.0f);
|
||||
private ManagedUniversalRenderPipelineProbeRendererData
|
||||
m_rendererData;
|
||||
|
||||
public ManagedUniversalRenderPipelineProbeAsset()
|
||||
{
|
||||
@@ -1774,20 +1740,35 @@ namespace Gameplay
|
||||
protected override ScriptableRenderPipeline CreatePipeline()
|
||||
{
|
||||
CreatePipelineCallCount++;
|
||||
rendererDataList = CreateRendererDataList();
|
||||
ApplyPostProcessScale();
|
||||
return base.CreatePipeline();
|
||||
}
|
||||
|
||||
protected override void ConfigureCameraFramePlan(
|
||||
ScriptableRenderPipelinePlanningContext context)
|
||||
{
|
||||
ApplyPostProcessScale();
|
||||
base.ConfigureCameraFramePlan(context);
|
||||
}
|
||||
|
||||
private ScriptableRendererData[] CreateRendererDataList()
|
||||
{
|
||||
ManagedUniversalRenderPipelineProbeRendererData rendererData =
|
||||
m_rendererData =
|
||||
ProbeScriptableObjectFactory
|
||||
.Create<ManagedUniversalRenderPipelineProbeRendererData>();
|
||||
rendererData.postProcessScale =
|
||||
postProcessScale;
|
||||
ApplyPostProcessScale();
|
||||
return ProbeScriptableObjectFactory
|
||||
.CreateRendererDataList(
|
||||
rendererData);
|
||||
m_rendererData);
|
||||
}
|
||||
|
||||
private void ApplyPostProcessScale()
|
||||
{
|
||||
if (m_rendererData != null)
|
||||
{
|
||||
m_rendererData.postProcessScale =
|
||||
postProcessScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -109,6 +109,54 @@ namespace Gameplay
|
||||
public bool HasRenderPassEventUnityNumericOrder;
|
||||
public bool HasRenderPassEventEngineExtensionOrder;
|
||||
|
||||
private static bool HasMethod(
|
||||
System.Type type,
|
||||
string name,
|
||||
BindingFlags flags)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MethodInfo[] methods = type.GetMethods(flags);
|
||||
for (int i = 0; i < methods.Length; ++i)
|
||||
{
|
||||
MethodInfo method = methods[i];
|
||||
if (method != null &&
|
||||
method.Name == name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool HasProperty(
|
||||
System.Type type,
|
||||
string name,
|
||||
BindingFlags flags)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PropertyInfo[] properties = type.GetProperties(flags);
|
||||
for (int i = 0; i < properties.Length; ++i)
|
||||
{
|
||||
PropertyInfo property = properties[i];
|
||||
if (property != null &&
|
||||
property.Name == name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
const BindingFlags PublicInstanceMethodFlags =
|
||||
@@ -334,38 +382,38 @@ namespace Gameplay
|
||||
HasScriptableObjectType =
|
||||
scriptableObjectType != null;
|
||||
HasScriptableObjectCreateInstance =
|
||||
scriptableObjectType != null &&
|
||||
scriptableObjectType.GetMethod(
|
||||
HasMethod(
|
||||
scriptableObjectType,
|
||||
"CreateInstance",
|
||||
BindingFlags.Static |
|
||||
BindingFlags.Public) != null;
|
||||
BindingFlags.Public);
|
||||
HasRenderPipelineAssetScriptableObjectBase =
|
||||
scriptableObjectType != null &&
|
||||
pipelineAssetType.BaseType == scriptableObjectType;
|
||||
HasPlanningContextType =
|
||||
contextType.Assembly.GetType(
|
||||
"XCEngine.Rendering.ScriptableRenderPipelinePlanningContext") != null;
|
||||
typeof(ScriptableRenderPipelinePlanningContext) != null;
|
||||
HasRendererFeatureConfigureCameraFramePlan =
|
||||
rendererFeatureType.GetMethod(
|
||||
HasMethod(
|
||||
rendererFeatureType,
|
||||
"ConfigureCameraFramePlan",
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.Public |
|
||||
BindingFlags.NonPublic) != null;
|
||||
BindingFlags.NonPublic);
|
||||
HasRendererRecordingContextType =
|
||||
System.Type.GetType(
|
||||
"XCEngine.Rendering.Universal.RendererRecordingContext, XCEngine.RenderPipelines.Universal") != null;
|
||||
universalAssembly.GetType(
|
||||
"XCEngine.Rendering.Universal.RendererRecordingContext") != null;
|
||||
HasRendererCameraRequestContextType =
|
||||
System.Type.GetType(
|
||||
"XCEngine.Rendering.Universal.RendererCameraRequestContext, XCEngine.RenderPipelines.Universal") != null;
|
||||
universalAssembly.GetType(
|
||||
"XCEngine.Rendering.Universal.RendererCameraRequestContext") != null;
|
||||
HasRendererBackedRenderPipelineAssetType =
|
||||
System.Type.GetType(
|
||||
"XCEngine.Rendering.Universal.RendererBackedRenderPipelineAsset, XCEngine.RenderPipelines.Universal") != null;
|
||||
universalAssembly.GetType(
|
||||
"XCEngine.Rendering.Universal.RendererBackedRenderPipelineAsset") != null;
|
||||
HasRendererBackedRenderPipelineType =
|
||||
System.Type.GetType(
|
||||
"XCEngine.Rendering.Universal.RendererBackedRenderPipeline, XCEngine.RenderPipelines.Universal") != null;
|
||||
universalAssembly.GetType(
|
||||
"XCEngine.Rendering.Universal.RendererBackedRenderPipeline") != null;
|
||||
HasRendererDrivenRenderPipelineType =
|
||||
System.Type.GetType(
|
||||
"XCEngine.Rendering.Universal.RendererDrivenRenderPipeline, XCEngine.RenderPipelines.Universal") != null;
|
||||
universalAssembly.GetType(
|
||||
"XCEngine.Rendering.Universal.RendererDrivenRenderPipeline") != null;
|
||||
HasRendererDataScriptableObjectBase =
|
||||
scriptableObjectType != null &&
|
||||
rendererDataType.BaseType == scriptableObjectType;
|
||||
@@ -373,31 +421,36 @@ namespace Gameplay
|
||||
scriptableObjectType != null &&
|
||||
rendererFeatureType.BaseType == scriptableObjectType;
|
||||
HasRendererDataSetupRenderer =
|
||||
rendererDataType.GetMethod(
|
||||
HasMethod(
|
||||
rendererDataType,
|
||||
"SetupRenderer",
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.NonPublic) != null;
|
||||
BindingFlags.NonPublic);
|
||||
HasRendererDataSetDirty =
|
||||
rendererDataType.GetMethod(
|
||||
HasMethod(
|
||||
rendererDataType,
|
||||
"SetDirty",
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.NonPublic) != null;
|
||||
BindingFlags.NonPublic);
|
||||
HasRendererDataIsInvalidated =
|
||||
rendererDataType.GetProperty(
|
||||
HasProperty(
|
||||
rendererDataType,
|
||||
"isInvalidated",
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.NonPublic |
|
||||
BindingFlags.Public) != null;
|
||||
BindingFlags.Public);
|
||||
HasRendererSupportsRendererRecording =
|
||||
rendererType.GetMethod(
|
||||
HasMethod(
|
||||
rendererType,
|
||||
"SupportsRendererRecording",
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.NonPublic) != null;
|
||||
BindingFlags.NonPublic);
|
||||
HasRendererRecordRenderer =
|
||||
rendererType.GetMethod(
|
||||
HasMethod(
|
||||
rendererType,
|
||||
"RecordRenderer",
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.NonPublic) != null;
|
||||
BindingFlags.NonPublic);
|
||||
HasPublicRendererSupportsStageRenderGraph =
|
||||
rendererType.GetMethod(
|
||||
"SupportsStageRenderGraph",
|
||||
|
||||
@@ -55,10 +55,12 @@ namespace XCEngine.Rendering.Universal
|
||||
protected override void ConfigureCameraFramePlan(
|
||||
ScriptableRenderPipelinePlanningContext context)
|
||||
{
|
||||
if (UsesExplicitFullscreenStagePlanning() &&
|
||||
if (UsesExplicitCameraFrameStagePlanning() &&
|
||||
context != null)
|
||||
{
|
||||
// Renderer-backed SRP owns fullscreen stage planning explicitly.
|
||||
// Renderer-backed SRP owns optional stage planning explicitly.
|
||||
context.ClearShadowCasterStage();
|
||||
context.ClearDepthOnlyStage();
|
||||
context.ClearFullscreenStage(
|
||||
CameraFrameStage.PostProcess);
|
||||
context.ClearFullscreenStage(
|
||||
@@ -165,6 +167,11 @@ namespace XCEngine.Rendering.Universal
|
||||
: -1);
|
||||
}
|
||||
|
||||
protected virtual bool UsesExplicitCameraFrameStagePlanning()
|
||||
{
|
||||
return UsesExplicitFullscreenStagePlanning();
|
||||
}
|
||||
|
||||
protected virtual bool UsesExplicitFullscreenStagePlanning()
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -114,6 +114,7 @@ namespace XCEngine.Rendering.Universal
|
||||
ScriptableRenderPipelinePlanningContext context)
|
||||
{
|
||||
ConfigureCameraFramePlan(context);
|
||||
ConfigureRendererFeaturesCameraFramePlan(context);
|
||||
}
|
||||
|
||||
internal void FinalizeCameraFramePlanInstance(
|
||||
@@ -126,12 +127,15 @@ namespace XCEngine.Rendering.Universal
|
||||
RenderSceneSetupContext context)
|
||||
{
|
||||
ConfigureRenderSceneSetup(context);
|
||||
ConfigureRendererFeaturesRenderSceneSetup(context);
|
||||
}
|
||||
|
||||
internal void ConfigureDirectionalShadowExecutionStateInstance(
|
||||
DirectionalShadowExecutionContext context)
|
||||
{
|
||||
ConfigureDirectionalShadowExecutionState(context);
|
||||
ConfigureRendererFeaturesDirectionalShadowExecutionState(
|
||||
context);
|
||||
}
|
||||
|
||||
internal bool RecordRendererInstance(
|
||||
@@ -211,6 +215,49 @@ namespace XCEngine.Rendering.Universal
|
||||
{
|
||||
}
|
||||
|
||||
private void ConfigureRendererFeaturesCameraFramePlan(
|
||||
ScriptableRenderPipelinePlanningContext context)
|
||||
{
|
||||
for (int i = 0; i < m_features.Count; ++i)
|
||||
{
|
||||
ScriptableRendererFeature feature = m_features[i];
|
||||
if (feature != null &&
|
||||
feature.isActive)
|
||||
{
|
||||
feature.ConfigureCameraFramePlan(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigureRendererFeaturesRenderSceneSetup(
|
||||
RenderSceneSetupContext context)
|
||||
{
|
||||
for (int i = 0; i < m_features.Count; ++i)
|
||||
{
|
||||
ScriptableRendererFeature feature = m_features[i];
|
||||
if (feature != null &&
|
||||
feature.isActive)
|
||||
{
|
||||
feature.ConfigureRenderSceneSetup(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigureRendererFeaturesDirectionalShadowExecutionState(
|
||||
DirectionalShadowExecutionContext context)
|
||||
{
|
||||
for (int i = 0; i < m_features.Count; ++i)
|
||||
{
|
||||
ScriptableRendererFeature feature = m_features[i];
|
||||
if (feature != null &&
|
||||
feature.isActive)
|
||||
{
|
||||
feature.ConfigureDirectionalShadowExecutionState(
|
||||
context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasRendererBlock(
|
||||
RendererBlock block)
|
||||
{
|
||||
|
||||
@@ -105,10 +105,6 @@ namespace XCEngine.Rendering.Universal
|
||||
context);
|
||||
}
|
||||
|
||||
m_featureCollection.ConfigureCameraFramePlan(
|
||||
ref rendererFeatures,
|
||||
context);
|
||||
|
||||
if (renderer != null)
|
||||
{
|
||||
renderer.FinalizeCameraFramePlanInstance(
|
||||
@@ -129,10 +125,6 @@ namespace XCEngine.Rendering.Universal
|
||||
context);
|
||||
}
|
||||
|
||||
m_featureCollection.ConfigureRenderSceneSetup(
|
||||
ref rendererFeatures,
|
||||
context);
|
||||
|
||||
return context != null &&
|
||||
context.isConfigured;
|
||||
}
|
||||
@@ -152,11 +144,6 @@ namespace XCEngine.Rendering.Universal
|
||||
context);
|
||||
}
|
||||
|
||||
m_featureCollection
|
||||
.ConfigureDirectionalShadowExecutionState(
|
||||
ref rendererFeatures,
|
||||
context);
|
||||
|
||||
return context != null &&
|
||||
context.isConfigured;
|
||||
}
|
||||
|
||||
@@ -904,12 +904,6 @@ namespace XCEngine
|
||||
string shaderPassName,
|
||||
ref Rendering.RenderStateBlock renderStateBlock);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool
|
||||
Rendering_ScriptableRenderContext_RecordSceneInjectionPoint(
|
||||
ulong nativeHandle,
|
||||
int injectionPoint);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern int
|
||||
Rendering_CameraRenderRequestContext_GetRenderedBaseCameraCount(
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace XCEngine.Rendering
|
||||
value);
|
||||
}
|
||||
|
||||
public bool hasDirectionalShadow =>
|
||||
internal bool hasDirectionalShadow =>
|
||||
InternalCalls
|
||||
.Rendering_CameraRenderRequestContext_GetHasDirectionalShadow(
|
||||
m_nativeHandle);
|
||||
@@ -78,7 +78,7 @@ namespace XCEngine.Rendering
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearDirectionalShadow()
|
||||
internal void ClearDirectionalShadow()
|
||||
{
|
||||
InternalCalls
|
||||
.Rendering_CameraRenderRequestContext_ClearDirectionalShadow(
|
||||
|
||||
@@ -2,7 +2,7 @@ using XCEngine;
|
||||
|
||||
namespace XCEngine.Rendering
|
||||
{
|
||||
// SRP v1 managed recording surface. Scene recording still delegates to the
|
||||
// SRP v1 managed recording surface. Scene draws still delegate to the
|
||||
// native SceneDrawBackend, and raster-pass recording is limited to the
|
||||
// fullscreen PostProcess / FinalOutput stages.
|
||||
public sealed class ScriptableRenderContext
|
||||
@@ -41,23 +41,14 @@ namespace XCEngine.Rendering
|
||||
.Rendering_ScriptableRenderContext_GetDepthTargetHandle(
|
||||
m_nativeHandle));
|
||||
|
||||
// Records the default native scene sequence for MainScene or explicit
|
||||
// scene-pass-request stages. This does not replace the native scene
|
||||
// extraction / culling / draw backend.
|
||||
public bool RecordScene()
|
||||
internal bool RecordScene()
|
||||
{
|
||||
return RecordBeforeOpaqueInjection() &&
|
||||
DrawOpaqueRenderers() &&
|
||||
RecordAfterOpaqueInjection() &&
|
||||
RecordBeforeSkyboxInjection() &&
|
||||
return DrawOpaqueRenderers() &&
|
||||
DrawSkybox() &&
|
||||
RecordAfterSkyboxInjection() &&
|
||||
RecordBeforeTransparentInjection() &&
|
||||
DrawTransparentRenderers() &&
|
||||
RecordAfterTransparentInjection();
|
||||
DrawTransparentRenderers();
|
||||
}
|
||||
|
||||
public bool RecordScenePhase(
|
||||
internal bool RecordScenePhase(
|
||||
SceneRenderPhase scenePhase)
|
||||
{
|
||||
return InternalCalls
|
||||
@@ -66,15 +57,6 @@ namespace XCEngine.Rendering
|
||||
(int)scenePhase);
|
||||
}
|
||||
|
||||
public bool RecordSceneInjectionPoint(
|
||||
SceneRenderInjectionPoint injectionPoint)
|
||||
{
|
||||
return InternalCalls
|
||||
.Rendering_ScriptableRenderContext_RecordSceneInjectionPoint(
|
||||
m_nativeHandle,
|
||||
(int)injectionPoint);
|
||||
}
|
||||
|
||||
public bool DrawRenderers(
|
||||
SceneRenderPhase scenePhase,
|
||||
RendererListType rendererListType)
|
||||
@@ -126,66 +108,12 @@ namespace XCEngine.Rendering
|
||||
ref renderStateBlock);
|
||||
}
|
||||
|
||||
public bool RecordOpaqueScenePhase()
|
||||
{
|
||||
return RecordScenePhase(
|
||||
SceneRenderPhase.Opaque);
|
||||
}
|
||||
|
||||
public bool RecordSkyboxScenePhase()
|
||||
{
|
||||
return RecordScenePhase(
|
||||
SceneRenderPhase.Skybox);
|
||||
}
|
||||
|
||||
public bool DrawSkybox()
|
||||
{
|
||||
return RecordScenePhase(
|
||||
SceneRenderPhase.Skybox);
|
||||
}
|
||||
|
||||
public bool RecordTransparentScenePhase()
|
||||
{
|
||||
return RecordScenePhase(
|
||||
SceneRenderPhase.Transparent);
|
||||
}
|
||||
|
||||
public bool RecordBeforeOpaqueInjection()
|
||||
{
|
||||
return RecordSceneInjectionPoint(
|
||||
SceneRenderInjectionPoint.BeforeOpaque);
|
||||
}
|
||||
|
||||
public bool RecordAfterOpaqueInjection()
|
||||
{
|
||||
return RecordSceneInjectionPoint(
|
||||
SceneRenderInjectionPoint.AfterOpaque);
|
||||
}
|
||||
|
||||
public bool RecordBeforeSkyboxInjection()
|
||||
{
|
||||
return RecordSceneInjectionPoint(
|
||||
SceneRenderInjectionPoint.BeforeSkybox);
|
||||
}
|
||||
|
||||
public bool RecordAfterSkyboxInjection()
|
||||
{
|
||||
return RecordSceneInjectionPoint(
|
||||
SceneRenderInjectionPoint.AfterSkybox);
|
||||
}
|
||||
|
||||
public bool RecordBeforeTransparentInjection()
|
||||
{
|
||||
return RecordSceneInjectionPoint(
|
||||
SceneRenderInjectionPoint.BeforeTransparent);
|
||||
}
|
||||
|
||||
public bool RecordAfterTransparentInjection()
|
||||
{
|
||||
return RecordSceneInjectionPoint(
|
||||
SceneRenderInjectionPoint.AfterTransparent);
|
||||
}
|
||||
|
||||
public bool DrawOpaqueRenderers()
|
||||
{
|
||||
return DrawRenderers(
|
||||
|
||||
72
tests/fixtures/RenderTestRhiStubs.h
vendored
72
tests/fixtures/RenderTestRhiStubs.h
vendored
@@ -16,11 +16,72 @@
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace XCTest {
|
||||
|
||||
class TestRenderViewBackingTexture final : public XCEngine::RHI::RHITexture {
|
||||
public:
|
||||
TestRenderViewBackingTexture(
|
||||
XCEngine::RHI::ResourceViewDimension dimension,
|
||||
XCEngine::RHI::Format format)
|
||||
: m_format(format)
|
||||
, m_textureType(ResolveTextureType(dimension)) {
|
||||
}
|
||||
|
||||
uint32_t GetWidth() const override { return 1u; }
|
||||
uint32_t GetHeight() const override { return 1u; }
|
||||
uint32_t GetDepth() const override { return 1u; }
|
||||
uint32_t GetMipLevels() const override { return 1u; }
|
||||
XCEngine::RHI::Format GetFormat() const override { return m_format; }
|
||||
XCEngine::RHI::TextureType GetTextureType() const override {
|
||||
return m_textureType;
|
||||
}
|
||||
XCEngine::RHI::ResourceStates GetState() const override {
|
||||
return m_state;
|
||||
}
|
||||
void SetState(XCEngine::RHI::ResourceStates state) override {
|
||||
m_state = state;
|
||||
}
|
||||
void* GetNativeHandle() override { return nullptr; }
|
||||
const std::string& GetName() const override { return m_name; }
|
||||
void SetName(const std::string& name) override { m_name = name; }
|
||||
void Shutdown() override {
|
||||
}
|
||||
|
||||
private:
|
||||
static XCEngine::RHI::TextureType ResolveTextureType(
|
||||
XCEngine::RHI::ResourceViewDimension dimension) {
|
||||
switch (dimension) {
|
||||
case XCEngine::RHI::ResourceViewDimension::Texture1D:
|
||||
return XCEngine::RHI::TextureType::Texture1D;
|
||||
case XCEngine::RHI::ResourceViewDimension::Texture2DArray:
|
||||
case XCEngine::RHI::ResourceViewDimension::Texture2DMSArray:
|
||||
return XCEngine::RHI::TextureType::Texture2DArray;
|
||||
case XCEngine::RHI::ResourceViewDimension::Texture3D:
|
||||
return XCEngine::RHI::TextureType::Texture3D;
|
||||
case XCEngine::RHI::ResourceViewDimension::TextureCube:
|
||||
return XCEngine::RHI::TextureType::TextureCube;
|
||||
case XCEngine::RHI::ResourceViewDimension::TextureCubeArray:
|
||||
return XCEngine::RHI::TextureType::TextureCubeArray;
|
||||
case XCEngine::RHI::ResourceViewDimension::Texture2D:
|
||||
case XCEngine::RHI::ResourceViewDimension::Texture2DMS:
|
||||
default:
|
||||
return XCEngine::RHI::TextureType::Texture2D;
|
||||
}
|
||||
}
|
||||
|
||||
XCEngine::RHI::Format m_format =
|
||||
XCEngine::RHI::Format::Unknown;
|
||||
XCEngine::RHI::TextureType m_textureType =
|
||||
XCEngine::RHI::TextureType::Texture2D;
|
||||
XCEngine::RHI::ResourceStates m_state =
|
||||
XCEngine::RHI::ResourceStates::Common;
|
||||
std::string m_name;
|
||||
};
|
||||
|
||||
class TestRenderResourceView final : public XCEngine::RHI::RHIResourceView {
|
||||
public:
|
||||
TestRenderResourceView(
|
||||
@@ -29,7 +90,11 @@ public:
|
||||
XCEngine::RHI::Format format)
|
||||
: m_viewType(viewType)
|
||||
, m_dimension(dimension)
|
||||
, m_format(format) {
|
||||
, m_format(format)
|
||||
, m_texture(
|
||||
std::make_unique<TestRenderViewBackingTexture>(
|
||||
dimension,
|
||||
format)) {
|
||||
}
|
||||
|
||||
void Shutdown() override {
|
||||
@@ -55,6 +120,10 @@ public:
|
||||
return m_format;
|
||||
}
|
||||
|
||||
XCEngine::RHI::RHITexture* GetTextureResource() const override {
|
||||
return m_texture.get();
|
||||
}
|
||||
|
||||
private:
|
||||
XCEngine::RHI::ResourceViewType m_viewType =
|
||||
XCEngine::RHI::ResourceViewType::ShaderResource;
|
||||
@@ -62,6 +131,7 @@ private:
|
||||
XCEngine::RHI::ResourceViewDimension::Texture2D;
|
||||
XCEngine::RHI::Format m_format =
|
||||
XCEngine::RHI::Format::Unknown;
|
||||
std::unique_ptr<TestRenderViewBackingTexture> m_texture;
|
||||
};
|
||||
|
||||
class TestRenderTexture final : public XCEngine::RHI::RHITexture {
|
||||
|
||||
@@ -1153,6 +1153,8 @@ TEST_F(
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
bool hasPublicContextRecordScene = false;
|
||||
bool hasPublicContextRecordScenePhase = false;
|
||||
bool hasPublicContextRecordSceneInjectionPoint = false;
|
||||
bool hasPublicContextRecordOpaqueScenePhase = false;
|
||||
bool hasPublicContextRecordBeforeOpaqueInjection = false;
|
||||
bool hasPublicContextRecordShaderVectorFullscreenPass = false;
|
||||
@@ -1192,6 +1194,14 @@ TEST_F(
|
||||
selectionScript,
|
||||
"HasPublicContextRecordScene",
|
||||
hasPublicContextRecordScene));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
selectionScript,
|
||||
"HasPublicContextRecordScenePhase",
|
||||
hasPublicContextRecordScenePhase));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
selectionScript,
|
||||
"HasPublicContextRecordSceneInjectionPoint",
|
||||
hasPublicContextRecordSceneInjectionPoint));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
selectionScript,
|
||||
"HasPublicContextRecordOpaqueScenePhase",
|
||||
@@ -1330,6 +1340,8 @@ TEST_F(
|
||||
hasPublicRendererRecordStageRenderGraph));
|
||||
|
||||
EXPECT_FALSE(hasPublicContextRecordScene);
|
||||
EXPECT_FALSE(hasPublicContextRecordScenePhase);
|
||||
EXPECT_FALSE(hasPublicContextRecordSceneInjectionPoint);
|
||||
EXPECT_FALSE(hasPublicContextRecordOpaqueScenePhase);
|
||||
EXPECT_FALSE(hasPublicContextRecordBeforeOpaqueInjection);
|
||||
EXPECT_FALSE(hasPublicContextRecordShaderVectorFullscreenPass);
|
||||
|
||||
Reference in New Issue
Block a user