test(rendering): prove managed forward pipeline scene render path

This commit is contained in:
2026-04-18 00:51:51 +08:00
parent b48760ca3d
commit afb2c1579c
3 changed files with 1147 additions and 0 deletions

View File

@@ -18,11 +18,24 @@
#include <XCEngine/Input/InputTypes.h>
#include <XCEngine/Rendering/Execution/CameraFramePlan.h>
#include <XCEngine/Rendering/Execution/CameraFrameRenderGraphFrameData.h>
#include <XCEngine/Rendering/Execution/CameraRenderer.h>
#include <XCEngine/Rendering/Execution/SceneRenderer.h>
#include <XCEngine/Rendering/Graph/RenderGraph.h>
#include <XCEngine/Rendering/Graph/RenderGraphCompiler.h>
#include <XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h>
#include <XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h>
#include <XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h>
#include <XCEngine/Rendering/RenderSurface.h>
#include <XCEngine/RHI/RHICommandList.h>
#include <XCEngine/RHI/RHICommandQueue.h>
#include <XCEngine/RHI/RHIDescriptorPool.h>
#include <XCEngine/RHI/RHIDescriptorSet.h>
#include <XCEngine/RHI/RHIDevice.h>
#include <XCEngine/RHI/RHIPipelineLayout.h>
#include <XCEngine/RHI/RHIPipelineState.h>
#include <XCEngine/RHI/RHIResourceView.h>
#include <XCEngine/RHI/RHISampler.h>
#include <XCEngine/RHI/RHITexture.h>
#include <XCEngine/Scene/Scene.h>
#include <XCEngine/Scene/SceneRuntime.h>
#include <XCEngine/Scripting/Mono/MonoScriptRuntime.h>
@@ -30,13 +43,19 @@
#include <XCEngine/Scripting/ScriptEngine.h>
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstring>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "../Fixtures/RenderTestRhiStubs.h"
using namespace XCEngine::Components;
using namespace XCEngine::Scripting;
using namespace XCTest;
namespace {
@@ -323,6 +342,221 @@ TEST_F(MonoScriptRuntimeTest, ManagedGraphicsSettingsRoundTripsRenderPipelineAss
"Gameplay.RenderPipelineApiProbeAsset");
}
TEST_F(
MonoScriptRuntimeTest,
DefaultCameraRendererUsesManagedGraphicsSelectionToRecordMainSceneGraph) {
Scene* runtimeScene = CreateScene("ManagedRenderPipelineDefaultRendererScene");
GameObject* selectionObject =
runtimeScene->CreateGameObject("ManagedRenderPipelineSelection");
ScriptComponent* selectionScript =
AddScript(
selectionObject,
"Gameplay",
"ManagedRenderPipelineRuntimeSelectionProbe");
ASSERT_NE(selectionScript, nullptr);
engine->OnRuntimeStart(runtimeScene);
engine->OnUpdate(0.016f);
XCEngine::Rendering::CameraRenderer renderer;
const auto* asset =
dynamic_cast<
const XCEngine::Rendering::Pipelines::ManagedScriptableRenderPipelineAsset*>(
renderer.GetPipelineAsset());
ASSERT_NE(asset, nullptr);
EXPECT_EQ(asset->GetDescriptor().assemblyName, "GameScripts");
EXPECT_EQ(asset->GetDescriptor().namespaceName, "Gameplay");
EXPECT_EQ(asset->GetDescriptor().className, "ManagedRenderPipelineProbeAsset");
auto* host =
dynamic_cast<XCEngine::Rendering::Pipelines::ScriptableRenderPipelineHost*>(
renderer.GetPipeline());
ASSERT_NE(host, nullptr);
ASSERT_NE(host->GetStageRecorder(), nullptr);
EXPECT_TRUE(
host->GetStageRecorder()->Initialize(
XCEngine::Rendering::RenderContext{}));
EXPECT_TRUE(
host->SupportsStageRenderGraph(
XCEngine::Rendering::CameraFrameStage::MainScene));
XCEngine::Rendering::RenderGraph graph;
XCEngine::Rendering::RenderGraphBuilder graphBuilder(graph);
XCEngine::Rendering::RenderGraphTextureDesc colorDesc = {};
colorDesc.width = 64u;
colorDesc.height = 64u;
colorDesc.format =
static_cast<XCEngine::Core::uint32>(
XCEngine::RHI::Format::R8G8B8A8_UNorm);
XCEngine::Rendering::RenderGraphTextureDesc depthDesc = colorDesc;
depthDesc.format =
static_cast<XCEngine::Core::uint32>(
XCEngine::RHI::Format::D32_Float);
const XCEngine::Rendering::RenderGraphTextureHandle colorTarget =
graphBuilder.CreateTransientTexture("ManagedSelectedMainSceneColor", colorDesc);
const XCEngine::Rendering::RenderGraphTextureHandle depthTarget =
graphBuilder.CreateTransientTexture("ManagedSelectedMainSceneDepth", depthDesc);
const XCEngine::Rendering::RenderSceneData sceneData = {};
const XCEngine::Rendering::RenderSurface surface(64u, 64u);
bool executionSucceeded = true;
XCEngine::Rendering::RenderGraphBlackboard blackboard = {};
const XCEngine::Rendering::RenderPipelineStageRenderGraphContext graphContext = {
graphBuilder,
"ManagedSelectedMainScene",
XCEngine::Rendering::CameraFrameStage::MainScene,
{},
sceneData,
surface,
nullptr,
nullptr,
XCEngine::RHI::ResourceStates::Common,
{},
{ colorTarget },
depthTarget,
&executionSucceeded,
&blackboard
};
EXPECT_TRUE(host->GetStageRecorder()->RecordStageRenderGraph(graphContext));
XCEngine::Rendering::CompiledRenderGraph compiledGraph = {};
XCEngine::Containers::String errorMessage;
ASSERT_TRUE(
XCEngine::Rendering::RenderGraphCompiler::Compile(
graph,
compiledGraph,
&errorMessage))
<< errorMessage.CStr();
ASSERT_EQ(compiledGraph.GetPassCount(), 3u);
EXPECT_STREQ(
compiledGraph.GetPassName(0).CStr(),
"ManagedSelectedMainScene.Opaque");
EXPECT_STREQ(
compiledGraph.GetPassName(1).CStr(),
"ManagedSelectedMainScene.Skybox");
EXPECT_STREQ(
compiledGraph.GetPassName(2).CStr(),
"ManagedSelectedMainScene.Transparent");
host->GetStageRecorder()->Shutdown();
}
TEST_F(
MonoScriptRuntimeTest,
DefaultSceneRendererUsesManagedForwardPipelineForPlannedMainSceneAndPostProcessRender) {
Scene* runtimeScene = CreateScene("ManagedForwardRenderPipelineSceneRendererScene");
GameObject* selectionObject =
runtimeScene->CreateGameObject("ManagedForwardRenderPipelineSelection");
ScriptComponent* selectionScript =
AddScript(
selectionObject,
"Gameplay",
"ManagedForwardRenderPipelineRuntimeSelectionProbe");
ASSERT_NE(selectionScript, nullptr);
GameObject* cameraObject = runtimeScene->CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
ASSERT_NE(camera, nullptr);
camera->SetPrimary(true);
engine->OnRuntimeStart(runtimeScene);
engine->OnUpdate(0.016f);
TestRenderDevice device;
TestRenderCommandList commandList;
TestRenderCommandQueue commandQueue;
TestRenderResourceView colorView(
XCEngine::RHI::ResourceViewType::RenderTarget,
XCEngine::RHI::ResourceViewDimension::Texture2D,
XCEngine::RHI::Format::R8G8B8A8_UNorm);
TestRenderResourceView depthView(
XCEngine::RHI::ResourceViewType::DepthStencil,
XCEngine::RHI::ResourceViewDimension::Texture2D,
XCEngine::RHI::Format::D32_Float);
const XCEngine::Rendering::RenderContext context =
CreateRenderContext(
device,
commandList,
commandQueue);
XCEngine::Rendering::RenderSurface surface(64u, 64u);
surface.SetColorAttachment(&colorView);
surface.SetDepthAttachment(&depthView);
XCEngine::Rendering::SceneRenderer renderer;
const auto* pipelineAsset =
dynamic_cast<
const XCEngine::Rendering::Pipelines::ManagedScriptableRenderPipelineAsset*>(
renderer.GetPipelineAsset());
ASSERT_NE(pipelineAsset, nullptr);
EXPECT_EQ(pipelineAsset->GetDescriptor().assemblyName, "GameScripts");
EXPECT_EQ(pipelineAsset->GetDescriptor().namespaceName, "Gameplay");
EXPECT_EQ(
pipelineAsset->GetDescriptor().className,
"ManagedForwardRenderPipelineProbeAsset");
const std::vector<XCEngine::Rendering::CameraFramePlan> plans =
renderer.BuildFramePlans(
*runtimeScene,
nullptr,
context,
surface);
ASSERT_EQ(plans.size(), 1u);
EXPECT_TRUE(plans[0].UsesGraphManagedSceneColor());
EXPECT_TRUE(
plans[0].IsFullscreenStageRequested(
XCEngine::Rendering::CameraFrameStage::PostProcess));
EXPECT_TRUE(plans[0].IsPostProcessStageValid());
ASSERT_TRUE(renderer.Render(plans));
EXPECT_EQ(commandList.drawCalls, 1u);
EXPECT_GT(device.createTextureCalls, 0u);
EXPECT_GT(device.createPipelineLayoutCalls, 0u);
EXPECT_GT(device.createPipelineStateCalls, 0u);
EXPECT_GT(device.createDescriptorPoolCalls, 0u);
engine->OnUpdate(0.016f);
int observedCreatePipelineCallCount = 0;
int observedSupportsMainSceneCallCount = 0;
int observedSupportsPostProcessCallCount = 0;
int observedRecordMainSceneCallCount = 0;
int observedRecordBuiltinForwardMainSceneCallCount = 0;
int observedRecordPostProcessCallCount = 0;
EXPECT_TRUE(runtime->TryGetFieldValue(
selectionScript,
"ObservedCreatePipelineCallCount",
observedCreatePipelineCallCount));
EXPECT_TRUE(runtime->TryGetFieldValue(
selectionScript,
"ObservedSupportsMainSceneCallCount",
observedSupportsMainSceneCallCount));
EXPECT_TRUE(runtime->TryGetFieldValue(
selectionScript,
"ObservedSupportsPostProcessCallCount",
observedSupportsPostProcessCallCount));
EXPECT_TRUE(runtime->TryGetFieldValue(
selectionScript,
"ObservedRecordMainSceneCallCount",
observedRecordMainSceneCallCount));
EXPECT_TRUE(runtime->TryGetFieldValue(
selectionScript,
"ObservedRecordBuiltinForwardMainSceneCallCount",
observedRecordBuiltinForwardMainSceneCallCount));
EXPECT_TRUE(runtime->TryGetFieldValue(
selectionScript,
"ObservedRecordPostProcessCallCount",
observedRecordPostProcessCallCount));
EXPECT_EQ(observedCreatePipelineCallCount, 1);
EXPECT_GT(observedSupportsMainSceneCallCount, 0);
EXPECT_GT(observedSupportsPostProcessCallCount, 0);
EXPECT_EQ(observedRecordMainSceneCallCount, 1);
EXPECT_EQ(observedRecordBuiltinForwardMainSceneCallCount, 1);
EXPECT_EQ(observedRecordPostProcessCallCount, 1);
}
TEST_F(
MonoScriptRuntimeTest,
RegistersManagedRenderPipelineBridgeThatCreatesManagedStageRecorders) {