From 5b89c2bb76323fcd1917b3b1010669432550f798 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Mon, 13 Apr 2026 19:57:25 +0800 Subject: [PATCH] Separate viewport target and descriptor ownership --- .../plan/NewEditor_宿主重构计划_2026-04-13.md | 4 +- new_editor/CMakeLists.txt | 2 + ...D3D12ShaderResourceDescriptorAllocator.cpp | 169 +++++++++++ .../D3D12ShaderResourceDescriptorAllocator.h | 55 ++++ new_editor/app/Host/D3D12WindowRenderer.cpp | 145 +-------- new_editor/app/Host/D3D12WindowRenderer.h | 26 -- .../Viewport/ProductViewportHostService.cpp | 15 +- .../app/Viewport/ProductViewportHostService.h | 3 + .../ProductViewportRenderTargetManager.cpp | 267 +++++++++++++++++ .../Viewport/ProductViewportRenderTargets.h | 281 ++---------------- 10 files changed, 534 insertions(+), 433 deletions(-) create mode 100644 new_editor/app/Host/D3D12ShaderResourceDescriptorAllocator.cpp create mode 100644 new_editor/app/Host/D3D12ShaderResourceDescriptorAllocator.h create mode 100644 new_editor/app/Viewport/ProductViewportRenderTargetManager.cpp diff --git a/docs/plan/NewEditor_宿主重构计划_2026-04-13.md b/docs/plan/NewEditor_宿主重构计划_2026-04-13.md index 66ce9fc3..033efbdc 100644 --- a/docs/plan/NewEditor_宿主重构计划_2026-04-13.md +++ b/docs/plan/NewEditor_宿主重构计划_2026-04-13.md @@ -175,4 +175,6 @@ 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. 下一步进入阶段 2 主体:继续拆 `NativeRenderer` 中的窗口互操作 / present 组合路径,并把 viewport render target 生命周期从 `ProductViewportHostService` 中收出去。 +4. 已把 viewport render target 资源工厂从 `ProductViewportRenderTargets.h` 收成独立 manager,`ProductViewportHostService` 只保留请求/返回 frame 的业务外壳。 +5. 已把 shader resource descriptor 分配职责从 `D3D12WindowRenderer` 抽到独立的 `D3D12ShaderResourceDescriptorAllocator`,减少窗口呈现器的非 swapchain 职责。 +6. 下一步进入阶段 2 主体:继续拆 `NativeRenderer` 中的窗口互操作 / present 组合路径,把 D2D UI 光栅化与 D3D11On12 窗口合成进一步分离。 diff --git a/new_editor/CMakeLists.txt b/new_editor/CMakeLists.txt index 8deccc67..2f432116 100644 --- a/new_editor/CMakeLists.txt +++ b/new_editor/CMakeLists.txt @@ -124,6 +124,7 @@ target_link_libraries(XCUIEditorLib PUBLIC add_library(XCUIEditorHost STATIC app/Host/AutoScreenshot.cpp + app/Host/D3D12ShaderResourceDescriptorAllocator.cpp app/Host/D3D12WindowRenderer.cpp app/Host/D3D12WindowRenderLoop.cpp app/Host/NativeRenderer.cpp @@ -166,6 +167,7 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP) app/Project/ProductProjectBrowserModel.cpp app/Shell/ProductShellAsset.cpp app/Viewport/ProductViewportHostService.cpp + app/Viewport/ProductViewportRenderTargetManager.cpp app/Viewport/ProductViewportRenderTargets.cpp app/Workspace/ProductEditorWorkspace.cpp app/Workspace/ProductEditorWorkspaceEventRouter.cpp diff --git a/new_editor/app/Host/D3D12ShaderResourceDescriptorAllocator.cpp b/new_editor/app/Host/D3D12ShaderResourceDescriptorAllocator.cpp new file mode 100644 index 00000000..da797ed8 --- /dev/null +++ b/new_editor/app/Host/D3D12ShaderResourceDescriptorAllocator.cpp @@ -0,0 +1,169 @@ +#include "D3D12ShaderResourceDescriptorAllocator.h" + +#include + +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(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(m_device); + auto* nativeTexture = dynamic_cast(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(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(index) * m_descriptorSize; + outGpuHandle->ptr = + m_descriptorHeap->GetGPUDescriptorHandleForHeapStart().ptr + + static_cast(index) * m_descriptorSize; + return; + } +} + +} // namespace XCEngine::UI::Editor::Host diff --git a/new_editor/app/Host/D3D12ShaderResourceDescriptorAllocator.h b/new_editor/app/Host/D3D12ShaderResourceDescriptorAllocator.h new file mode 100644 index 00000000..e0bf9e83 --- /dev/null +++ b/new_editor/app/Host/D3D12ShaderResourceDescriptorAllocator.h @@ -0,0 +1,55 @@ +#pragma once + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +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 m_descriptorUsage = {}; + UINT m_descriptorSize = 0u; + UINT m_descriptorCount = 0u; +}; + +} // namespace XCEngine::UI::Editor::Host diff --git a/new_editor/app/Host/D3D12WindowRenderer.cpp b/new_editor/app/Host/D3D12WindowRenderer.cpp index 117e5f7d..a2b584e2 100644 --- a/new_editor/app/Host/D3D12WindowRenderer.cpp +++ b/new_editor/app/Host/D3D12WindowRenderer.cpp @@ -8,11 +8,8 @@ namespace XCEngine::UI::Editor::Host { using ::XCEngine::RHI::CommandListDesc; using ::XCEngine::RHI::CommandQueueDesc; -using ::XCEngine::RHI::DescriptorHeapType; -using ::XCEngine::RHI::DescriptorPoolDesc; using ::XCEngine::RHI::D3D12CommandList; using ::XCEngine::RHI::D3D12CommandQueue; -using ::XCEngine::RHI::D3D12DescriptorHeap; using ::XCEngine::RHI::D3D12Device; using ::XCEngine::RHI::D3D12SwapChain; using ::XCEngine::RHI::D3D12Texture; @@ -101,20 +98,6 @@ bool D3D12WindowRenderer::Initialize(HWND hwnd, int width, int height) { 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(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()) { m_lastError = "Failed to create swap chain back buffer views."; Shutdown(); @@ -137,14 +120,6 @@ void D3D12WindowRenderer::Shutdown() { ReleaseFrameCompletionFence(); ReleaseBackBufferViews(); - if (m_srvPool != nullptr) { - m_srvPool->Shutdown(); - delete m_srvPool; - m_srvPool = nullptr; - } - m_srvHeap = nullptr; - m_srvUsage.clear(); - if (m_swapChain != nullptr) { m_swapChain->Shutdown(); delete m_swapChain; @@ -175,7 +150,6 @@ void D3D12WindowRenderer::Shutdown() { m_width = 0; m_height = 0; m_activeBackBufferIndex = 0u; - m_srvDescriptorSize = 0; m_lastError.clear(); } @@ -250,8 +224,8 @@ bool D3D12WindowRenderer::Resize(int width, int height) { } bool D3D12WindowRenderer::BeginFrame() { - if (m_swapChain == nullptr || m_srvHeap == nullptr) { - m_lastError = "BeginFrame requires a swap chain, command list, and SRV heap."; + if (m_swapChain == nullptr) { + m_lastError = "BeginFrame requires an initialized swap chain."; return false; } @@ -355,10 +329,6 @@ ID3D12Device* D3D12WindowRenderer::GetDevice() const { return device != nullptr ? device->GetDevice() : nullptr; } -ID3D12DescriptorHeap* D3D12WindowRenderer::GetSrvHeap() const { - return m_srvHeap != nullptr ? m_srvHeap->GetDescriptorHeap() : nullptr; -} - ID3D12CommandQueue* D3D12WindowRenderer::GetCommandQueue() const { const D3D12CommandQueue* queue = GetD3D12CommandQueue(); return queue != nullptr ? queue->GetCommandQueue() : nullptr; @@ -368,68 +338,6 @@ const std::string& D3D12WindowRenderer::GetLastError() const { 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(device); - auto* nativeTexture = dynamic_cast(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 { return m_device; } @@ -504,55 +412,6 @@ D3D12SwapChain* D3D12WindowRenderer::GetD3D12SwapChain() const { : 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(index) * m_srvDescriptorSize; - outGpuHandle->ptr = - m_srvHeap->GetGPUDescriptorHandleForHeapStart().ptr + - static_cast(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(offset / m_srvDescriptorSize); - if (index < m_srvUsage.size()) { - m_srvUsage[index] = false; - } -} - bool D3D12WindowRenderer::InitializeFrameCompletionFence() { ReleaseFrameCompletionFence(); diff --git a/new_editor/app/Host/D3D12WindowRenderer.h b/new_editor/app/Host/D3D12WindowRenderer.h index 666f4f81..2df79a3b 100644 --- a/new_editor/app/Host/D3D12WindowRenderer.h +++ b/new_editor/app/Host/D3D12WindowRenderer.h @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -32,7 +31,6 @@ namespace XCEngine::UI::Editor::Host { class D3D12WindowRenderer { public: - static constexpr UINT kSrvDescriptorCount = 64; static constexpr std::uint32_t kSwapChainBufferCount = 3; bool Initialize(HWND hwnd, int width, int height); @@ -45,22 +43,8 @@ public: bool PresentFrame(); ID3D12Device* GetDevice() const; - ID3D12DescriptorHeap* GetSrvHeap() const; ID3D12CommandQueue* GetCommandQueue() const; const std::string& GetLastError() const; - void AllocateShaderResourceDescriptor( - D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle, - D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle); - 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::RHISwapChain* GetSwapChain() const; const ::XCEngine::Rendering::RenderSurface* GetCurrentRenderSurface() const; @@ -75,12 +59,6 @@ private: ::XCEngine::RHI::D3D12CommandList* GetD3D12CommandList() const; ::XCEngine::RHI::D3D12SwapChain* GetD3D12SwapChain() const; ::XCEngine::RHI::RHICommandList* GetCurrentCommandList() const; - void AllocateShaderResourceDescriptorInternal( - D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle, - D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle); - void FreeShaderResourceDescriptorInternal( - D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, - D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle); bool InitializeFrameCompletionFence(); void ReleaseFrameCompletionFence(); void WaitForBackBufferFrame(std::uint32_t backBufferIndex); @@ -97,9 +75,6 @@ private: ::XCEngine::RHI::RHICommandQueue* m_commandQueue = nullptr; std::array<::XCEngine::RHI::RHICommandList*, kSwapChainBufferCount> m_commandLists = {}; ::XCEngine::RHI::RHISwapChain* m_swapChain = nullptr; - ::XCEngine::RHI::RHIDescriptorPool* m_srvPool = nullptr; - ::XCEngine::RHI::D3D12DescriptorHeap* m_srvHeap = nullptr; - std::vector m_srvUsage = {}; std::vector<::XCEngine::RHI::RHIResourceView*> m_backBufferViews = {}; std::vector<::XCEngine::Rendering::RenderSurface> m_backBufferSurfaces = {}; Microsoft::WRL::ComPtr m_frameCompletionFence = {}; @@ -108,7 +83,6 @@ private: std::uint32_t m_activeBackBufferIndex = 0u; std::uint64_t m_lastSubmittedFrameValue = 0; std::string m_lastError = {}; - UINT m_srvDescriptorSize = 0; }; } // namespace XCEngine::UI::Editor::Host diff --git a/new_editor/app/Viewport/ProductViewportHostService.cpp b/new_editor/app/Viewport/ProductViewportHostService.cpp index e9bd29ac..649aa1f6 100644 --- a/new_editor/app/Viewport/ProductViewportHostService.cpp +++ b/new_editor/app/Viewport/ProductViewportHostService.cpp @@ -14,12 +14,18 @@ void ProductViewportHostService::AttachWindowRenderer( Host::D3D12WindowRenderer& windowRenderer) { if (m_windowRenderer == &windowRenderer) { m_device = windowRenderer.GetRHIDevice(); + if (m_device != nullptr && !m_textureDescriptorAllocator.IsInitialized()) { + m_textureDescriptorAllocator.Initialize(*m_device); + } return; } Shutdown(); m_windowRenderer = &windowRenderer; m_device = windowRenderer.GetRHIDevice(); + if (m_device != nullptr) { + m_textureDescriptorAllocator.Initialize(*m_device); + } } void ProductViewportHostService::DetachWindowRenderer() { @@ -35,6 +41,7 @@ void ProductViewportHostService::Shutdown() { DestroyViewportEntry(entry); } + m_textureDescriptorAllocator.Shutdown(); m_windowRenderer = nullptr; m_device = nullptr; m_surfacePresentationEnabled = false; @@ -113,7 +120,7 @@ const ProductViewportHostService::ViewportEntry& ProductViewportHostService::Get } void ProductViewportHostService::DestroyViewportEntry(ViewportEntry& entry) { - DestroyProductViewportRenderTargets(m_windowRenderer, entry.renderTargets); + m_renderTargetManager.DestroyTargets(&m_textureDescriptorAllocator, entry.renderTargets); entry = {}; } @@ -135,12 +142,12 @@ bool ProductViewportHostService::EnsureViewportResources(ViewportEntry& entry) { return false; } - return CreateProductViewportRenderTargets( + return m_renderTargetManager.EnsureTargets( entry.kind, entry.requestedWidth, entry.requestedHeight, - m_device, - *m_windowRenderer, + *m_device, + m_textureDescriptorAllocator, entry.renderTargets); } diff --git a/new_editor/app/Viewport/ProductViewportHostService.h b/new_editor/app/Viewport/ProductViewportHostService.h index df090d15..7799c623 100644 --- a/new_editor/app/Viewport/ProductViewportHostService.h +++ b/new_editor/app/Viewport/ProductViewportHostService.h @@ -3,6 +3,7 @@ #include "ProductViewportRenderTargets.h" #include +#include #include #include @@ -57,6 +58,8 @@ private: Host::D3D12WindowRenderer* m_windowRenderer = nullptr; ::XCEngine::RHI::RHIDevice* m_device = nullptr; + Host::D3D12ShaderResourceDescriptorAllocator m_textureDescriptorAllocator = {}; + ProductViewportRenderTargetManager m_renderTargetManager = {}; bool m_surfacePresentationEnabled = false; std::array m_entries = {}; }; diff --git a/new_editor/app/Viewport/ProductViewportRenderTargetManager.cpp b/new_editor/app/Viewport/ProductViewportRenderTargetManager.cpp new file mode 100644 index 00000000..95a788d8 --- /dev/null +++ b/new_editor/app/Viewport/ProductViewportRenderTargetManager.cpp @@ -0,0 +1,267 @@ +#include "ProductViewportRenderTargets.h" + +namespace XCEngine::UI::Editor::App { + +namespace { + +template +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(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(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 diff --git a/new_editor/app/Viewport/ProductViewportRenderTargets.h b/new_editor/app/Viewport/ProductViewportRenderTargets.h index 9fc557e6..513cfbda 100644 --- a/new_editor/app/Viewport/ProductViewportRenderTargets.h +++ b/new_editor/app/Viewport/ProductViewportRenderTargets.h @@ -2,7 +2,7 @@ #include "ProductViewportSurfaceUtils.h" -#include +#include #include #include @@ -36,268 +36,31 @@ struct ProductViewportRenderTargets { bool hasValidObjectIdFrame = false; }; -inline ProductViewportResourceReuseQuery BuildProductViewportRenderTargetsReuseQuery( +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; -} + std::uint32_t requestedHeight); -inline ::XCEngine::Rendering::RenderSurface BuildProductViewportColorSurface( - const ProductViewportRenderTargets& targets) { - return BuildProductViewportRenderSurface( - targets.width, - targets.height, - targets.colorView, - targets.depthView, - targets.colorState); -} +::XCEngine::Rendering::RenderSurface BuildProductViewportColorSurface( + const ProductViewportRenderTargets& targets); +::XCEngine::Rendering::RenderSurface BuildProductViewportObjectIdSurface( + const ProductViewportRenderTargets& targets); +::XCEngine::Rendering::RenderSurface BuildProductViewportSelectionMaskSurface( + const ProductViewportRenderTargets& targets); -inline ::XCEngine::Rendering::RenderSurface BuildProductViewportObjectIdSurface( - const ProductViewportRenderTargets& targets) { - return BuildProductViewportRenderSurface( - targets.width, - targets.height, - targets.objectIdView, - targets.objectIdDepthView, - targets.objectIdState); -} - -inline ::XCEngine::Rendering::RenderSurface BuildProductViewportSelectionMaskSurface( - const ProductViewportRenderTargets& targets) { - return BuildProductViewportRenderSurface( - targets.width, - targets.height, - targets.selectionMaskView, - targets.depthView, - targets.selectionMaskState); -} - -namespace Internal { - -template -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(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(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; -} +class ProductViewportRenderTargetManager { +public: + bool EnsureTargets( + ProductViewportKind kind, + std::uint32_t width, + std::uint32_t height, + ::XCEngine::RHI::RHIDevice& device, + Host::D3D12ShaderResourceDescriptorAllocator& textureDescriptorAllocator, + ProductViewportRenderTargets& targets) const; + void DestroyTargets( + Host::D3D12ShaderResourceDescriptorAllocator* textureDescriptorAllocator, + ProductViewportRenderTargets& targets) const; +}; } // namespace XCEngine::UI::Editor::App