refactor(srp): move render scene setup into managed urp

This commit is contained in:
2026-04-21 03:09:08 +08:00
parent db08861183
commit 8e4576de95
13 changed files with 388 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
# SRP Universal Render Scene Setup Policy Managed Ownership Plan 2026-04-21
## Goal
Move render-scene setup policy selection out of native `RenderPipeline` hardcoded defaults and into managed URP renderer-data ownership.
This stage still keeps the actual `RenderSceneData` population native.
It only makes managed URP explicitly choose which native scene-setup 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 policy into managed URP asset ownership;
4. shadow execution policy into managed URP renderer-data ownership;
5. shadow-caster standalone pass selection into managed URP renderer-data ownership.
But `RenderPipeline::ConfigureRenderSceneData()` still directly hardcodes:
1. global shader keyword setup;
2. environment / skybox setup.
That means managed URP still cannot explicitly own how extracted scene data is finalized before the renderer consumes it.
## Scope
Included:
1. add a native registry for render-scene setup policies;
2. add managed asset / renderer-data API for render-scene setup policy asset keys;
3. let Mono runtime resolve those keys from managed pipeline assets;
4. let `ScriptableRenderPipelineHost` use managed-selected render-scene setup policy keys;
5. make `UniversalRendererData` explicitly own the builtin render-scene setup policy key;
6. rebuild `XCEditor` and run old editor smoke.
Not included:
1. exposing mutable `RenderSceneData` editing directly to C#;
2. custom managed skybox authoring APIs;
3. custom global shader keyword authoring APIs;
4. changing render-scene extraction itself.
## Acceptance
This stage is complete when:
1. managed URP explicitly owns render-scene setup policy selection;
2. native host no longer blindly applies the default render-scene setup for managed pipelines;
3. builtin scene setup still works for the default URP renderer;
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:07:29`.

View File

@@ -96,6 +96,14 @@ public:
(void)rendererIndex;
return GetPipelineRendererAsset();
}
virtual std::string GetRenderSceneSetupPolicyAssetKey() const {
return {};
}
virtual std::string GetRenderSceneSetupPolicyAssetKey(
int32_t rendererIndex) const {
(void)rendererIndex;
return GetRenderSceneSetupPolicyAssetKey();
}
virtual std::string GetCameraFrameStandalonePassAssetKey(
CameraFrameStage stage) const {
(void)stage;

View File

@@ -58,6 +58,9 @@ public:
const RenderContext& context,
const RenderSurface& surface,
const RenderSceneData& sceneData) override;
void ConfigureRenderSceneData(
const CameraFramePlan& plan,
RenderSceneData& sceneData) const override;
bool ConfigureDirectionalShadowExecutionState(
const CameraFramePlan& plan,
const DirectionalShadowSurfaceAllocation& shadowAllocation,

View File

@@ -29,6 +29,9 @@ void ApplyDefaultRenderPipelineDirectionalShadowExecutionPolicy(
const CameraFramePlan& plan,
const DirectionalShadowSurfaceAllocation& shadowAllocation,
DirectionalShadowExecutionState& shadowState);
void ApplyDefaultRenderPipelineSceneSetupPolicy(
const CameraFramePlan& plan,
RenderSceneData& sceneData);
struct RenderPipelineStageRenderGraphContext {
RenderGraphBuilder& graphBuilder;

View File

@@ -1,6 +1,7 @@
#include "Rendering/Internal/RenderPipelineFactory.h"
#include <XCEngine/Rendering/RenderPipelineAsset.h>
#include <XCEngine/Rendering/RenderPipeline.h>
#include "Rendering/Execution/DirectionalShadowExecutionState.h"
#include "Rendering/Pipelines/BuiltinForwardPipeline.h"
@@ -46,6 +47,8 @@ using CameraFrameStandalonePassRegistry =
std::unordered_map<std::string, CameraFrameStandalonePassFactory>;
using DirectionalShadowPlanningPolicyRegistry =
std::unordered_map<std::string, DirectionalShadowPlanningPolicy>;
using RenderSceneSetupPolicyRegistry =
std::unordered_map<std::string, RenderSceneSetupPolicy>;
using DirectionalShadowExecutionPolicyRegistry =
std::unordered_map<std::string, DirectionalShadowExecutionPolicy>;
@@ -65,6 +68,12 @@ GetDirectionalShadowPlanningPolicyRegistry() {
return registry;
}
RenderSceneSetupPolicyRegistry&
GetRenderSceneSetupPolicyRegistry() {
static RenderSceneSetupPolicyRegistry registry = {};
return registry;
}
DirectionalShadowExecutionPolicyRegistry&
GetDirectionalShadowExecutionPolicyRegistry() {
static DirectionalShadowExecutionPolicyRegistry registry = {};
@@ -86,6 +95,11 @@ std::unordered_set<std::string>& GetBuiltinDirectionalShadowPlanningPolicyKeys()
return builtinKeys;
}
std::unordered_set<std::string>& GetBuiltinRenderSceneSetupPolicyKeys() {
static std::unordered_set<std::string> builtinKeys = {};
return builtinKeys;
}
std::unordered_set<std::string>&
GetBuiltinDirectionalShadowExecutionPolicyKeys() {
static std::unordered_set<std::string> builtinKeys = {};
@@ -107,6 +121,11 @@ std::mutex& GetDirectionalShadowPlanningPolicyRegistryMutex() {
return mutex;
}
std::mutex& GetRenderSceneSetupPolicyRegistryMutex() {
static std::mutex mutex;
return mutex;
}
std::mutex& GetDirectionalShadowExecutionPolicyRegistryMutex() {
static std::mutex mutex;
return mutex;
@@ -171,6 +190,25 @@ void EnsureBuiltinDirectionalShadowPlanningPolicyRegistryInitialized() {
(void)initialized;
}
void EnsureBuiltinRenderSceneSetupPolicyRegistryInitialized() {
static const bool initialized = []() {
RenderSceneSetupPolicyRegistry& registry =
GetRenderSceneSetupPolicyRegistry();
registry.emplace(
"BuiltinDefaultSceneSetup",
[](const CameraFramePlan& plan,
RenderSceneData& sceneData) {
ApplyDefaultRenderPipelineSceneSetupPolicy(
plan,
sceneData);
});
GetBuiltinRenderSceneSetupPolicyKeys().insert(
"BuiltinDefaultSceneSetup");
return true;
}();
(void)initialized;
}
void EnsureBuiltinDirectionalShadowExecutionPolicyRegistryInitialized() {
static const bool initialized = []() {
DirectionalShadowExecutionPolicyRegistry& registry =
@@ -416,6 +454,72 @@ bool ApplyDirectionalShadowPlanningPolicyByKey(
return true;
}
bool RegisterRenderSceneSetupPolicy(
const std::string& key,
RenderSceneSetupPolicy policy) {
if (key.empty() || !policy) {
return false;
}
EnsureBuiltinRenderSceneSetupPolicyRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetRenderSceneSetupPolicyRegistryMutex());
RenderSceneSetupPolicyRegistry& registry =
GetRenderSceneSetupPolicyRegistry();
if (registry.find(key) != registry.end()) {
return false;
}
registry.emplace(key, std::move(policy));
return true;
}
bool UnregisterRenderSceneSetupPolicy(
const std::string& key) {
if (key.empty()) {
return false;
}
EnsureBuiltinRenderSceneSetupPolicyRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetRenderSceneSetupPolicyRegistryMutex());
if (GetBuiltinRenderSceneSetupPolicyKeys().find(key) !=
GetBuiltinRenderSceneSetupPolicyKeys().end()) {
return false;
}
RenderSceneSetupPolicyRegistry& registry =
GetRenderSceneSetupPolicyRegistry();
return registry.erase(key) != 0u;
}
bool ApplyRenderSceneSetupPolicyByKey(
const std::string& key,
const CameraFramePlan& plan,
RenderSceneData& sceneData) {
if (key.empty()) {
return false;
}
EnsureBuiltinRenderSceneSetupPolicyRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetRenderSceneSetupPolicyRegistryMutex());
const RenderSceneSetupPolicyRegistry& registry =
GetRenderSceneSetupPolicyRegistry();
const auto it = registry.find(key);
if (it == registry.end() || !it->second) {
return false;
}
it->second(
plan,
sceneData);
return true;
}
bool RegisterDirectionalShadowExecutionPolicy(
const std::string& key,
DirectionalShadowExecutionPolicy policy) {

View File

@@ -13,6 +13,7 @@ class RenderPipelineAsset;
class RenderPass;
struct CameraRenderRequest;
struct CameraFramePlan;
struct RenderSceneData;
struct DirectionalShadowPlanningSettings;
struct DirectionalShadowExecutionState;
struct DirectionalShadowSurfaceAllocation;
@@ -29,6 +30,10 @@ using DirectionalShadowPlanningPolicy =
size_t,
size_t,
const DirectionalShadowPlanningSettings&)>;
using RenderSceneSetupPolicy =
std::function<void(
const CameraFramePlan&,
RenderSceneData&)>;
using DirectionalShadowExecutionPolicy =
std::function<bool(
const CameraFramePlan&,
@@ -61,6 +66,15 @@ bool ApplyDirectionalShadowPlanningPolicyByKey(
size_t renderedBaseCameraCount,
size_t renderedRequestCount,
const DirectionalShadowPlanningSettings& settings);
bool RegisterRenderSceneSetupPolicy(
const std::string& key,
RenderSceneSetupPolicy policy);
bool UnregisterRenderSceneSetupPolicy(
const std::string& key);
bool ApplyRenderSceneSetupPolicyByKey(
const std::string& key,
const CameraFramePlan& plan,
RenderSceneData& sceneData);
bool RegisterDirectionalShadowExecutionPolicy(
const std::string& key,
DirectionalShadowExecutionPolicy policy);

View File

@@ -171,6 +171,42 @@ bool ScriptableRenderPipelineHost::Render(
m_pipelineRenderer->Render(context, surface, sceneData);
}
void ScriptableRenderPipelineHost::ConfigureRenderSceneData(
const CameraFramePlan& plan,
RenderSceneData& sceneData) const {
if (m_managedAssetRuntime == nullptr) {
RenderPipeline::ConfigureRenderSceneData(
plan,
sceneData);
return;
}
const std::string assetKey =
m_managedAssetRuntime
->GetRenderSceneSetupPolicyAssetKey(
plan.request.rendererIndex);
if (assetKey.empty()) {
RenderPipeline::ConfigureRenderSceneData(
plan,
sceneData);
return;
}
if (!Rendering::Internal::ApplyRenderSceneSetupPolicyByKey(
assetKey,
plan,
sceneData)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
Containers::String(
"ScriptableRenderPipelineHost failed to resolve render scene setup policy asset key: ") +
assetKey.c_str());
RenderPipeline::ConfigureRenderSceneData(
plan,
sceneData);
}
}
bool ScriptableRenderPipelineHost::ConfigureDirectionalShadowExecutionState(
const CameraFramePlan& plan,
const DirectionalShadowSurfaceAllocation& shadowAllocation,

View File

@@ -52,6 +52,14 @@ RenderEnvironmentData BuildDefaultEnvironmentData(const CameraFramePlan& plan) {
void RenderPipeline::ConfigureRenderSceneData(
const CameraFramePlan& plan,
RenderSceneData& sceneData) const {
ApplyDefaultRenderPipelineSceneSetupPolicy(
plan,
sceneData);
}
void ApplyDefaultRenderPipelineSceneSetupPolicy(
const CameraFramePlan& plan,
RenderSceneData& sceneData) {
sceneData.globalShaderKeywords =
BuildDefaultSceneGlobalShaderKeywords(sceneData);
sceneData.environment =

View File

@@ -1319,6 +1319,10 @@ public:
GetPipelineRendererAsset() const override;
std::shared_ptr<const Rendering::RenderPipelineAsset>
GetPipelineRendererAsset(int32_t rendererIndex) const override;
std::string GetRenderSceneSetupPolicyAssetKey() const
override;
std::string GetRenderSceneSetupPolicyAssetKey(
int32_t rendererIndex) const override;
std::string GetDirectionalShadowPlanningPolicyAssetKey() const
override;
std::string GetDirectionalShadowExecutionPolicyAssetKey() const
@@ -1364,6 +1368,10 @@ private:
MonoObject* assetObject) const;
MonoMethod* ResolveGetPipelineRendererAssetKeyContextualMethod(
MonoObject* assetObject) const;
MonoMethod* ResolveGetRenderSceneSetupPolicyAssetKeyMethod(
MonoObject* assetObject) const;
MonoMethod* ResolveGetRenderSceneSetupPolicyAssetKeyContextualMethod(
MonoObject* assetObject) const;
MonoMethod* ResolveGetDirectionalShadowPlanningPolicyAssetKeyMethod(
MonoObject* assetObject) const;
MonoMethod* ResolveGetDirectionalShadowExecutionPolicyAssetKeyMethod(
@@ -1392,6 +1400,11 @@ private:
mutable MonoMethod* m_getPipelineRendererAssetKeyMethod = nullptr;
mutable MonoMethod* m_getPipelineRendererAssetKeyContextualMethod =
nullptr;
mutable MonoMethod* m_getRenderSceneSetupPolicyAssetKeyMethod =
nullptr;
mutable MonoMethod*
m_getRenderSceneSetupPolicyAssetKeyContextualMethod =
nullptr;
mutable MonoMethod*
m_getDirectionalShadowPlanningPolicyAssetKeyMethod = nullptr;
mutable MonoMethod*
@@ -2050,6 +2063,61 @@ MonoManagedRenderPipelineAssetRuntime::GetPipelineRendererAsset(
return m_pipelineRendererAsset;
}
std::string MonoManagedRenderPipelineAssetRuntime::
GetRenderSceneSetupPolicyAssetKey() const {
return GetRenderSceneSetupPolicyAssetKey(-1);
}
std::string MonoManagedRenderPipelineAssetRuntime::
GetRenderSceneSetupPolicyAssetKey(
int32_t rendererIndex) const {
if (!SyncManagedAssetRuntimeState()) {
return {};
}
MonoObject* const assetObject = GetManagedAssetObject();
if (assetObject == nullptr) {
return {};
}
MonoMethod* const contextualMethod =
ResolveGetRenderSceneSetupPolicyAssetKeyContextualMethod(
assetObject);
if (contextualMethod != nullptr) {
void* args[1] = { &rendererIndex };
MonoObject* managedKeyObject = nullptr;
if (!m_runtime->InvokeManagedMethod(
assetObject,
contextualMethod,
args,
&managedKeyObject)) {
return {};
}
return MonoStringToUtf8(
reinterpret_cast<MonoString*>(managedKeyObject));
}
MonoMethod* const method =
ResolveGetRenderSceneSetupPolicyAssetKeyMethod(
assetObject);
if (method == nullptr) {
return {};
}
MonoObject* managedKeyObject = nullptr;
if (!m_runtime->InvokeManagedMethod(
assetObject,
method,
nullptr,
&managedKeyObject)) {
return {};
}
return MonoStringToUtf8(
reinterpret_cast<MonoString*>(managedKeyObject));
}
std::string MonoManagedRenderPipelineAssetRuntime::
GetDirectionalShadowPlanningPolicyAssetKey() const {
if (!SyncManagedAssetRuntimeState()) {
@@ -2409,6 +2477,8 @@ void MonoManagedRenderPipelineAssetRuntime::ReleaseManagedAsset() const {
m_getRuntimeResourceVersionMethod = nullptr;
m_getPipelineRendererAssetKeyMethod = nullptr;
m_getPipelineRendererAssetKeyContextualMethod = nullptr;
m_getRenderSceneSetupPolicyAssetKeyMethod = nullptr;
m_getRenderSceneSetupPolicyAssetKeyContextualMethod = nullptr;
m_getDirectionalShadowPlanningPolicyAssetKeyMethod = nullptr;
m_getDirectionalShadowExecutionPolicyAssetKeyMethod = nullptr;
m_getDirectionalShadowExecutionPolicyAssetKeyContextualMethod =
@@ -2563,6 +2633,37 @@ MonoManagedRenderPipelineAssetRuntime::ResolveGetPipelineRendererAssetKeyContext
return m_getPipelineRendererAssetKeyContextualMethod;
}
MonoMethod*
MonoManagedRenderPipelineAssetRuntime::
ResolveGetRenderSceneSetupPolicyAssetKeyMethod(
MonoObject* assetObject) const {
if (m_getRenderSceneSetupPolicyAssetKeyMethod == nullptr) {
m_getRenderSceneSetupPolicyAssetKeyMethod =
m_runtime->ResolveManagedMethod(
assetObject,
"GetRenderSceneSetupPolicyAssetKey",
0);
}
return m_getRenderSceneSetupPolicyAssetKeyMethod;
}
MonoMethod*
MonoManagedRenderPipelineAssetRuntime::
ResolveGetRenderSceneSetupPolicyAssetKeyContextualMethod(
MonoObject* assetObject) const {
if (m_getRenderSceneSetupPolicyAssetKeyContextualMethod ==
nullptr) {
m_getRenderSceneSetupPolicyAssetKeyContextualMethod =
m_runtime->ResolveManagedMethod(
assetObject,
"GetRenderSceneSetupPolicyAssetKeyContextual",
1);
}
return m_getRenderSceneSetupPolicyAssetKeyContextualMethod;
}
MonoMethod*
MonoManagedRenderPipelineAssetRuntime::
ResolveGetDirectionalShadowPlanningPolicyAssetKeyMethod(

View File

@@ -78,6 +78,28 @@ namespace XCEngine.Rendering.Universal
: string.Empty;
}
protected override string
GetRenderSceneSetupPolicyAssetKeyContextual(
int rendererIndex)
{
ScriptableRendererData resolvedRendererData =
GetRendererData(rendererIndex);
if (resolvedRendererData != null)
{
string assetKey =
resolvedRendererData
.GetRenderSceneSetupPolicyAssetKeyInstance();
if (!string.IsNullOrEmpty(assetKey))
{
return assetKey;
}
}
return base
.GetRenderSceneSetupPolicyAssetKeyContextual(
rendererIndex);
}
protected override string
GetCameraFrameStandalonePassAssetKeyContextual(
CameraFrameStage stage,

View File

@@ -61,6 +61,11 @@ namespace XCEngine.Rendering.Universal
return GetPipelineRendererAssetKey();
}
internal string GetRenderSceneSetupPolicyAssetKeyInstance()
{
return GetRenderSceneSetupPolicyAssetKey();
}
internal string GetCameraFrameStandalonePassAssetKeyInstance(
CameraFrameStage stage)
{
@@ -166,6 +171,11 @@ namespace XCEngine.Rendering.Universal
return string.Empty;
}
protected virtual string GetRenderSceneSetupPolicyAssetKey()
{
return string.Empty;
}
protected virtual string GetCameraFrameStandalonePassAssetKey(
CameraFrameStage stage)
{

View File

@@ -32,6 +32,11 @@ namespace XCEngine.Rendering.Universal
return "BuiltinForward";
}
protected override string GetRenderSceneSetupPolicyAssetKey()
{
return "BuiltinDefaultSceneSetup";
}
protected override string GetCameraFrameStandalonePassAssetKey(
CameraFrameStage stage)
{

View File

@@ -58,6 +58,18 @@ namespace XCEngine.Rendering
return GetPipelineRendererAssetKey();
}
protected virtual string GetRenderSceneSetupPolicyAssetKey()
{
return string.Empty;
}
protected virtual string
GetRenderSceneSetupPolicyAssetKeyContextual(
int rendererIndex)
{
return GetRenderSceneSetupPolicyAssetKey();
}
protected virtual string GetCameraFrameStandalonePassAssetKey(
CameraFrameStage stage)
{