Move scene request planning behind pipeline asset

This commit is contained in:
2026-04-29 03:29:17 +08:00
parent 313a571e43
commit 2fde2f16c2
10 changed files with 393 additions and 25 deletions

View File

@@ -517,6 +517,7 @@ public:
struct MockPipelineAssetState {
int createCalls = 0;
int buildSceneRenderRequestsCalls = 0;
int configureCameraRenderRequestCalls = 0;
int configureCameraFramePlanCalls = 0;
bool createNullPipeline = false;
@@ -525,6 +526,12 @@ struct MockPipelineAssetState {
RenderPipeline* lastCreatedPipeline = nullptr;
FinalColorSettings defaultFinalColorSettings = {};
std::function<void(RenderPipeline&)> configurePipeline = {};
std::function<std::vector<CameraRenderRequest>(
const Scene&,
CameraComponent*,
const RenderContext&,
const RenderSurface&,
const DirectionalShadowPlanningSettings&)> buildSceneRenderRequests = {};
std::function<void(
CameraRenderRequest&,
size_t,
@@ -858,6 +865,30 @@ public:
return m_state->defaultFinalColorSettings;
}
std::vector<CameraRenderRequest> BuildSceneRenderRequests(
const Scene& scene,
CameraComponent* overrideCamera,
const RenderContext& context,
const RenderSurface& surface,
const DirectionalShadowPlanningSettings& directionalShadowSettings) const override {
++m_state->buildSceneRenderRequestsCalls;
if (m_state->buildSceneRenderRequests) {
return m_state->buildSceneRenderRequests(
scene,
overrideCamera,
context,
surface,
directionalShadowSettings);
}
return RenderPipelineAsset::BuildSceneRenderRequests(
scene,
overrideCamera,
context,
surface,
directionalShadowSettings);
}
void ConfigureCameraRenderRequest(
CameraRenderRequest& request,
size_t renderedBaseCameraCount,
@@ -896,6 +927,7 @@ private:
struct MockManagedRenderPipelineAssetRuntimeState {
int createStageRecorderCalls = 0;
int buildSceneRenderRequestsCalls = 0;
int configureCameraRenderRequestCalls = 0;
int getPipelineBackendAssetCalls = 0;
int getDefaultFinalColorSettingsCalls = 0;
@@ -909,6 +941,13 @@ struct MockManagedRenderPipelineAssetRuntimeState {
pipelineBackendAssetPolicy =
Pipelines::ManagedPipelineBackendAssetPolicy::Unspecified;
std::shared_ptr<MockStageRecorderState> lastCreatedStageRecorderState;
std::function<bool(
const Scene&,
CameraComponent*,
const RenderContext&,
const RenderSurface&,
const DirectionalShadowPlanningSettings&,
std::vector<CameraRenderRequest>&)> buildSceneRenderRequests = {};
std::function<void(
CameraRenderRequest&,
size_t,
@@ -932,6 +971,27 @@ public:
m_state->lastCreatedStageRecorderState);
}
bool BuildSceneRenderRequests(
const Scene& scene,
CameraComponent* overrideCamera,
const RenderContext& context,
const RenderSurface& surface,
const DirectionalShadowPlanningSettings& directionalShadowSettings,
std::vector<CameraRenderRequest>& requests) const override {
++m_state->buildSceneRenderRequestsCalls;
if (!m_state->buildSceneRenderRequests) {
return false;
}
return m_state->buildSceneRenderRequests(
scene,
overrideCamera,
context,
surface,
directionalShadowSettings,
requests);
}
void ConfigureCameraRenderRequest(
CameraRenderRequest& request,
size_t renderedBaseCameraCount,
@@ -993,6 +1053,13 @@ struct MockManagedRenderPipelineBridgeState {
Pipelines::ManagedPipelineBackendAssetPolicy
pipelineBackendAssetPolicy =
Pipelines::ManagedPipelineBackendAssetPolicy::Unspecified;
std::function<bool(
const Scene&,
CameraComponent*,
const RenderContext&,
const RenderSurface&,
const DirectionalShadowPlanningSettings&,
std::vector<CameraRenderRequest>&)> buildSceneRenderRequests = {};
std::function<void(
CameraRenderRequest&,
size_t,
@@ -1026,6 +1093,8 @@ public:
m_state->pipelineBackendAsset;
m_state->lastCreatedRuntimeState->pipelineBackendAssetPolicy =
m_state->pipelineBackendAssetPolicy;
m_state->lastCreatedRuntimeState->buildSceneRenderRequests =
m_state->buildSceneRenderRequests;
m_state->lastCreatedRuntimeState->configureCameraRenderRequest =
m_state->configureCameraRenderRequest;
return std::make_shared<MockManagedRenderPipelineAssetRuntime>(
@@ -3834,6 +3903,56 @@ TEST(SceneRenderer_Test, UsesPipelineAssetCameraRenderRequestConfigurationHook)
EXPECT_FALSE(plans[0].directionalShadow.IsValid());
}
TEST(SceneRenderer_Test, DelegatesSceneRequestPlanningToPipelineAssetAuthority) {
Scene scene("SceneRendererAssetOwnedPlanningScene");
GameObject* firstCameraObject = scene.CreateGameObject("FirstCamera");
auto* firstCamera = firstCameraObject->AddComponent<CameraComponent>();
firstCamera->SetPrimary(true);
firstCamera->SetDepth(1.0f);
GameObject* secondCameraObject = scene.CreateGameObject("SecondCamera");
auto* secondCamera = secondCameraObject->AddComponent<CameraComponent>();
secondCamera->SetPrimary(true);
secondCamera->SetDepth(5.0f);
auto assetState = std::make_shared<MockPipelineAssetState>();
assetState->buildSceneRenderRequests =
[secondCamera](
const Scene& scene,
CameraComponent* overrideCamera,
const RenderContext& context,
const RenderSurface& surface,
const DirectionalShadowPlanningSettings&) {
EXPECT_EQ(overrideCamera, nullptr);
CameraRenderRequest request = {};
request.scene = &scene;
request.camera = secondCamera;
request.context = context;
request.surface = surface;
request.cameraStackId = 7u;
request.cameraDepth = secondCamera->GetDepth();
request.cameraStackOrder = 0u;
request.clearFlags = RenderClearFlags::All;
return std::vector<CameraRenderRequest>{ request };
};
SceneRenderer renderer(std::make_shared<MockPipelineAsset>(assetState));
const std::vector<CameraFramePlan> plans =
renderer.BuildFramePlans(
scene,
nullptr,
CreateValidContext(),
RenderSurface(640, 360));
ASSERT_EQ(plans.size(), 1u);
EXPECT_EQ(assetState->buildSceneRenderRequestsCalls, 1);
EXPECT_EQ(assetState->configureCameraRenderRequestCalls, 0);
EXPECT_EQ(plans[0].request.camera, secondCamera);
EXPECT_EQ(plans[0].request.cameraStackId, 7u);
}
TEST(SceneRenderer_Test, BuildsFinalOutputRequestFromResolvedFinalColorPolicy) {
Scene scene("SceneRendererFinalOutputScene");
@@ -5472,6 +5591,79 @@ TEST(ManagedScriptableRenderPipelineAsset_Test, ReusesManagedAssetRuntimeAcrossP
Pipelines::ClearManagedRenderPipelineBridge();
}
TEST(ManagedScriptableRenderPipelineAsset_Test, LetsManagedBridgeBuildSceneRenderRequests) {
Pipelines::ClearManagedRenderPipelineBridge();
Scene scene("ManagedPipelineAssetBuildSceneRequests");
GameObject* firstCameraObject = scene.CreateGameObject("FirstCamera");
auto* firstCamera = firstCameraObject->AddComponent<CameraComponent>();
firstCamera->SetPrimary(true);
firstCamera->SetDepth(1.0f);
GameObject* secondCameraObject = scene.CreateGameObject("SecondCamera");
auto* secondCamera = secondCameraObject->AddComponent<CameraComponent>();
secondCamera->SetPrimary(true);
secondCamera->SetDepth(3.0f);
const Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {
"GameScripts",
"Gameplay",
"ManagedRenderPipelineProbeAsset"
};
auto bridgeState = std::make_shared<MockManagedRenderPipelineBridgeState>();
bridgeState->pipelineBackendAsset = std::make_shared<MockPipelineAsset>(
std::make_shared<MockPipelineAssetState>());
bridgeState->buildSceneRenderRequests =
[secondCamera](
const Scene& scene,
CameraComponent* overrideCamera,
const RenderContext& context,
const RenderSurface& surface,
const DirectionalShadowPlanningSettings&,
std::vector<CameraRenderRequest>& requests) {
EXPECT_EQ(overrideCamera, nullptr);
CameraRenderRequest request = {};
request.scene = &scene;
request.camera = secondCamera;
request.context = context;
request.surface = surface;
request.cameraStackId = 9u;
request.cameraDepth = secondCamera->GetDepth();
request.cameraStackOrder = 0u;
request.clearFlags = RenderClearFlags::All;
requests = { request };
return true;
};
Pipelines::SetManagedRenderPipelineBridge(
std::make_shared<MockManagedRenderPipelineBridge>(bridgeState));
Pipelines::ManagedScriptableRenderPipelineAsset asset(descriptor);
const std::vector<CameraRenderRequest> requests =
asset.BuildSceneRenderRequests(
scene,
nullptr,
CreateValidContext(),
RenderSurface(320, 180),
DirectionalShadowPlanningSettings{});
ASSERT_NE(bridgeState->lastCreatedRuntimeState, nullptr);
ASSERT_EQ(requests.size(), 1u);
EXPECT_EQ(
bridgeState->lastCreatedRuntimeState->buildSceneRenderRequestsCalls,
1);
EXPECT_EQ(
bridgeState->lastCreatedRuntimeState->configureCameraRenderRequestCalls,
0);
EXPECT_EQ(requests[0].camera, secondCamera);
EXPECT_EQ(requests[0].cameraStackId, 9u);
Pipelines::ClearManagedRenderPipelineBridge();
}
TEST(ManagedScriptableRenderPipelineAsset_Test, RebindsManagedAssetRuntimeWhenBridgeChanges) {
Pipelines::ClearManagedRenderPipelineBridge();