Add scriptable render pipeline host

This commit is contained in:
2026-04-15 01:33:42 +08:00
parent 82b8bd22cc
commit ec6965b0dd
6 changed files with 345 additions and 4 deletions

View File

@@ -10,6 +10,7 @@
#include <XCEngine/Rendering/Execution/CameraRenderer.h>
#include <XCEngine/Rendering/Execution/RenderPipelineHost.h>
#include <XCEngine/Rendering/Graph/RenderGraph.h>
#include <XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h>
#include <XCEngine/Rendering/RenderPipelineAsset.h>
#include <XCEngine/Rendering/RenderSurface.h>
#include <XCEngine/Rendering/Execution/SceneRenderer.h>
@@ -861,6 +862,18 @@ RenderContext CreateValidContext() {
return context;
}
RenderSceneData CreateSceneDataForCamera(
Scene&,
CameraComponent& camera,
const RenderSurface& surface) {
RenderSceneData sceneData = {};
sceneData.camera = &camera;
sceneData.cameraData.viewportWidth = surface.GetRenderAreaWidth();
sceneData.cameraData.viewportHeight = surface.GetRenderAreaHeight();
sceneData.cameraData.clearFlags = RenderClearFlags::All;
return sceneData;
}
} // namespace
TEST(CameraRenderRequest_Test, ReportsFormalFrameStageContract) {
@@ -3602,6 +3615,108 @@ TEST(RenderPipelineHost_Test, SortsManualFramePlansByDepthBeforeRendering) {
EXPECT_EQ(state->renderedClearFlags[1], RenderClearFlags::None);
}
TEST(ScriptableRenderPipelineHost_Test, ForwardsRendererLifetimeAndFrameRendering) {
Scene scene("ScriptableRenderPipelineHostScene");
GameObject* cameraObject = scene.CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
camera->SetPrimary(true);
camera->SetDepth(2.0f);
auto initialState = std::make_shared<MockPipelineState>();
auto replacementState = std::make_shared<MockPipelineState>();
{
auto initialRenderer = std::make_unique<MockPipeline>(initialState);
MockPipeline* initialRendererRaw = initialRenderer.get();
Pipelines::ScriptableRenderPipelineHost host(std::move(initialRenderer));
EXPECT_EQ(host.GetMainSceneRenderer(), initialRendererRaw);
auto replacementRenderer = std::make_unique<MockPipeline>(replacementState);
MockPipeline* replacementRendererRaw = replacementRenderer.get();
host.SetMainSceneRenderer(std::move(replacementRenderer));
EXPECT_EQ(initialState->shutdownCalls, 1);
EXPECT_EQ(host.GetMainSceneRenderer(), replacementRendererRaw);
CameraRenderRequest request = {};
request.scene = &scene;
request.camera = camera;
request.context = CreateValidContext();
request.surface = RenderSurface(800, 600);
request.cameraDepth = camera->GetDepth();
request.clearFlags = RenderClearFlags::All;
RenderSceneData sceneData =
CreateSceneDataForCamera(scene, *camera, request.surface);
ASSERT_TRUE(host.Render(
request.context,
request.surface,
sceneData));
EXPECT_EQ(replacementState->renderCalls, 1);
EXPECT_EQ(replacementState->lastSurfaceWidth, 800u);
EXPECT_EQ(replacementState->lastSurfaceHeight, 600u);
EXPECT_EQ(replacementState->lastCamera, camera);
replacementState->supportsMainSceneRenderGraph = true;
RenderGraph graph = {};
RenderGraphBuilder graphBuilder(graph);
RenderGraphBlackboard blackboard = {};
bool executionSucceeded = true;
RenderSceneData graphSceneData =
CreateSceneDataForCamera(scene, *camera, request.surface);
const RenderPipelineMainSceneRenderGraphContext graphContext = {
graphBuilder,
"MainScene",
request.context,
graphSceneData,
request.surface,
nullptr,
nullptr,
XCEngine::RHI::ResourceStates::Common,
{},
{},
&executionSucceeded,
&blackboard
};
EXPECT_TRUE(host.SupportsMainSceneRenderGraph());
EXPECT_TRUE(host.RecordMainSceneRenderGraph(graphContext));
EXPECT_EQ(replacementState->recordMainSceneCalls, 1);
}
EXPECT_EQ(initialState->shutdownCalls, 1);
EXPECT_EQ(replacementState->shutdownCalls, 1);
}
TEST(ScriptableRenderPipelineHostAsset_Test, CreatesHostFromRendererAssetAndForwardsDefaults) {
auto assetState = std::make_shared<MockPipelineAssetState>();
assetState->defaultFinalColorSettings.outputTransferMode =
FinalColorOutputTransferMode::LinearToSRGB;
assetState->defaultFinalColorSettings.exposureMode =
FinalColorExposureMode::Fixed;
assetState->defaultFinalColorSettings.exposureValue = 1.5f;
Pipelines::ScriptableRenderPipelineHostAsset asset(
std::make_shared<MockPipelineAsset>(assetState));
EXPECT_EQ(
asset.GetDefaultFinalColorSettings().outputTransferMode,
FinalColorOutputTransferMode::LinearToSRGB);
EXPECT_EQ(
asset.GetDefaultFinalColorSettings().exposureMode,
FinalColorExposureMode::Fixed);
EXPECT_FLOAT_EQ(
asset.GetDefaultFinalColorSettings().exposureValue,
1.5f);
std::unique_ptr<RenderPipeline> pipeline = asset.CreatePipeline();
ASSERT_NE(pipeline, nullptr);
auto* host =
dynamic_cast<Pipelines::ScriptableRenderPipelineHost*>(pipeline.get());
ASSERT_NE(host, nullptr);
EXPECT_NE(host->GetMainSceneRenderer(), nullptr);
EXPECT_EQ(assetState->createCalls, 1);
}
TEST(SceneRenderer_Test, CreatesPipelineInstancesFromPipelineAssetsAndShutsDownReplacedPipelines) {
Scene scene("SceneRendererAssetScene");