Compare commits
2 Commits
d2140bf5cc
...
5b89c2bb76
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b89c2bb76 | |||
| f3fc34898a |
180
docs/plan/NewEditor_宿主重构计划_2026-04-13.md
Normal file
180
docs/plan/NewEditor_宿主重构计划_2026-04-13.md
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
# NewEditor 宿主重构计划
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
把 `new_editor` 当前的窗口宿主从“功能可运行的过渡方案”收敛成可长期演进的 Editor 宿主架构,核心目标如下:
|
||||||
|
|
||||||
|
1. 主显示链最终统一到纯 D3D12。
|
||||||
|
2. 窗口线程只负责消息和状态,不承担 GPU 重活。
|
||||||
|
3. live resize 必须真实更新,但不能再走同步阻塞窗口线程的路径。
|
||||||
|
4. Editor shell 和 Scene/Game viewport 统一纳入宿主合成层。
|
||||||
|
5. 当前 `D3D11On12 + D2D` 只允许作为过渡路径,不能继续加深耦合。
|
||||||
|
|
||||||
|
## 当前问题
|
||||||
|
|
||||||
|
### 1. 宿主职责混在 `Application`
|
||||||
|
|
||||||
|
当前 `Application` 同时承担:
|
||||||
|
|
||||||
|
- Win32 消息调度
|
||||||
|
- 宿主运行时状态
|
||||||
|
- resize / dpi / deferred render 调度
|
||||||
|
- editor 状态更新
|
||||||
|
- present 前后的宿主控制
|
||||||
|
|
||||||
|
这会导致宿主问题难以单独定位和演进。
|
||||||
|
|
||||||
|
### 2. 主显示链过厚
|
||||||
|
|
||||||
|
当前主路径仍然依赖:
|
||||||
|
|
||||||
|
- D3D12 viewport 渲染
|
||||||
|
- swapchain backbuffer
|
||||||
|
- D3D11On12 wrapped resource
|
||||||
|
- D2D 绘制 shell
|
||||||
|
- present
|
||||||
|
|
||||||
|
这条链在 live resize、frame pacing、backbuffer 生命周期上都偏重。
|
||||||
|
|
||||||
|
### 3. resize 热路径仍然偏保守
|
||||||
|
|
||||||
|
虽然已经把 `WM_SIZE` 从直接同步 resize 调整为 deferred render 触发,但 resize 热路径里仍存在:
|
||||||
|
|
||||||
|
- backbuffer interop target 重建
|
||||||
|
- swapchain resize
|
||||||
|
- 资源生命周期收束
|
||||||
|
|
||||||
|
这还不是最终架构。
|
||||||
|
|
||||||
|
## 重构阶段
|
||||||
|
|
||||||
|
## 阶段 1:宿主分层
|
||||||
|
|
||||||
|
### 目标
|
||||||
|
|
||||||
|
先把结构理顺,停止继续把宿主逻辑堆进 `Application`。
|
||||||
|
|
||||||
|
### 任务
|
||||||
|
|
||||||
|
1. 拆出宿主运行时状态对象。
|
||||||
|
2. 拆出窗口消息调度与 deferred render 调度。
|
||||||
|
3. 让 `Application` 只保留 editor 业务更新与高层协作职责。
|
||||||
|
4. 为后续 HostRenderer / HostCompositor 留清晰边界。
|
||||||
|
|
||||||
|
### 完成标准
|
||||||
|
|
||||||
|
1. resize / dpi / deferred render / interactive resize 状态不再散落在 `Application` 成员里。
|
||||||
|
2. `Application` 的宿主状态字段明显减少。
|
||||||
|
3. 现有功能与布局不回退。
|
||||||
|
|
||||||
|
## 阶段 2:建立 HostRenderer / HostCompositor 边界
|
||||||
|
|
||||||
|
### 目标
|
||||||
|
|
||||||
|
把宿主渲染拆成明确两层:
|
||||||
|
|
||||||
|
1. `HostRenderer`
|
||||||
|
责任:device / queue / swapchain / backbuffer / fence / present
|
||||||
|
2. `HostCompositor`
|
||||||
|
责任:把 shell draw data、viewport texture、icon/text 统一合成到 backbuffer
|
||||||
|
|
||||||
|
### 任务
|
||||||
|
|
||||||
|
1. 停止让 `NativeRenderer` 既像窗口绘制器又像过渡 compositor。
|
||||||
|
2. 把“主窗口显示”和“UI 绘制命令解释”职责显式拆开。
|
||||||
|
3. 为纯 D3D12 compositor 做接口准备。
|
||||||
|
|
||||||
|
### 完成标准
|
||||||
|
|
||||||
|
1. `HostRenderer` 不依赖 D2D 语义。
|
||||||
|
2. `HostCompositor` 成为唯一的宿主 UI 合成入口。
|
||||||
|
3. 现有 `NativeRenderer` 明确退化为过渡层或 fallback。
|
||||||
|
|
||||||
|
## 阶段 3:主显示链切换到纯 D3D12
|
||||||
|
|
||||||
|
### 目标
|
||||||
|
|
||||||
|
去掉 `D3D11On12 + D2D` 在主显示链中的核心地位。
|
||||||
|
|
||||||
|
### 任务
|
||||||
|
|
||||||
|
1. shell 矩形、线条、图像、文字统一进入 D3D12 UI compositor。
|
||||||
|
2. Scene/Game viewport 作为普通 SRV 输入参与同一条 compositor pass。
|
||||||
|
3. backbuffer 只通过 D3D12 呈现。
|
||||||
|
|
||||||
|
### 完成标准
|
||||||
|
|
||||||
|
1. 主窗口显示不再依赖 D2D。
|
||||||
|
2. resize 时不再重建 D3D11On12 backbuffer interop target。
|
||||||
|
3. `new_editor` 主显示链可在没有 D3D11On12 的条件下工作。
|
||||||
|
|
||||||
|
## 阶段 4:重写 resize 状态机
|
||||||
|
|
||||||
|
### 目标
|
||||||
|
|
||||||
|
做到真实 live resize,但不阻塞窗口线程。
|
||||||
|
|
||||||
|
### 任务
|
||||||
|
|
||||||
|
1. `WM_SIZE` 只更新最新目标尺寸。
|
||||||
|
2. render tick 只消费最新尺寸,不处理过期尺寸。
|
||||||
|
3. resize 不允许在消息处理里做 GPU 等待。
|
||||||
|
4. resize / present / viewport surface 生命周期统一到宿主状态机。
|
||||||
|
|
||||||
|
### 完成标准
|
||||||
|
|
||||||
|
1. 拖动窗口边界时不黑屏。
|
||||||
|
2. 不出现黑白垃圾区。
|
||||||
|
3. 窗口拖动体感明显优于当前实现。
|
||||||
|
|
||||||
|
## 阶段 5:去掉 resize 路径里的全队列等待
|
||||||
|
|
||||||
|
### 目标
|
||||||
|
|
||||||
|
去掉当前最重的同步点。
|
||||||
|
|
||||||
|
### 任务
|
||||||
|
|
||||||
|
1. 改成 per-backbuffer / per-frame 生命周期管理。
|
||||||
|
2. 只等待必须退休的资源代际。
|
||||||
|
3. 禁止 resize 路径里的整队列 idle 等待。
|
||||||
|
|
||||||
|
### 完成标准
|
||||||
|
|
||||||
|
1. resize 期间 CPU/GPU 同步明显减少。
|
||||||
|
2. live resize 手感继续改善。
|
||||||
|
|
||||||
|
## 阶段 6:viewport 生命周期收口
|
||||||
|
|
||||||
|
### 目标
|
||||||
|
|
||||||
|
让 Scene/Game viewport 与外层宿主真正解耦。
|
||||||
|
|
||||||
|
### 任务
|
||||||
|
|
||||||
|
1. viewport render target 长期存活,不跟着宿主链大拆大建。
|
||||||
|
2. 宿主 compositor 只采样 viewport 结果,不干预其内部资源生命周期。
|
||||||
|
3. Scene/Game 在 interactive resize 期间保持稳定。
|
||||||
|
|
||||||
|
### 完成标准
|
||||||
|
|
||||||
|
1. viewport 不再因宿主 resize 逻辑出现黑屏或闪烁。
|
||||||
|
2. 宿主和 viewport 各自职责明确。
|
||||||
|
|
||||||
|
## 执行顺序
|
||||||
|
|
||||||
|
1. 先完成阶段 1。
|
||||||
|
2. 然后搭好阶段 2 的 HostRenderer / HostCompositor 边界。
|
||||||
|
3. 再推进阶段 3,切主显示链到纯 D3D12。
|
||||||
|
4. 最后做阶段 4、5、6 的性能与生命周期收口。
|
||||||
|
|
||||||
|
## 当前落点
|
||||||
|
|
||||||
|
当前阶段 1 已完成,阶段 2 已开始收口:
|
||||||
|
|
||||||
|
1. 已新增 `HostRuntimeState`,把宿主 DPI / interactive resize / pending resize / deferred render 状态从 `Application` 中抽离。
|
||||||
|
2. 已新增 `WindowMessageDispatcher`,把 `WndProc` 中的宿主消息调度与 deferred render 调度拆到 `Host` 层。
|
||||||
|
3. 已把 `D3D12WindowRenderLoop` 从悬空 helper 升级为主窗口帧编排入口,开始统一 `BeginFrame / viewport render / UI present / fallback / resize interop` 这条链。
|
||||||
|
4. 已把 viewport render target 资源工厂从 `ProductViewportRenderTargets.h` 收成独立 manager,`ProductViewportHostService` 只保留请求/返回 frame 的业务外壳。
|
||||||
|
5. 已把 shader resource descriptor 分配职责从 `D3D12WindowRenderer` 抽到独立的 `D3D12ShaderResourceDescriptorAllocator`,减少窗口呈现器的非 swapchain 职责。
|
||||||
|
6. 下一步进入阶段 2 主体:继续拆 `NativeRenderer` 中的窗口互操作 / present 组合路径,把 D2D UI 光栅化与 D3D11On12 窗口合成进一步分离。
|
||||||
@@ -124,9 +124,11 @@ target_link_libraries(XCUIEditorLib PUBLIC
|
|||||||
|
|
||||||
add_library(XCUIEditorHost STATIC
|
add_library(XCUIEditorHost STATIC
|
||||||
app/Host/AutoScreenshot.cpp
|
app/Host/AutoScreenshot.cpp
|
||||||
|
app/Host/D3D12ShaderResourceDescriptorAllocator.cpp
|
||||||
app/Host/D3D12WindowRenderer.cpp
|
app/Host/D3D12WindowRenderer.cpp
|
||||||
app/Host/D3D12WindowRenderLoop.cpp
|
app/Host/D3D12WindowRenderLoop.cpp
|
||||||
app/Host/NativeRenderer.cpp
|
app/Host/NativeRenderer.cpp
|
||||||
|
app/Host/WindowMessageDispatcher.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(XCUIEditorHost
|
target_include_directories(XCUIEditorHost
|
||||||
@@ -165,6 +167,7 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP)
|
|||||||
app/Project/ProductProjectBrowserModel.cpp
|
app/Project/ProductProjectBrowserModel.cpp
|
||||||
app/Shell/ProductShellAsset.cpp
|
app/Shell/ProductShellAsset.cpp
|
||||||
app/Viewport/ProductViewportHostService.cpp
|
app/Viewport/ProductViewportHostService.cpp
|
||||||
|
app/Viewport/ProductViewportRenderTargetManager.cpp
|
||||||
app/Viewport/ProductViewportRenderTargets.cpp
|
app/Viewport/ProductViewportRenderTargets.cpp
|
||||||
app/Workspace/ProductEditorWorkspace.cpp
|
app/Workspace/ProductEditorWorkspace.cpp
|
||||||
app/Workspace/ProductEditorWorkspaceEventRouter.cpp
|
app/Workspace/ProductEditorWorkspaceEventRouter.cpp
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
|
||||||
|
#include <Host/WindowMessageDispatcher.h>
|
||||||
|
|
||||||
#include <XCEditor/Foundation/UIEditorRuntimeTrace.h>
|
#include <XCEditor/Foundation/UIEditorRuntimeTrace.h>
|
||||||
#include <XCEditor/Foundation/UIEditorTheme.h>
|
#include <XCEditor/Foundation/UIEditorTheme.h>
|
||||||
|
|
||||||
@@ -36,7 +38,6 @@ constexpr const wchar_t* kWindowClassName = L"XCEditorShellHost";
|
|||||||
constexpr const wchar_t* kWindowTitle = L"Main Scene * - Main.xx - XCEngine Editor";
|
constexpr const wchar_t* kWindowTitle = L"Main Scene * - Main.xx - XCEngine Editor";
|
||||||
constexpr UINT kDefaultDpi = 96u;
|
constexpr UINT kDefaultDpi = 96u;
|
||||||
constexpr float kBaseDpiScale = 96.0f;
|
constexpr float kBaseDpiScale = 96.0f;
|
||||||
constexpr UINT kDeferredRenderMessage = WM_APP + 1u;
|
|
||||||
|
|
||||||
bool ResolveVerboseRuntimeTraceEnabled() {
|
bool ResolveVerboseRuntimeTraceEnabled() {
|
||||||
wchar_t buffer[8] = {};
|
wchar_t buffer[8] = {};
|
||||||
@@ -47,10 +48,6 @@ bool ResolveVerboseRuntimeTraceEnabled() {
|
|||||||
return length > 0u && buffer[0] != L'0';
|
return length > 0u && buffer[0] != L'0';
|
||||||
}
|
}
|
||||||
|
|
||||||
Application* GetApplicationFromWindow(HWND hwnd) {
|
|
||||||
return reinterpret_cast<Application*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT QuerySystemDpi() {
|
UINT QuerySystemDpi() {
|
||||||
HDC screenDc = GetDC(nullptr);
|
HDC screenDc = GetDC(nullptr);
|
||||||
if (screenDc == nullptr) {
|
if (screenDc == nullptr) {
|
||||||
@@ -131,25 +128,6 @@ void EnableDpiAwareness() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TryEnableNonClientDpiScaling(HWND hwnd) {
|
|
||||||
if (hwnd == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const HMODULE user32 = GetModuleHandleW(L"user32.dll");
|
|
||||||
if (user32 == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using EnableNonClientDpiScalingFn = BOOL(WINAPI*)(HWND);
|
|
||||||
const auto enableNonClientDpiScaling =
|
|
||||||
reinterpret_cast<EnableNonClientDpiScalingFn>(
|
|
||||||
GetProcAddress(user32, "EnableNonClientDpiScaling"));
|
|
||||||
if (enableNonClientDpiScaling != nullptr) {
|
|
||||||
enableNonClientDpiScaling(hwnd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string TruncateText(const std::string& text, std::size_t maxLength) {
|
std::string TruncateText(const std::string& text, std::size_t maxLength) {
|
||||||
if (text.size() <= maxLength) {
|
if (text.size() <= maxLength) {
|
||||||
return text;
|
return text;
|
||||||
@@ -456,9 +434,9 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
|
|||||||
LogRuntimeTrace("app", "window creation failed");
|
LogRuntimeTrace("app", "window creation failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_windowDpi = QueryWindowDpi(m_hwnd);
|
m_hostRuntime.Reset();
|
||||||
m_dpiScale = GetDpiScale();
|
m_hostRuntime.SetWindowDpi(QueryWindowDpi(m_hwnd));
|
||||||
m_renderer.SetDpiScale(m_dpiScale);
|
m_renderer.SetDpiScale(GetDpiScale());
|
||||||
m_editorContext.SetExitRequestHandler([this]() {
|
m_editorContext.SetExitRequestHandler([this]() {
|
||||||
if (m_hwnd != nullptr) {
|
if (m_hwnd != nullptr) {
|
||||||
PostMessageW(m_hwnd, WM_CLOSE, 0, 0);
|
PostMessageW(m_hwnd, WM_CLOSE, 0, 0);
|
||||||
@@ -466,7 +444,7 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
std::ostringstream dpiTrace = {};
|
std::ostringstream dpiTrace = {};
|
||||||
dpiTrace << "initial dpi=" << m_windowDpi << " scale=" << m_dpiScale;
|
dpiTrace << "initial dpi=" << m_hostRuntime.GetWindowDpi() << " scale=" << GetDpiScale();
|
||||||
LogRuntimeTrace("window", dpiTrace.str());
|
LogRuntimeTrace("window", dpiTrace.str());
|
||||||
|
|
||||||
if (!m_renderer.Initialize(m_hwnd)) {
|
if (!m_renderer.Initialize(m_hwnd)) {
|
||||||
@@ -481,17 +459,18 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
|
|||||||
LogRuntimeTrace("app", "d3d12 window renderer initialization failed");
|
LogRuntimeTrace("app", "d3d12 window renderer initialization failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const bool hasD3D12WindowInterop = m_renderer.AttachWindowRenderer(m_windowRenderer);
|
const Host::D3D12WindowRenderLoopAttachResult attachResult =
|
||||||
if (!hasD3D12WindowInterop) {
|
m_windowRenderLoop.Attach(m_renderer, m_windowRenderer);
|
||||||
|
if (!attachResult.interopWarning.empty()) {
|
||||||
LogRuntimeTrace(
|
LogRuntimeTrace(
|
||||||
"app",
|
"app",
|
||||||
"native renderer d3d12 interop unavailable; falling back to hwnd renderer: " +
|
attachResult.interopWarning);
|
||||||
m_renderer.GetLastRenderError());
|
|
||||||
}
|
}
|
||||||
m_editorContext.AttachTextMeasurer(m_renderer);
|
m_editorContext.AttachTextMeasurer(m_renderer);
|
||||||
m_editorWorkspace.Initialize(repoRoot, m_renderer);
|
m_editorWorkspace.Initialize(repoRoot, m_renderer);
|
||||||
m_editorWorkspace.AttachViewportWindowRenderer(m_windowRenderer);
|
m_editorWorkspace.AttachViewportWindowRenderer(m_windowRenderer);
|
||||||
m_editorWorkspace.SetViewportSurfacePresentationEnabled(hasD3D12WindowInterop);
|
m_editorWorkspace.SetViewportSurfacePresentationEnabled(
|
||||||
|
attachResult.hasViewportSurfacePresentation);
|
||||||
if (!m_editorWorkspace.GetBuiltInIconError().empty()) {
|
if (!m_editorWorkspace.GetBuiltInIconError().empty()) {
|
||||||
LogRuntimeTrace("icons", m_editorWorkspace.GetBuiltInIconError());
|
LogRuntimeTrace("icons", m_editorWorkspace.GetBuiltInIconError());
|
||||||
}
|
}
|
||||||
@@ -520,6 +499,7 @@ void Application::Shutdown() {
|
|||||||
|
|
||||||
m_autoScreenshot.Shutdown();
|
m_autoScreenshot.Shutdown();
|
||||||
m_editorWorkspace.Shutdown();
|
m_editorWorkspace.Shutdown();
|
||||||
|
m_windowRenderLoop.Detach();
|
||||||
m_windowRenderer.Shutdown();
|
m_windowRenderer.Shutdown();
|
||||||
m_renderer.Shutdown();
|
m_renderer.Shutdown();
|
||||||
|
|
||||||
@@ -570,11 +550,10 @@ void Application::RenderFrame() {
|
|||||||
m_editorWorkspace.GetShellInteractionState()));
|
m_editorWorkspace.GetShellInteractionState()));
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool canUseWindowRenderer = m_renderer.HasAttachedWindowRenderer();
|
const Host::D3D12WindowRenderLoopFrameContext frameContext =
|
||||||
const bool d3d12FrameBegun =
|
m_windowRenderLoop.BeginFrame();
|
||||||
canUseWindowRenderer && m_windowRenderer.BeginFrame();
|
if (!frameContext.warning.empty()) {
|
||||||
if (canUseWindowRenderer && !d3d12FrameBegun) {
|
LogRuntimeTrace("viewport", frameContext.warning);
|
||||||
LogRuntimeTrace("viewport", "d3d12 frame begin failed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_editorWorkspace.Update(
|
m_editorWorkspace.Update(
|
||||||
@@ -610,8 +589,8 @@ void Application::RenderFrame() {
|
|||||||
ApplyHostedContentCaptureRequests();
|
ApplyHostedContentCaptureRequests();
|
||||||
ApplyCurrentCursor();
|
ApplyCurrentCursor();
|
||||||
m_editorWorkspace.Append(drawList);
|
m_editorWorkspace.Append(drawList);
|
||||||
if (d3d12FrameBegun) {
|
if (frameContext.canRenderViewports) {
|
||||||
m_editorWorkspace.RenderRequestedViewports(m_windowRenderer.GetRenderContext());
|
m_editorWorkspace.RenderRequestedViewports(frameContext.renderContext);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
drawList.AddText(
|
drawList.AddText(
|
||||||
@@ -628,31 +607,37 @@ void Application::RenderFrame() {
|
|||||||
12.0f);
|
12.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool framePresented = false;
|
const Host::D3D12WindowRenderLoopPresentResult presentResult =
|
||||||
if (m_renderer.HasAttachedWindowRenderer()) {
|
m_windowRenderLoop.Present(drawData);
|
||||||
framePresented = m_renderer.RenderToWindowRenderer(drawData);
|
if (!presentResult.warning.empty()) {
|
||||||
if (!framePresented) {
|
LogRuntimeTrace("present", presentResult.warning);
|
||||||
LogRuntimeTrace(
|
|
||||||
"present",
|
|
||||||
"d3d12 window composition failed, falling back to hwnd renderer: " +
|
|
||||||
m_renderer.GetLastRenderError());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!framePresented) {
|
|
||||||
framePresented = m_renderer.Render(drawData);
|
|
||||||
}
|
}
|
||||||
m_autoScreenshot.CaptureIfRequested(
|
m_autoScreenshot.CaptureIfRequested(
|
||||||
m_renderer,
|
m_renderer,
|
||||||
drawData,
|
drawData,
|
||||||
pixelWidth,
|
pixelWidth,
|
||||||
pixelHeight,
|
pixelHeight,
|
||||||
framePresented);
|
presentResult.framePresented);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::OnDeferredRenderMessage() {
|
||||||
|
m_hostRuntime.ClearDeferredRenderRequest();
|
||||||
|
RenderFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::OnPaintMessage() {
|
||||||
|
if (m_hwnd == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PAINTSTRUCT paintStruct = {};
|
||||||
|
BeginPaint(m_hwnd, &paintStruct);
|
||||||
|
RenderFrame();
|
||||||
|
EndPaint(m_hwnd, &paintStruct);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Application::GetDpiScale() const {
|
float Application::GetDpiScale() const {
|
||||||
const UINT dpi = m_windowDpi == 0u ? kDefaultDpi : m_windowDpi;
|
return m_hostRuntime.GetDpiScale(kBaseDpiScale);
|
||||||
return static_cast<float>(dpi) / kBaseDpiScale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float Application::PixelsToDips(float pixels) const {
|
float Application::PixelsToDips(float pixels) const {
|
||||||
@@ -767,22 +752,16 @@ void Application::OnResize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Application::OnEnterSizeMove() {
|
void Application::OnEnterSizeMove() {
|
||||||
m_inInteractiveResize = true;
|
m_hostRuntime.BeginInteractiveResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::OnExitSizeMove() {
|
void Application::OnExitSizeMove() {
|
||||||
m_inInteractiveResize = false;
|
m_hostRuntime.EndInteractiveResize();
|
||||||
QueueCurrentClientResize();
|
QueueCurrentClientResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::QueueWindowResize(UINT width, UINT height) {
|
void Application::QueueWindowResize(UINT width, UINT height) {
|
||||||
if (width == 0u || height == 0u) {
|
m_hostRuntime.QueueWindowResize(width, height);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pendingWindowResizeWidth = width;
|
|
||||||
m_pendingWindowResizeHeight = height;
|
|
||||||
m_hasPendingWindowResize = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::QueueCurrentClientResize() {
|
void Application::QueueCurrentClientResize() {
|
||||||
@@ -796,51 +775,26 @@ void Application::QueueCurrentClientResize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Application::ApplyPendingWindowResize() {
|
bool Application::ApplyPendingWindowResize() {
|
||||||
if (!m_hasPendingWindowResize) {
|
UINT width = 0u;
|
||||||
|
UINT height = 0u;
|
||||||
|
if (!m_hostRuntime.ConsumePendingWindowResize(width, height)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UINT width = m_pendingWindowResizeWidth;
|
const Host::D3D12WindowRenderLoopResizeResult resizeResult =
|
||||||
const UINT height = m_pendingWindowResizeHeight;
|
m_windowRenderLoop.ApplyResize(width, height);
|
||||||
m_hasPendingWindowResize = false;
|
m_editorWorkspace.SetViewportSurfacePresentationEnabled(
|
||||||
if (width == 0u || height == 0u) {
|
resizeResult.hasViewportSurfacePresentation);
|
||||||
return false;
|
|
||||||
|
if (!resizeResult.windowRendererWarning.empty()) {
|
||||||
|
LogRuntimeTrace("present", resizeResult.windowRendererWarning);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_renderer.Resize(width, height);
|
if (!resizeResult.interopWarning.empty()) {
|
||||||
m_renderer.DetachWindowRenderer();
|
LogRuntimeTrace("present", resizeResult.interopWarning);
|
||||||
const bool resizedWindowRenderer =
|
|
||||||
m_windowRenderer.Resize(static_cast<int>(width), static_cast<int>(height));
|
|
||||||
const bool hasD3D12WindowInterop = resizedWindowRenderer &&
|
|
||||||
m_renderer.AttachWindowRenderer(m_windowRenderer);
|
|
||||||
const bool hasHealthyD3D12WindowInterop =
|
|
||||||
resizedWindowRenderer &&
|
|
||||||
hasD3D12WindowInterop;
|
|
||||||
m_editorWorkspace.SetViewportSurfacePresentationEnabled(hasHealthyD3D12WindowInterop);
|
|
||||||
|
|
||||||
if (!resizedWindowRenderer || !m_windowRenderer.GetLastError().empty()) {
|
|
||||||
LogRuntimeTrace(
|
|
||||||
"present",
|
|
||||||
"window renderer resize warning: " + m_windowRenderer.GetLastError());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasD3D12WindowInterop) {
|
return resizeResult.hasViewportSurfacePresentation;
|
||||||
LogRuntimeTrace(
|
|
||||||
"present",
|
|
||||||
"failed to rebuild d3d12 window interop after resize: " +
|
|
||||||
m_renderer.GetLastRenderError());
|
|
||||||
}
|
|
||||||
|
|
||||||
return hasHealthyD3D12WindowInterop;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::RequestDeferredRenderFrame() {
|
|
||||||
if (m_hwnd == nullptr || !IsWindow(m_hwnd) || m_renderFrameQueued) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_renderFrameQueued = true;
|
|
||||||
PostMessageW(m_hwnd, kDeferredRenderMessage, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::QueryCurrentClientPixelSize(UINT& outWidth, UINT& outHeight) const {
|
bool Application::QueryCurrentClientPixelSize(UINT& outWidth, UINT& outHeight) const {
|
||||||
@@ -867,9 +821,8 @@ bool Application::QueryCurrentClientPixelSize(UINT& outWidth, UINT& outHeight) c
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Application::OnDpiChanged(UINT dpi, const RECT& suggestedRect) {
|
void Application::OnDpiChanged(UINT dpi, const RECT& suggestedRect) {
|
||||||
m_windowDpi = dpi == 0u ? kDefaultDpi : dpi;
|
m_hostRuntime.SetWindowDpi(dpi == 0u ? kDefaultDpi : dpi);
|
||||||
m_dpiScale = GetDpiScale();
|
m_renderer.SetDpiScale(GetDpiScale());
|
||||||
m_renderer.SetDpiScale(m_dpiScale);
|
|
||||||
if (m_hwnd != nullptr) {
|
if (m_hwnd != nullptr) {
|
||||||
const LONG windowWidth = suggestedRect.right - suggestedRect.left;
|
const LONG windowWidth = suggestedRect.right - suggestedRect.left;
|
||||||
const LONG windowHeight = suggestedRect.bottom - suggestedRect.top;
|
const LONG windowHeight = suggestedRect.bottom - suggestedRect.top;
|
||||||
@@ -882,11 +835,10 @@ void Application::OnDpiChanged(UINT dpi, const RECT& suggestedRect) {
|
|||||||
windowHeight,
|
windowHeight,
|
||||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||||
QueueCurrentClientResize();
|
QueueCurrentClientResize();
|
||||||
RequestDeferredRenderFrame();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostringstream trace = {};
|
std::ostringstream trace = {};
|
||||||
trace << "dpi changed to " << m_windowDpi << " scale=" << m_dpiScale;
|
trace << "dpi changed to " << m_hostRuntime.GetWindowDpi() << " scale=" << GetDpiScale();
|
||||||
LogRuntimeTrace("window", trace.str());
|
LogRuntimeTrace("window", trace.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1006,66 +958,27 @@ LONG WINAPI Application::HandleUnhandledException(EXCEPTION_POINTERS* exceptionI
|
|||||||
}
|
}
|
||||||
|
|
||||||
LRESULT CALLBACK Application::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
LRESULT CALLBACK Application::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||||
if (message == WM_NCCREATE) {
|
LRESULT dispatcherResult = 0;
|
||||||
TryEnableNonClientDpiScaling(hwnd);
|
if (Host::WindowMessageDispatcher::TryHandleNonClientCreate(
|
||||||
const auto* createStruct = reinterpret_cast<CREATESTRUCTW*>(lParam);
|
hwnd,
|
||||||
auto* application = reinterpret_cast<Application*>(createStruct->lpCreateParams);
|
message,
|
||||||
SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(application));
|
lParam,
|
||||||
return TRUE;
|
dispatcherResult)) {
|
||||||
|
return dispatcherResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
Application* application = Host::WindowMessageDispatcher::GetApplicationFromWindow(hwnd);
|
||||||
|
if (application != nullptr &&
|
||||||
|
Host::WindowMessageDispatcher::TryDispatch(
|
||||||
|
*application,
|
||||||
|
message,
|
||||||
|
wParam,
|
||||||
|
lParam,
|
||||||
|
dispatcherResult)) {
|
||||||
|
return dispatcherResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
Application* application = GetApplicationFromWindow(hwnd);
|
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case WM_SETCURSOR:
|
|
||||||
if (application != nullptr &&
|
|
||||||
LOWORD(lParam) == HTCLIENT &&
|
|
||||||
application->ApplyCurrentCursor()) {
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WM_DPICHANGED:
|
|
||||||
if (application != nullptr && lParam != 0) {
|
|
||||||
application->OnDpiChanged(
|
|
||||||
static_cast<UINT>(LOWORD(wParam)),
|
|
||||||
*reinterpret_cast<RECT*>(lParam));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WM_ENTERSIZEMOVE:
|
|
||||||
if (application != nullptr) {
|
|
||||||
application->OnEnterSizeMove();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WM_EXITSIZEMOVE:
|
|
||||||
if (application != nullptr) {
|
|
||||||
application->OnExitSizeMove();
|
|
||||||
application->RequestDeferredRenderFrame();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WM_SIZE:
|
|
||||||
if (application != nullptr && wParam != SIZE_MINIMIZED) {
|
|
||||||
application->OnResize();
|
|
||||||
application->RequestDeferredRenderFrame();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
case kDeferredRenderMessage:
|
|
||||||
if (application != nullptr) {
|
|
||||||
application->m_renderFrameQueued = false;
|
|
||||||
application->RenderFrame();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WM_PAINT:
|
|
||||||
if (application != nullptr) {
|
|
||||||
PAINTSTRUCT paintStruct = {};
|
|
||||||
BeginPaint(hwnd, &paintStruct);
|
|
||||||
application->RenderFrame();
|
|
||||||
EndPaint(hwnd, &paintStruct);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WM_MOUSEMOVE:
|
case WM_MOUSEMOVE:
|
||||||
if (application != nullptr) {
|
if (application != nullptr) {
|
||||||
if (!application->m_trackingMouseLeave) {
|
if (!application->m_trackingMouseLeave) {
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include <Host/AutoScreenshot.h>
|
#include <Host/AutoScreenshot.h>
|
||||||
#include <Host/D3D12WindowRenderer.h>
|
#include <Host/D3D12WindowRenderer.h>
|
||||||
|
#include <Host/D3D12WindowRenderLoop.h>
|
||||||
|
#include <Host/HostRuntimeState.h>
|
||||||
#include <Host/InputModifierTracker.h>
|
#include <Host/InputModifierTracker.h>
|
||||||
#include <Host/NativeRenderer.h>
|
#include <Host/NativeRenderer.h>
|
||||||
|
|
||||||
@@ -23,6 +25,10 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor::Host {
|
||||||
|
class WindowMessageDispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
namespace XCEngine::UI::Editor {
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
class Application {
|
class Application {
|
||||||
@@ -32,11 +38,15 @@ public:
|
|||||||
int Run(HINSTANCE hInstance, int nCmdShow);
|
int Run(HINSTANCE hInstance, int nCmdShow);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class ::XCEngine::UI::Editor::Host::WindowMessageDispatcher;
|
||||||
|
|
||||||
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
bool Initialize(HINSTANCE hInstance, int nCmdShow);
|
bool Initialize(HINSTANCE hInstance, int nCmdShow);
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
void RenderFrame();
|
void RenderFrame();
|
||||||
|
void OnDeferredRenderMessage();
|
||||||
|
void OnPaintMessage();
|
||||||
void OnResize();
|
void OnResize();
|
||||||
void OnEnterSizeMove();
|
void OnEnterSizeMove();
|
||||||
void OnExitSizeMove();
|
void OnExitSizeMove();
|
||||||
@@ -44,7 +54,6 @@ private:
|
|||||||
void QueueWindowResize(UINT width, UINT height);
|
void QueueWindowResize(UINT width, UINT height);
|
||||||
void QueueCurrentClientResize();
|
void QueueCurrentClientResize();
|
||||||
bool ApplyPendingWindowResize();
|
bool ApplyPendingWindowResize();
|
||||||
void RequestDeferredRenderFrame();
|
|
||||||
bool QueryCurrentClientPixelSize(UINT& outWidth, UINT& outHeight) const;
|
bool QueryCurrentClientPixelSize(UINT& outWidth, UINT& outHeight) const;
|
||||||
bool IsPointerInsideClientArea() const;
|
bool IsPointerInsideClientArea() const;
|
||||||
bool ApplyCurrentCursor() const;
|
bool ApplyCurrentCursor() const;
|
||||||
@@ -78,19 +87,14 @@ private:
|
|||||||
ATOM m_windowClassAtom = 0;
|
ATOM m_windowClassAtom = 0;
|
||||||
::XCEngine::UI::Editor::Host::NativeRenderer m_renderer = {};
|
::XCEngine::UI::Editor::Host::NativeRenderer m_renderer = {};
|
||||||
::XCEngine::UI::Editor::Host::D3D12WindowRenderer m_windowRenderer = {};
|
::XCEngine::UI::Editor::Host::D3D12WindowRenderer m_windowRenderer = {};
|
||||||
|
::XCEngine::UI::Editor::Host::D3D12WindowRenderLoop m_windowRenderLoop = {};
|
||||||
::XCEngine::UI::Editor::Host::AutoScreenshotController m_autoScreenshot = {};
|
::XCEngine::UI::Editor::Host::AutoScreenshotController m_autoScreenshot = {};
|
||||||
::XCEngine::UI::Editor::Host::InputModifierTracker m_inputModifierTracker = {};
|
::XCEngine::UI::Editor::Host::InputModifierTracker m_inputModifierTracker = {};
|
||||||
App::ProductEditorContext m_editorContext = {};
|
App::ProductEditorContext m_editorContext = {};
|
||||||
App::ProductEditorWorkspace m_editorWorkspace = {};
|
App::ProductEditorWorkspace m_editorWorkspace = {};
|
||||||
std::vector<::XCEngine::UI::UIInputEvent> m_pendingInputEvents = {};
|
std::vector<::XCEngine::UI::UIInputEvent> m_pendingInputEvents = {};
|
||||||
bool m_trackingMouseLeave = false;
|
bool m_trackingMouseLeave = false;
|
||||||
UINT m_windowDpi = 96u;
|
::XCEngine::UI::Editor::Host::HostRuntimeState m_hostRuntime = {};
|
||||||
float m_dpiScale = 1.0f;
|
|
||||||
bool m_inInteractiveResize = false;
|
|
||||||
bool m_renderFrameQueued = false;
|
|
||||||
bool m_hasPendingWindowResize = false;
|
|
||||||
UINT m_pendingWindowResizeWidth = 0u;
|
|
||||||
UINT m_pendingWindowResizeHeight = 0u;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int RunXCUIEditorApp(HINSTANCE hInstance, int nCmdShow);
|
int RunXCUIEditorApp(HINSTANCE hInstance, int nCmdShow);
|
||||||
|
|||||||
169
new_editor/app/Host/D3D12ShaderResourceDescriptorAllocator.cpp
Normal file
169
new_editor/app/Host/D3D12ShaderResourceDescriptorAllocator.cpp
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
#include "D3D12ShaderResourceDescriptorAllocator.h"
|
||||||
|
|
||||||
|
#include <XCEngine/RHI/RHITypes.h>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor::Host {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ::XCEngine::RHI::D3D12DescriptorHeap;
|
||||||
|
using ::XCEngine::RHI::D3D12Device;
|
||||||
|
using ::XCEngine::RHI::D3D12Texture;
|
||||||
|
using ::XCEngine::RHI::DescriptorHeapType;
|
||||||
|
using ::XCEngine::RHI::DescriptorPoolDesc;
|
||||||
|
using ::XCEngine::RHI::RHIDevice;
|
||||||
|
using ::XCEngine::RHI::RHITexture;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool D3D12ShaderResourceDescriptorAllocator::Initialize(RHIDevice& device, UINT descriptorCount) {
|
||||||
|
Shutdown();
|
||||||
|
|
||||||
|
DescriptorPoolDesc descriptorPoolDesc = {};
|
||||||
|
descriptorPoolDesc.type = DescriptorHeapType::CBV_SRV_UAV;
|
||||||
|
descriptorPoolDesc.descriptorCount = descriptorCount;
|
||||||
|
descriptorPoolDesc.shaderVisible = true;
|
||||||
|
m_descriptorPool = device.CreateDescriptorPool(descriptorPoolDesc);
|
||||||
|
m_descriptorHeap = dynamic_cast<D3D12DescriptorHeap*>(m_descriptorPool);
|
||||||
|
if (m_descriptorPool == nullptr || m_descriptorHeap == nullptr) {
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device = &device;
|
||||||
|
m_descriptorSize = m_descriptorHeap->GetDescriptorSize();
|
||||||
|
m_descriptorCount = descriptorCount;
|
||||||
|
m_descriptorUsage.assign(descriptorCount, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12ShaderResourceDescriptorAllocator::Shutdown() {
|
||||||
|
if (m_descriptorPool != nullptr) {
|
||||||
|
m_descriptorPool->Shutdown();
|
||||||
|
delete m_descriptorPool;
|
||||||
|
m_descriptorPool = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device = nullptr;
|
||||||
|
m_descriptorHeap = nullptr;
|
||||||
|
m_descriptorUsage.clear();
|
||||||
|
m_descriptorSize = 0u;
|
||||||
|
m_descriptorCount = 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12ShaderResourceDescriptorAllocator::IsInitialized() const {
|
||||||
|
return m_device != nullptr &&
|
||||||
|
m_descriptorHeap != nullptr &&
|
||||||
|
m_descriptorSize > 0u &&
|
||||||
|
!m_descriptorUsage.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D12DescriptorHeap* D3D12ShaderResourceDescriptorAllocator::GetDescriptorHeap() const {
|
||||||
|
return m_descriptorHeap != nullptr ? m_descriptorHeap->GetDescriptorHeap() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT D3D12ShaderResourceDescriptorAllocator::GetDescriptorSize() const {
|
||||||
|
return m_descriptorSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT D3D12ShaderResourceDescriptorAllocator::GetDescriptorCount() const {
|
||||||
|
return m_descriptorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12ShaderResourceDescriptorAllocator::Allocate(
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle) {
|
||||||
|
AllocateInternal(outCpuHandle, outGpuHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12ShaderResourceDescriptorAllocator::CreateTextureDescriptor(
|
||||||
|
RHITexture* texture,
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle) {
|
||||||
|
if (m_device == nullptr ||
|
||||||
|
texture == nullptr ||
|
||||||
|
outCpuHandle == nullptr ||
|
||||||
|
outGpuHandle == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outCpuHandle = {};
|
||||||
|
*outGpuHandle = {};
|
||||||
|
|
||||||
|
auto* nativeDevice = dynamic_cast<D3D12Device*>(m_device);
|
||||||
|
auto* nativeTexture = dynamic_cast<D3D12Texture*>(texture);
|
||||||
|
if (nativeDevice == nullptr ||
|
||||||
|
nativeTexture == nullptr ||
|
||||||
|
nativeTexture->GetResource() == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AllocateInternal(outCpuHandle, outGpuHandle);
|
||||||
|
if (outCpuHandle->ptr == 0 || outGpuHandle->ptr == 0) {
|
||||||
|
*outCpuHandle = {};
|
||||||
|
*outGpuHandle = {};
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||||
|
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||||
|
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||||
|
srvDesc.Texture2D.MipLevels = 1;
|
||||||
|
nativeDevice->GetDevice()->CreateShaderResourceView(
|
||||||
|
nativeTexture->GetResource(),
|
||||||
|
&srvDesc,
|
||||||
|
*outCpuHandle);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12ShaderResourceDescriptorAllocator::Free(
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE) {
|
||||||
|
if (m_descriptorHeap == nullptr ||
|
||||||
|
m_descriptorSize == 0u ||
|
||||||
|
cpuHandle.ptr < m_descriptorHeap->GetCPUDescriptorHandleForHeapStart().ptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SIZE_T offset =
|
||||||
|
cpuHandle.ptr - m_descriptorHeap->GetCPUDescriptorHandleForHeapStart().ptr;
|
||||||
|
const std::size_t index =
|
||||||
|
static_cast<std::size_t>(offset / m_descriptorSize);
|
||||||
|
if (index < m_descriptorUsage.size()) {
|
||||||
|
m_descriptorUsage[index] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12ShaderResourceDescriptorAllocator::AllocateInternal(
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle) {
|
||||||
|
if (outCpuHandle == nullptr || outGpuHandle == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outCpuHandle = {};
|
||||||
|
*outGpuHandle = {};
|
||||||
|
if (m_descriptorHeap == nullptr ||
|
||||||
|
m_descriptorSize == 0u ||
|
||||||
|
m_descriptorUsage.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t index = 0; index < m_descriptorUsage.size(); ++index) {
|
||||||
|
if (m_descriptorUsage[index]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_descriptorUsage[index] = true;
|
||||||
|
outCpuHandle->ptr =
|
||||||
|
m_descriptorHeap->GetCPUDescriptorHandleForHeapStart().ptr +
|
||||||
|
static_cast<SIZE_T>(index) * m_descriptorSize;
|
||||||
|
outGpuHandle->ptr =
|
||||||
|
m_descriptorHeap->GetGPUDescriptorHandleForHeapStart().ptr +
|
||||||
|
static_cast<UINT64>(index) * m_descriptorSize;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor::Host
|
||||||
55
new_editor/app/Host/D3D12ShaderResourceDescriptorAllocator.h
Normal file
55
new_editor/app/Host/D3D12ShaderResourceDescriptorAllocator.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <XCEngine/RHI/D3D12/D3D12DescriptorHeap.h>
|
||||||
|
#include <XCEngine/RHI/D3D12/D3D12Device.h>
|
||||||
|
#include <XCEngine/RHI/D3D12/D3D12Texture.h>
|
||||||
|
#include <XCEngine/RHI/RHIDescriptorPool.h>
|
||||||
|
#include <XCEngine/RHI/RHIDevice.h>
|
||||||
|
#include <XCEngine/RHI/RHITexture.h>
|
||||||
|
|
||||||
|
#include <d3d12.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor::Host {
|
||||||
|
|
||||||
|
class D3D12ShaderResourceDescriptorAllocator {
|
||||||
|
public:
|
||||||
|
bool Initialize(::XCEngine::RHI::RHIDevice& device, UINT descriptorCount = 64u);
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
bool IsInitialized() const;
|
||||||
|
ID3D12DescriptorHeap* GetDescriptorHeap() const;
|
||||||
|
UINT GetDescriptorSize() const;
|
||||||
|
UINT GetDescriptorCount() const;
|
||||||
|
|
||||||
|
void Allocate(
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle);
|
||||||
|
bool CreateTextureDescriptor(
|
||||||
|
::XCEngine::RHI::RHITexture* texture,
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle);
|
||||||
|
void Free(
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void AllocateInternal(
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle);
|
||||||
|
|
||||||
|
::XCEngine::RHI::RHIDevice* m_device = nullptr;
|
||||||
|
::XCEngine::RHI::RHIDescriptorPool* m_descriptorPool = nullptr;
|
||||||
|
::XCEngine::RHI::D3D12DescriptorHeap* m_descriptorHeap = nullptr;
|
||||||
|
std::vector<bool> m_descriptorUsage = {};
|
||||||
|
UINT m_descriptorSize = 0u;
|
||||||
|
UINT m_descriptorCount = 0u;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor::Host
|
||||||
@@ -2,57 +2,115 @@
|
|||||||
|
|
||||||
namespace XCEngine::UI::Editor::Host {
|
namespace XCEngine::UI::Editor::Host {
|
||||||
|
|
||||||
bool RenderD3D12WindowFrame(
|
D3D12WindowRenderLoopAttachResult D3D12WindowRenderLoop::Attach(
|
||||||
D3D12WindowRenderer& windowRenderer,
|
NativeRenderer& uiRenderer,
|
||||||
const float clearColor[4],
|
D3D12WindowRenderer& windowRenderer) {
|
||||||
const D3D12WindowRenderCallback& beforePresent,
|
m_uiRenderer = &uiRenderer;
|
||||||
const D3D12WindowRenderCallback& afterPresent) {
|
m_windowRenderer = &windowRenderer;
|
||||||
const ::XCEngine::Rendering::RenderSurface* renderSurface =
|
|
||||||
windowRenderer.GetCurrentRenderSurface();
|
D3D12WindowRenderLoopAttachResult result = {};
|
||||||
::XCEngine::Rendering::RenderContext renderContext =
|
result.hasViewportSurfacePresentation = m_uiRenderer->AttachWindowRenderer(*m_windowRenderer);
|
||||||
windowRenderer.GetRenderContext();
|
if (!result.hasViewportSurfacePresentation) {
|
||||||
if (!renderContext.IsValid() ||
|
const std::string& interopError = m_uiRenderer->GetLastRenderError();
|
||||||
renderContext.commandList == nullptr ||
|
result.interopWarning = interopError.empty()
|
||||||
renderContext.commandQueue == nullptr ||
|
? "native renderer d3d12 interop unavailable; falling back to hwnd renderer."
|
||||||
windowRenderer.GetSwapChain() == nullptr ||
|
: "native renderer d3d12 interop unavailable; falling back to hwnd renderer: " +
|
||||||
renderSurface == nullptr) {
|
interopError;
|
||||||
return false;
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12WindowRenderLoop::Detach() {
|
||||||
|
if (m_uiRenderer != nullptr) {
|
||||||
|
m_uiRenderer->DetachWindowRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* d3d12CommandList =
|
m_uiRenderer = nullptr;
|
||||||
static_cast<::XCEngine::RHI::D3D12CommandList*>(renderContext.commandList);
|
m_windowRenderer = nullptr;
|
||||||
if (d3d12CommandList == nullptr) {
|
}
|
||||||
return false;
|
|
||||||
|
D3D12WindowRenderLoopFrameContext D3D12WindowRenderLoop::BeginFrame() const {
|
||||||
|
D3D12WindowRenderLoopFrameContext context = {};
|
||||||
|
if (!HasViewportSurfacePresentation()) {
|
||||||
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& colorAttachments = renderSurface->GetColorAttachments();
|
if (!m_windowRenderer->BeginFrame()) {
|
||||||
if (colorAttachments.empty() || colorAttachments[0] == nullptr) {
|
const std::string& frameError = m_windowRenderer->GetLastError();
|
||||||
return false;
|
context.warning = frameError.empty()
|
||||||
|
? "d3d12 frame begin failed"
|
||||||
|
: "d3d12 frame begin failed: " + frameError;
|
||||||
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
::XCEngine::RHI::RHIResourceView* renderTargetView = colorAttachments[0];
|
context.canRenderViewports = true;
|
||||||
renderContext.commandList->TransitionBarrier(
|
context.renderContext = m_windowRenderer->GetRenderContext();
|
||||||
renderTargetView,
|
return context;
|
||||||
::XCEngine::RHI::ResourceStates::Present,
|
}
|
||||||
::XCEngine::RHI::ResourceStates::RenderTarget);
|
|
||||||
renderContext.commandList->SetRenderTargets(1, &renderTargetView, nullptr);
|
|
||||||
renderContext.commandList->ClearRenderTarget(renderTargetView, clearColor);
|
|
||||||
|
|
||||||
if (beforePresent) {
|
D3D12WindowRenderLoopResizeResult D3D12WindowRenderLoop::ApplyResize(UINT width, UINT height) {
|
||||||
beforePresent(renderContext, *renderSurface);
|
D3D12WindowRenderLoopResizeResult result = {};
|
||||||
renderContext.commandList->SetRenderTargets(1, &renderTargetView, nullptr);
|
if (m_uiRenderer == nullptr || m_windowRenderer == nullptr) {
|
||||||
|
result.interopWarning = "window render loop is detached.";
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (afterPresent) {
|
m_uiRenderer->Resize(width, height);
|
||||||
afterPresent(renderContext, *renderSurface);
|
m_uiRenderer->DetachWindowRenderer();
|
||||||
renderContext.commandList->SetRenderTargets(1, &renderTargetView, nullptr);
|
|
||||||
|
const bool resizedWindowRenderer =
|
||||||
|
m_windowRenderer->Resize(static_cast<int>(width), static_cast<int>(height));
|
||||||
|
if (!resizedWindowRenderer || !m_windowRenderer->GetLastError().empty()) {
|
||||||
|
const std::string& resizeError = m_windowRenderer->GetLastError();
|
||||||
|
result.windowRendererWarning = resizeError.empty()
|
||||||
|
? "window renderer resize warning."
|
||||||
|
: "window renderer resize warning: " + resizeError;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderContext.commandList->TransitionBarrier(
|
if (!resizedWindowRenderer) {
|
||||||
renderTargetView,
|
return result;
|
||||||
::XCEngine::RHI::ResourceStates::RenderTarget,
|
}
|
||||||
::XCEngine::RHI::ResourceStates::Present);
|
|
||||||
return windowRenderer.SubmitFrame(true);
|
const D3D12WindowRenderLoopAttachResult attachResult =
|
||||||
|
Attach(*m_uiRenderer, *m_windowRenderer);
|
||||||
|
result.hasViewportSurfacePresentation = attachResult.hasViewportSurfacePresentation;
|
||||||
|
result.interopWarning = attachResult.interopWarning;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12WindowRenderLoopPresentResult D3D12WindowRenderLoop::Present(
|
||||||
|
const ::XCEngine::UI::UIDrawData& drawData) const {
|
||||||
|
D3D12WindowRenderLoopPresentResult result = {};
|
||||||
|
if (m_uiRenderer == nullptr) {
|
||||||
|
result.warning = "window render loop has no ui renderer.";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasViewportSurfacePresentation()) {
|
||||||
|
result.framePresented = m_uiRenderer->RenderToWindowRenderer(drawData);
|
||||||
|
if (!result.framePresented) {
|
||||||
|
const std::string& composeError = m_uiRenderer->GetLastRenderError();
|
||||||
|
result.warning = composeError.empty()
|
||||||
|
? "d3d12 window composition failed, falling back to hwnd renderer."
|
||||||
|
: "d3d12 window composition failed, falling back to hwnd renderer: " +
|
||||||
|
composeError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.framePresented) {
|
||||||
|
result.framePresented = m_uiRenderer->Render(drawData);
|
||||||
|
if (!result.framePresented && result.warning.empty()) {
|
||||||
|
result.warning = m_uiRenderer->GetLastRenderError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12WindowRenderLoop::HasViewportSurfacePresentation() const {
|
||||||
|
return m_uiRenderer != nullptr &&
|
||||||
|
m_windowRenderer != nullptr &&
|
||||||
|
m_uiRenderer->HasAttachedWindowRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace XCEngine::UI::Editor::Host
|
} // namespace XCEngine::UI::Editor::Host
|
||||||
|
|||||||
@@ -1,20 +1,53 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "D3D12WindowRenderer.h"
|
#include "D3D12WindowRenderer.h"
|
||||||
|
#include "NativeRenderer.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <XCEngine/UI/DrawData.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace XCEngine::UI::Editor::Host {
|
namespace XCEngine::UI::Editor::Host {
|
||||||
|
|
||||||
using D3D12WindowRenderCallback =
|
struct D3D12WindowRenderLoopAttachResult {
|
||||||
std::function<void(
|
bool hasViewportSurfacePresentation = false;
|
||||||
const ::XCEngine::Rendering::RenderContext&,
|
std::string interopWarning = {};
|
||||||
const ::XCEngine::Rendering::RenderSurface&)>;
|
};
|
||||||
|
|
||||||
bool RenderD3D12WindowFrame(
|
struct D3D12WindowRenderLoopFrameContext {
|
||||||
D3D12WindowRenderer& windowRenderer,
|
bool canRenderViewports = false;
|
||||||
const float clearColor[4],
|
::XCEngine::Rendering::RenderContext renderContext = {};
|
||||||
const D3D12WindowRenderCallback& beforePresent = {},
|
std::string warning = {};
|
||||||
const D3D12WindowRenderCallback& afterPresent = {});
|
};
|
||||||
|
|
||||||
|
struct D3D12WindowRenderLoopResizeResult {
|
||||||
|
bool hasViewportSurfacePresentation = false;
|
||||||
|
std::string windowRendererWarning = {};
|
||||||
|
std::string interopWarning = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct D3D12WindowRenderLoopPresentResult {
|
||||||
|
bool framePresented = false;
|
||||||
|
std::string warning = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class D3D12WindowRenderLoop {
|
||||||
|
public:
|
||||||
|
D3D12WindowRenderLoopAttachResult Attach(
|
||||||
|
NativeRenderer& uiRenderer,
|
||||||
|
D3D12WindowRenderer& windowRenderer);
|
||||||
|
void Detach();
|
||||||
|
|
||||||
|
D3D12WindowRenderLoopFrameContext BeginFrame() const;
|
||||||
|
D3D12WindowRenderLoopResizeResult ApplyResize(UINT width, UINT height);
|
||||||
|
D3D12WindowRenderLoopPresentResult Present(
|
||||||
|
const ::XCEngine::UI::UIDrawData& drawData) const;
|
||||||
|
|
||||||
|
bool HasViewportSurfacePresentation() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
NativeRenderer* m_uiRenderer = nullptr;
|
||||||
|
D3D12WindowRenderer* m_windowRenderer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace XCEngine::UI::Editor::Host
|
} // namespace XCEngine::UI::Editor::Host
|
||||||
|
|||||||
@@ -8,11 +8,8 @@ namespace XCEngine::UI::Editor::Host {
|
|||||||
|
|
||||||
using ::XCEngine::RHI::CommandListDesc;
|
using ::XCEngine::RHI::CommandListDesc;
|
||||||
using ::XCEngine::RHI::CommandQueueDesc;
|
using ::XCEngine::RHI::CommandQueueDesc;
|
||||||
using ::XCEngine::RHI::DescriptorHeapType;
|
|
||||||
using ::XCEngine::RHI::DescriptorPoolDesc;
|
|
||||||
using ::XCEngine::RHI::D3D12CommandList;
|
using ::XCEngine::RHI::D3D12CommandList;
|
||||||
using ::XCEngine::RHI::D3D12CommandQueue;
|
using ::XCEngine::RHI::D3D12CommandQueue;
|
||||||
using ::XCEngine::RHI::D3D12DescriptorHeap;
|
|
||||||
using ::XCEngine::RHI::D3D12Device;
|
using ::XCEngine::RHI::D3D12Device;
|
||||||
using ::XCEngine::RHI::D3D12SwapChain;
|
using ::XCEngine::RHI::D3D12SwapChain;
|
||||||
using ::XCEngine::RHI::D3D12Texture;
|
using ::XCEngine::RHI::D3D12Texture;
|
||||||
@@ -101,20 +98,6 @@ bool D3D12WindowRenderer::Initialize(HWND hwnd, int width, int height) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DescriptorPoolDesc srvPoolDesc = {};
|
|
||||||
srvPoolDesc.type = DescriptorHeapType::CBV_SRV_UAV;
|
|
||||||
srvPoolDesc.descriptorCount = kSrvDescriptorCount;
|
|
||||||
srvPoolDesc.shaderVisible = true;
|
|
||||||
m_srvPool = m_device->CreateDescriptorPool(srvPoolDesc);
|
|
||||||
m_srvHeap = dynamic_cast<D3D12DescriptorHeap*>(m_srvPool);
|
|
||||||
if (m_srvPool == nullptr || m_srvHeap == nullptr) {
|
|
||||||
m_lastError = "Failed to create the D3D12 SRV descriptor heap.";
|
|
||||||
Shutdown();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_srvDescriptorSize = m_srvHeap->GetDescriptorSize();
|
|
||||||
m_srvUsage.assign(kSrvDescriptorCount, false);
|
|
||||||
if (!RecreateBackBufferViews()) {
|
if (!RecreateBackBufferViews()) {
|
||||||
m_lastError = "Failed to create swap chain back buffer views.";
|
m_lastError = "Failed to create swap chain back buffer views.";
|
||||||
Shutdown();
|
Shutdown();
|
||||||
@@ -137,14 +120,6 @@ void D3D12WindowRenderer::Shutdown() {
|
|||||||
ReleaseFrameCompletionFence();
|
ReleaseFrameCompletionFence();
|
||||||
ReleaseBackBufferViews();
|
ReleaseBackBufferViews();
|
||||||
|
|
||||||
if (m_srvPool != nullptr) {
|
|
||||||
m_srvPool->Shutdown();
|
|
||||||
delete m_srvPool;
|
|
||||||
m_srvPool = nullptr;
|
|
||||||
}
|
|
||||||
m_srvHeap = nullptr;
|
|
||||||
m_srvUsage.clear();
|
|
||||||
|
|
||||||
if (m_swapChain != nullptr) {
|
if (m_swapChain != nullptr) {
|
||||||
m_swapChain->Shutdown();
|
m_swapChain->Shutdown();
|
||||||
delete m_swapChain;
|
delete m_swapChain;
|
||||||
@@ -175,7 +150,6 @@ void D3D12WindowRenderer::Shutdown() {
|
|||||||
m_width = 0;
|
m_width = 0;
|
||||||
m_height = 0;
|
m_height = 0;
|
||||||
m_activeBackBufferIndex = 0u;
|
m_activeBackBufferIndex = 0u;
|
||||||
m_srvDescriptorSize = 0;
|
|
||||||
m_lastError.clear();
|
m_lastError.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,8 +224,8 @@ bool D3D12WindowRenderer::Resize(int width, int height) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool D3D12WindowRenderer::BeginFrame() {
|
bool D3D12WindowRenderer::BeginFrame() {
|
||||||
if (m_swapChain == nullptr || m_srvHeap == nullptr) {
|
if (m_swapChain == nullptr) {
|
||||||
m_lastError = "BeginFrame requires a swap chain, command list, and SRV heap.";
|
m_lastError = "BeginFrame requires an initialized swap chain.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,10 +329,6 @@ ID3D12Device* D3D12WindowRenderer::GetDevice() const {
|
|||||||
return device != nullptr ? device->GetDevice() : nullptr;
|
return device != nullptr ? device->GetDevice() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ID3D12DescriptorHeap* D3D12WindowRenderer::GetSrvHeap() const {
|
|
||||||
return m_srvHeap != nullptr ? m_srvHeap->GetDescriptorHeap() : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D12CommandQueue* D3D12WindowRenderer::GetCommandQueue() const {
|
ID3D12CommandQueue* D3D12WindowRenderer::GetCommandQueue() const {
|
||||||
const D3D12CommandQueue* queue = GetD3D12CommandQueue();
|
const D3D12CommandQueue* queue = GetD3D12CommandQueue();
|
||||||
return queue != nullptr ? queue->GetCommandQueue() : nullptr;
|
return queue != nullptr ? queue->GetCommandQueue() : nullptr;
|
||||||
@@ -368,68 +338,6 @@ const std::string& D3D12WindowRenderer::GetLastError() const {
|
|||||||
return m_lastError;
|
return m_lastError;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12WindowRenderer::AllocateShaderResourceDescriptor(
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
|
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle) {
|
|
||||||
AllocateShaderResourceDescriptorInternal(outCpuHandle, outGpuHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool D3D12WindowRenderer::CreateShaderResourceTextureDescriptor(
|
|
||||||
RHIDevice* device,
|
|
||||||
::XCEngine::RHI::RHITexture* texture,
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
|
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle) {
|
|
||||||
if (device == nullptr ||
|
|
||||||
texture == nullptr ||
|
|
||||||
outCpuHandle == nullptr ||
|
|
||||||
outGpuHandle == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*outCpuHandle = {};
|
|
||||||
*outGpuHandle = {};
|
|
||||||
|
|
||||||
auto* nativeDevice = dynamic_cast<D3D12Device*>(device);
|
|
||||||
auto* nativeTexture = dynamic_cast<D3D12Texture*>(texture);
|
|
||||||
if (nativeDevice == nullptr ||
|
|
||||||
nativeTexture == nullptr ||
|
|
||||||
nativeTexture->GetResource() == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AllocateShaderResourceDescriptorInternal(outCpuHandle, outGpuHandle);
|
|
||||||
if (outCpuHandle->ptr == 0 || outGpuHandle->ptr == 0) {
|
|
||||||
*outCpuHandle = {};
|
|
||||||
*outGpuHandle = {};
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
|
||||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
|
||||||
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
|
||||||
srvDesc.Texture2D.MipLevels = 1;
|
|
||||||
nativeDevice->GetDevice()->CreateShaderResourceView(
|
|
||||||
nativeTexture->GetResource(),
|
|
||||||
&srvDesc,
|
|
||||||
*outCpuHandle);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void D3D12WindowRenderer::FreeShaderResourceDescriptor(
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,
|
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle) {
|
|
||||||
FreeShaderResourceDescriptorInternal(cpuHandle, gpuHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT D3D12WindowRenderer::GetSrvDescriptorSize() const {
|
|
||||||
return m_srvDescriptorSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT D3D12WindowRenderer::GetSrvDescriptorCount() const {
|
|
||||||
return kSrvDescriptorCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
RHIDevice* D3D12WindowRenderer::GetRHIDevice() const {
|
RHIDevice* D3D12WindowRenderer::GetRHIDevice() const {
|
||||||
return m_device;
|
return m_device;
|
||||||
}
|
}
|
||||||
@@ -504,55 +412,6 @@ D3D12SwapChain* D3D12WindowRenderer::GetD3D12SwapChain() const {
|
|||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12WindowRenderer::AllocateShaderResourceDescriptorInternal(
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
|
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle) {
|
|
||||||
if (outCpuHandle == nullptr || outGpuHandle == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
*outCpuHandle = {};
|
|
||||||
*outGpuHandle = {};
|
|
||||||
if (m_srvHeap == nullptr ||
|
|
||||||
m_srvDescriptorSize == 0 ||
|
|
||||||
m_srvUsage.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t index = 0; index < m_srvUsage.size(); ++index) {
|
|
||||||
if (m_srvUsage[index]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_srvUsage[index] = true;
|
|
||||||
outCpuHandle->ptr =
|
|
||||||
m_srvHeap->GetCPUDescriptorHandleForHeapStart().ptr +
|
|
||||||
static_cast<SIZE_T>(index) * m_srvDescriptorSize;
|
|
||||||
outGpuHandle->ptr =
|
|
||||||
m_srvHeap->GetGPUDescriptorHandleForHeapStart().ptr +
|
|
||||||
static_cast<UINT64>(index) * m_srvDescriptorSize;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void D3D12WindowRenderer::FreeShaderResourceDescriptorInternal(
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,
|
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE) {
|
|
||||||
if (m_srvHeap == nullptr ||
|
|
||||||
m_srvDescriptorSize == 0 ||
|
|
||||||
cpuHandle.ptr < m_srvHeap->GetCPUDescriptorHandleForHeapStart().ptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SIZE_T offset =
|
|
||||||
cpuHandle.ptr - m_srvHeap->GetCPUDescriptorHandleForHeapStart().ptr;
|
|
||||||
const std::size_t index =
|
|
||||||
static_cast<std::size_t>(offset / m_srvDescriptorSize);
|
|
||||||
if (index < m_srvUsage.size()) {
|
|
||||||
m_srvUsage[index] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool D3D12WindowRenderer::InitializeFrameCompletionFence() {
|
bool D3D12WindowRenderer::InitializeFrameCompletionFence() {
|
||||||
ReleaseFrameCompletionFence();
|
ReleaseFrameCompletionFence();
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include <XCEngine/Rendering/RenderSurface.h>
|
#include <XCEngine/Rendering/RenderSurface.h>
|
||||||
#include <XCEngine/RHI/D3D12/D3D12CommandList.h>
|
#include <XCEngine/RHI/D3D12/D3D12CommandList.h>
|
||||||
#include <XCEngine/RHI/D3D12/D3D12CommandQueue.h>
|
#include <XCEngine/RHI/D3D12/D3D12CommandQueue.h>
|
||||||
#include <XCEngine/RHI/D3D12/D3D12DescriptorHeap.h>
|
|
||||||
#include <XCEngine/RHI/D3D12/D3D12Device.h>
|
#include <XCEngine/RHI/D3D12/D3D12Device.h>
|
||||||
#include <XCEngine/RHI/D3D12/D3D12SwapChain.h>
|
#include <XCEngine/RHI/D3D12/D3D12SwapChain.h>
|
||||||
#include <XCEngine/RHI/D3D12/D3D12Texture.h>
|
#include <XCEngine/RHI/D3D12/D3D12Texture.h>
|
||||||
@@ -32,7 +31,6 @@ namespace XCEngine::UI::Editor::Host {
|
|||||||
|
|
||||||
class D3D12WindowRenderer {
|
class D3D12WindowRenderer {
|
||||||
public:
|
public:
|
||||||
static constexpr UINT kSrvDescriptorCount = 64;
|
|
||||||
static constexpr std::uint32_t kSwapChainBufferCount = 3;
|
static constexpr std::uint32_t kSwapChainBufferCount = 3;
|
||||||
|
|
||||||
bool Initialize(HWND hwnd, int width, int height);
|
bool Initialize(HWND hwnd, int width, int height);
|
||||||
@@ -45,22 +43,8 @@ public:
|
|||||||
bool PresentFrame();
|
bool PresentFrame();
|
||||||
|
|
||||||
ID3D12Device* GetDevice() const;
|
ID3D12Device* GetDevice() const;
|
||||||
ID3D12DescriptorHeap* GetSrvHeap() const;
|
|
||||||
ID3D12CommandQueue* GetCommandQueue() const;
|
ID3D12CommandQueue* GetCommandQueue() const;
|
||||||
const std::string& GetLastError() const;
|
const std::string& GetLastError() const;
|
||||||
void AllocateShaderResourceDescriptor(
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
|
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle);
|
|
||||||
bool CreateShaderResourceTextureDescriptor(
|
|
||||||
::XCEngine::RHI::RHIDevice* device,
|
|
||||||
::XCEngine::RHI::RHITexture* texture,
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
|
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle);
|
|
||||||
void FreeShaderResourceDescriptor(
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,
|
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle);
|
|
||||||
UINT GetSrvDescriptorSize() const;
|
|
||||||
UINT GetSrvDescriptorCount() const;
|
|
||||||
::XCEngine::RHI::RHIDevice* GetRHIDevice() const;
|
::XCEngine::RHI::RHIDevice* GetRHIDevice() const;
|
||||||
::XCEngine::RHI::RHISwapChain* GetSwapChain() const;
|
::XCEngine::RHI::RHISwapChain* GetSwapChain() const;
|
||||||
const ::XCEngine::Rendering::RenderSurface* GetCurrentRenderSurface() const;
|
const ::XCEngine::Rendering::RenderSurface* GetCurrentRenderSurface() const;
|
||||||
@@ -75,12 +59,6 @@ private:
|
|||||||
::XCEngine::RHI::D3D12CommandList* GetD3D12CommandList() const;
|
::XCEngine::RHI::D3D12CommandList* GetD3D12CommandList() const;
|
||||||
::XCEngine::RHI::D3D12SwapChain* GetD3D12SwapChain() const;
|
::XCEngine::RHI::D3D12SwapChain* GetD3D12SwapChain() const;
|
||||||
::XCEngine::RHI::RHICommandList* GetCurrentCommandList() const;
|
::XCEngine::RHI::RHICommandList* GetCurrentCommandList() const;
|
||||||
void AllocateShaderResourceDescriptorInternal(
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
|
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle);
|
|
||||||
void FreeShaderResourceDescriptorInternal(
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,
|
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle);
|
|
||||||
bool InitializeFrameCompletionFence();
|
bool InitializeFrameCompletionFence();
|
||||||
void ReleaseFrameCompletionFence();
|
void ReleaseFrameCompletionFence();
|
||||||
void WaitForBackBufferFrame(std::uint32_t backBufferIndex);
|
void WaitForBackBufferFrame(std::uint32_t backBufferIndex);
|
||||||
@@ -97,9 +75,6 @@ private:
|
|||||||
::XCEngine::RHI::RHICommandQueue* m_commandQueue = nullptr;
|
::XCEngine::RHI::RHICommandQueue* m_commandQueue = nullptr;
|
||||||
std::array<::XCEngine::RHI::RHICommandList*, kSwapChainBufferCount> m_commandLists = {};
|
std::array<::XCEngine::RHI::RHICommandList*, kSwapChainBufferCount> m_commandLists = {};
|
||||||
::XCEngine::RHI::RHISwapChain* m_swapChain = nullptr;
|
::XCEngine::RHI::RHISwapChain* m_swapChain = nullptr;
|
||||||
::XCEngine::RHI::RHIDescriptorPool* m_srvPool = nullptr;
|
|
||||||
::XCEngine::RHI::D3D12DescriptorHeap* m_srvHeap = nullptr;
|
|
||||||
std::vector<bool> m_srvUsage = {};
|
|
||||||
std::vector<::XCEngine::RHI::RHIResourceView*> m_backBufferViews = {};
|
std::vector<::XCEngine::RHI::RHIResourceView*> m_backBufferViews = {};
|
||||||
std::vector<::XCEngine::Rendering::RenderSurface> m_backBufferSurfaces = {};
|
std::vector<::XCEngine::Rendering::RenderSurface> m_backBufferSurfaces = {};
|
||||||
Microsoft::WRL::ComPtr<ID3D12Fence> m_frameCompletionFence = {};
|
Microsoft::WRL::ComPtr<ID3D12Fence> m_frameCompletionFence = {};
|
||||||
@@ -108,7 +83,6 @@ private:
|
|||||||
std::uint32_t m_activeBackBufferIndex = 0u;
|
std::uint32_t m_activeBackBufferIndex = 0u;
|
||||||
std::uint64_t m_lastSubmittedFrameValue = 0;
|
std::uint64_t m_lastSubmittedFrameValue = 0;
|
||||||
std::string m_lastError = {};
|
std::string m_lastError = {};
|
||||||
UINT m_srvDescriptorSize = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace XCEngine::UI::Editor::Host
|
} // namespace XCEngine::UI::Editor::Host
|
||||||
|
|||||||
89
new_editor/app/Host/HostRuntimeState.h
Normal file
89
new_editor/app/Host/HostRuntimeState.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor::Host {
|
||||||
|
|
||||||
|
class HostRuntimeState {
|
||||||
|
public:
|
||||||
|
void Reset() {
|
||||||
|
m_windowDpi = 96u;
|
||||||
|
m_inInteractiveResize = false;
|
||||||
|
m_renderFrameQueued = false;
|
||||||
|
m_hasPendingWindowResize = false;
|
||||||
|
m_pendingWindowResizeWidth = 0u;
|
||||||
|
m_pendingWindowResizeHeight = 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetWindowDpi(UINT dpi) {
|
||||||
|
m_windowDpi = dpi == 0u ? 96u : dpi;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT GetWindowDpi() const {
|
||||||
|
return m_windowDpi;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetDpiScale(float baseDpiScale) const {
|
||||||
|
return baseDpiScale > 0.0f
|
||||||
|
? static_cast<float>(m_windowDpi) / baseDpiScale
|
||||||
|
: 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeginInteractiveResize() {
|
||||||
|
m_inInteractiveResize = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndInteractiveResize() {
|
||||||
|
m_inInteractiveResize = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInteractiveResize() const {
|
||||||
|
return m_inInteractiveResize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QueueWindowResize(UINT width, UINT height) {
|
||||||
|
if (width == 0u || height == 0u) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pendingWindowResizeWidth = width;
|
||||||
|
m_pendingWindowResizeHeight = height;
|
||||||
|
m_hasPendingWindowResize = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConsumePendingWindowResize(UINT& outWidth, UINT& outHeight) {
|
||||||
|
outWidth = 0u;
|
||||||
|
outHeight = 0u;
|
||||||
|
if (!m_hasPendingWindowResize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_hasPendingWindowResize = false;
|
||||||
|
outWidth = m_pendingWindowResizeWidth;
|
||||||
|
outHeight = m_pendingWindowResizeHeight;
|
||||||
|
return outWidth > 0u && outHeight > 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryQueueDeferredRender() {
|
||||||
|
if (m_renderFrameQueued) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_renderFrameQueued = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearDeferredRenderRequest() {
|
||||||
|
m_renderFrameQueued = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
UINT m_windowDpi = 96u;
|
||||||
|
bool m_inInteractiveResize = false;
|
||||||
|
bool m_renderFrameQueued = false;
|
||||||
|
bool m_hasPendingWindowResize = false;
|
||||||
|
UINT m_pendingWindowResizeWidth = 0u;
|
||||||
|
UINT m_pendingWindowResizeHeight = 0u;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor::Host
|
||||||
115
new_editor/app/Host/WindowMessageDispatcher.cpp
Normal file
115
new_editor/app/Host/WindowMessageDispatcher.cpp
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
#include "WindowMessageDispatcher.h"
|
||||||
|
|
||||||
|
#include "../Application.h"
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor::Host {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr UINT kDeferredRenderMessage = WM_APP + 1u;
|
||||||
|
|
||||||
|
void TryEnableNonClientDpiScaling(HWND hwnd) {
|
||||||
|
if (hwnd == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HMODULE user32 = GetModuleHandleW(L"user32.dll");
|
||||||
|
if (user32 == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using EnableNonClientDpiScalingFn = BOOL(WINAPI*)(HWND);
|
||||||
|
const auto enableNonClientDpiScaling =
|
||||||
|
reinterpret_cast<EnableNonClientDpiScalingFn>(
|
||||||
|
GetProcAddress(user32, "EnableNonClientDpiScaling"));
|
||||||
|
if (enableNonClientDpiScaling != nullptr) {
|
||||||
|
enableNonClientDpiScaling(hwnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Application* WindowMessageDispatcher::GetApplicationFromWindow(HWND hwnd) {
|
||||||
|
return reinterpret_cast<Application*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowMessageDispatcher::TryHandleNonClientCreate(
|
||||||
|
HWND hwnd,
|
||||||
|
UINT message,
|
||||||
|
LPARAM lParam,
|
||||||
|
LRESULT& outResult) {
|
||||||
|
if (message != WM_NCCREATE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TryEnableNonClientDpiScaling(hwnd);
|
||||||
|
const auto* createStruct = reinterpret_cast<CREATESTRUCTW*>(lParam);
|
||||||
|
auto* application = reinterpret_cast<Application*>(createStruct->lpCreateParams);
|
||||||
|
SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(application));
|
||||||
|
outResult = TRUE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowMessageDispatcher::TryDispatch(
|
||||||
|
Application& application,
|
||||||
|
UINT message,
|
||||||
|
WPARAM wParam,
|
||||||
|
LPARAM lParam,
|
||||||
|
LRESULT& outResult) {
|
||||||
|
switch (message) {
|
||||||
|
case WM_SETCURSOR:
|
||||||
|
if (LOWORD(lParam) == HTCLIENT && application.ApplyCurrentCursor()) {
|
||||||
|
outResult = TRUE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case WM_DPICHANGED:
|
||||||
|
if (lParam == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
application.OnDpiChanged(
|
||||||
|
static_cast<UINT>(LOWORD(wParam)),
|
||||||
|
*reinterpret_cast<const RECT*>(lParam));
|
||||||
|
RequestDeferredRenderFrame(application);
|
||||||
|
outResult = 0;
|
||||||
|
return true;
|
||||||
|
case WM_ENTERSIZEMOVE:
|
||||||
|
application.OnEnterSizeMove();
|
||||||
|
outResult = 0;
|
||||||
|
return true;
|
||||||
|
case WM_EXITSIZEMOVE:
|
||||||
|
application.OnExitSizeMove();
|
||||||
|
RequestDeferredRenderFrame(application);
|
||||||
|
outResult = 0;
|
||||||
|
return true;
|
||||||
|
case WM_SIZE:
|
||||||
|
if (wParam != SIZE_MINIMIZED) {
|
||||||
|
application.OnResize();
|
||||||
|
RequestDeferredRenderFrame(application);
|
||||||
|
}
|
||||||
|
outResult = 0;
|
||||||
|
return true;
|
||||||
|
case kDeferredRenderMessage:
|
||||||
|
application.OnDeferredRenderMessage();
|
||||||
|
outResult = 0;
|
||||||
|
return true;
|
||||||
|
case WM_PAINT:
|
||||||
|
application.OnPaintMessage();
|
||||||
|
outResult = 0;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMessageDispatcher::RequestDeferredRenderFrame(Application& application) {
|
||||||
|
if (application.m_hwnd == nullptr ||
|
||||||
|
!IsWindow(application.m_hwnd) ||
|
||||||
|
!application.m_hostRuntime.TryQueueDeferredRender()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PostMessageW(application.m_hwnd, kDeferredRenderMessage, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor::Host
|
||||||
34
new_editor/app/Host/WindowMessageDispatcher.h
Normal file
34
new_editor/app/Host/WindowMessageDispatcher.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor {
|
||||||
|
class Application;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor::Host {
|
||||||
|
|
||||||
|
class WindowMessageDispatcher {
|
||||||
|
public:
|
||||||
|
static Application* GetApplicationFromWindow(HWND hwnd);
|
||||||
|
static bool TryHandleNonClientCreate(
|
||||||
|
HWND hwnd,
|
||||||
|
UINT message,
|
||||||
|
LPARAM lParam,
|
||||||
|
LRESULT& outResult);
|
||||||
|
static bool TryDispatch(
|
||||||
|
Application& application,
|
||||||
|
UINT message,
|
||||||
|
WPARAM wParam,
|
||||||
|
LPARAM lParam,
|
||||||
|
LRESULT& outResult);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void RequestDeferredRenderFrame(Application& application);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor::Host
|
||||||
@@ -14,12 +14,18 @@ void ProductViewportHostService::AttachWindowRenderer(
|
|||||||
Host::D3D12WindowRenderer& windowRenderer) {
|
Host::D3D12WindowRenderer& windowRenderer) {
|
||||||
if (m_windowRenderer == &windowRenderer) {
|
if (m_windowRenderer == &windowRenderer) {
|
||||||
m_device = windowRenderer.GetRHIDevice();
|
m_device = windowRenderer.GetRHIDevice();
|
||||||
|
if (m_device != nullptr && !m_textureDescriptorAllocator.IsInitialized()) {
|
||||||
|
m_textureDescriptorAllocator.Initialize(*m_device);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shutdown();
|
Shutdown();
|
||||||
m_windowRenderer = &windowRenderer;
|
m_windowRenderer = &windowRenderer;
|
||||||
m_device = windowRenderer.GetRHIDevice();
|
m_device = windowRenderer.GetRHIDevice();
|
||||||
|
if (m_device != nullptr) {
|
||||||
|
m_textureDescriptorAllocator.Initialize(*m_device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProductViewportHostService::DetachWindowRenderer() {
|
void ProductViewportHostService::DetachWindowRenderer() {
|
||||||
@@ -35,6 +41,7 @@ void ProductViewportHostService::Shutdown() {
|
|||||||
DestroyViewportEntry(entry);
|
DestroyViewportEntry(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_textureDescriptorAllocator.Shutdown();
|
||||||
m_windowRenderer = nullptr;
|
m_windowRenderer = nullptr;
|
||||||
m_device = nullptr;
|
m_device = nullptr;
|
||||||
m_surfacePresentationEnabled = false;
|
m_surfacePresentationEnabled = false;
|
||||||
@@ -113,7 +120,7 @@ const ProductViewportHostService::ViewportEntry& ProductViewportHostService::Get
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ProductViewportHostService::DestroyViewportEntry(ViewportEntry& entry) {
|
void ProductViewportHostService::DestroyViewportEntry(ViewportEntry& entry) {
|
||||||
DestroyProductViewportRenderTargets(m_windowRenderer, entry.renderTargets);
|
m_renderTargetManager.DestroyTargets(&m_textureDescriptorAllocator, entry.renderTargets);
|
||||||
entry = {};
|
entry = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,12 +142,12 @@ bool ProductViewportHostService::EnsureViewportResources(ViewportEntry& entry) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateProductViewportRenderTargets(
|
return m_renderTargetManager.EnsureTargets(
|
||||||
entry.kind,
|
entry.kind,
|
||||||
entry.requestedWidth,
|
entry.requestedWidth,
|
||||||
entry.requestedHeight,
|
entry.requestedHeight,
|
||||||
m_device,
|
*m_device,
|
||||||
*m_windowRenderer,
|
m_textureDescriptorAllocator,
|
||||||
entry.renderTargets);
|
entry.renderTargets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "ProductViewportRenderTargets.h"
|
#include "ProductViewportRenderTargets.h"
|
||||||
|
|
||||||
#include <Host/D3D12WindowRenderer.h>
|
#include <Host/D3D12WindowRenderer.h>
|
||||||
|
#include <Host/D3D12ShaderResourceDescriptorAllocator.h>
|
||||||
|
|
||||||
#include <XCEngine/Rendering/RenderContext.h>
|
#include <XCEngine/Rendering/RenderContext.h>
|
||||||
#include <XCEngine/UI/Types.h>
|
#include <XCEngine/UI/Types.h>
|
||||||
@@ -57,6 +58,8 @@ private:
|
|||||||
|
|
||||||
Host::D3D12WindowRenderer* m_windowRenderer = nullptr;
|
Host::D3D12WindowRenderer* m_windowRenderer = nullptr;
|
||||||
::XCEngine::RHI::RHIDevice* m_device = nullptr;
|
::XCEngine::RHI::RHIDevice* m_device = nullptr;
|
||||||
|
Host::D3D12ShaderResourceDescriptorAllocator m_textureDescriptorAllocator = {};
|
||||||
|
ProductViewportRenderTargetManager m_renderTargetManager = {};
|
||||||
bool m_surfacePresentationEnabled = false;
|
bool m_surfacePresentationEnabled = false;
|
||||||
std::array<ViewportEntry, 2> m_entries = {};
|
std::array<ViewportEntry, 2> m_entries = {};
|
||||||
};
|
};
|
||||||
|
|||||||
267
new_editor/app/Viewport/ProductViewportRenderTargetManager.cpp
Normal file
267
new_editor/app/Viewport/ProductViewportRenderTargetManager.cpp
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
#include "ProductViewportRenderTargets.h"
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor::App {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <typename ResourceType>
|
||||||
|
void ShutdownAndDeleteViewportResource(ResourceType*& resource) {
|
||||||
|
if (resource == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resource->Shutdown();
|
||||||
|
delete resource;
|
||||||
|
resource = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateViewportColorResources(
|
||||||
|
::XCEngine::RHI::RHIDevice& device,
|
||||||
|
ProductViewportRenderTargets& targets) {
|
||||||
|
const auto colorDesc =
|
||||||
|
BuildProductViewportTextureDesc(targets.width, targets.height, ::XCEngine::RHI::Format::R8G8B8A8_UNorm);
|
||||||
|
targets.colorTexture = device.CreateTexture(colorDesc);
|
||||||
|
if (targets.colorTexture == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto colorViewDesc =
|
||||||
|
BuildProductViewportTextureViewDesc(::XCEngine::RHI::Format::R8G8B8A8_UNorm);
|
||||||
|
targets.colorView = device.CreateRenderTargetView(targets.colorTexture, colorViewDesc);
|
||||||
|
return targets.colorView != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateViewportDepthResources(
|
||||||
|
::XCEngine::RHI::RHIDevice& device,
|
||||||
|
ProductViewportRenderTargets& targets) {
|
||||||
|
const auto depthDesc =
|
||||||
|
BuildProductViewportTextureDesc(targets.width, targets.height, ::XCEngine::RHI::Format::D24_UNorm_S8_UInt);
|
||||||
|
targets.depthTexture = device.CreateTexture(depthDesc);
|
||||||
|
if (targets.depthTexture == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto depthViewDesc =
|
||||||
|
BuildProductViewportTextureViewDesc(::XCEngine::RHI::Format::D24_UNorm_S8_UInt);
|
||||||
|
targets.depthView = device.CreateDepthStencilView(targets.depthTexture, depthViewDesc);
|
||||||
|
if (targets.depthView == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
::XCEngine::RHI::ResourceViewDesc depthShaderViewDesc = {};
|
||||||
|
depthShaderViewDesc.dimension = ::XCEngine::RHI::ResourceViewDimension::Texture2D;
|
||||||
|
depthShaderViewDesc.mipLevel = 0;
|
||||||
|
targets.depthShaderView = device.CreateShaderResourceView(
|
||||||
|
targets.depthTexture,
|
||||||
|
depthShaderViewDesc);
|
||||||
|
return targets.depthShaderView != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateViewportObjectIdResources(
|
||||||
|
::XCEngine::RHI::RHIDevice& device,
|
||||||
|
ProductViewportRenderTargets& targets) {
|
||||||
|
const auto objectIdDesc =
|
||||||
|
BuildProductViewportTextureDesc(targets.width, targets.height, ::XCEngine::RHI::Format::R8G8B8A8_UNorm);
|
||||||
|
targets.objectIdTexture = device.CreateTexture(objectIdDesc);
|
||||||
|
if (targets.objectIdTexture == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto objectIdViewDesc =
|
||||||
|
BuildProductViewportTextureViewDesc(::XCEngine::RHI::Format::R8G8B8A8_UNorm);
|
||||||
|
targets.objectIdView = device.CreateRenderTargetView(targets.objectIdTexture, objectIdViewDesc);
|
||||||
|
if (targets.objectIdView == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
targets.objectIdShaderView = device.CreateShaderResourceView(
|
||||||
|
targets.objectIdTexture,
|
||||||
|
objectIdViewDesc);
|
||||||
|
if (targets.objectIdShaderView == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto objectIdDepthDesc =
|
||||||
|
BuildProductViewportTextureDesc(targets.width, targets.height, ::XCEngine::RHI::Format::D24_UNorm_S8_UInt);
|
||||||
|
targets.objectIdDepthTexture = device.CreateTexture(objectIdDepthDesc);
|
||||||
|
if (targets.objectIdDepthTexture == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto objectIdDepthViewDesc =
|
||||||
|
BuildProductViewportTextureViewDesc(::XCEngine::RHI::Format::D24_UNorm_S8_UInt);
|
||||||
|
targets.objectIdDepthView = device.CreateDepthStencilView(
|
||||||
|
targets.objectIdDepthTexture,
|
||||||
|
objectIdDepthViewDesc);
|
||||||
|
return targets.objectIdDepthView != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateViewportSelectionMaskResources(
|
||||||
|
::XCEngine::RHI::RHIDevice& device,
|
||||||
|
ProductViewportRenderTargets& targets) {
|
||||||
|
const auto selectionMaskDesc =
|
||||||
|
BuildProductViewportTextureDesc(targets.width, targets.height, ::XCEngine::RHI::Format::R8G8B8A8_UNorm);
|
||||||
|
targets.selectionMaskTexture = device.CreateTexture(selectionMaskDesc);
|
||||||
|
if (targets.selectionMaskTexture == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto selectionMaskViewDesc =
|
||||||
|
BuildProductViewportTextureViewDesc(::XCEngine::RHI::Format::R8G8B8A8_UNorm);
|
||||||
|
targets.selectionMaskView = device.CreateRenderTargetView(
|
||||||
|
targets.selectionMaskTexture,
|
||||||
|
selectionMaskViewDesc);
|
||||||
|
if (targets.selectionMaskView == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
targets.selectionMaskShaderView = device.CreateShaderResourceView(
|
||||||
|
targets.selectionMaskTexture,
|
||||||
|
selectionMaskViewDesc);
|
||||||
|
return targets.selectionMaskShaderView != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateViewportTextureDescriptor(
|
||||||
|
Host::D3D12ShaderResourceDescriptorAllocator& textureDescriptorAllocator,
|
||||||
|
ProductViewportRenderTargets& targets) {
|
||||||
|
if (!textureDescriptorAllocator.CreateTextureDescriptor(
|
||||||
|
targets.colorTexture,
|
||||||
|
&targets.srvCpuHandle,
|
||||||
|
&targets.srvGpuHandle)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
targets.textureHandle.nativeHandle = static_cast<std::uintptr_t>(targets.srvGpuHandle.ptr);
|
||||||
|
targets.textureHandle.width = targets.width;
|
||||||
|
targets.textureHandle.height = targets.height;
|
||||||
|
targets.textureHandle.kind = ::XCEngine::UI::UITextureHandleKind::ShaderResourceView;
|
||||||
|
targets.textureHandle.resourceHandle =
|
||||||
|
reinterpret_cast<std::uintptr_t>(targets.colorTexture);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
ProductViewportResourceReuseQuery BuildProductViewportRenderTargetsReuseQuery(
|
||||||
|
ProductViewportKind kind,
|
||||||
|
const ProductViewportRenderTargets& targets,
|
||||||
|
std::uint32_t requestedWidth,
|
||||||
|
std::uint32_t requestedHeight) {
|
||||||
|
ProductViewportResourceReuseQuery query = {};
|
||||||
|
query.kind = kind;
|
||||||
|
query.width = targets.width;
|
||||||
|
query.height = targets.height;
|
||||||
|
query.requestedWidth = requestedWidth;
|
||||||
|
query.requestedHeight = requestedHeight;
|
||||||
|
query.resources.hasColorTexture = targets.colorTexture != nullptr;
|
||||||
|
query.resources.hasColorView = targets.colorView != nullptr;
|
||||||
|
query.resources.hasDepthTexture = targets.depthTexture != nullptr;
|
||||||
|
query.resources.hasDepthView = targets.depthView != nullptr;
|
||||||
|
query.resources.hasDepthShaderView = targets.depthShaderView != nullptr;
|
||||||
|
query.resources.hasObjectIdTexture = targets.objectIdTexture != nullptr;
|
||||||
|
query.resources.hasObjectIdDepthTexture = targets.objectIdDepthTexture != nullptr;
|
||||||
|
query.resources.hasObjectIdDepthView = targets.objectIdDepthView != nullptr;
|
||||||
|
query.resources.hasObjectIdView = targets.objectIdView != nullptr;
|
||||||
|
query.resources.hasObjectIdShaderView = targets.objectIdShaderView != nullptr;
|
||||||
|
query.resources.hasSelectionMaskTexture = targets.selectionMaskTexture != nullptr;
|
||||||
|
query.resources.hasSelectionMaskView = targets.selectionMaskView != nullptr;
|
||||||
|
query.resources.hasSelectionMaskShaderView = targets.selectionMaskShaderView != nullptr;
|
||||||
|
query.resources.hasTextureDescriptor = targets.textureHandle.IsValid();
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
::XCEngine::Rendering::RenderSurface BuildProductViewportColorSurface(
|
||||||
|
const ProductViewportRenderTargets& targets) {
|
||||||
|
return BuildProductViewportRenderSurface(
|
||||||
|
targets.width,
|
||||||
|
targets.height,
|
||||||
|
targets.colorView,
|
||||||
|
targets.depthView,
|
||||||
|
targets.colorState);
|
||||||
|
}
|
||||||
|
|
||||||
|
::XCEngine::Rendering::RenderSurface BuildProductViewportObjectIdSurface(
|
||||||
|
const ProductViewportRenderTargets& targets) {
|
||||||
|
return BuildProductViewportRenderSurface(
|
||||||
|
targets.width,
|
||||||
|
targets.height,
|
||||||
|
targets.objectIdView,
|
||||||
|
targets.objectIdDepthView,
|
||||||
|
targets.objectIdState);
|
||||||
|
}
|
||||||
|
|
||||||
|
::XCEngine::Rendering::RenderSurface BuildProductViewportSelectionMaskSurface(
|
||||||
|
const ProductViewportRenderTargets& targets) {
|
||||||
|
return BuildProductViewportRenderSurface(
|
||||||
|
targets.width,
|
||||||
|
targets.height,
|
||||||
|
targets.selectionMaskView,
|
||||||
|
targets.depthView,
|
||||||
|
targets.selectionMaskState);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProductViewportRenderTargetManager::EnsureTargets(
|
||||||
|
ProductViewportKind kind,
|
||||||
|
std::uint32_t width,
|
||||||
|
std::uint32_t height,
|
||||||
|
::XCEngine::RHI::RHIDevice& device,
|
||||||
|
Host::D3D12ShaderResourceDescriptorAllocator& textureDescriptorAllocator,
|
||||||
|
ProductViewportRenderTargets& targets) const {
|
||||||
|
if (width == 0u || height == 0u) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DestroyTargets(&textureDescriptorAllocator, targets);
|
||||||
|
targets.width = width;
|
||||||
|
targets.height = height;
|
||||||
|
|
||||||
|
if (!CreateViewportColorResources(device, targets) ||
|
||||||
|
!CreateViewportDepthResources(device, targets) ||
|
||||||
|
(ProductViewportRequiresObjectIdResources(kind) &&
|
||||||
|
(!CreateViewportObjectIdResources(device, targets) ||
|
||||||
|
!CreateViewportSelectionMaskResources(device, targets))) ||
|
||||||
|
!CreateViewportTextureDescriptor(textureDescriptorAllocator, targets)) {
|
||||||
|
DestroyTargets(&textureDescriptorAllocator, targets);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
targets.colorState = ::XCEngine::RHI::ResourceStates::Common;
|
||||||
|
targets.objectIdState = ::XCEngine::RHI::ResourceStates::Common;
|
||||||
|
targets.selectionMaskState = ::XCEngine::RHI::ResourceStates::Common;
|
||||||
|
targets.hasValidObjectIdFrame = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProductViewportRenderTargetManager::DestroyTargets(
|
||||||
|
Host::D3D12ShaderResourceDescriptorAllocator* textureDescriptorAllocator,
|
||||||
|
ProductViewportRenderTargets& targets) const {
|
||||||
|
if (textureDescriptorAllocator != nullptr && targets.srvCpuHandle.ptr != 0) {
|
||||||
|
textureDescriptorAllocator->Free(targets.srvCpuHandle, targets.srvGpuHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShutdownAndDeleteViewportResource(targets.objectIdView);
|
||||||
|
ShutdownAndDeleteViewportResource(targets.objectIdShaderView);
|
||||||
|
ShutdownAndDeleteViewportResource(targets.objectIdDepthView);
|
||||||
|
ShutdownAndDeleteViewportResource(targets.objectIdDepthTexture);
|
||||||
|
ShutdownAndDeleteViewportResource(targets.objectIdTexture);
|
||||||
|
ShutdownAndDeleteViewportResource(targets.selectionMaskView);
|
||||||
|
ShutdownAndDeleteViewportResource(targets.selectionMaskShaderView);
|
||||||
|
ShutdownAndDeleteViewportResource(targets.selectionMaskTexture);
|
||||||
|
ShutdownAndDeleteViewportResource(targets.depthShaderView);
|
||||||
|
ShutdownAndDeleteViewportResource(targets.depthView);
|
||||||
|
ShutdownAndDeleteViewportResource(targets.depthTexture);
|
||||||
|
ShutdownAndDeleteViewportResource(targets.colorView);
|
||||||
|
ShutdownAndDeleteViewportResource(targets.colorTexture);
|
||||||
|
|
||||||
|
targets.width = 0;
|
||||||
|
targets.height = 0;
|
||||||
|
targets.srvCpuHandle = {};
|
||||||
|
targets.srvGpuHandle = {};
|
||||||
|
targets.textureHandle = {};
|
||||||
|
targets.colorState = ::XCEngine::RHI::ResourceStates::Common;
|
||||||
|
targets.objectIdState = ::XCEngine::RHI::ResourceStates::Common;
|
||||||
|
targets.selectionMaskState = ::XCEngine::RHI::ResourceStates::Common;
|
||||||
|
targets.hasValidObjectIdFrame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor::App
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "ProductViewportSurfaceUtils.h"
|
#include "ProductViewportSurfaceUtils.h"
|
||||||
|
|
||||||
#include <Host/D3D12WindowRenderer.h>
|
#include <Host/D3D12ShaderResourceDescriptorAllocator.h>
|
||||||
|
|
||||||
#include <XCEngine/RHI/RHIDevice.h>
|
#include <XCEngine/RHI/RHIDevice.h>
|
||||||
#include <XCEngine/RHI/RHIResourceView.h>
|
#include <XCEngine/RHI/RHIResourceView.h>
|
||||||
@@ -36,268 +36,31 @@ struct ProductViewportRenderTargets {
|
|||||||
bool hasValidObjectIdFrame = false;
|
bool hasValidObjectIdFrame = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline ProductViewportResourceReuseQuery BuildProductViewportRenderTargetsReuseQuery(
|
ProductViewportResourceReuseQuery BuildProductViewportRenderTargetsReuseQuery(
|
||||||
ProductViewportKind kind,
|
ProductViewportKind kind,
|
||||||
const ProductViewportRenderTargets& targets,
|
const ProductViewportRenderTargets& targets,
|
||||||
std::uint32_t requestedWidth,
|
std::uint32_t requestedWidth,
|
||||||
std::uint32_t requestedHeight) {
|
std::uint32_t requestedHeight);
|
||||||
ProductViewportResourceReuseQuery query = {};
|
|
||||||
query.kind = kind;
|
|
||||||
query.width = targets.width;
|
|
||||||
query.height = targets.height;
|
|
||||||
query.requestedWidth = requestedWidth;
|
|
||||||
query.requestedHeight = requestedHeight;
|
|
||||||
query.resources.hasColorTexture = targets.colorTexture != nullptr;
|
|
||||||
query.resources.hasColorView = targets.colorView != nullptr;
|
|
||||||
query.resources.hasDepthTexture = targets.depthTexture != nullptr;
|
|
||||||
query.resources.hasDepthView = targets.depthView != nullptr;
|
|
||||||
query.resources.hasDepthShaderView = targets.depthShaderView != nullptr;
|
|
||||||
query.resources.hasObjectIdTexture = targets.objectIdTexture != nullptr;
|
|
||||||
query.resources.hasObjectIdDepthTexture = targets.objectIdDepthTexture != nullptr;
|
|
||||||
query.resources.hasObjectIdDepthView = targets.objectIdDepthView != nullptr;
|
|
||||||
query.resources.hasObjectIdView = targets.objectIdView != nullptr;
|
|
||||||
query.resources.hasObjectIdShaderView = targets.objectIdShaderView != nullptr;
|
|
||||||
query.resources.hasSelectionMaskTexture = targets.selectionMaskTexture != nullptr;
|
|
||||||
query.resources.hasSelectionMaskView = targets.selectionMaskView != nullptr;
|
|
||||||
query.resources.hasSelectionMaskShaderView = targets.selectionMaskShaderView != nullptr;
|
|
||||||
query.resources.hasTextureDescriptor = targets.textureHandle.IsValid();
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ::XCEngine::Rendering::RenderSurface BuildProductViewportColorSurface(
|
::XCEngine::Rendering::RenderSurface BuildProductViewportColorSurface(
|
||||||
const ProductViewportRenderTargets& targets) {
|
const ProductViewportRenderTargets& targets);
|
||||||
return BuildProductViewportRenderSurface(
|
::XCEngine::Rendering::RenderSurface BuildProductViewportObjectIdSurface(
|
||||||
targets.width,
|
const ProductViewportRenderTargets& targets);
|
||||||
targets.height,
|
::XCEngine::Rendering::RenderSurface BuildProductViewportSelectionMaskSurface(
|
||||||
targets.colorView,
|
const ProductViewportRenderTargets& targets);
|
||||||
targets.depthView,
|
|
||||||
targets.colorState);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ::XCEngine::Rendering::RenderSurface BuildProductViewportObjectIdSurface(
|
class ProductViewportRenderTargetManager {
|
||||||
const ProductViewportRenderTargets& targets) {
|
public:
|
||||||
return BuildProductViewportRenderSurface(
|
bool EnsureTargets(
|
||||||
targets.width,
|
ProductViewportKind kind,
|
||||||
targets.height,
|
std::uint32_t width,
|
||||||
targets.objectIdView,
|
std::uint32_t height,
|
||||||
targets.objectIdDepthView,
|
::XCEngine::RHI::RHIDevice& device,
|
||||||
targets.objectIdState);
|
Host::D3D12ShaderResourceDescriptorAllocator& textureDescriptorAllocator,
|
||||||
}
|
ProductViewportRenderTargets& targets) const;
|
||||||
|
void DestroyTargets(
|
||||||
inline ::XCEngine::Rendering::RenderSurface BuildProductViewportSelectionMaskSurface(
|
Host::D3D12ShaderResourceDescriptorAllocator* textureDescriptorAllocator,
|
||||||
const ProductViewportRenderTargets& targets) {
|
ProductViewportRenderTargets& targets) const;
|
||||||
return BuildProductViewportRenderSurface(
|
};
|
||||||
targets.width,
|
|
||||||
targets.height,
|
|
||||||
targets.selectionMaskView,
|
|
||||||
targets.depthView,
|
|
||||||
targets.selectionMaskState);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
template <typename ResourceType>
|
|
||||||
inline void ShutdownAndDeleteViewportResource(ResourceType*& resource) {
|
|
||||||
if (resource == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
resource->Shutdown();
|
|
||||||
delete resource;
|
|
||||||
resource = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool CreateViewportColorResources(
|
|
||||||
::XCEngine::RHI::RHIDevice* device,
|
|
||||||
ProductViewportRenderTargets& targets) {
|
|
||||||
const auto colorDesc =
|
|
||||||
BuildProductViewportTextureDesc(targets.width, targets.height, ::XCEngine::RHI::Format::R8G8B8A8_UNorm);
|
|
||||||
targets.colorTexture = device->CreateTexture(colorDesc);
|
|
||||||
if (targets.colorTexture == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto colorViewDesc =
|
|
||||||
BuildProductViewportTextureViewDesc(::XCEngine::RHI::Format::R8G8B8A8_UNorm);
|
|
||||||
targets.colorView = device->CreateRenderTargetView(targets.colorTexture, colorViewDesc);
|
|
||||||
return targets.colorView != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool CreateViewportDepthResources(
|
|
||||||
::XCEngine::RHI::RHIDevice* device,
|
|
||||||
ProductViewportRenderTargets& targets) {
|
|
||||||
const auto depthDesc =
|
|
||||||
BuildProductViewportTextureDesc(targets.width, targets.height, ::XCEngine::RHI::Format::D24_UNorm_S8_UInt);
|
|
||||||
targets.depthTexture = device->CreateTexture(depthDesc);
|
|
||||||
if (targets.depthTexture == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto depthViewDesc =
|
|
||||||
BuildProductViewportTextureViewDesc(::XCEngine::RHI::Format::D24_UNorm_S8_UInt);
|
|
||||||
targets.depthView = device->CreateDepthStencilView(targets.depthTexture, depthViewDesc);
|
|
||||||
if (targets.depthView == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
::XCEngine::RHI::ResourceViewDesc depthShaderViewDesc = {};
|
|
||||||
depthShaderViewDesc.dimension = ::XCEngine::RHI::ResourceViewDimension::Texture2D;
|
|
||||||
depthShaderViewDesc.mipLevel = 0;
|
|
||||||
targets.depthShaderView = device->CreateShaderResourceView(
|
|
||||||
targets.depthTexture,
|
|
||||||
depthShaderViewDesc);
|
|
||||||
return targets.depthShaderView != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool CreateViewportObjectIdResources(
|
|
||||||
::XCEngine::RHI::RHIDevice* device,
|
|
||||||
ProductViewportRenderTargets& targets) {
|
|
||||||
const auto objectIdDesc =
|
|
||||||
BuildProductViewportTextureDesc(targets.width, targets.height, ::XCEngine::RHI::Format::R8G8B8A8_UNorm);
|
|
||||||
targets.objectIdTexture = device->CreateTexture(objectIdDesc);
|
|
||||||
if (targets.objectIdTexture == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto objectIdViewDesc =
|
|
||||||
BuildProductViewportTextureViewDesc(::XCEngine::RHI::Format::R8G8B8A8_UNorm);
|
|
||||||
targets.objectIdView = device->CreateRenderTargetView(targets.objectIdTexture, objectIdViewDesc);
|
|
||||||
if (targets.objectIdView == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
targets.objectIdShaderView = device->CreateShaderResourceView(
|
|
||||||
targets.objectIdTexture,
|
|
||||||
objectIdViewDesc);
|
|
||||||
if (targets.objectIdShaderView == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto objectIdDepthDesc =
|
|
||||||
BuildProductViewportTextureDesc(targets.width, targets.height, ::XCEngine::RHI::Format::D24_UNorm_S8_UInt);
|
|
||||||
targets.objectIdDepthTexture = device->CreateTexture(objectIdDepthDesc);
|
|
||||||
if (targets.objectIdDepthTexture == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto objectIdDepthViewDesc =
|
|
||||||
BuildProductViewportTextureViewDesc(::XCEngine::RHI::Format::D24_UNorm_S8_UInt);
|
|
||||||
targets.objectIdDepthView = device->CreateDepthStencilView(
|
|
||||||
targets.objectIdDepthTexture,
|
|
||||||
objectIdDepthViewDesc);
|
|
||||||
return targets.objectIdDepthView != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool CreateViewportSelectionMaskResources(
|
|
||||||
::XCEngine::RHI::RHIDevice* device,
|
|
||||||
ProductViewportRenderTargets& targets) {
|
|
||||||
const auto selectionMaskDesc =
|
|
||||||
BuildProductViewportTextureDesc(targets.width, targets.height, ::XCEngine::RHI::Format::R8G8B8A8_UNorm);
|
|
||||||
targets.selectionMaskTexture = device->CreateTexture(selectionMaskDesc);
|
|
||||||
if (targets.selectionMaskTexture == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto selectionMaskViewDesc =
|
|
||||||
BuildProductViewportTextureViewDesc(::XCEngine::RHI::Format::R8G8B8A8_UNorm);
|
|
||||||
targets.selectionMaskView = device->CreateRenderTargetView(
|
|
||||||
targets.selectionMaskTexture,
|
|
||||||
selectionMaskViewDesc);
|
|
||||||
if (targets.selectionMaskView == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
targets.selectionMaskShaderView = device->CreateShaderResourceView(
|
|
||||||
targets.selectionMaskTexture,
|
|
||||||
selectionMaskViewDesc);
|
|
||||||
return targets.selectionMaskShaderView != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool CreateViewportTextureDescriptor(
|
|
||||||
Host::D3D12WindowRenderer& windowRenderer,
|
|
||||||
::XCEngine::RHI::RHIDevice* device,
|
|
||||||
ProductViewportRenderTargets& targets) {
|
|
||||||
if (!windowRenderer.CreateShaderResourceTextureDescriptor(
|
|
||||||
device,
|
|
||||||
targets.colorTexture,
|
|
||||||
&targets.srvCpuHandle,
|
|
||||||
&targets.srvGpuHandle)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
targets.textureHandle.nativeHandle = static_cast<std::uintptr_t>(targets.srvGpuHandle.ptr);
|
|
||||||
targets.textureHandle.width = targets.width;
|
|
||||||
targets.textureHandle.height = targets.height;
|
|
||||||
targets.textureHandle.kind = ::XCEngine::UI::UITextureHandleKind::ShaderResourceView;
|
|
||||||
targets.textureHandle.resourceHandle =
|
|
||||||
reinterpret_cast<std::uintptr_t>(targets.colorTexture);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Internal
|
|
||||||
|
|
||||||
inline void DestroyProductViewportRenderTargets(
|
|
||||||
Host::D3D12WindowRenderer* windowRenderer,
|
|
||||||
ProductViewportRenderTargets& targets) {
|
|
||||||
if (windowRenderer != nullptr && targets.srvCpuHandle.ptr != 0) {
|
|
||||||
windowRenderer->FreeShaderResourceDescriptor(targets.srvCpuHandle, targets.srvGpuHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
Internal::ShutdownAndDeleteViewportResource(targets.objectIdView);
|
|
||||||
Internal::ShutdownAndDeleteViewportResource(targets.objectIdShaderView);
|
|
||||||
Internal::ShutdownAndDeleteViewportResource(targets.objectIdDepthView);
|
|
||||||
Internal::ShutdownAndDeleteViewportResource(targets.objectIdDepthTexture);
|
|
||||||
Internal::ShutdownAndDeleteViewportResource(targets.objectIdTexture);
|
|
||||||
Internal::ShutdownAndDeleteViewportResource(targets.selectionMaskView);
|
|
||||||
Internal::ShutdownAndDeleteViewportResource(targets.selectionMaskShaderView);
|
|
||||||
Internal::ShutdownAndDeleteViewportResource(targets.selectionMaskTexture);
|
|
||||||
Internal::ShutdownAndDeleteViewportResource(targets.depthShaderView);
|
|
||||||
Internal::ShutdownAndDeleteViewportResource(targets.depthView);
|
|
||||||
Internal::ShutdownAndDeleteViewportResource(targets.depthTexture);
|
|
||||||
Internal::ShutdownAndDeleteViewportResource(targets.colorView);
|
|
||||||
Internal::ShutdownAndDeleteViewportResource(targets.colorTexture);
|
|
||||||
|
|
||||||
targets.width = 0;
|
|
||||||
targets.height = 0;
|
|
||||||
targets.srvCpuHandle = {};
|
|
||||||
targets.srvGpuHandle = {};
|
|
||||||
targets.textureHandle = {};
|
|
||||||
targets.colorState = ::XCEngine::RHI::ResourceStates::Common;
|
|
||||||
targets.objectIdState = ::XCEngine::RHI::ResourceStates::Common;
|
|
||||||
targets.selectionMaskState = ::XCEngine::RHI::ResourceStates::Common;
|
|
||||||
targets.hasValidObjectIdFrame = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool CreateProductViewportRenderTargets(
|
|
||||||
ProductViewportKind kind,
|
|
||||||
std::uint32_t width,
|
|
||||||
std::uint32_t height,
|
|
||||||
::XCEngine::RHI::RHIDevice* device,
|
|
||||||
Host::D3D12WindowRenderer& windowRenderer,
|
|
||||||
ProductViewportRenderTargets& targets) {
|
|
||||||
if (width == 0u || height == 0u || device == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DestroyProductViewportRenderTargets(&windowRenderer, targets);
|
|
||||||
targets.width = width;
|
|
||||||
targets.height = height;
|
|
||||||
|
|
||||||
if (!Internal::CreateViewportColorResources(device, targets) ||
|
|
||||||
!Internal::CreateViewportDepthResources(device, targets) ||
|
|
||||||
(ProductViewportRequiresObjectIdResources(kind) &&
|
|
||||||
(!Internal::CreateViewportObjectIdResources(device, targets) ||
|
|
||||||
!Internal::CreateViewportSelectionMaskResources(device, targets))) ||
|
|
||||||
!Internal::CreateViewportTextureDescriptor(windowRenderer, device, targets)) {
|
|
||||||
DestroyProductViewportRenderTargets(&windowRenderer, targets);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
targets.colorState = ::XCEngine::RHI::ResourceStates::Common;
|
|
||||||
targets.objectIdState = ::XCEngine::RHI::ResourceStates::Common;
|
|
||||||
targets.selectionMaskState = ::XCEngine::RHI::ResourceStates::Common;
|
|
||||||
targets.hasValidObjectIdFrame = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace XCEngine::UI::Editor::App
|
} // namespace XCEngine::UI::Editor::App
|
||||||
|
|||||||
Reference in New Issue
Block a user