From e2b2df4c8f6ce25400d3bd4d433ec9f0c57a0fba Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Tue, 21 Apr 2026 02:38:56 +0800 Subject: [PATCH] refactor(srp): move shadow caster stage selection into managed urp - add standalone pass asset factories for camera frame stages\n- let managed pipeline assets declare stage pass asset keys\n- make universal renderer data explicitly own the builtin shadow caster stage --- ...anagedOwnershipPlan_完成归档_2026-04-21.md | 47 +++++++ .../ManagedScriptableRenderPipelineAsset.h | 11 ++ .../Pipelines/ScriptableRenderPipelineHost.h | 37 ++++++ .../XCEngine/Rendering/RenderPipeline.h | 7 + .../CameraFrameGraph/PassRecorder.cpp | 3 +- .../CameraFrameGraph/StageContract.cpp | 10 +- .../Internal/CameraFrameGraph/StageContract.h | 3 +- .../Internal/RenderPipelineFactory.cpp | 116 +++++++++++++++++ .../Internal/RenderPipelineFactory.h | 10 ++ .../ManagedScriptableRenderPipelineAsset.cpp | 10 +- .../ScriptableRenderPipelineHost.cpp | 123 +++++++++++++++++- .../src/Scripting/Mono/MonoScriptRuntime.cpp | 113 ++++++++++++++++ .../RendererBackedRenderPipelineAsset.cs | 26 ++++ .../Universal/ScriptableRendererData.cs | 13 ++ .../Universal/UniversalRendererData.cs | 14 ++ .../Core/ScriptableRenderPipelineAsset.cs | 15 +++ 16 files changed, 544 insertions(+), 14 deletions(-) create mode 100644 docs/used/SRP_UniversalShadowCasterStageManagedOwnershipPlan_完成归档_2026-04-21.md diff --git a/docs/used/SRP_UniversalShadowCasterStageManagedOwnershipPlan_完成归档_2026-04-21.md b/docs/used/SRP_UniversalShadowCasterStageManagedOwnershipPlan_完成归档_2026-04-21.md new file mode 100644 index 00000000..615ae318 --- /dev/null +++ b/docs/used/SRP_UniversalShadowCasterStageManagedOwnershipPlan_完成归档_2026-04-21.md @@ -0,0 +1,47 @@ +# SRP Universal Shadow Caster Stage Managed Ownership Plan 2026-04-21 + +## Goal + +Move `CameraFrameStage::ShadowCaster` pass selection out of the native host hardcode and into managed URP ownership. + +This stage does **not** move shadow rasterization itself into C#. +It only makes managed URP explicitly declare which native shadow-caster pass asset it wants to use. + +## Why This Stage + +The current managed URP already owns: + +1. renderer selection; +2. main-scene builtin feature ownership; +3. shadow enable / planning defaults. + +But the actual `ShadowCaster` standalone stage is still installed in native host code through a hardcoded `BuiltinShadowCasterPass`. + +That means shadow stage ownership is still not aligned with the SRP/URP boundary. + +## Scope + +Included: + +1. add a native registry/factory for camera-frame standalone pass assets; +2. let managed `ScriptableRenderPipelineAsset` expose standalone pass asset keys by stage; +3. let `RendererBackedRenderPipelineAsset` route that decision through selected renderer data; +4. make `UniversalRendererData` explicitly declare the builtin shadow-caster pass asset key; +5. let `ScriptableRenderPipelineHost` resolve contextual standalone passes from managed asset runtime instead of hardcoding shadow caster; +6. rebuild `XCEditor` and run old editor smoke. + +Not included: + +1. managed shadow raster pass recording; +2. cascades; +3. shadow atlas packing; +4. editor UI for standalone pass selection. + +## Acceptance + +This stage is complete when: + +1. managed URP explicitly owns the `ShadowCaster` standalone pass selection; +2. native host no longer hardcodes shadow caster for managed pipelines; +3. builtin fallback pipeline still keeps depth-only / object-id / shadow-caster working; +4. `XCEditor` build and old editor smoke both pass. diff --git a/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h b/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h index c1bc89dd..f866380a 100644 --- a/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h +++ b/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h @@ -96,6 +96,17 @@ public: (void)rendererIndex; return GetPipelineRendererAsset(); } + virtual std::string GetCameraFrameStandalonePassAssetKey( + CameraFrameStage stage) const { + (void)stage; + return {}; + } + virtual std::string GetCameraFrameStandalonePassAssetKey( + CameraFrameStage stage, + int32_t rendererIndex) const { + (void)rendererIndex; + return GetCameraFrameStandalonePassAssetKey(stage); + } virtual bool TryGetDefaultFinalColorSettings(FinalColorSettings&) const { return false; diff --git a/engine/include/XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h b/engine/include/XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h index 0252db5b..45539179 100644 --- a/engine/include/XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h +++ b/engine/include/XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h @@ -3,12 +3,17 @@ #include #include +#include #include +#include +#include namespace XCEngine { namespace Rendering { namespace Pipelines { +class ManagedRenderPipelineAssetRuntime; + class ScriptableRenderPipelineHost final : public RenderPipeline { public: ScriptableRenderPipelineHost(); @@ -16,6 +21,10 @@ public: std::unique_ptr pipelineRenderer); explicit ScriptableRenderPipelineHost( std::shared_ptr pipelineRendererAsset); + ScriptableRenderPipelineHost( + std::shared_ptr pipelineRendererAsset, + std::shared_ptr + managedAssetRuntime); ~ScriptableRenderPipelineHost() override; using RenderPipeline::Render; @@ -24,6 +33,9 @@ public: void SetPipelineRenderer(std::unique_ptr pipelineRenderer); void SetPipelineRendererAsset( std::shared_ptr pipelineRendererAsset); + void SetManagedAssetRuntime( + std::shared_ptr + managedAssetRuntime); RenderPipelineStageRecorder* GetStageRecorder() const { return m_stageRecorder.get(); } @@ -46,19 +58,38 @@ public: const RenderContext& context, const RenderSurface& surface, const RenderSceneData& sceneData) override; + RenderPass* GetCameraFrameStandalonePass( + CameraFrameStage stage, + int32_t rendererIndex) const override; private: + struct ContextualCameraFrameStandalonePassEntry { + std::string assetKey = {}; + std::unique_ptr pass = nullptr; + }; + bool EnsureInitialized(const RenderContext& context); void BindStageRecorderPipelineRenderer(); + void ShutdownContextualCameraFrameStandalonePasses(); void ShutdownInitializedComponents(); void ResetInitializationState(); void ClearInitializationContextIfNoComponentsAreInitialized(); void ResetStageRecorder(std::unique_ptr stageRecorder); void ResetPipelineRenderer(std::unique_ptr pipelineRenderer); + RenderPass* ResolveContextualCameraFrameStandalonePass( + CameraFrameStage stage, + int32_t rendererIndex, + const std::string& assetKey); std::unique_ptr m_stageRecorder; std::shared_ptr m_pipelineRendererAsset; + std::shared_ptr + m_managedAssetRuntime; std::unique_ptr m_pipelineRenderer; + std::array< + std::unordered_map, + kCameraFrameStageCount> + m_contextualCameraFrameStandalonePasses = {}; RHI::RHIDevice* m_initializedDevice = nullptr; RHI::RHIType m_initializedBackendType = RHI::RHIType::D3D12; bool m_pipelineRendererInitialized = false; @@ -70,6 +101,10 @@ public: ScriptableRenderPipelineHostAsset(); explicit ScriptableRenderPipelineHostAsset( std::shared_ptr pipelineRendererAsset); + ScriptableRenderPipelineHostAsset( + std::shared_ptr pipelineRendererAsset, + std::shared_ptr + managedAssetRuntime); std::unique_ptr CreatePipeline() const override; void ConfigurePipeline(RenderPipeline& pipeline) const override; @@ -77,6 +112,8 @@ public: private: std::shared_ptr m_pipelineRendererAsset; + std::shared_ptr + m_managedAssetRuntime; }; } // namespace Pipelines diff --git a/engine/include/XCEngine/Rendering/RenderPipeline.h b/engine/include/XCEngine/Rendering/RenderPipeline.h index cca7be47..618e5324 100644 --- a/engine/include/XCEngine/Rendering/RenderPipeline.h +++ b/engine/include/XCEngine/Rendering/RenderPipeline.h @@ -149,6 +149,13 @@ public: : nullptr; } + virtual RenderPass* GetCameraFrameStandalonePass( + CameraFrameStage stage, + int32_t rendererIndex) const { + (void)rendererIndex; + return GetCameraFrameStandalonePass(stage); + } + protected: void ShutdownCameraFrameStandalonePasses() { for (std::unique_ptr& pass : m_cameraFrameStandalonePasses) { diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/PassRecorder.cpp b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/PassRecorder.cpp index 25a17434..b1d7a1bc 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/PassRecorder.cpp +++ b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/PassRecorder.cpp @@ -31,7 +31,8 @@ bool TryRecordCameraFrameStageStandaloneRenderGraphPass( RenderPass* const standaloneStagePass = ResolveCameraFrameStandaloneStagePass( stageState.stage, - builder.executionState); + builder.executionState, + context.plan.request.rendererIndex); if (standaloneStagePass == nullptr || !standaloneStagePass->SupportsRenderGraph()) { handled = false; diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.cpp b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.cpp index bf4b8e05..b6bb72df 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.cpp +++ b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.cpp @@ -217,9 +217,12 @@ RenderSceneData BuildCameraFrameStandaloneStageSceneData( RenderPass* ResolveCameraFrameStandaloneStagePass( CameraFrameStage stage, - CameraFrameExecutionState& executionState) { + CameraFrameExecutionState& executionState, + int32_t rendererIndex) { return executionState.pipeline != nullptr - ? executionState.pipeline->GetCameraFrameStandalonePass(stage) + ? executionState.pipeline->GetCameraFrameStandalonePass( + stage, + rendererIndex) : nullptr; } @@ -256,7 +259,8 @@ bool ExecuteCameraFrameRecordedStagePass( RenderPass* const standaloneStagePass = ResolveCameraFrameStandaloneStagePass( stage, - executionState); + executionState, + context.plan.request.rendererIndex); return ExecuteCameraFrameStandaloneStagePass( standaloneStagePass, context.plan.request.context, diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.h b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.h index 90399f82..b2b19a9c 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.h +++ b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.h @@ -47,7 +47,8 @@ RenderSceneData BuildCameraFrameStandaloneStageSceneData( RenderPass* ResolveCameraFrameStandaloneStagePass( CameraFrameStage stage, - CameraFrameExecutionState& executionState); + CameraFrameExecutionState& executionState, + int32_t rendererIndex); bool InitializeCameraFrameStandaloneStagePass( RenderPass* pass, diff --git a/engine/src/Rendering/Internal/RenderPipelineFactory.cpp b/engine/src/Rendering/Internal/RenderPipelineFactory.cpp index 21dd5aaa..01264195 100644 --- a/engine/src/Rendering/Internal/RenderPipelineFactory.cpp +++ b/engine/src/Rendering/Internal/RenderPipelineFactory.cpp @@ -3,6 +3,9 @@ #include "Rendering/Pipelines/BuiltinForwardPipeline.h" #include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h" #include "Rendering/Pipelines/ScriptableRenderPipelineHost.h" +#include "Rendering/Passes/BuiltinDepthOnlyPass.h" +#include "Rendering/Passes/BuiltinObjectIdPass.h" +#include "Rendering/Passes/BuiltinShadowCasterPass.h" #include #include @@ -22,24 +25,53 @@ CreateBuiltinForwardPipelineRendererAsset() { return s_builtinForwardPipelineAsset; } +std::unique_ptr CreateBuiltinDepthOnlyStandalonePass() { + return std::make_unique(); +} + +std::unique_ptr CreateBuiltinObjectIdStandalonePass() { + return std::make_unique(); +} + +std::unique_ptr CreateBuiltinShadowCasterStandalonePass() { + return std::make_unique(); +} + using PipelineRendererAssetRegistry = std::unordered_map; +using CameraFrameStandalonePassRegistry = + std::unordered_map; PipelineRendererAssetRegistry& GetPipelineRendererAssetRegistry() { static PipelineRendererAssetRegistry registry = {}; return registry; } +CameraFrameStandalonePassRegistry& GetCameraFrameStandalonePassRegistry() { + static CameraFrameStandalonePassRegistry registry = {}; + return registry; +} + std::unordered_set& GetBuiltinPipelineRendererAssetKeys() { static std::unordered_set builtinKeys = {}; return builtinKeys; } +std::unordered_set& GetBuiltinCameraFrameStandalonePassKeys() { + static std::unordered_set builtinKeys = {}; + return builtinKeys; +} + std::mutex& GetPipelineRendererAssetRegistryMutex() { static std::mutex mutex; return mutex; } +std::mutex& GetCameraFrameStandalonePassRegistryMutex() { + static std::mutex mutex; + return mutex; +} + void EnsureBuiltinPipelineRendererAssetRegistryInitialized() { static const bool initialized = []() { PipelineRendererAssetRegistry& registry = @@ -53,6 +85,29 @@ void EnsureBuiltinPipelineRendererAssetRegistryInitialized() { (void)initialized; } +void EnsureBuiltinCameraFrameStandalonePassRegistryInitialized() { + static const bool initialized = []() { + CameraFrameStandalonePassRegistry& registry = + GetCameraFrameStandalonePassRegistry(); + registry.emplace( + "BuiltinDepthOnly", + &CreateBuiltinDepthOnlyStandalonePass); + registry.emplace( + "BuiltinObjectId", + &CreateBuiltinObjectIdStandalonePass); + registry.emplace( + "BuiltinShadowCaster", + &CreateBuiltinShadowCasterStandalonePass); + std::unordered_set& builtinKeys = + GetBuiltinCameraFrameStandalonePassKeys(); + builtinKeys.insert("BuiltinDepthOnly"); + builtinKeys.insert("BuiltinObjectId"); + builtinKeys.insert("BuiltinShadowCaster"); + return true; + }(); + (void)initialized; +} + std::unique_ptr TryCreateNativeSceneRendererFromAsset( const std::shared_ptr& asset) { if (asset == nullptr) { @@ -144,6 +199,67 @@ std::shared_ptr CreatePipelineRendererAssetByKey( return it->second(); } +bool RegisterCameraFrameStandalonePassFactory( + const std::string& key, + CameraFrameStandalonePassFactory factory) { + if (key.empty() || !factory) { + return false; + } + + EnsureBuiltinCameraFrameStandalonePassRegistryInitialized(); + + std::lock_guard lock( + GetCameraFrameStandalonePassRegistryMutex()); + CameraFrameStandalonePassRegistry& registry = + GetCameraFrameStandalonePassRegistry(); + if (registry.find(key) != registry.end()) { + return false; + } + + registry.emplace(key, std::move(factory)); + return true; +} + +bool UnregisterCameraFrameStandalonePassFactory( + const std::string& key) { + if (key.empty()) { + return false; + } + + EnsureBuiltinCameraFrameStandalonePassRegistryInitialized(); + + std::lock_guard lock( + GetCameraFrameStandalonePassRegistryMutex()); + if (GetBuiltinCameraFrameStandalonePassKeys().find(key) != + GetBuiltinCameraFrameStandalonePassKeys().end()) { + return false; + } + + CameraFrameStandalonePassRegistry& registry = + GetCameraFrameStandalonePassRegistry(); + return registry.erase(key) != 0u; +} + +std::unique_ptr CreateCameraFrameStandalonePassByKey( + const std::string& key) { + if (key.empty()) { + return nullptr; + } + + EnsureBuiltinCameraFrameStandalonePassRegistryInitialized(); + + std::lock_guard lock( + GetCameraFrameStandalonePassRegistryMutex()); + const CameraFrameStandalonePassRegistry& registry = + GetCameraFrameStandalonePassRegistry(); + const auto it = registry.find(key); + if (it == registry.end() || !it->second) { + return nullptr; + } + + return it->second(); +} + std::shared_ptr ResolveRenderPipelineAssetOrDefault( std::shared_ptr preferredAsset) { if (preferredAsset != nullptr) { diff --git a/engine/src/Rendering/Internal/RenderPipelineFactory.h b/engine/src/Rendering/Internal/RenderPipelineFactory.h index b6ab6456..bb78efef 100644 --- a/engine/src/Rendering/Internal/RenderPipelineFactory.h +++ b/engine/src/Rendering/Internal/RenderPipelineFactory.h @@ -10,11 +10,14 @@ namespace Rendering { class NativeSceneRenderer; class RenderPipeline; class RenderPipelineAsset; +class RenderPass; namespace Internal { using PipelineRendererAssetFactory = std::function()>; +using CameraFrameStandalonePassFactory = + std::function()>; std::shared_ptr CreateConfiguredRenderPipelineAsset(); std::shared_ptr CreateFallbackRenderPipelineAsset(); @@ -24,6 +27,13 @@ bool RegisterPipelineRendererAssetFactory( bool UnregisterPipelineRendererAssetFactory(const std::string& key); std::shared_ptr CreatePipelineRendererAssetByKey( const std::string& key); +bool RegisterCameraFrameStandalonePassFactory( + const std::string& key, + CameraFrameStandalonePassFactory factory); +bool UnregisterCameraFrameStandalonePassFactory( + const std::string& key); +std::unique_ptr CreateCameraFrameStandalonePassByKey( + const std::string& key); std::shared_ptr ResolveRenderPipelineAssetOrDefault( std::shared_ptr preferredAsset); diff --git a/engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp b/engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp index ffbb8c2d..27f81870 100644 --- a/engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp +++ b/engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp @@ -50,13 +50,19 @@ ManagedScriptableRenderPipelineAsset::ResolvePipelineRendererAsset() const { ScriptableRenderPipelineHostAsset ManagedScriptableRenderPipelineAsset::CreateExecutionHostAsset() const { + const std::shared_ptr runtime = + ResolveManagedAssetRuntime(); if (const std::shared_ptr pipelineRendererAsset = ResolvePipelineRendererAsset(); pipelineRendererAsset != nullptr) { - return ScriptableRenderPipelineHostAsset(pipelineRendererAsset); + return ScriptableRenderPipelineHostAsset( + pipelineRendererAsset, + runtime); } - return ScriptableRenderPipelineHostAsset(); + return ScriptableRenderPipelineHostAsset( + nullptr, + runtime); } std::unique_ptr ManagedScriptableRenderPipelineAsset::CreatePipeline() const { diff --git a/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp b/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp index 23da429e..bbcaae6c 100644 --- a/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp +++ b/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp @@ -1,6 +1,9 @@ #include "Rendering/Pipelines/ScriptableRenderPipelineHost.h" +#include "Debug/Logger.h" +#include "Rendering/Internal/RenderPipelineFactory.h" #include "Rendering/Pipelines/BuiltinForwardPipeline.h" +#include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h" #include "Rendering/Passes/BuiltinDepthOnlyPass.h" #include "Rendering/Passes/BuiltinObjectIdPass.h" #include "Rendering/Passes/BuiltinShadowCasterPass.h" @@ -45,10 +48,20 @@ ScriptableRenderPipelineHost::ScriptableRenderPipelineHost( ScriptableRenderPipelineHost::ScriptableRenderPipelineHost( std::shared_ptr pipelineRendererAsset) + : ScriptableRenderPipelineHost( + std::move(pipelineRendererAsset), + nullptr) { +} + +ScriptableRenderPipelineHost::ScriptableRenderPipelineHost( + std::shared_ptr pipelineRendererAsset, + std::shared_ptr + managedAssetRuntime) : m_pipelineRendererAsset( pipelineRendererAsset != nullptr ? std::move(pipelineRendererAsset) - : CreateDefaultPipelineRendererAsset()) { + : CreateDefaultPipelineRendererAsset()) + , m_managedAssetRuntime(std::move(managedAssetRuntime)) { ResetPipelineRenderer( CreatePipelineRendererFromAsset(m_pipelineRendererAsset)); } @@ -78,6 +91,13 @@ void ScriptableRenderPipelineHost::SetPipelineRendererAsset( CreatePipelineRendererFromAsset(m_pipelineRendererAsset)); } +void ScriptableRenderPipelineHost::SetManagedAssetRuntime( + std::shared_ptr + managedAssetRuntime) { + m_managedAssetRuntime = std::move(managedAssetRuntime); + ShutdownContextualCameraFrameStandalonePasses(); +} + bool ScriptableRenderPipelineHost::Initialize(const RenderContext& context) { return EnsureInitialized(context); } @@ -89,6 +109,7 @@ void ScriptableRenderPipelineHost::Shutdown() { if (m_pipelineRenderer != nullptr) { m_pipelineRenderer->Shutdown(); } + ShutdownContextualCameraFrameStandalonePasses(); ShutdownCameraFrameStandalonePasses(); ResetInitializationState(); } @@ -150,6 +171,32 @@ bool ScriptableRenderPipelineHost::Render( m_pipelineRenderer->Render(context, surface, sceneData); } +RenderPass* ScriptableRenderPipelineHost::GetCameraFrameStandalonePass( + CameraFrameStage stage, + int32_t rendererIndex) const { + RenderPass* const defaultPass = + RenderPipeline::GetCameraFrameStandalonePass(stage); + if (m_managedAssetRuntime == nullptr || + !SupportsCameraFrameStandalonePass(stage)) { + return defaultPass; + } + + const std::string assetKey = + m_managedAssetRuntime + ->GetCameraFrameStandalonePassAssetKey( + stage, + rendererIndex); + if (assetKey.empty()) { + return defaultPass; + } + + return const_cast(this) + ->ResolveContextualCameraFrameStandalonePass( + stage, + rendererIndex, + assetKey); +} + bool ScriptableRenderPipelineHost::EnsureInitialized(const RenderContext& context) { if (!context.IsValid() || m_pipelineRenderer == nullptr) { return false; @@ -199,6 +246,18 @@ void ScriptableRenderPipelineHost::BindStageRecorderPipelineRenderer() { } } +void ScriptableRenderPipelineHost::ShutdownContextualCameraFrameStandalonePasses() { + for (auto& stageEntries : m_contextualCameraFrameStandalonePasses) { + for (auto& entryIt : stageEntries) { + if (entryIt.second.pass != nullptr) { + entryIt.second.pass->Shutdown(); + } + } + + stageEntries.clear(); + } +} + void ScriptableRenderPipelineHost::ShutdownInitializedComponents() { if (m_stageRecorderInitialized && m_stageRecorder != nullptr) { @@ -256,26 +315,74 @@ void ScriptableRenderPipelineHost::ResetPipelineRenderer( } m_pipelineRendererInitialized = false; + ShutdownContextualCameraFrameStandalonePasses(); BindStageRecorderPipelineRenderer(); ClearInitializationContextIfNoComponentsAreInitialized(); } +RenderPass* +ScriptableRenderPipelineHost::ResolveContextualCameraFrameStandalonePass( + CameraFrameStage stage, + int32_t rendererIndex, + const std::string& assetKey) { + auto& stageEntries = + m_contextualCameraFrameStandalonePasses[ + GetCameraFrameStageIndex(stage)]; + ContextualCameraFrameStandalonePassEntry& entry = + stageEntries[rendererIndex]; + if (entry.assetKey == assetKey) { + return entry.pass.get(); + } + + if (entry.pass != nullptr) { + entry.pass->Shutdown(); + } + + entry = {}; + entry.assetKey = assetKey; + entry.pass = + Rendering::Internal::CreateCameraFrameStandalonePassByKey( + assetKey); + if (entry.pass == nullptr) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + Containers::String( + "ScriptableRenderPipelineHost failed to resolve standalone pass asset key: ") + + assetKey.c_str()); + } + + return entry.pass.get(); +} + ScriptableRenderPipelineHostAsset::ScriptableRenderPipelineHostAsset() - : ScriptableRenderPipelineHostAsset(CreateDefaultPipelineRendererAsset()) { + : ScriptableRenderPipelineHostAsset( + CreateDefaultPipelineRendererAsset(), + nullptr) { } ScriptableRenderPipelineHostAsset::ScriptableRenderPipelineHostAsset( std::shared_ptr pipelineRendererAsset) + : ScriptableRenderPipelineHostAsset( + std::move(pipelineRendererAsset), + nullptr) { +} + +ScriptableRenderPipelineHostAsset::ScriptableRenderPipelineHostAsset( + std::shared_ptr pipelineRendererAsset, + std::shared_ptr + managedAssetRuntime) : m_pipelineRendererAsset( pipelineRendererAsset != nullptr ? std::move(pipelineRendererAsset) - : CreateDefaultPipelineRendererAsset()) { + : CreateDefaultPipelineRendererAsset()) + , m_managedAssetRuntime(std::move(managedAssetRuntime)) { } std::unique_ptr ScriptableRenderPipelineHostAsset::CreatePipeline() const { std::unique_ptr pipeline = std::make_unique( - m_pipelineRendererAsset); + m_pipelineRendererAsset, + m_managedAssetRuntime); if (pipeline != nullptr) { ConfigurePipeline(*pipeline); } @@ -291,9 +398,11 @@ void ScriptableRenderPipelineHostAsset::ConfigurePipeline( pipeline.SetCameraFrameStandalonePass( CameraFrameStage::DepthOnly, std::make_unique()); - pipeline.SetCameraFrameStandalonePass( - CameraFrameStage::ShadowCaster, - std::make_unique()); + if (m_managedAssetRuntime == nullptr) { + pipeline.SetCameraFrameStandalonePass( + CameraFrameStage::ShadowCaster, + std::make_unique()); + } } FinalColorSettings ScriptableRenderPipelineHostAsset::GetDefaultFinalColorSettings() const { diff --git a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp index c0a57c53..26d0e3ba 100644 --- a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp +++ b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp @@ -1319,6 +1319,11 @@ public: GetPipelineRendererAsset() const override; std::shared_ptr GetPipelineRendererAsset(int32_t rendererIndex) const override; + std::string GetCameraFrameStandalonePassAssetKey( + Rendering::CameraFrameStage stage) const override; + std::string GetCameraFrameStandalonePassAssetKey( + Rendering::CameraFrameStage stage, + int32_t rendererIndex) const override; MonoScriptRuntime* GetRuntime() const { return m_runtime; @@ -1353,6 +1358,11 @@ private: MonoObject* assetObject) const; MonoMethod* ResolveGetPipelineRendererAssetKeyContextualMethod( MonoObject* assetObject) const; + MonoMethod* ResolveGetCameraFrameStandalonePassAssetKeyMethod( + MonoObject* assetObject) const; + MonoMethod* + ResolveGetCameraFrameStandalonePassAssetKeyContextualMethod( + MonoObject* assetObject) const; MonoMethod* ResolveReleaseRuntimeResourcesMethod( MonoObject* assetObject) const; @@ -1369,6 +1379,10 @@ private: mutable MonoMethod* m_getPipelineRendererAssetKeyMethod = nullptr; mutable MonoMethod* m_getPipelineRendererAssetKeyContextualMethod = nullptr; + mutable MonoMethod* m_getCameraFrameStandalonePassAssetKeyMethod = + nullptr; + mutable MonoMethod* + m_getCameraFrameStandalonePassAssetKeyContextualMethod = nullptr; mutable MonoMethod* m_releaseRuntimeResourcesMethod = nullptr; mutable bool m_ownsManagedAssetHandle = false; mutable bool m_assetCreationAttempted = false; @@ -2001,6 +2015,72 @@ MonoManagedRenderPipelineAssetRuntime::GetPipelineRendererAsset( return m_pipelineRendererAsset; } +std::string MonoManagedRenderPipelineAssetRuntime:: + GetCameraFrameStandalonePassAssetKey( + Rendering::CameraFrameStage stage) const { + return GetCameraFrameStandalonePassAssetKey( + stage, + -1); +} + +std::string MonoManagedRenderPipelineAssetRuntime:: + GetCameraFrameStandalonePassAssetKey( + Rendering::CameraFrameStage stage, + int32_t rendererIndex) const { + if (!SyncManagedAssetRuntimeState()) { + return {}; + } + + MonoObject* const assetObject = GetManagedAssetObject(); + if (assetObject == nullptr) { + return {}; + } + + MonoMethod* const contextualMethod = + ResolveGetCameraFrameStandalonePassAssetKeyContextualMethod( + assetObject); + if (contextualMethod != nullptr) { + int32_t managedStage = + static_cast(stage); + void* args[2] = { + &managedStage, + &rendererIndex }; + MonoObject* managedKeyObject = nullptr; + if (!m_runtime->InvokeManagedMethod( + assetObject, + contextualMethod, + args, + &managedKeyObject)) { + return {}; + } + + return MonoStringToUtf8( + reinterpret_cast(managedKeyObject)); + } + + MonoMethod* const method = + ResolveGetCameraFrameStandalonePassAssetKeyMethod( + assetObject); + if (method == nullptr) { + return {}; + } + + int32_t managedStage = + static_cast(stage); + void* args[1] = { &managedStage }; + MonoObject* managedKeyObject = nullptr; + if (!m_runtime->InvokeManagedMethod( + assetObject, + method, + args, + &managedKeyObject)) { + return {}; + } + + return MonoStringToUtf8( + reinterpret_cast(managedKeyObject)); +} + bool MonoManagedRenderPipelineAssetRuntime::AcquireManagedPipelineHandle( uint32_t& outPipelineHandle) const { if (!SyncManagedAssetRuntimeState()) { @@ -2208,6 +2288,8 @@ void MonoManagedRenderPipelineAssetRuntime::ReleaseManagedAsset() const { m_getRuntimeResourceVersionMethod = nullptr; m_getPipelineRendererAssetKeyMethod = nullptr; m_getPipelineRendererAssetKeyContextualMethod = nullptr; + m_getCameraFrameStandalonePassAssetKeyMethod = nullptr; + m_getCameraFrameStandalonePassAssetKeyContextualMethod = nullptr; m_pipelineRendererAsset.reset(); m_pipelineRendererAssetResolved = false; m_contextualPipelineRendererAssets.clear(); @@ -2356,6 +2438,37 @@ MonoManagedRenderPipelineAssetRuntime::ResolveGetPipelineRendererAssetKeyContext return m_getPipelineRendererAssetKeyContextualMethod; } +MonoMethod* +MonoManagedRenderPipelineAssetRuntime:: + ResolveGetCameraFrameStandalonePassAssetKeyMethod( + MonoObject* assetObject) const { + if (m_getCameraFrameStandalonePassAssetKeyMethod == nullptr) { + m_getCameraFrameStandalonePassAssetKeyMethod = + m_runtime->ResolveManagedMethod( + assetObject, + "GetCameraFrameStandalonePassAssetKey", + 1); + } + + return m_getCameraFrameStandalonePassAssetKeyMethod; +} + +MonoMethod* +MonoManagedRenderPipelineAssetRuntime:: + ResolveGetCameraFrameStandalonePassAssetKeyContextualMethod( + MonoObject* assetObject) const { + if (m_getCameraFrameStandalonePassAssetKeyContextualMethod == + nullptr) { + m_getCameraFrameStandalonePassAssetKeyContextualMethod = + m_runtime->ResolveManagedMethod( + assetObject, + "GetCameraFrameStandalonePassAssetKeyContextual", + 2); + } + + return m_getCameraFrameStandalonePassAssetKeyContextualMethod; +} + MonoMethod* MonoManagedRenderPipelineAssetRuntime::ResolveReleaseRuntimeResourcesMethod( MonoObject* assetObject) const { diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RendererBackedRenderPipelineAsset.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RendererBackedRenderPipelineAsset.cs index 0e56a203..f8c599a4 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RendererBackedRenderPipelineAsset.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RendererBackedRenderPipelineAsset.cs @@ -78,6 +78,32 @@ namespace XCEngine.Rendering.Universal : string.Empty; } + protected override string + GetCameraFrameStandalonePassAssetKeyContextual( + CameraFrameStage stage, + int rendererIndex) + { + ScriptableRendererData resolvedRendererData = + GetRendererData(rendererIndex); + if (resolvedRendererData != null) + { + string standalonePassAssetKey = + resolvedRendererData + .GetCameraFrameStandalonePassAssetKeyInstance( + stage); + if (!string.IsNullOrEmpty( + standalonePassAssetKey)) + { + return standalonePassAssetKey; + } + } + + return base + .GetCameraFrameStandalonePassAssetKeyContextual( + stage, + rendererIndex); + } + protected override void ReleaseRuntimeResources() { ReleaseRendererDataRuntimeResources(); diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRendererData.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRendererData.cs index 63ab4c7e..4d69e523 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRendererData.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRendererData.cs @@ -61,6 +61,13 @@ namespace XCEngine.Rendering.Universal return GetPipelineRendererAssetKey(); } + internal string GetCameraFrameStandalonePassAssetKeyInstance( + CameraFrameStage stage) + { + return GetCameraFrameStandalonePassAssetKey( + stage); + } + internal int GetRuntimeStateVersionInstance() { return m_runtimeStateVersion; @@ -153,6 +160,12 @@ namespace XCEngine.Rendering.Universal return string.Empty; } + protected virtual string GetCameraFrameStandalonePassAssetKey( + CameraFrameStage stage) + { + return string.Empty; + } + protected virtual ScriptableRendererFeature[] CreateRendererFeatures() { return Array.Empty(); diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRendererData.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRendererData.cs index e8087cbe..9e916ffc 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRendererData.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRendererData.cs @@ -32,6 +32,20 @@ namespace XCEngine.Rendering.Universal return "BuiltinForward"; } + protected override string GetCameraFrameStandalonePassAssetKey( + CameraFrameStage stage) + { + switch (stage) + { + case CameraFrameStage.ShadowCaster: + return "BuiltinShadowCaster"; + default: + return base + .GetCameraFrameStandalonePassAssetKey( + stage); + } + } + internal UniversalMainSceneData GetMainSceneInstance() { if (mainScene == null) diff --git a/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderPipelineAsset.cs b/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderPipelineAsset.cs index 56baa624..f07b3f86 100644 --- a/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderPipelineAsset.cs +++ b/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderPipelineAsset.cs @@ -58,6 +58,21 @@ namespace XCEngine.Rendering return GetPipelineRendererAssetKey(); } + protected virtual string GetCameraFrameStandalonePassAssetKey( + CameraFrameStage stage) + { + return string.Empty; + } + + protected virtual string + GetCameraFrameStandalonePassAssetKeyContextual( + CameraFrameStage stage, + int rendererIndex) + { + return GetCameraFrameStandalonePassAssetKey( + stage); + } + protected virtual void ReleaseRuntimeResources() { }