diff --git a/docs/used/SRP_URP_ManagedStandaloneStageFallbackPlan_完成归档_2026-04-21.md b/docs/used/SRP_URP_ManagedStandaloneStageFallbackPlan_完成归档_2026-04-21.md new file mode 100644 index 00000000..bcc76c0d --- /dev/null +++ b/docs/used/SRP_URP_ManagedStandaloneStageFallbackPlan_完成归档_2026-04-21.md @@ -0,0 +1,70 @@ +# SRP URP Managed Standalone Stage Fallback Plan + +Date: 2026-04-21 + +## Goal + +Remove the now-dead managed standalone-pass asset-key seam and make +`ShadowCaster` / `DepthOnly` native standalone fallback depend on actual +managed stage-recording capability instead of being silently hardwired. + +This keeps native fallback available for pipelines that still need it, while +allowing Unity-style URP renderer-owned shadow/depth passes to become the real +primary path. + +## Why This Stage + +After the previous SRP stages: + +1. renderer selection is already owned by managed URP; +2. render-scene setup is already managed-owned; +3. directional-shadow planning is already driven by managed camera request + configuration; +4. directional-shadow execution is already managed-configurable through direct + execution context callbacks; +5. `ScriptableRenderer` already knows how to record `ShadowCaster` and + `DepthOnly` through managed pass queues. + +But one architectural inconsistency remains: + +1. native host still exposes `GetCameraFrameStandalonePassAssetKey(...)`; +2. Mono runtime still resolves that method even though no current managed URP + code overrides it anymore; +3. host still carries contextual standalone-pass cache machinery for that seam; +4. native default `DepthOnly` standalone pass can still preempt managed URP + renderer recording if it stays installed. + +That means the shadow/depth path is not fully aligned with Unity-style +`ScriptableRenderer` ownership yet. + +## Scope + +Included: + +1. remove `GetCameraFrameStandalonePassAssetKey*` from managed runtime C++ / + Mono / C# surfaces; +2. delete native contextual standalone-pass cache / factory resolution path + that only existed for that seam; +3. make host-managed `ShadowCaster` / `DepthOnly` fallback installation depend + on whether the current stage recorder actually supports those stages; +4. keep `ObjectId` native standalone pass intact; +5. rebuild `XCEditor` and run old editor smoke. + +Not included: + +1. deferred renderer / GBuffer work; +2. moving object-id rendering into managed SRP; +3. moving native shadow raster implementation into C#; +4. editor-side renderer asset UX changes. + +## Done Criteria + +1. managed SRP runtime no longer exposes `GetCameraFrameStandalonePassAssetKey*`; +2. native host no longer keeps contextual standalone-pass resolution state for + managed pipelines; +3. `ShadowCaster` / `DepthOnly` native standalone fallback is retained only + when managed stage recording does not support those stages; +4. current URP renderer-owned shadow/depth passes become the active path; +5. `cmake --build . --config Debug --target XCEditor` passes; +6. old editor smoke passes for at least about 10 seconds and a fresh + `SceneReady` appears in `editor/bin/Debug/editor.log`. diff --git a/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h b/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h index 9b756420..14932cbf 100644 --- a/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h +++ b/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h @@ -117,18 +117,6 @@ public: (void)rendererIndex; return UsesNativeCameraFramePlanBaseline(); } - 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 760dcc7a..662265ac 100644 --- a/engine/include/XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h +++ b/engine/include/XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h @@ -5,8 +5,6 @@ #include #include -#include -#include namespace XCEngine { namespace Rendering { @@ -70,33 +68,19 @@ public: 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; diff --git a/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp b/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp index c5f1e33b..cb4b9a40 100644 --- a/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp +++ b/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp @@ -1,8 +1,6 @@ #include "Rendering/Pipelines/ScriptableRenderPipelineHost.h" -#include "Debug/Logger.h" #include "Rendering/Execution/DirectionalShadowExecutionState.h" -#include "Rendering/Internal/RenderPipelineFactory.h" #include "Rendering/Pipelines/BuiltinForwardPipeline.h" #include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h" #include "Rendering/Passes/BuiltinDepthOnlyPass.h" @@ -96,7 +94,6 @@ void ScriptableRenderPipelineHost::SetManagedAssetRuntime( std::shared_ptr managedAssetRuntime) { m_managedAssetRuntime = std::move(managedAssetRuntime); - ShutdownContextualCameraFrameStandalonePasses(); } bool ScriptableRenderPipelineHost::Initialize(const RenderContext& context) { @@ -110,7 +107,6 @@ void ScriptableRenderPipelineHost::Shutdown() { if (m_pipelineRenderer != nullptr) { m_pipelineRenderer->Shutdown(); } - ShutdownContextualCameraFrameStandalonePasses(); ShutdownCameraFrameStandalonePasses(); ResetInitializationState(); } @@ -210,27 +206,16 @@ bool ScriptableRenderPipelineHost::ConfigureDirectionalShadowExecutionState( 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( + if (m_managedAssetRuntime != nullptr && + IsCameraFrameScenePassRequestStage(stage) && + SupportsStageRenderGraph( + RenderPipelineStageSupportContext{ stage, - rendererIndex); - if (assetKey.empty()) { - return defaultPass; + rendererIndex })) { + return nullptr; } - return const_cast(this) - ->ResolveContextualCameraFrameStandalonePass( - stage, - rendererIndex, - assetKey); + return RenderPipeline::GetCameraFrameStandalonePass(stage); } bool ScriptableRenderPipelineHost::EnsureInitialized(const RenderContext& context) { @@ -282,18 +267,6 @@ 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) { @@ -351,45 +324,10 @@ 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(), @@ -434,11 +372,9 @@ void ScriptableRenderPipelineHostAsset::ConfigurePipeline( pipeline.SetCameraFrameStandalonePass( CameraFrameStage::DepthOnly, std::make_unique()); - if (m_managedAssetRuntime == nullptr) { - pipeline.SetCameraFrameStandalonePass( - CameraFrameStage::ShadowCaster, - std::make_unique()); - } + 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 319df474..a604b0a5 100644 --- a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp +++ b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp @@ -1504,11 +1504,6 @@ public: bool UsesNativeCameraFramePlanBaseline() const override; bool UsesNativeCameraFramePlanBaseline( 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; @@ -1551,11 +1546,6 @@ private: MonoObject* assetObject) const; MonoMethod* ResolveConfigureDirectionalShadowExecutionStateMethod( MonoObject* assetObject) const; - MonoMethod* ResolveGetCameraFrameStandalonePassAssetKeyMethod( - MonoObject* assetObject) const; - MonoMethod* - ResolveGetCameraFrameStandalonePassAssetKeyContextualMethod( - MonoObject* assetObject) const; MonoMethod* ResolveReleaseRuntimeResourcesMethod( MonoObject* assetObject) const; @@ -1581,10 +1571,6 @@ private: nullptr; mutable MonoMethod* m_configureDirectionalShadowExecutionStateMethod = 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; @@ -2380,72 +2366,6 @@ bool MonoManagedRenderPipelineAssetRuntime::UsesNativeCameraFramePlanBaseline( usesBaseline; } -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()) { @@ -2657,8 +2577,6 @@ void MonoManagedRenderPipelineAssetRuntime::ReleaseManagedAsset() const { m_usesNativeCameraFramePlanBaselineContextualMethod = nullptr; m_configureRenderSceneSetupMethod = nullptr; m_configureDirectionalShadowExecutionStateMethod = nullptr; - m_getCameraFrameStandalonePassAssetKeyMethod = nullptr; - m_getCameraFrameStandalonePassAssetKeyContextualMethod = nullptr; m_pipelineRendererAsset.reset(); m_pipelineRendererAssetResolved = false; m_contextualPipelineRendererAssets.clear(); @@ -2869,37 +2787,6 @@ MonoManagedRenderPipelineAssetRuntime:: return m_configureDirectionalShadowExecutionStateMethod; } -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 586844a6..030c3b1f 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RendererBackedRenderPipelineAsset.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RendererBackedRenderPipelineAsset.cs @@ -110,36 +110,6 @@ namespace XCEngine.Rendering.Universal : string.Empty; } - private protected virtual string GetCameraFrameStandalonePassAssetKey( - CameraFrameStage stage) - { - return string.Empty; - } - - private protected virtual 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 GetCameraFrameStandalonePassAssetKey( - stage); - } - 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 fb9e31b9..7cf6e99d 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRendererData.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRendererData.cs @@ -64,13 +64,6 @@ namespace XCEngine.Rendering.Universal return GetPipelineRendererAssetKey(); } - internal string GetCameraFrameStandalonePassAssetKeyInstance( - CameraFrameStage stage) - { - return GetCameraFrameStandalonePassAssetKey( - stage); - } - internal int GetRuntimeStateVersionInstance() { return m_runtimeStateVersion; @@ -248,12 +241,6 @@ namespace XCEngine.Rendering.Universal return string.Empty; } - private protected virtual string GetCameraFrameStandalonePassAssetKey( - CameraFrameStage stage) - { - return string.Empty; - } - protected virtual ScriptableRendererFeature[] CreateRendererFeatures() { return rendererFeatures ??