refactor(rendering): retain managed pipeline asset runtime per native asset

This commit is contained in:
2026-04-17 23:54:04 +08:00
parent 6838b00d97
commit fa9a5ffb00
6 changed files with 395 additions and 214 deletions

View File

@@ -772,12 +772,44 @@ private:
std::shared_ptr<MockPipelineAssetState> m_state;
};
struct MockManagedRenderPipelineBridgeState {
struct MockManagedRenderPipelineAssetRuntimeState {
int createStageRecorderCalls = 0;
Pipelines::ManagedRenderPipelineAssetDescriptor lastDescriptor = {};
std::shared_ptr<MockStageRecorderState> lastCreatedStageRecorderState;
int configureCameraFramePlanCalls = 0;
Pipelines::ManagedRenderPipelineAssetDescriptor lastPlanningDescriptor = {};
std::shared_ptr<MockStageRecorderState> lastCreatedStageRecorderState;
std::function<void(CameraFramePlan&)> configureCameraFramePlan = {};
};
class MockManagedRenderPipelineAssetRuntime final
: public Pipelines::ManagedRenderPipelineAssetRuntime {
public:
explicit MockManagedRenderPipelineAssetRuntime(
std::shared_ptr<MockManagedRenderPipelineAssetRuntimeState> state)
: m_state(std::move(state)) {
}
std::unique_ptr<RenderPipelineStageRecorder> CreateStageRecorder() const override {
++m_state->createStageRecorderCalls;
m_state->lastCreatedStageRecorderState =
std::make_shared<MockStageRecorderState>();
return std::make_unique<MockStageRecorder>(
m_state->lastCreatedStageRecorderState);
}
void ConfigureCameraFramePlan(CameraFramePlan& plan) const override {
++m_state->configureCameraFramePlanCalls;
if (m_state->configureCameraFramePlan) {
m_state->configureCameraFramePlan(plan);
}
}
private:
std::shared_ptr<MockManagedRenderPipelineAssetRuntimeState> m_state;
};
struct MockManagedRenderPipelineBridgeState {
int createAssetRuntimeCalls = 0;
Pipelines::ManagedRenderPipelineAssetDescriptor lastDescriptor = {};
std::shared_ptr<MockManagedRenderPipelineAssetRuntimeState> lastCreatedRuntimeState;
std::function<void(CameraFramePlan&)> configureCameraFramePlan = {};
};
@@ -789,24 +821,17 @@ public:
: m_state(std::move(state)) {
}
std::unique_ptr<RenderPipelineStageRecorder> CreateStageRecorder(
std::shared_ptr<const Pipelines::ManagedRenderPipelineAssetRuntime>
CreateAssetRuntime(
const Pipelines::ManagedRenderPipelineAssetDescriptor& descriptor) const override {
++m_state->createStageRecorderCalls;
++m_state->createAssetRuntimeCalls;
m_state->lastDescriptor = descriptor;
m_state->lastCreatedStageRecorderState =
std::make_shared<MockStageRecorderState>();
return std::make_unique<MockStageRecorder>(
m_state->lastCreatedStageRecorderState);
}
void ConfigureCameraFramePlan(
const Pipelines::ManagedRenderPipelineAssetDescriptor& descriptor,
CameraFramePlan& plan) const override {
++m_state->configureCameraFramePlanCalls;
m_state->lastPlanningDescriptor = descriptor;
if (m_state->configureCameraFramePlan) {
m_state->configureCameraFramePlan(plan);
}
m_state->lastCreatedRuntimeState =
std::make_shared<MockManagedRenderPipelineAssetRuntimeState>();
m_state->lastCreatedRuntimeState->configureCameraFramePlan =
m_state->configureCameraFramePlan;
return std::make_shared<MockManagedRenderPipelineAssetRuntime>(
m_state->lastCreatedRuntimeState);
}
private:
@@ -4471,13 +4496,17 @@ TEST(ManagedScriptableRenderPipelineAsset_Test, CreatesHostWithStageRecorderFrom
ASSERT_NE(host, nullptr);
EXPECT_NE(host->GetPipelineRenderer(), nullptr);
EXPECT_NE(host->GetStageRecorder(), nullptr);
EXPECT_EQ(bridgeState->createStageRecorderCalls, 1);
EXPECT_EQ(bridgeState->createAssetRuntimeCalls, 1);
EXPECT_EQ(bridgeState->lastDescriptor.assemblyName, "GameScripts");
EXPECT_EQ(bridgeState->lastDescriptor.namespaceName, "Gameplay");
EXPECT_EQ(bridgeState->lastDescriptor.className, "ManagedRenderPipelineProbeAsset");
ASSERT_NE(bridgeState->lastCreatedStageRecorderState, nullptr);
bridgeState->lastCreatedStageRecorderState->supportsMainSceneRenderGraph = true;
ASSERT_NE(bridgeState->lastCreatedRuntimeState, nullptr);
ASSERT_NE(
bridgeState->lastCreatedRuntimeState->lastCreatedStageRecorderState,
nullptr);
bridgeState->lastCreatedRuntimeState->lastCreatedStageRecorderState
->supportsMainSceneRenderGraph = true;
EXPECT_TRUE(host->SupportsStageRenderGraph(CameraFrameStage::MainScene));
}
@@ -4532,12 +4561,14 @@ TEST(ManagedScriptableRenderPipelineAsset_Test, LetsManagedBridgeRequestFullscre
Pipelines::ManagedScriptableRenderPipelineAsset asset(descriptor);
asset.ConfigureCameraFramePlan(plan);
EXPECT_EQ(bridgeState->configureCameraFramePlanCalls, 1);
EXPECT_EQ(bridgeState->lastPlanningDescriptor.assemblyName, "GameScripts");
EXPECT_EQ(bridgeState->lastPlanningDescriptor.namespaceName, "Gameplay");
EXPECT_EQ(bridgeState->createAssetRuntimeCalls, 1);
ASSERT_NE(bridgeState->lastCreatedRuntimeState, nullptr);
EXPECT_EQ(
bridgeState->lastPlanningDescriptor.className,
"ManagedPlannedFullscreenRenderPipelineProbeAsset");
bridgeState->lastCreatedRuntimeState->configureCameraFramePlanCalls,
1);
EXPECT_EQ(bridgeState->lastDescriptor.assemblyName, "GameScripts");
EXPECT_EQ(bridgeState->lastDescriptor.namespaceName, "Gameplay");
EXPECT_EQ(bridgeState->lastDescriptor.className, "ManagedPlannedFullscreenRenderPipelineProbeAsset");
EXPECT_TRUE(plan.IsFullscreenStageRequested(CameraFrameStage::PostProcess));
EXPECT_TRUE(plan.IsFullscreenStageRequested(CameraFrameStage::FinalOutput));
EXPECT_EQ(plan.postProcess.passes, nullptr);
@@ -4556,6 +4587,53 @@ TEST(ManagedScriptableRenderPipelineAsset_Test, LetsManagedBridgeRequestFullscre
Pipelines::ClearManagedRenderPipelineBridge();
}
TEST(ManagedScriptableRenderPipelineAsset_Test, ReusesManagedAssetRuntimeAcrossPipelineAndPlanRequests) {
Pipelines::ClearManagedRenderPipelineBridge();
const Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {
"GameScripts",
"Gameplay",
"ManagedRenderPipelineProbeAsset"
};
auto bridgeState = std::make_shared<MockManagedRenderPipelineBridgeState>();
Pipelines::SetManagedRenderPipelineBridge(
std::make_shared<MockManagedRenderPipelineBridge>(bridgeState));
Pipelines::ManagedScriptableRenderPipelineAsset asset(descriptor);
std::unique_ptr<RenderPipeline> firstPipeline = asset.CreatePipeline();
std::unique_ptr<RenderPipeline> secondPipeline = asset.CreatePipeline();
ASSERT_NE(firstPipeline, nullptr);
ASSERT_NE(secondPipeline, nullptr);
ASSERT_NE(bridgeState->lastCreatedRuntimeState, nullptr);
auto runtimeState = bridgeState->lastCreatedRuntimeState;
EXPECT_EQ(bridgeState->createAssetRuntimeCalls, 1);
EXPECT_EQ(runtimeState->createStageRecorderCalls, 2);
ASSERT_NE(runtimeState->lastCreatedStageRecorderState, nullptr);
auto* firstHost =
dynamic_cast<Pipelines::ScriptableRenderPipelineHost*>(firstPipeline.get());
auto* secondHost =
dynamic_cast<Pipelines::ScriptableRenderPipelineHost*>(secondPipeline.get());
ASSERT_NE(firstHost, nullptr);
ASSERT_NE(secondHost, nullptr);
EXPECT_NE(firstHost->GetStageRecorder(), nullptr);
EXPECT_NE(secondHost->GetStageRecorder(), nullptr);
CameraRenderRequest request = {};
request.surface = RenderSurface(128, 72);
CameraFramePlan firstPlan = CameraFramePlan::FromRequest(request);
CameraFramePlan secondPlan = CameraFramePlan::FromRequest(request);
asset.ConfigureCameraFramePlan(firstPlan);
asset.ConfigureCameraFramePlan(secondPlan);
EXPECT_EQ(bridgeState->createAssetRuntimeCalls, 1);
EXPECT_EQ(runtimeState->configureCameraFramePlanCalls, 2);
Pipelines::ClearManagedRenderPipelineBridge();
}
TEST(CameraRenderer_Test, RendersManagedRequestedPostProcessWithoutLegacySequence) {
Scene scene("CameraRendererManagedRequestedPostProcessScene");