refactor(srp): add managed lifecycle cleanup seams
Invoke managed pipeline disposal and asset runtime cleanup from the native bridge lifecycle. Add Universal renderer and feature cleanup hooks plus regression probes to verify runtime cache teardown semantics.
This commit is contained in:
@@ -2499,6 +2499,337 @@ TEST_F(
|
||||
secondRecorder->Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
MonoScriptRuntimeTest,
|
||||
ManagedRenderPipelineBridgeInvokesManagedPipelineDisposeBeforeAssetRuntimeRelease) {
|
||||
Scene* runtimeScene =
|
||||
CreateScene("ManagedLifecycleDisposeObservationScene");
|
||||
GameObject* scriptObject =
|
||||
runtimeScene->CreateGameObject("ManagedLifecycleObservationProbe");
|
||||
ScriptComponent* script =
|
||||
AddScript(
|
||||
scriptObject,
|
||||
"Gameplay",
|
||||
"ManagedLifecycleObservationProbe");
|
||||
ASSERT_NE(script, nullptr);
|
||||
|
||||
engine->OnRuntimeStart(runtimeScene);
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
{
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {
|
||||
"GameScripts",
|
||||
"Gameplay",
|
||||
"ManagedPipelineDisposeProbeAsset"
|
||||
};
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
|
||||
std::unique_ptr<XCEngine::Rendering::RenderPipelineStageRecorder>
|
||||
recorder = assetRuntime->CreateStageRecorder();
|
||||
ASSERT_NE(recorder, nullptr);
|
||||
|
||||
const XCEngine::Rendering::RenderContext context = {};
|
||||
ASSERT_TRUE(recorder->Initialize(context));
|
||||
EXPECT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
|
||||
recorder->Shutdown();
|
||||
}
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
EXPECT_TRUE(runtime->GetLastError().empty()) << runtime->GetLastError();
|
||||
|
||||
int observedCreatePipelineCallCount = 0;
|
||||
int observedCreateRendererCallCount = 0;
|
||||
int observedCreateFeatureCallCount = 0;
|
||||
int observedReleaseRendererDataRuntimeResourcesCallCount = 0;
|
||||
int observedDisposePipelineCallCount = 0;
|
||||
int observedReleaseAssetRuntimeResourcesCallCount = 0;
|
||||
int observedDisposeRendererCallCount = 0;
|
||||
int observedDisposeFeatureCallCount = 0;
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedCreatePipelineCallCount",
|
||||
observedCreatePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedCreateRendererCallCount",
|
||||
observedCreateRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedCreateFeatureCallCount",
|
||||
observedCreateFeatureCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedReleaseRendererDataRuntimeResourcesCallCount",
|
||||
observedReleaseRendererDataRuntimeResourcesCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedDisposePipelineCallCount",
|
||||
observedDisposePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedReleaseAssetRuntimeResourcesCallCount",
|
||||
observedReleaseAssetRuntimeResourcesCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedDisposeRendererCallCount",
|
||||
observedDisposeRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedDisposeFeatureCallCount",
|
||||
observedDisposeFeatureCallCount));
|
||||
|
||||
EXPECT_EQ(observedCreatePipelineCallCount, 1);
|
||||
EXPECT_EQ(observedCreateRendererCallCount, 0);
|
||||
EXPECT_EQ(observedCreateFeatureCallCount, 0);
|
||||
EXPECT_EQ(observedReleaseRendererDataRuntimeResourcesCallCount, 0);
|
||||
EXPECT_EQ(observedDisposePipelineCallCount, 1);
|
||||
EXPECT_EQ(observedReleaseAssetRuntimeResourcesCallCount, 0);
|
||||
EXPECT_EQ(observedDisposeRendererCallCount, 0);
|
||||
EXPECT_EQ(observedDisposeFeatureCallCount, 0);
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
MonoScriptRuntimeTest,
|
||||
ManagedRenderPipelineBridgeReleasesUniversalRendererCachesOnAssetRuntimeRelease) {
|
||||
Scene* runtimeScene =
|
||||
CreateScene("ManagedUniversalLifecycleObservationScene");
|
||||
GameObject* scriptObject =
|
||||
runtimeScene->CreateGameObject("ManagedUniversalLifecycleSelectionProbe");
|
||||
ScriptComponent* script =
|
||||
AddScript(
|
||||
scriptObject,
|
||||
"Gameplay",
|
||||
"ManagedUniversalLifecycleRuntimeSelectionProbe");
|
||||
ASSERT_NE(script, nullptr);
|
||||
|
||||
engine->OnRuntimeStart(runtimeScene);
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor =
|
||||
XCEngine::Rendering::Pipelines::GetConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
ASSERT_TRUE(descriptor.IsValid());
|
||||
ASSERT_NE(descriptor.managedAssetHandle, 0u);
|
||||
EXPECT_EQ(descriptor.assemblyName, "GameScripts");
|
||||
EXPECT_EQ(descriptor.namespaceName, "Gameplay");
|
||||
EXPECT_EQ(descriptor.className, "ManagedUniversalLifecycleProbeAsset");
|
||||
|
||||
{
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
|
||||
std::unique_ptr<XCEngine::Rendering::RenderPipelineStageRecorder>
|
||||
recorder = assetRuntime->CreateStageRecorder();
|
||||
ASSERT_NE(recorder, nullptr);
|
||||
|
||||
const XCEngine::Rendering::RenderContext context = {};
|
||||
ASSERT_TRUE(recorder->Initialize(context));
|
||||
EXPECT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
|
||||
recorder->Shutdown();
|
||||
}
|
||||
|
||||
{
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
|
||||
std::unique_ptr<XCEngine::Rendering::RenderPipelineStageRecorder>
|
||||
recorder = assetRuntime->CreateStageRecorder();
|
||||
ASSERT_NE(recorder, nullptr);
|
||||
|
||||
const XCEngine::Rendering::RenderContext context = {};
|
||||
ASSERT_TRUE(recorder->Initialize(context));
|
||||
EXPECT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
|
||||
recorder->Shutdown();
|
||||
}
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
EXPECT_TRUE(runtime->GetLastError().empty()) << runtime->GetLastError();
|
||||
|
||||
int observedCreatePipelineCallCount = 0;
|
||||
int observedCreateRendererCallCount = 0;
|
||||
int observedCreateFeatureCallCount = 0;
|
||||
int observedReleaseRendererDataRuntimeResourcesCallCount = 0;
|
||||
int observedDisposePipelineCallCount = 0;
|
||||
int observedReleaseAssetRuntimeResourcesCallCount = 0;
|
||||
int observedDisposeRendererCallCount = 0;
|
||||
int observedDisposeFeatureCallCount = 0;
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedCreatePipelineCallCount",
|
||||
observedCreatePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedCreateRendererCallCount",
|
||||
observedCreateRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedCreateFeatureCallCount",
|
||||
observedCreateFeatureCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedReleaseRendererDataRuntimeResourcesCallCount",
|
||||
observedReleaseRendererDataRuntimeResourcesCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedDisposePipelineCallCount",
|
||||
observedDisposePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedReleaseAssetRuntimeResourcesCallCount",
|
||||
observedReleaseAssetRuntimeResourcesCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedDisposeRendererCallCount",
|
||||
observedDisposeRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedDisposeFeatureCallCount",
|
||||
observedDisposeFeatureCallCount));
|
||||
|
||||
EXPECT_EQ(observedCreatePipelineCallCount, 2);
|
||||
EXPECT_EQ(observedCreateRendererCallCount, 2);
|
||||
EXPECT_EQ(observedCreateFeatureCallCount, 2);
|
||||
EXPECT_EQ(observedReleaseRendererDataRuntimeResourcesCallCount, 2);
|
||||
EXPECT_EQ(observedDisposePipelineCallCount, 0);
|
||||
EXPECT_EQ(observedReleaseAssetRuntimeResourcesCallCount, 2);
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
MonoScriptRuntimeTest,
|
||||
ManagedRenderPipelineBridgeReleasesUniversalFeatureCachesWithoutPipelineCreation) {
|
||||
Scene* runtimeScene =
|
||||
CreateScene("ManagedUniversalLifecycleRequestObservationScene");
|
||||
GameObject* scriptObject =
|
||||
runtimeScene->CreateGameObject("ManagedUniversalLifecycleSelectionProbe");
|
||||
ScriptComponent* script =
|
||||
AddScript(
|
||||
scriptObject,
|
||||
"Gameplay",
|
||||
"ManagedUniversalLifecycleRuntimeSelectionProbe");
|
||||
ASSERT_NE(script, nullptr);
|
||||
|
||||
engine->OnRuntimeStart(runtimeScene);
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor =
|
||||
XCEngine::Rendering::Pipelines::GetConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
ASSERT_TRUE(descriptor.IsValid());
|
||||
ASSERT_NE(descriptor.managedAssetHandle, 0u);
|
||||
EXPECT_EQ(descriptor.assemblyName, "GameScripts");
|
||||
EXPECT_EQ(descriptor.namespaceName, "Gameplay");
|
||||
EXPECT_EQ(descriptor.className, "ManagedUniversalLifecycleProbeAsset");
|
||||
|
||||
{
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
|
||||
XCEngine::Rendering::CameraRenderRequest request = {};
|
||||
assetRuntime->ConfigureCameraRenderRequest(
|
||||
request,
|
||||
0u,
|
||||
0u,
|
||||
XCEngine::Rendering::DirectionalShadowPlanningSettings{});
|
||||
}
|
||||
|
||||
{
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
|
||||
XCEngine::Rendering::CameraRenderRequest request = {};
|
||||
assetRuntime->ConfigureCameraRenderRequest(
|
||||
request,
|
||||
0u,
|
||||
0u,
|
||||
XCEngine::Rendering::DirectionalShadowPlanningSettings{});
|
||||
}
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
EXPECT_TRUE(runtime->GetLastError().empty()) << runtime->GetLastError();
|
||||
|
||||
int observedCreatePipelineCallCount = 0;
|
||||
int observedCreateRendererCallCount = 0;
|
||||
int observedCreateFeatureCallCount = 0;
|
||||
int observedReleaseRendererDataRuntimeResourcesCallCount = 0;
|
||||
int observedDisposePipelineCallCount = 0;
|
||||
int observedReleaseAssetRuntimeResourcesCallCount = 0;
|
||||
int observedDisposeRendererCallCount = 0;
|
||||
int observedDisposeFeatureCallCount = 0;
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedCreatePipelineCallCount",
|
||||
observedCreatePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedCreateRendererCallCount",
|
||||
observedCreateRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedCreateFeatureCallCount",
|
||||
observedCreateFeatureCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedReleaseRendererDataRuntimeResourcesCallCount",
|
||||
observedReleaseRendererDataRuntimeResourcesCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedDisposePipelineCallCount",
|
||||
observedDisposePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedReleaseAssetRuntimeResourcesCallCount",
|
||||
observedReleaseAssetRuntimeResourcesCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedDisposeRendererCallCount",
|
||||
observedDisposeRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
script,
|
||||
"ObservedDisposeFeatureCallCount",
|
||||
observedDisposeFeatureCallCount));
|
||||
|
||||
EXPECT_EQ(observedCreatePipelineCallCount, 0);
|
||||
EXPECT_EQ(observedCreateRendererCallCount, 0);
|
||||
EXPECT_EQ(observedCreateFeatureCallCount, 2);
|
||||
EXPECT_EQ(observedReleaseRendererDataRuntimeResourcesCallCount, 2);
|
||||
EXPECT_EQ(observedDisposePipelineCallCount, 0);
|
||||
EXPECT_EQ(observedReleaseAssetRuntimeResourcesCallCount, 2);
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
MonoScriptRuntimeTest,
|
||||
ManagedRenderPipelineBridgeRuntimeExposesBuiltinForwardRendererAsset) {
|
||||
|
||||
Reference in New Issue
Block a user