From 697deb4e41b214d56799ca3c3e50e6d91e7f03f0 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Thu, 2 Apr 2026 12:47:06 +0800 Subject: [PATCH] refactor: route scene view passes through camera renderer --- .../Viewport/ViewportHostRenderFlowUtils.h | 8 +++ editor/src/Viewport/ViewportHostService.h | 51 ++++++++----------- .../XCEngine/Rendering/CameraRenderRequest.h | 14 +++++ .../XCEngine/Rendering/CameraRenderer.h | 2 + engine/src/Rendering/CameraRenderer.cpp | 36 +++++++++++++ .../unit/test_camera_scene_renderer.cpp | 25 +++++++++ 6 files changed, 107 insertions(+), 29 deletions(-) diff --git a/editor/src/Viewport/ViewportHostRenderFlowUtils.h b/editor/src/Viewport/ViewportHostRenderFlowUtils.h index 34c726ac..7c285ee2 100644 --- a/editor/src/Viewport/ViewportHostRenderFlowUtils.h +++ b/editor/src/Viewport/ViewportHostRenderFlowUtils.h @@ -114,15 +114,23 @@ inline ViewportRenderFallbackPolicy BuildGameViewportRenderFailurePolicy( inline void ApplySceneViewportRenderRequestSetup( const ViewportRenderTargets& targets, + const Rendering::BuiltinSceneViewPostProcessRequest* builtinSceneViewPostProcess, Rendering::RenderPassSequence* postPasses, Rendering::CameraRenderRequest& request) { request.postScenePasses = nullptr; request.objectId = {}; + request.builtinSceneViewPostProcess = {}; if (postPasses != nullptr && postPasses->GetPassCount() > 0) { request.postScenePasses = postPasses; } + if (builtinSceneViewPostProcess != nullptr && + builtinSceneViewPostProcess->IsRequested()) { + request.builtinSceneViewPostProcess = *builtinSceneViewPostProcess; + request.builtinSceneViewPostProcess.objectIdTextureView = targets.objectIdShaderView; + } + if (targets.objectIdView == nullptr) { return; } diff --git a/editor/src/Viewport/ViewportHostService.h b/editor/src/Viewport/ViewportHostService.h index aefe08da..7cee5260 100644 --- a/editor/src/Viewport/ViewportHostService.h +++ b/editor/src/Viewport/ViewportHostService.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -92,7 +91,6 @@ public: m_sceneViewLastRenderContext = {}; m_device = nullptr; m_backend = nullptr; - m_sceneViewPostPassBuilder.Shutdown(); m_sceneRenderer.reset(); } @@ -280,7 +278,7 @@ private: struct SceneViewportRenderState { SceneViewportOverlayData overlay = {}; - Rendering::RenderPassSequence postPasses; + Rendering::BuiltinSceneViewPostProcessRequest builtinSceneViewPostProcess = {}; std::vector selectedObjectIds; }; @@ -412,32 +410,28 @@ private: policy.clearColor.a); } - bool BuildSceneViewPostPassSequence( + void BuildSceneViewBuiltinPostProcessRequest( ViewportEntry& entry, const SceneViewportOverlayData& overlay, const std::vector& selectedObjectIds, - Rendering::RenderPassSequence& outPostPasses) { - Rendering::Passes::ObjectIdOutlineStyle outlineStyle = {}; - outlineStyle.outlineColor = Math::Color(1.0f, 0.4f, 0.0f, 1.0f); - outlineStyle.outlineWidthPixels = 2.0f; - outlineStyle.debugSelectionMask = kDebugSceneSelectionMask; - - const Rendering::Passes::BuiltinSceneViewPostPassSequenceBuildResult result = - m_sceneViewPostPassBuilder.Build( - { - BuildInfiniteGridPassData(overlay), - entry.renderTargets.objectIdShaderView, - selectedObjectIds, - outlineStyle - }, - outPostPasses); - - if (result.missingObjectIdTextureViewForSelection && - !kDebugSceneSelectionMask) { - SetViewportStatusIfEmpty(entry.statusText, "Scene object id shader view is unavailable"); + Rendering::BuiltinSceneViewPostProcessRequest& outRequest) { + if (!overlay.valid) { + outRequest = {}; + return; } - return result.valid; + outRequest.gridPassData = BuildInfiniteGridPassData(overlay); + outRequest.selectedObjectIds = selectedObjectIds; + outRequest.outlineStyle = {}; + outRequest.outlineStyle.outlineColor = Math::Color(1.0f, 0.4f, 0.0f, 1.0f); + outRequest.outlineStyle.outlineWidthPixels = 2.0f; + outRequest.outlineStyle.debugSelectionMask = kDebugSceneSelectionMask; + + if (!selectedObjectIds.empty() && + !kDebugSceneSelectionMask && + entry.renderTargets.objectIdShaderView == nullptr) { + SetViewportStatusIfEmpty(entry.statusText, "Scene object id shader view is unavailable"); + } } void BuildSceneViewportRenderState( @@ -452,12 +446,11 @@ private: } outState.selectedObjectIds = context.GetSelectionManager().GetSelectedEntities(); - - BuildSceneViewPostPassSequence( + BuildSceneViewBuiltinPostProcessRequest( entry, outState.overlay, outState.selectedObjectIds, - outState.postPasses); + outState.builtinSceneViewPostProcess); } bool RenderSceneViewportEntry( @@ -502,7 +495,8 @@ private: ApplySceneViewportRenderRequestSetup( entry.renderTargets, - &sceneState.postPasses, + &sceneState.builtinSceneViewPostProcess, + nullptr, requests[0]); requests[0].hasClearColorOverride = true; requests[0].clearColorOverride = Math::Color(0.27f, 0.27f, 0.27f, 1.0f); @@ -657,7 +651,6 @@ private: Rendering::RenderContext m_sceneViewLastRenderContext = {}; std::array m_entries = {}; SceneViewCameraState m_sceneViewCamera; - Rendering::Passes::BuiltinSceneViewPostPassSequenceBuilder m_sceneViewPostPassBuilder; }; } // namespace Editor diff --git a/engine/include/XCEngine/Rendering/CameraRenderRequest.h b/engine/include/XCEngine/Rendering/CameraRenderRequest.h index 93e34884..85098c5e 100644 --- a/engine/include/XCEngine/Rendering/CameraRenderRequest.h +++ b/engine/include/XCEngine/Rendering/CameraRenderRequest.h @@ -1,5 +1,7 @@ #pragma once +#include +#include #include #include #include @@ -30,12 +32,24 @@ struct ObjectIdRenderRequest { } }; +struct BuiltinSceneViewPostProcessRequest { + Passes::InfiniteGridPassData gridPassData = {}; + RHI::RHIResourceView* objectIdTextureView = nullptr; + std::vector selectedObjectIds = {}; + Passes::ObjectIdOutlineStyle outlineStyle = {}; + + bool IsRequested() const { + return gridPassData.valid; + } +}; + struct CameraRenderRequest { const Components::Scene* scene = nullptr; Components::CameraComponent* camera = nullptr; RenderContext context; RenderSurface surface; ObjectIdRenderRequest objectId; + BuiltinSceneViewPostProcessRequest builtinSceneViewPostProcess; float cameraDepth = 0.0f; uint8_t cameraStackOrder = 0; RenderClearFlags clearFlags = RenderClearFlags::All; diff --git a/engine/include/XCEngine/Rendering/CameraRenderer.h b/engine/include/XCEngine/Rendering/CameraRenderer.h index 4ecae49b..2e8dc0c9 100644 --- a/engine/include/XCEngine/Rendering/CameraRenderer.h +++ b/engine/include/XCEngine/Rendering/CameraRenderer.h @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -43,6 +44,7 @@ private: std::shared_ptr m_pipelineAsset; std::unique_ptr m_pipeline; std::unique_ptr m_objectIdPass; + Passes::BuiltinSceneViewPostPassSequenceBuilder m_builtinSceneViewPostProcessBuilder; }; } // namespace Rendering diff --git a/engine/src/Rendering/CameraRenderer.cpp b/engine/src/Rendering/CameraRenderer.cpp index eaeb1a2b..f15dbba6 100644 --- a/engine/src/Rendering/CameraRenderer.cpp +++ b/engine/src/Rendering/CameraRenderer.cpp @@ -86,6 +86,7 @@ CameraRenderer::~CameraRenderer() { if (m_objectIdPass != nullptr) { m_objectIdPass->Shutdown(); } + m_builtinSceneViewPostProcessBuilder.Shutdown(); } void CameraRenderer::SetPipeline(std::unique_ptr pipeline) { @@ -135,6 +136,11 @@ bool CameraRenderer::Render( !request.objectId.IsValid()) { return false; } + if (request.builtinSceneViewPostProcess.IsRequested() && + request.builtinSceneViewPostProcess.objectIdTextureView != nullptr && + !request.objectId.IsRequested()) { + return false; + } RenderSceneData sceneData = m_sceneExtractor.ExtractForCamera( *request.scene, @@ -195,6 +201,36 @@ bool CameraRenderer::Render( return false; } + RenderPassSequence builtinSceneViewPostPasses = {}; + bool builtinSceneViewPostPassesInitialized = false; + if (request.builtinSceneViewPostProcess.IsRequested()) { + const Passes::BuiltinSceneViewPostPassSequenceBuildResult buildResult = + m_builtinSceneViewPostProcessBuilder.Build( + { + request.builtinSceneViewPostProcess.gridPassData, + request.builtinSceneViewPostProcess.objectIdTextureView, + request.builtinSceneViewPostProcess.selectedObjectIds, + request.builtinSceneViewPostProcess.outlineStyle + }, + builtinSceneViewPostPasses); + if (!buildResult.valid || + !InitializePassSequence( + &builtinSceneViewPostPasses, + request.context, + builtinSceneViewPostPassesInitialized)) { + ShutdownPassSequence(request.postScenePasses, postScenePassesInitialized); + ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); + return false; + } + if (!builtinSceneViewPostPasses.Execute(passContext)) { + ShutdownPassSequence(&builtinSceneViewPostPasses, builtinSceneViewPostPassesInitialized); + ShutdownPassSequence(request.postScenePasses, postScenePassesInitialized); + ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); + return false; + } + } + + ShutdownPassSequence(&builtinSceneViewPostPasses, builtinSceneViewPostPassesInitialized); ShutdownPassSequence(request.postScenePasses, postScenePassesInitialized); ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); diff --git a/tests/Rendering/unit/test_camera_scene_renderer.cpp b/tests/Rendering/unit/test_camera_scene_renderer.cpp index d81f8759..1e0021a1 100644 --- a/tests/Rendering/unit/test_camera_scene_renderer.cpp +++ b/tests/Rendering/unit/test_camera_scene_renderer.cpp @@ -438,6 +438,31 @@ TEST(CameraRenderer_Test, ShutsDownSequencesWhenPostPassInitializationFails) { "shutdown:pre" })); } +TEST(CameraRenderer_Test, RejectsBuiltinSceneViewPostProcessThatCannotProduceFreshObjectIdData) { + Scene scene("CameraRendererSceneViewPostProcessValidationScene"); + + GameObject* cameraObject = scene.CreateGameObject("Camera"); + auto* camera = cameraObject->AddComponent(); + camera->SetPrimary(true); + camera->SetDepth(4.0f); + + auto state = std::make_shared(); + CameraRenderer renderer(std::make_unique(state)); + + CameraRenderRequest request; + request.scene = &scene; + request.camera = camera; + request.context = CreateValidContext(); + request.surface = RenderSurface(512, 512); + request.cameraDepth = camera->GetDepth(); + request.builtinSceneViewPostProcess.gridPassData.valid = true; + request.builtinSceneViewPostProcess.objectIdTextureView = + reinterpret_cast(1); + + EXPECT_FALSE(renderer.Render(request)); + EXPECT_TRUE(state->eventLog.empty()); +} + TEST(SceneRenderer_Test, BuildsSortedRequestsForAllUsableCamerasAndHonorsOverrideCamera) { Scene scene("SceneRendererRequestScene");