From db08861183bebb48569c28e47331fda160a01932 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Tue, 21 Apr 2026 03:01:56 +0800 Subject: [PATCH] refactor(srp): move directional shadow planning policy into managed urp --- ...anagedOwnershipPlan_完成归档_2026-04-21.md | 63 ++++++++++ .../ManagedScriptableRenderPipelineAsset.h | 4 + .../Internal/RenderPipelineFactory.cpp | 113 ++++++++++++++++++ .../Internal/RenderPipelineFactory.h | 19 +++ .../ManagedScriptableRenderPipelineAsset.cpp | 54 ++++++++- .../src/Scripting/Mono/MonoScriptRuntime.cpp | 81 ++++++++++++- .../Universal/UniversalRenderPipelineAsset.cs | 6 + .../Core/ScriptableRenderPipelineAsset.cs | 6 + 8 files changed, 334 insertions(+), 12 deletions(-) create mode 100644 docs/used/SRP_UniversalDirectionalShadowPlanningPolicyManagedOwnershipPlan_完成归档_2026-04-21.md diff --git a/docs/used/SRP_UniversalDirectionalShadowPlanningPolicyManagedOwnershipPlan_完成归档_2026-04-21.md b/docs/used/SRP_UniversalDirectionalShadowPlanningPolicyManagedOwnershipPlan_完成归档_2026-04-21.md new file mode 100644 index 00000000..99dec791 --- /dev/null +++ b/docs/used/SRP_UniversalDirectionalShadowPlanningPolicyManagedOwnershipPlan_完成归档_2026-04-21.md @@ -0,0 +1,63 @@ +# SRP Universal Directional Shadow Planning Policy Managed Ownership Plan 2026-04-21 + +## Goal + +Move directional shadow planning policy selection out of native `RenderPipelineAsset` default flow and into managed URP asset ownership. + +This stage still keeps the actual shadow-plan construction native. +It only makes managed URP explicitly choose which native directional-shadow planning policy asset key should be used. + +## Why This Stage + +The current SRP split already moved: + +1. renderer selection into managed URP; +2. builtin scene feature ownership into managed renderer features; +3. shadow planning settings into managed URP asset settings; +4. shadow-caster stage pass selection into managed URP renderer data; +5. directional shadow execution policy selection into managed URP. + +The remaining shadow entry gap is earlier in the pipeline: + +1. `RenderPipelineAsset::ConfigureCameraRenderRequest()` still blindly applies the native default directional-shadow planning policy; +2. managed URP can only tweak planning settings afterward or clear the request entirely. + +That means the managed package still does not explicitly own which shadow-planning path gets executed. + +## Scope + +Included: + +1. add a native registry for directional shadow planning policies; +2. add managed asset API for directional shadow planning policy asset keys; +3. let Mono runtime resolve those keys from managed pipeline assets; +4. let `ManagedScriptableRenderPipelineAsset` use managed-selected planning policy keys before invoking managed request configuration; +5. let managed request re-planning after settings changes use the same managed-selected policy key; +6. make `UniversalRenderPipelineAsset` explicitly own the builtin directional shadow planning policy key; +7. rebuild `XCEditor` and run old editor smoke. + +Not included: + +1. moving directional shadow plan construction into C#; +2. exposing raw light-selection logic to managed code; +3. renderer-specific shadow planning overrides; +4. shadow atlas / cascade authoring. + +## Acceptance + +This stage is complete when: + +1. managed URP explicitly owns directional shadow planning policy selection; +2. native default planning is no longer blindly hardcoded for managed pipeline assets; +3. managed re-planning after shadow-setting changes uses the same managed-owned planning policy; +4. `XCEditor` build and old editor smoke both pass. + +## Result + +Completed on 2026-04-21. + +Validation: + +1. `cmake --build . --config Debug --target XCEditor` passed; +2. old editor smoke passed with `editor/bin/Debug/XCEngine.exe`; +3. `editor/bin/Debug/editor.log` recorded `SceneReady` at `2026-04-21 03:00:17`. diff --git a/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h b/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h index e2cc8d2a..8d7a722c 100644 --- a/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h +++ b/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h @@ -107,6 +107,10 @@ public: (void)rendererIndex; return GetCameraFrameStandalonePassAssetKey(stage); } + virtual std::string GetDirectionalShadowPlanningPolicyAssetKey() + const { + return {}; + } virtual std::string GetDirectionalShadowExecutionPolicyAssetKey() const { return {}; diff --git a/engine/src/Rendering/Internal/RenderPipelineFactory.cpp b/engine/src/Rendering/Internal/RenderPipelineFactory.cpp index afb2f3dc..c93e2b5e 100644 --- a/engine/src/Rendering/Internal/RenderPipelineFactory.cpp +++ b/engine/src/Rendering/Internal/RenderPipelineFactory.cpp @@ -1,5 +1,7 @@ #include "Rendering/Internal/RenderPipelineFactory.h" +#include + #include "Rendering/Execution/DirectionalShadowExecutionState.h" #include "Rendering/Pipelines/BuiltinForwardPipeline.h" #include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h" @@ -42,6 +44,8 @@ using PipelineRendererAssetRegistry = std::unordered_map; using CameraFrameStandalonePassRegistry = std::unordered_map; +using DirectionalShadowPlanningPolicyRegistry = + std::unordered_map; using DirectionalShadowExecutionPolicyRegistry = std::unordered_map; @@ -55,6 +59,12 @@ CameraFrameStandalonePassRegistry& GetCameraFrameStandalonePassRegistry() { return registry; } +DirectionalShadowPlanningPolicyRegistry& +GetDirectionalShadowPlanningPolicyRegistry() { + static DirectionalShadowPlanningPolicyRegistry registry = {}; + return registry; +} + DirectionalShadowExecutionPolicyRegistry& GetDirectionalShadowExecutionPolicyRegistry() { static DirectionalShadowExecutionPolicyRegistry registry = {}; @@ -71,6 +81,11 @@ std::unordered_set& GetBuiltinCameraFrameStandalonePassKeys() { return builtinKeys; } +std::unordered_set& GetBuiltinDirectionalShadowPlanningPolicyKeys() { + static std::unordered_set builtinKeys = {}; + return builtinKeys; +} + std::unordered_set& GetBuiltinDirectionalShadowExecutionPolicyKeys() { static std::unordered_set builtinKeys = {}; @@ -87,6 +102,11 @@ std::mutex& GetCameraFrameStandalonePassRegistryMutex() { return mutex; } +std::mutex& GetDirectionalShadowPlanningPolicyRegistryMutex() { + static std::mutex mutex; + return mutex; +} + std::mutex& GetDirectionalShadowExecutionPolicyRegistryMutex() { static std::mutex mutex; return mutex; @@ -128,6 +148,29 @@ void EnsureBuiltinCameraFrameStandalonePassRegistryInitialized() { (void)initialized; } +void EnsureBuiltinDirectionalShadowPlanningPolicyRegistryInitialized() { + static const bool initialized = []() { + DirectionalShadowPlanningPolicyRegistry& registry = + GetDirectionalShadowPlanningPolicyRegistry(); + registry.emplace( + "BuiltinDirectionalShadowPlanning", + [](CameraRenderRequest& request, + size_t renderedBaseCameraCount, + size_t renderedRequestCount, + const DirectionalShadowPlanningSettings& settings) { + ApplyDefaultRenderPipelineAssetCameraRenderRequestPolicy( + request, + renderedBaseCameraCount, + renderedRequestCount, + settings); + }); + GetBuiltinDirectionalShadowPlanningPolicyKeys().insert( + "BuiltinDirectionalShadowPlanning"); + return true; + }(); + (void)initialized; +} + void EnsureBuiltinDirectionalShadowExecutionPolicyRegistryInitialized() { static const bool initialized = []() { DirectionalShadowExecutionPolicyRegistry& registry = @@ -303,6 +346,76 @@ std::unique_ptr CreateCameraFrameStandalonePassByKey( return it->second(); } +bool RegisterDirectionalShadowPlanningPolicy( + const std::string& key, + DirectionalShadowPlanningPolicy policy) { + if (key.empty() || !policy) { + return false; + } + + EnsureBuiltinDirectionalShadowPlanningPolicyRegistryInitialized(); + + std::lock_guard lock( + GetDirectionalShadowPlanningPolicyRegistryMutex()); + DirectionalShadowPlanningPolicyRegistry& registry = + GetDirectionalShadowPlanningPolicyRegistry(); + if (registry.find(key) != registry.end()) { + return false; + } + + registry.emplace(key, std::move(policy)); + return true; +} + +bool UnregisterDirectionalShadowPlanningPolicy( + const std::string& key) { + if (key.empty()) { + return false; + } + + EnsureBuiltinDirectionalShadowPlanningPolicyRegistryInitialized(); + + std::lock_guard lock( + GetDirectionalShadowPlanningPolicyRegistryMutex()); + if (GetBuiltinDirectionalShadowPlanningPolicyKeys().find(key) != + GetBuiltinDirectionalShadowPlanningPolicyKeys().end()) { + return false; + } + + DirectionalShadowPlanningPolicyRegistry& registry = + GetDirectionalShadowPlanningPolicyRegistry(); + return registry.erase(key) != 0u; +} + +bool ApplyDirectionalShadowPlanningPolicyByKey( + const std::string& key, + CameraRenderRequest& request, + size_t renderedBaseCameraCount, + size_t renderedRequestCount, + const DirectionalShadowPlanningSettings& settings) { + if (key.empty()) { + return false; + } + + EnsureBuiltinDirectionalShadowPlanningPolicyRegistryInitialized(); + + std::lock_guard lock( + GetDirectionalShadowPlanningPolicyRegistryMutex()); + const DirectionalShadowPlanningPolicyRegistry& registry = + GetDirectionalShadowPlanningPolicyRegistry(); + const auto it = registry.find(key); + if (it == registry.end() || !it->second) { + return false; + } + + it->second( + request, + renderedBaseCameraCount, + renderedRequestCount, + settings); + return true; +} + bool RegisterDirectionalShadowExecutionPolicy( const std::string& key, DirectionalShadowExecutionPolicy policy) { diff --git a/engine/src/Rendering/Internal/RenderPipelineFactory.h b/engine/src/Rendering/Internal/RenderPipelineFactory.h index 6d40087e..1e273173 100644 --- a/engine/src/Rendering/Internal/RenderPipelineFactory.h +++ b/engine/src/Rendering/Internal/RenderPipelineFactory.h @@ -11,7 +11,9 @@ class NativeSceneRenderer; class RenderPipeline; class RenderPipelineAsset; class RenderPass; +struct CameraRenderRequest; struct CameraFramePlan; +struct DirectionalShadowPlanningSettings; struct DirectionalShadowExecutionState; struct DirectionalShadowSurfaceAllocation; @@ -21,6 +23,12 @@ using PipelineRendererAssetFactory = std::function()>; using CameraFrameStandalonePassFactory = std::function()>; +using DirectionalShadowPlanningPolicy = + std::function; using DirectionalShadowExecutionPolicy = std::function CreateCameraFrameStandalonePassByKey( const std::string& key); +bool RegisterDirectionalShadowPlanningPolicy( + const std::string& key, + DirectionalShadowPlanningPolicy policy); +bool UnregisterDirectionalShadowPlanningPolicy( + const std::string& key); +bool ApplyDirectionalShadowPlanningPolicyByKey( + const std::string& key, + CameraRenderRequest& request, + size_t renderedBaseCameraCount, + size_t renderedRequestCount, + const DirectionalShadowPlanningSettings& settings); bool RegisterDirectionalShadowExecutionPolicy( const std::string& key, DirectionalShadowExecutionPolicy policy); diff --git a/engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp b/engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp index 27f81870..32a33800 100644 --- a/engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp +++ b/engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp @@ -1,6 +1,8 @@ #include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h" +#include "Debug/Logger.h" #include "Rendering/GraphicsSettingsState.h" +#include "Rendering/Internal/RenderPipelineFactory.h" #include @@ -8,6 +10,39 @@ namespace XCEngine { namespace Rendering { namespace Pipelines { +namespace { + +void ApplyManagedDirectionalShadowPlanningPolicyOrDefault( + const std::string& assetKey, + CameraRenderRequest& request, + size_t renderedBaseCameraCount, + size_t renderedRequestCount, + const DirectionalShadowPlanningSettings& directionalShadowSettings) { + if (assetKey.empty()) { + ApplyDefaultRenderPipelineAssetCameraRenderRequestPolicy( + request, + renderedBaseCameraCount, + renderedRequestCount, + directionalShadowSettings); + return; + } + + if (!Rendering::Internal::ApplyDirectionalShadowPlanningPolicyByKey( + assetKey, + request, + renderedBaseCameraCount, + renderedRequestCount, + directionalShadowSettings)) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + Containers::String( + "ManagedScriptableRenderPipelineAsset failed to resolve directional shadow planning policy asset key: ") + + assetKey.c_str()); + } +} + +} // namespace + ManagedScriptableRenderPipelineAsset::ManagedScriptableRenderPipelineAsset( ManagedRenderPipelineAssetDescriptor descriptor) : m_descriptor(std::move(descriptor)) { @@ -89,21 +124,28 @@ void ManagedScriptableRenderPipelineAsset::ConfigureCameraRenderRequest( size_t renderedBaseCameraCount, size_t renderedRequestCount, const DirectionalShadowPlanningSettings& directionalShadowSettings) const { - RenderPipelineAsset::ConfigureCameraRenderRequest( - request, - renderedBaseCameraCount, - renderedRequestCount, - directionalShadowSettings); - if (const std::shared_ptr runtime = ResolveManagedAssetRuntime(); runtime != nullptr) { + ApplyManagedDirectionalShadowPlanningPolicyOrDefault( + runtime->GetDirectionalShadowPlanningPolicyAssetKey(), + request, + renderedBaseCameraCount, + renderedRequestCount, + directionalShadowSettings); runtime->ConfigureCameraRenderRequest( request, renderedBaseCameraCount, renderedRequestCount, directionalShadowSettings); + return; } + + RenderPipelineAsset::ConfigureCameraRenderRequest( + request, + renderedBaseCameraCount, + renderedRequestCount, + directionalShadowSettings); } void ManagedScriptableRenderPipelineAsset::ConfigureCameraFramePlan( diff --git a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp index 186d3aba..16709ec7 100644 --- a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp +++ b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp @@ -1319,6 +1319,8 @@ public: GetPipelineRendererAsset() const override; std::shared_ptr GetPipelineRendererAsset(int32_t rendererIndex) const override; + std::string GetDirectionalShadowPlanningPolicyAssetKey() const + override; std::string GetDirectionalShadowExecutionPolicyAssetKey() const override; std::string GetDirectionalShadowExecutionPolicyAssetKey( @@ -1362,6 +1364,8 @@ private: MonoObject* assetObject) const; MonoMethod* ResolveGetPipelineRendererAssetKeyContextualMethod( MonoObject* assetObject) const; + MonoMethod* ResolveGetDirectionalShadowPlanningPolicyAssetKeyMethod( + MonoObject* assetObject) const; MonoMethod* ResolveGetDirectionalShadowExecutionPolicyAssetKeyMethod( MonoObject* assetObject) const; MonoMethod* @@ -1388,6 +1392,8 @@ private: mutable MonoMethod* m_getPipelineRendererAssetKeyMethod = nullptr; mutable MonoMethod* m_getPipelineRendererAssetKeyContextualMethod = nullptr; + mutable MonoMethod* + m_getDirectionalShadowPlanningPolicyAssetKeyMethod = nullptr; mutable MonoMethod* m_getDirectionalShadowExecutionPolicyAssetKeyMethod = nullptr; mutable MonoMethod* @@ -1846,15 +1852,30 @@ void MonoManagedRenderPipelineAssetRuntime::ConfigureCameraRenderRequest( method, args, nullptr); + const std::string directionalShadowPlanningPolicyAssetKey = + GetDirectionalShadowPlanningPolicyAssetKey(); if (requestContextState.suppressDirectionalShadow) { request.directionalShadow = {}; } else if (requestContextState.directionalShadowPlanningSettingsDirty) { request.directionalShadow = {}; - Rendering::ApplyDefaultRenderPipelineAssetCameraRenderRequestPolicy( - request, - renderedBaseCameraCount, - renderedRequestCount, - requestContextState.directionalShadowPlanningSettings); + if (directionalShadowPlanningPolicyAssetKey.empty()) { + Rendering::ApplyDefaultRenderPipelineAssetCameraRenderRequestPolicy( + request, + renderedBaseCameraCount, + renderedRequestCount, + requestContextState.directionalShadowPlanningSettings); + } else if (!Rendering::Internal::ApplyDirectionalShadowPlanningPolicyByKey( + directionalShadowPlanningPolicyAssetKey, + request, + renderedBaseCameraCount, + renderedRequestCount, + requestContextState.directionalShadowPlanningSettings)) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + Containers::String( + "MonoManagedRenderPipelineAssetRuntime failed to resolve directional shadow planning policy asset key: ") + + directionalShadowPlanningPolicyAssetKey.c_str()); + } } UnregisterManagedCameraRenderRequestContextState( requestContextHandle); @@ -1935,7 +1956,7 @@ MonoManagedRenderPipelineAssetRuntime::GetPipelineRendererAsset() const { std::shared_ptr MonoManagedRenderPipelineAssetRuntime::GetPipelineRendererAsset( - int32_t rendererIndex) const { + int32_t rendererIndex) const { if (!SyncManagedAssetRuntimeState()) { return nullptr; } @@ -2029,6 +2050,37 @@ MonoManagedRenderPipelineAssetRuntime::GetPipelineRendererAsset( return m_pipelineRendererAsset; } +std::string MonoManagedRenderPipelineAssetRuntime:: + GetDirectionalShadowPlanningPolicyAssetKey() const { + if (!SyncManagedAssetRuntimeState()) { + return {}; + } + + MonoObject* const assetObject = GetManagedAssetObject(); + if (assetObject == nullptr) { + return {}; + } + + MonoMethod* const method = + ResolveGetDirectionalShadowPlanningPolicyAssetKeyMethod( + assetObject); + if (method == nullptr) { + return {}; + } + + MonoObject* managedKeyObject = nullptr; + if (!m_runtime->InvokeManagedMethod( + assetObject, + method, + nullptr, + &managedKeyObject)) { + return {}; + } + + return MonoStringToUtf8( + reinterpret_cast(managedKeyObject)); +} + std::string MonoManagedRenderPipelineAssetRuntime:: GetDirectionalShadowExecutionPolicyAssetKey() const { return GetDirectionalShadowExecutionPolicyAssetKey(-1); @@ -2357,6 +2409,7 @@ void MonoManagedRenderPipelineAssetRuntime::ReleaseManagedAsset() const { m_getRuntimeResourceVersionMethod = nullptr; m_getPipelineRendererAssetKeyMethod = nullptr; m_getPipelineRendererAssetKeyContextualMethod = nullptr; + m_getDirectionalShadowPlanningPolicyAssetKeyMethod = nullptr; m_getDirectionalShadowExecutionPolicyAssetKeyMethod = nullptr; m_getDirectionalShadowExecutionPolicyAssetKeyContextualMethod = nullptr; @@ -2510,6 +2563,22 @@ MonoManagedRenderPipelineAssetRuntime::ResolveGetPipelineRendererAssetKeyContext return m_getPipelineRendererAssetKeyContextualMethod; } +MonoMethod* +MonoManagedRenderPipelineAssetRuntime:: + ResolveGetDirectionalShadowPlanningPolicyAssetKeyMethod( + MonoObject* assetObject) const { + if (m_getDirectionalShadowPlanningPolicyAssetKeyMethod == + nullptr) { + m_getDirectionalShadowPlanningPolicyAssetKeyMethod = + m_runtime->ResolveManagedMethod( + assetObject, + "GetDirectionalShadowPlanningPolicyAssetKey", + 0); + } + + return m_getDirectionalShadowPlanningPolicyAssetKeyMethod; +} + MonoMethod* MonoManagedRenderPipelineAssetRuntime:: ResolveGetDirectionalShadowExecutionPolicyAssetKeyMethod( diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderPipelineAsset.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderPipelineAsset.cs index 17b4bd3c..da3a7228 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderPipelineAsset.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderPipelineAsset.cs @@ -20,6 +20,12 @@ namespace XCEngine.Rendering.Universal return new UniversalRenderPipeline(this); } + protected override string + GetDirectionalShadowPlanningPolicyAssetKey() + { + return "BuiltinDirectionalShadowPlanning"; + } + protected override void ConfigureRendererCameraRequest( RendererCameraRequestContext context) { diff --git a/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderPipelineAsset.cs b/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderPipelineAsset.cs index 1e594b82..f1945d27 100644 --- a/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderPipelineAsset.cs +++ b/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderPipelineAsset.cs @@ -73,6 +73,12 @@ namespace XCEngine.Rendering stage); } + protected virtual string + GetDirectionalShadowPlanningPolicyAssetKey() + { + return string.Empty; + } + protected virtual string GetDirectionalShadowExecutionPolicyAssetKey() {