feat(srp): add managed camera frame planning seam
Expose native camera frame planning controls to managed pipeline assets and renderer features. Allow managed planning to override fullscreen stage heuristics while keeping CameraFramePlan as the native execution contract. Add scripting coverage, probe assets, and archive the phase plan after build, test, and editor smoke validation.
This commit is contained in:
@@ -111,6 +111,11 @@ struct ManagedCameraRenderRequestContextState {
|
||||
size_t renderedRequestCount = 0u;
|
||||
};
|
||||
|
||||
struct ManagedScriptableRenderPipelinePlanningContextState {
|
||||
uint64_t handle = 0;
|
||||
Rendering::CameraFramePlan* plan = nullptr;
|
||||
};
|
||||
|
||||
uint64_t& GetManagedScriptableRenderContextNextHandle() {
|
||||
static uint64_t nextHandle = 1;
|
||||
return nextHandle;
|
||||
@@ -274,6 +279,92 @@ void UnregisterManagedCameraRenderRequestContextState(
|
||||
GetManagedCameraRenderRequestContextRegistry().erase(handle);
|
||||
}
|
||||
|
||||
uint64_t& GetManagedScriptableRenderPipelinePlanningContextNextHandle() {
|
||||
static uint64_t nextHandle = 1;
|
||||
return nextHandle;
|
||||
}
|
||||
|
||||
std::unordered_map<uint64_t, ManagedScriptableRenderPipelinePlanningContextState*>&
|
||||
GetManagedScriptableRenderPipelinePlanningContextRegistry() {
|
||||
static std::unordered_map<
|
||||
uint64_t,
|
||||
ManagedScriptableRenderPipelinePlanningContextState*> registry;
|
||||
return registry;
|
||||
}
|
||||
|
||||
ManagedScriptableRenderPipelinePlanningContextState*
|
||||
FindManagedScriptableRenderPipelinePlanningContextState(
|
||||
uint64_t handle) {
|
||||
const auto it =
|
||||
GetManagedScriptableRenderPipelinePlanningContextRegistry().find(
|
||||
handle);
|
||||
return it !=
|
||||
GetManagedScriptableRenderPipelinePlanningContextRegistry().end()
|
||||
? it->second
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
uint64_t RegisterManagedScriptableRenderPipelinePlanningContextState(
|
||||
ManagedScriptableRenderPipelinePlanningContextState& state) {
|
||||
uint64_t handle =
|
||||
GetManagedScriptableRenderPipelinePlanningContextNextHandle()++;
|
||||
if (handle == 0) {
|
||||
handle =
|
||||
GetManagedScriptableRenderPipelinePlanningContextNextHandle()++;
|
||||
}
|
||||
|
||||
state.handle = handle;
|
||||
GetManagedScriptableRenderPipelinePlanningContextRegistry()[handle] =
|
||||
&state;
|
||||
return handle;
|
||||
}
|
||||
|
||||
void UnregisterManagedScriptableRenderPipelinePlanningContextState(
|
||||
uint64_t handle) {
|
||||
if (handle == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
GetManagedScriptableRenderPipelinePlanningContextRegistry().erase(handle);
|
||||
}
|
||||
|
||||
bool TryResolveManagedCameraFrameStage(
|
||||
int32_t value,
|
||||
Rendering::CameraFrameStage& outStage) {
|
||||
switch (value) {
|
||||
case static_cast<int32_t>(Rendering::CameraFrameStage::PreScenePasses):
|
||||
outStage = Rendering::CameraFrameStage::PreScenePasses;
|
||||
return true;
|
||||
case static_cast<int32_t>(Rendering::CameraFrameStage::ShadowCaster):
|
||||
outStage = Rendering::CameraFrameStage::ShadowCaster;
|
||||
return true;
|
||||
case static_cast<int32_t>(Rendering::CameraFrameStage::DepthOnly):
|
||||
outStage = Rendering::CameraFrameStage::DepthOnly;
|
||||
return true;
|
||||
case static_cast<int32_t>(Rendering::CameraFrameStage::MainScene):
|
||||
outStage = Rendering::CameraFrameStage::MainScene;
|
||||
return true;
|
||||
case static_cast<int32_t>(Rendering::CameraFrameStage::PostProcess):
|
||||
outStage = Rendering::CameraFrameStage::PostProcess;
|
||||
return true;
|
||||
case static_cast<int32_t>(Rendering::CameraFrameStage::FinalOutput):
|
||||
outStage = Rendering::CameraFrameStage::FinalOutput;
|
||||
return true;
|
||||
case static_cast<int32_t>(Rendering::CameraFrameStage::ObjectId):
|
||||
outStage = Rendering::CameraFrameStage::ObjectId;
|
||||
return true;
|
||||
case static_cast<int32_t>(Rendering::CameraFrameStage::PostScenePasses):
|
||||
outStage = Rendering::CameraFrameStage::PostScenePasses;
|
||||
return true;
|
||||
case static_cast<int32_t>(Rendering::CameraFrameStage::OverlayPasses):
|
||||
outStage = Rendering::CameraFrameStage::OverlayPasses;
|
||||
return true;
|
||||
default:
|
||||
outStage = Rendering::CameraFrameStage::MainScene;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CleanupMonoRootDomainAtExit() {
|
||||
MonoRootState& rootState = GetMonoRootState();
|
||||
if (!rootState.rootDomain) {
|
||||
@@ -715,6 +806,8 @@ public:
|
||||
size_t renderedRequestCount,
|
||||
const Rendering::DirectionalShadowPlanningSettings&
|
||||
directionalShadowSettings) const override;
|
||||
void ConfigureCameraFramePlan(
|
||||
Rendering::CameraFramePlan& plan) const override;
|
||||
|
||||
bool TryGetDefaultFinalColorSettings(
|
||||
Rendering::FinalColorSettings& settings) const override;
|
||||
@@ -742,6 +835,8 @@ private:
|
||||
MonoMethod* ResolveCreatePipelineMethod(MonoObject* assetObject) const;
|
||||
MonoMethod* ResolveConfigureCameraRenderRequestMethod(
|
||||
MonoObject* assetObject) const;
|
||||
MonoMethod* ResolveConfigureCameraFramePlanMethod(
|
||||
MonoObject* assetObject) const;
|
||||
MonoMethod* ResolveGetDefaultFinalColorSettingsMethod(
|
||||
MonoObject* assetObject) const;
|
||||
MonoMethod* ResolveGetPipelineRendererAssetKeyMethod(
|
||||
@@ -756,6 +851,7 @@ private:
|
||||
mutable MonoMethod* m_disposePipelineMethod = nullptr;
|
||||
mutable MonoMethod* m_createPipelineMethod = nullptr;
|
||||
mutable MonoMethod* m_configureCameraRenderRequestMethod = nullptr;
|
||||
mutable MonoMethod* m_configureCameraFramePlanMethod = nullptr;
|
||||
mutable MonoMethod* m_getDefaultFinalColorSettingsMethod = nullptr;
|
||||
mutable MonoMethod* m_getPipelineRendererAssetKeyMethod = nullptr;
|
||||
mutable MonoMethod* m_releaseRuntimeResourcesMethod = nullptr;
|
||||
@@ -1051,6 +1147,44 @@ void MonoManagedRenderPipelineAssetRuntime::ConfigureCameraRenderRequest(
|
||||
requestContextHandle);
|
||||
}
|
||||
|
||||
void MonoManagedRenderPipelineAssetRuntime::ConfigureCameraFramePlan(
|
||||
Rendering::CameraFramePlan& plan) const {
|
||||
if (!EnsureManagedAsset()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MonoObject* const assetObject = GetManagedAssetObject();
|
||||
MonoMethod* const method =
|
||||
ResolveConfigureCameraFramePlanMethod(assetObject);
|
||||
if (assetObject == nullptr || method == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ManagedScriptableRenderPipelinePlanningContextState
|
||||
planningContextState = {};
|
||||
planningContextState.plan = &plan;
|
||||
const uint64_t planningContextHandle =
|
||||
RegisterManagedScriptableRenderPipelinePlanningContextState(
|
||||
planningContextState);
|
||||
MonoObject* const planningContextObject =
|
||||
m_runtime->CreateManagedScriptableRenderPipelinePlanningContext(
|
||||
planningContextHandle);
|
||||
if (planningContextObject == nullptr) {
|
||||
UnregisterManagedScriptableRenderPipelinePlanningContextState(
|
||||
planningContextHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
void* args[1] = { planningContextObject };
|
||||
m_runtime->InvokeManagedMethod(
|
||||
assetObject,
|
||||
method,
|
||||
args,
|
||||
nullptr);
|
||||
UnregisterManagedScriptableRenderPipelinePlanningContextState(
|
||||
planningContextHandle);
|
||||
}
|
||||
|
||||
bool MonoManagedRenderPipelineAssetRuntime::TryGetDefaultFinalColorSettings(
|
||||
Rendering::FinalColorSettings& settings) const {
|
||||
settings = {};
|
||||
@@ -1268,6 +1402,7 @@ void MonoManagedRenderPipelineAssetRuntime::ReleaseManagedAsset() const {
|
||||
m_releaseRuntimeResourcesMethod = nullptr;
|
||||
m_createPipelineMethod = nullptr;
|
||||
m_configureCameraRenderRequestMethod = nullptr;
|
||||
m_configureCameraFramePlanMethod = nullptr;
|
||||
m_getDefaultFinalColorSettingsMethod = nullptr;
|
||||
m_getPipelineRendererAssetKeyMethod = nullptr;
|
||||
m_pipelineRendererAsset.reset();
|
||||
@@ -1345,6 +1480,20 @@ MonoManagedRenderPipelineAssetRuntime::ResolveConfigureCameraRenderRequestMethod
|
||||
return m_configureCameraRenderRequestMethod;
|
||||
}
|
||||
|
||||
MonoMethod*
|
||||
MonoManagedRenderPipelineAssetRuntime::ResolveConfigureCameraFramePlanMethod(
|
||||
MonoObject* assetObject) const {
|
||||
if (m_configureCameraFramePlanMethod == nullptr) {
|
||||
m_configureCameraFramePlanMethod =
|
||||
m_runtime->ResolveManagedMethod(
|
||||
assetObject,
|
||||
"ConfigureCameraFramePlanInstance",
|
||||
1);
|
||||
}
|
||||
|
||||
return m_configureCameraFramePlanMethod;
|
||||
}
|
||||
|
||||
MonoMethod*
|
||||
MonoManagedRenderPipelineAssetRuntime::ResolveGetDefaultFinalColorSettingsMethod(
|
||||
MonoObject* assetObject) const {
|
||||
@@ -3803,6 +3952,115 @@ void InternalCall_Rendering_CameraRenderRequestContext_ClearDirectionalShadow(
|
||||
state->request->directionalShadow = {};
|
||||
}
|
||||
|
||||
mono_bool
|
||||
InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_IsStageRequested(
|
||||
uint64_t nativeHandle,
|
||||
int32_t stage) {
|
||||
const ManagedScriptableRenderPipelinePlanningContextState* const state =
|
||||
FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle);
|
||||
if (state == nullptr || state->plan == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Rendering::CameraFrameStage resolvedStage =
|
||||
Rendering::CameraFrameStage::MainScene;
|
||||
if (!TryResolveManagedCameraFrameStage(stage, resolvedStage)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return state->plan->HasFrameStage(resolvedStage) ? 1 : 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetStageColorSource(
|
||||
uint64_t nativeHandle,
|
||||
int32_t stage) {
|
||||
const ManagedScriptableRenderPipelinePlanningContextState* const state =
|
||||
FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle);
|
||||
if (state == nullptr || state->plan == nullptr) {
|
||||
return static_cast<int32_t>(
|
||||
Rendering::CameraFrameColorSource::ExplicitSurface);
|
||||
}
|
||||
|
||||
Rendering::CameraFrameStage resolvedStage =
|
||||
Rendering::CameraFrameStage::MainScene;
|
||||
if (!TryResolveManagedCameraFrameStage(stage, resolvedStage)) {
|
||||
return static_cast<int32_t>(
|
||||
Rendering::CameraFrameColorSource::ExplicitSurface);
|
||||
}
|
||||
|
||||
return static_cast<int32_t>(
|
||||
state->plan->ResolveStageColorSource(resolvedStage));
|
||||
}
|
||||
|
||||
mono_bool
|
||||
InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetStageUsesGraphManagedOutputColor(
|
||||
uint64_t nativeHandle,
|
||||
int32_t stage) {
|
||||
const ManagedScriptableRenderPipelinePlanningContextState* const state =
|
||||
FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle);
|
||||
if (state == nullptr || state->plan == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Rendering::CameraFrameStage resolvedStage =
|
||||
Rendering::CameraFrameStage::MainScene;
|
||||
if (!TryResolveManagedCameraFrameStage(stage, resolvedStage)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return state->plan->UsesGraphManagedOutputColor(resolvedStage)
|
||||
? 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
mono_bool
|
||||
InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_RequestFullscreenStage(
|
||||
uint64_t nativeHandle,
|
||||
int32_t stage,
|
||||
int32_t source,
|
||||
mono_bool usesGraphManagedOutputColor) {
|
||||
ManagedScriptableRenderPipelinePlanningContextState* const state =
|
||||
FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle);
|
||||
if (state == nullptr || state->plan == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Rendering::CameraFrameStage resolvedStage =
|
||||
Rendering::CameraFrameStage::MainScene;
|
||||
if (!TryResolveManagedCameraFrameStage(stage, resolvedStage)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Rendering::CameraFrameColorSource resolvedSource =
|
||||
static_cast<Rendering::CameraFrameColorSource>(source);
|
||||
return state->plan->RequestFullscreenStage(
|
||||
resolvedStage,
|
||||
resolvedSource,
|
||||
usesGraphManagedOutputColor != 0,
|
||||
true)
|
||||
? 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
void InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_ClearFullscreenStage(
|
||||
uint64_t nativeHandle,
|
||||
int32_t stage) {
|
||||
ManagedScriptableRenderPipelinePlanningContextState* const state =
|
||||
FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle);
|
||||
if (state == nullptr || state->plan == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Rendering::CameraFrameStage resolvedStage =
|
||||
Rendering::CameraFrameStage::MainScene;
|
||||
if (!TryResolveManagedCameraFrameStage(stage, resolvedStage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
state->plan->ClearFullscreenStage(resolvedStage, true);
|
||||
}
|
||||
|
||||
void RegisterInternalCalls() {
|
||||
if (GetInternalCallRegistrationState()) {
|
||||
return;
|
||||
@@ -3986,6 +4244,11 @@ void RegisterInternalCalls() {
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordScenePhase", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_RecordScenePhase));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordSceneInjectionPoint", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_RecordSceneInjectionPoint));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordFullscreenPass", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_RecordFullscreenPass));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_IsStageRequested", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_IsStageRequested));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetStageColorSource", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetStageColorSource));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetStageUsesGraphManagedOutputColor", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetStageUsesGraphManagedOutputColor));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_RequestFullscreenStage", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_RequestFullscreenStage));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_ClearFullscreenStage", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_ClearFullscreenStage));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetRenderedBaseCameraCount", reinterpret_cast<const void*>(&InternalCall_Rendering_CameraRenderRequestContext_GetRenderedBaseCameraCount));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetRenderedRequestCount", reinterpret_cast<const void*>(&InternalCall_Rendering_CameraRenderRequestContext_GetRenderedRequestCount));
|
||||
mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetHasDirectionalShadow", reinterpret_cast<const void*>(&InternalCall_Rendering_CameraRenderRequestContext_GetHasDirectionalShadow));
|
||||
@@ -4049,6 +4312,8 @@ void MonoScriptRuntime::Shutdown() {
|
||||
GetManagedScriptableRenderContextNextHandle() = 1;
|
||||
GetManagedCameraRenderRequestContextRegistry().clear();
|
||||
GetManagedCameraRenderRequestContextNextHandle() = 1;
|
||||
GetManagedScriptableRenderPipelinePlanningContextRegistry().clear();
|
||||
GetManagedScriptableRenderPipelinePlanningContextNextHandle() = 1;
|
||||
ClearManagedInstances();
|
||||
ClearExternalManagedObjects();
|
||||
ClearClassCache();
|
||||
@@ -4066,10 +4331,12 @@ void MonoScriptRuntime::Shutdown() {
|
||||
m_scriptableRenderPipelineClass = nullptr;
|
||||
m_scriptableRenderContextClass = nullptr;
|
||||
m_cameraRenderRequestContextClass = nullptr;
|
||||
m_scriptableRenderPipelinePlanningContextClass = nullptr;
|
||||
m_serializeFieldAttributeClass = nullptr;
|
||||
m_gameObjectConstructor = nullptr;
|
||||
m_scriptableRenderContextConstructor = nullptr;
|
||||
m_cameraRenderRequestContextConstructor = nullptr;
|
||||
m_scriptableRenderPipelinePlanningContextConstructor = nullptr;
|
||||
m_managedGameObjectUUIDField = nullptr;
|
||||
m_gameObjectUUIDField = nullptr;
|
||||
m_scriptComponentUUIDField = nullptr;
|
||||
@@ -4863,6 +5130,27 @@ bool MonoScriptRuntime::DiscoverScriptClasses() {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_scriptableRenderPipelinePlanningContextClass = mono_class_from_name(
|
||||
m_coreImage,
|
||||
kManagedRenderingNamespace,
|
||||
"ScriptableRenderPipelinePlanningContext");
|
||||
if (!m_scriptableRenderPipelinePlanningContextClass) {
|
||||
SetError(
|
||||
"Failed to locate the managed ScriptableRenderPipelinePlanningContext type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_scriptableRenderPipelinePlanningContextConstructor =
|
||||
mono_class_get_method_from_name(
|
||||
m_scriptableRenderPipelinePlanningContextClass,
|
||||
".ctor",
|
||||
1);
|
||||
if (!m_scriptableRenderPipelinePlanningContextConstructor) {
|
||||
SetError(
|
||||
"Failed to locate the managed ScriptableRenderPipelinePlanningContext constructor.");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_serializeFieldAttributeClass = mono_class_from_name(
|
||||
m_coreImage,
|
||||
m_settings.baseNamespace.c_str(),
|
||||
@@ -5458,6 +5746,46 @@ MonoScriptRuntime::CreateManagedCameraRenderRequestContext(
|
||||
return contextObject;
|
||||
}
|
||||
|
||||
MonoObject*
|
||||
MonoScriptRuntime::CreateManagedScriptableRenderPipelinePlanningContext(
|
||||
uint64_t nativeHandle) {
|
||||
if (!m_initialized ||
|
||||
nativeHandle == 0 ||
|
||||
m_scriptableRenderPipelinePlanningContextClass == nullptr ||
|
||||
m_scriptableRenderPipelinePlanningContextConstructor == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SetCurrentDomain();
|
||||
|
||||
MonoObject* const contextObject =
|
||||
mono_object_new(
|
||||
m_appDomain,
|
||||
m_scriptableRenderPipelinePlanningContextClass);
|
||||
if (contextObject == nullptr) {
|
||||
SetError(
|
||||
"Mono failed to allocate a managed ScriptableRenderPipelinePlanningContext.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* args[1];
|
||||
uint64_t nativeHandleArgument = nativeHandle;
|
||||
args[0] = &nativeHandleArgument;
|
||||
|
||||
MonoObject* exception = nullptr;
|
||||
mono_runtime_invoke(
|
||||
m_scriptableRenderPipelinePlanningContextConstructor,
|
||||
contextObject,
|
||||
args,
|
||||
&exception);
|
||||
if (exception != nullptr) {
|
||||
RecordException(exception);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return contextObject;
|
||||
}
|
||||
|
||||
MonoScriptRuntime::InstanceData* MonoScriptRuntime::FindInstance(const ScriptRuntimeContext& context) {
|
||||
const auto it = m_instances.find(InstanceKey{context.gameObjectUUID, context.scriptComponentUUID});
|
||||
return it != m_instances.end() ? &it->second : nullptr;
|
||||
|
||||
Reference in New Issue
Block a user