#pragma once #include "ViewportHostSurfaceUtils.h" #include "UI/ImGuiBackendBridge.h" #include #include #include #include namespace XCEngine { namespace Editor { struct ViewportRenderTargets { uint32_t width = 0; uint32_t height = 0; RHI::RHITexture* colorTexture = nullptr; RHI::RHIResourceView* colorView = nullptr; RHI::RHITexture* depthTexture = nullptr; RHI::RHIResourceView* depthView = nullptr; RHI::RHITexture* objectIdTexture = nullptr; RHI::RHIResourceView* objectIdView = nullptr; RHI::RHIResourceView* objectIdShaderView = nullptr; D3D12_CPU_DESCRIPTOR_HANDLE imguiCpuHandle = {}; D3D12_GPU_DESCRIPTOR_HANDLE imguiGpuHandle = {}; ::XCEngine::UI::UITextureHandle textureHandle = {}; RHI::ResourceStates colorState = RHI::ResourceStates::Common; RHI::ResourceStates objectIdState = RHI::ResourceStates::Common; bool hasValidObjectIdFrame = false; }; inline ViewportHostResourceReuseQuery BuildViewportRenderTargetsReuseQuery( EditorViewportKind kind, const ViewportRenderTargets& targets, uint32_t requestedWidth, uint32_t requestedHeight) { ViewportHostResourceReuseQuery 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.hasObjectIdTexture = targets.objectIdTexture != nullptr; query.resources.hasObjectIdView = targets.objectIdView != nullptr; query.resources.hasObjectIdShaderView = targets.objectIdShaderView != nullptr; query.resources.hasTextureDescriptor = targets.textureHandle.IsValid(); return query; } inline Rendering::RenderSurface BuildViewportColorSurface(const ViewportRenderTargets& targets) { return BuildViewportRenderSurface( targets.width, targets.height, targets.colorView, targets.depthView, targets.colorState); } inline Rendering::RenderSurface BuildViewportObjectIdSurface(const ViewportRenderTargets& targets) { return BuildViewportRenderSurface( targets.width, targets.height, targets.objectIdView, targets.depthView, targets.objectIdState); } namespace Detail { template inline void ShutdownAndDelete(ResourceType*& resource) { if (resource == nullptr) { return; } resource->Shutdown(); delete resource; resource = nullptr; } inline bool CreateViewportColorResources( RHI::RHIDevice* device, ViewportRenderTargets& targets) { const RHI::TextureDesc colorDesc = BuildViewportTextureDesc(targets.width, targets.height, RHI::Format::R8G8B8A8_UNorm); targets.colorTexture = device->CreateTexture(colorDesc); if (targets.colorTexture == nullptr) { return false; } const RHI::ResourceViewDesc colorViewDesc = BuildViewportTextureViewDesc(RHI::Format::R8G8B8A8_UNorm); targets.colorView = device->CreateRenderTargetView(targets.colorTexture, colorViewDesc); return targets.colorView != nullptr; } inline bool CreateViewportDepthResources( RHI::RHIDevice* device, ViewportRenderTargets& targets) { const RHI::TextureDesc depthDesc = BuildViewportTextureDesc(targets.width, targets.height, RHI::Format::D24_UNorm_S8_UInt); targets.depthTexture = device->CreateTexture(depthDesc); if (targets.depthTexture == nullptr) { return false; } const RHI::ResourceViewDesc depthViewDesc = BuildViewportTextureViewDesc(RHI::Format::D24_UNorm_S8_UInt); targets.depthView = device->CreateDepthStencilView(targets.depthTexture, depthViewDesc); return targets.depthView != nullptr; } inline bool CreateViewportObjectIdResources( RHI::RHIDevice* device, ViewportRenderTargets& targets) { const RHI::TextureDesc objectIdDesc = BuildViewportTextureDesc(targets.width, targets.height, RHI::Format::R8G8B8A8_UNorm); targets.objectIdTexture = device->CreateTexture(objectIdDesc); if (targets.objectIdTexture == nullptr) { return false; } const RHI::ResourceViewDesc objectIdViewDesc = BuildViewportTextureViewDesc(RHI::Format::R8G8B8A8_UNorm); targets.objectIdView = device->CreateRenderTargetView( targets.objectIdTexture, objectIdViewDesc); if (targets.objectIdView == nullptr) { return false; } targets.objectIdShaderView = device->CreateShaderResourceView( targets.objectIdTexture, objectIdViewDesc); return targets.objectIdShaderView != nullptr; } inline bool CreateViewportTextureDescriptor( UI::ImGuiBackendBridge* backend, RHI::RHIDevice* device, ViewportRenderTargets& targets) { ImTextureID imguiTextureId = {}; if (!backend->CreateTextureDescriptor( device, targets.colorTexture, &targets.imguiCpuHandle, &targets.imguiGpuHandle, &imguiTextureId)) { return false; } targets.textureHandle.nativeHandle = static_cast(targets.imguiGpuHandle.ptr); targets.textureHandle.width = targets.width; targets.textureHandle.height = targets.height; return true; } } // namespace Detail inline void DestroyViewportRenderTargets( UI::ImGuiBackendBridge* backend, ViewportRenderTargets& targets) { if (backend != nullptr && targets.imguiCpuHandle.ptr != 0) { backend->FreeTextureDescriptor(targets.imguiCpuHandle, targets.imguiGpuHandle); } Detail::ShutdownAndDelete(targets.objectIdView); Detail::ShutdownAndDelete(targets.objectIdShaderView); Detail::ShutdownAndDelete(targets.objectIdTexture); Detail::ShutdownAndDelete(targets.depthView); Detail::ShutdownAndDelete(targets.depthTexture); Detail::ShutdownAndDelete(targets.colorView); Detail::ShutdownAndDelete(targets.colorTexture); targets.width = 0; targets.height = 0; targets.imguiCpuHandle = {}; targets.imguiGpuHandle = {}; targets.textureHandle = {}; targets.colorState = RHI::ResourceStates::Common; targets.objectIdState = RHI::ResourceStates::Common; targets.hasValidObjectIdFrame = false; } inline bool CreateViewportRenderTargets( EditorViewportKind kind, uint32_t width, uint32_t height, RHI::RHIDevice* device, UI::ImGuiBackendBridge* backend, ViewportRenderTargets& targets) { if (width == 0 || height == 0 || device == nullptr || backend == nullptr) { return false; } DestroyViewportRenderTargets(backend, targets); targets.width = width; targets.height = height; if (!Detail::CreateViewportColorResources(device, targets) || !Detail::CreateViewportDepthResources(device, targets) || (ViewportRequiresObjectIdResources(kind) && !Detail::CreateViewportObjectIdResources(device, targets)) || !Detail::CreateViewportTextureDescriptor(backend, device, targets)) { DestroyViewportRenderTargets(backend, targets); return false; } targets.colorState = RHI::ResourceStates::Common; targets.objectIdState = RHI::ResourceStates::Common; targets.hasValidObjectIdFrame = false; return true; } } // namespace Editor } // namespace XCEngine