diff --git a/engine/include/XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h b/engine/include/XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h index cb5713dc..538adb21 100644 --- a/engine/include/XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h +++ b/engine/include/XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h @@ -46,12 +46,20 @@ public: const RenderSceneData& sceneData) override; private: + bool EnsureInitialized(const RenderContext& context); + void ShutdownInitializedComponents(); + void ResetInitializationState(); + void ClearInitializationContextIfNoComponentsAreInitialized(); void ResetStageRecorder(std::unique_ptr stageRecorder); void ResetPipelineRenderer(std::unique_ptr pipelineRenderer); std::unique_ptr m_stageRecorder; std::shared_ptr m_pipelineRendererAsset; std::unique_ptr m_pipelineRenderer; + RHI::RHIDevice* m_initializedDevice = nullptr; + RHI::RHIType m_initializedBackendType = RHI::RHIType::D3D12; + bool m_pipelineRendererInitialized = false; + bool m_stageRecorderInitialized = false; }; class ScriptableRenderPipelineHostAsset final : public RenderPipelineAsset { diff --git a/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp b/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp index 987fa506..0f3a2472 100644 --- a/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp +++ b/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp @@ -93,19 +93,7 @@ void ScriptableRenderPipelineHost::SetPipelineRendererAsset( } bool ScriptableRenderPipelineHost::Initialize(const RenderContext& context) { - if (m_pipelineRenderer == nullptr || - !m_pipelineRenderer->Initialize(context)) { - return false; - } - - if (m_stageRecorder != nullptr && - !m_stageRecorder->Initialize(context)) { - m_stageRecorder->Shutdown(); - m_pipelineRenderer->Shutdown(); - return false; - } - - return true; + return EnsureInitialized(context); } void ScriptableRenderPipelineHost::Shutdown() { @@ -116,6 +104,7 @@ void ScriptableRenderPipelineHost::Shutdown() { m_pipelineRenderer->Shutdown(); } ShutdownCameraFrameStandalonePasses(); + ResetInitializationState(); } bool ScriptableRenderPipelineHost::SupportsStageRenderGraph( @@ -128,6 +117,10 @@ bool ScriptableRenderPipelineHost::SupportsStageRenderGraph( bool ScriptableRenderPipelineHost::RecordStageRenderGraph( const RenderPipelineStageRenderGraphContext& context) { + if (!EnsureInitialized(context.renderContext)) { + return false; + } + if (m_stageRecorder != nullptr && m_stageRecorder->SupportsStageRenderGraph(context.stage)) { return m_stageRecorder->RecordStageRenderGraph(context); @@ -139,6 +132,10 @@ bool ScriptableRenderPipelineHost::RecordStageRenderGraph( bool ScriptableRenderPipelineHost::Render( const FrameExecutionContext& executionContext) { + if (!EnsureInitialized(executionContext.renderContext)) { + return false; + } + return m_pipelineRenderer != nullptr && m_pipelineRenderer->Render(executionContext); } @@ -147,10 +144,86 @@ bool ScriptableRenderPipelineHost::Render( const RenderContext& context, const RenderSurface& surface, const RenderSceneData& sceneData) { + if (!EnsureInitialized(context)) { + return false; + } + return m_pipelineRenderer != nullptr && m_pipelineRenderer->Render(context, surface, sceneData); } +bool ScriptableRenderPipelineHost::EnsureInitialized(const RenderContext& context) { + if (!context.IsValid() || m_pipelineRenderer == nullptr) { + return false; + } + + const bool hasInitializationContext = + m_initializedDevice != nullptr || + m_pipelineRendererInitialized || + m_stageRecorderInitialized; + if (hasInitializationContext && + (m_initializedDevice != context.device || + m_initializedBackendType != context.backendType)) { + ShutdownInitializedComponents(); + } + + if (!m_pipelineRendererInitialized) { + if (!m_pipelineRenderer->Initialize(context)) { + m_pipelineRenderer->Shutdown(); + ClearInitializationContextIfNoComponentsAreInitialized(); + return false; + } + + m_pipelineRendererInitialized = true; + m_initializedDevice = context.device; + m_initializedBackendType = context.backendType; + } + + if (m_stageRecorder != nullptr && + !m_stageRecorderInitialized) { + if (!m_stageRecorder->Initialize(context)) { + m_stageRecorder->Shutdown(); + ShutdownInitializedComponents(); + return false; + } + + m_stageRecorderInitialized = true; + m_initializedDevice = context.device; + m_initializedBackendType = context.backendType; + } + + return true; +} + +void ScriptableRenderPipelineHost::ShutdownInitializedComponents() { + if (m_stageRecorderInitialized && + m_stageRecorder != nullptr) { + m_stageRecorder->Shutdown(); + } + + if (m_pipelineRendererInitialized && + m_pipelineRenderer != nullptr) { + m_pipelineRenderer->Shutdown(); + } + + ResetInitializationState(); +} + +void ScriptableRenderPipelineHost::ResetInitializationState() { + m_initializedDevice = nullptr; + m_initializedBackendType = RHI::RHIType::D3D12; + m_pipelineRendererInitialized = false; + m_stageRecorderInitialized = false; +} + +void ScriptableRenderPipelineHost::ClearInitializationContextIfNoComponentsAreInitialized() { + if (!m_pipelineRendererInitialized && + !m_stageRecorderInitialized) { + m_initializedDevice = nullptr; + m_initializedBackendType = RHI::RHIType::D3D12; + } +} + void ScriptableRenderPipelineHost::ResetStageRecorder( std::unique_ptr stageRecorder) { if (m_stageRecorder != nullptr) { @@ -158,6 +231,8 @@ void ScriptableRenderPipelineHost::ResetStageRecorder( } m_stageRecorder = std::move(stageRecorder); + m_stageRecorderInitialized = false; + ClearInitializationContextIfNoComponentsAreInitialized(); } void ScriptableRenderPipelineHost::ResetPipelineRenderer( @@ -174,6 +249,9 @@ void ScriptableRenderPipelineHost::ResetPipelineRenderer( m_pipelineRenderer = CreatePipelineRendererFromAsset(m_pipelineRendererAsset); } + + m_pipelineRendererInitialized = false; + ClearInitializationContextIfNoComponentsAreInitialized(); } ScriptableRenderPipelineHostAsset::ScriptableRenderPipelineHostAsset() diff --git a/tests/Rendering/unit/test_camera_scene_renderer.cpp b/tests/Rendering/unit/test_camera_scene_renderer.cpp index a30f9677..631ffd98 100644 --- a/tests/Rendering/unit/test_camera_scene_renderer.cpp +++ b/tests/Rendering/unit/test_camera_scene_renderer.cpp @@ -3853,11 +3853,19 @@ TEST(ScriptableRenderPipelineHost_Test, ForwardsRendererLifetimeAndFrameRenderin request.context, request.surface, sceneData)); + EXPECT_EQ(replacementState->initializeCalls, 1); EXPECT_EQ(replacementState->renderCalls, 1); EXPECT_EQ(replacementState->lastSurfaceWidth, 800u); EXPECT_EQ(replacementState->lastSurfaceHeight, 600u); EXPECT_EQ(replacementState->lastCamera, camera); + ASSERT_TRUE(host.Render(FrameExecutionContext( + request.context, + request.surface, + sceneData))); + EXPECT_EQ(replacementState->initializeCalls, 1); + EXPECT_EQ(replacementState->renderCalls, 2); + replacementState->supportsMainSceneRenderGraph = true; RenderGraph graph = {}; RenderGraphBuilder graphBuilder(graph); @@ -3883,6 +3891,7 @@ TEST(ScriptableRenderPipelineHost_Test, ForwardsRendererLifetimeAndFrameRenderin }; EXPECT_TRUE(host.SupportsStageRenderGraph(CameraFrameStage::MainScene)); EXPECT_TRUE(host.RecordStageRenderGraph(graphContext)); + EXPECT_EQ(replacementState->initializeCalls, 1); EXPECT_EQ(replacementState->recordMainSceneCalls, 1); } @@ -3950,7 +3959,13 @@ TEST(ScriptableRenderPipelineHost_Test, PrefersStageRecorderBeforeFallbackRender EXPECT_TRUE(host.SupportsStageRenderGraph(CameraFrameStage::MainScene)); EXPECT_TRUE(host.RecordStageRenderGraph(graphContext)); + EXPECT_EQ(rendererState->initializeCalls, 1); + EXPECT_EQ(replacementRecorderState->initializeCalls, 1); EXPECT_EQ(replacementRecorderState->recordMainSceneCalls, 1); + EXPECT_TRUE(host.RecordStageRenderGraph(graphContext)); + EXPECT_EQ(rendererState->initializeCalls, 1); + EXPECT_EQ(replacementRecorderState->initializeCalls, 1); + EXPECT_EQ(replacementRecorderState->recordMainSceneCalls, 2); EXPECT_TRUE(replacementRecorderState->lastReceivedRenderGraphBlackboard); EXPECT_EQ(rendererState->recordMainSceneCalls, 0); }