refactor: extract scene viewport post-pass planning
This commit is contained in:
@@ -19,6 +19,7 @@ struct MockPipelineState {
|
||||
int initializeCalls = 0;
|
||||
int shutdownCalls = 0;
|
||||
int renderCalls = 0;
|
||||
bool renderResult = true;
|
||||
uint32_t lastSurfaceWidth = 0;
|
||||
uint32_t lastSurfaceHeight = 0;
|
||||
CameraComponent* lastCamera = nullptr;
|
||||
@@ -57,7 +58,7 @@ public:
|
||||
m_state->lastClearFlags = sceneData.cameraData.clearFlags;
|
||||
m_state->renderedCameras.push_back(sceneData.camera);
|
||||
m_state->renderedClearFlags.push_back(sceneData.cameraData.clearFlags);
|
||||
return true;
|
||||
return m_state->renderResult;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -66,9 +67,15 @@ private:
|
||||
|
||||
class TrackingPass final : public RenderPass {
|
||||
public:
|
||||
TrackingPass(std::shared_ptr<MockPipelineState> state, const char* label)
|
||||
TrackingPass(
|
||||
std::shared_ptr<MockPipelineState> state,
|
||||
const char* label,
|
||||
bool initializeResult = true,
|
||||
bool executeResult = true)
|
||||
: m_state(std::move(state))
|
||||
, m_label(label) {
|
||||
, m_label(label)
|
||||
, m_initializeResult(initializeResult)
|
||||
, m_executeResult(executeResult) {
|
||||
}
|
||||
|
||||
const char* GetName() const override {
|
||||
@@ -77,17 +84,23 @@ public:
|
||||
|
||||
bool Initialize(const RenderContext&) override {
|
||||
m_state->eventLog.push_back(std::string("init:") + m_label);
|
||||
return true;
|
||||
return m_initializeResult;
|
||||
}
|
||||
|
||||
bool Execute(const RenderPassContext&) override {
|
||||
m_state->eventLog.push_back(m_label);
|
||||
return true;
|
||||
return m_executeResult;
|
||||
}
|
||||
|
||||
void Shutdown() override {
|
||||
m_state->eventLog.push_back(std::string("shutdown:") + m_label);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<MockPipelineState> m_state;
|
||||
const char* m_label = "";
|
||||
bool m_initializeResult = true;
|
||||
bool m_executeResult = true;
|
||||
};
|
||||
|
||||
RenderContext CreateValidContext() {
|
||||
@@ -163,7 +176,81 @@ TEST(CameraRenderer_Test, ExecutesInjectedPreAndPostPassSequencesAroundPipelineR
|
||||
ASSERT_TRUE(renderer.Render(request));
|
||||
EXPECT_EQ(
|
||||
state->eventLog,
|
||||
(std::vector<std::string>{ "init:pre", "pre", "pipeline", "init:post", "post" }));
|
||||
(std::vector<std::string>{
|
||||
"init:pre",
|
||||
"pre",
|
||||
"pipeline",
|
||||
"init:post",
|
||||
"post",
|
||||
"shutdown:post",
|
||||
"shutdown:pre" }));
|
||||
}
|
||||
|
||||
TEST(CameraRenderer_Test, ShutsDownInitializedPassesWhenPipelineRenderFails) {
|
||||
Scene scene("CameraRendererFailureScene");
|
||||
|
||||
GameObject* cameraObject = scene.CreateGameObject("Camera");
|
||||
auto* camera = cameraObject->AddComponent<CameraComponent>();
|
||||
camera->SetPrimary(true);
|
||||
camera->SetDepth(2.0f);
|
||||
|
||||
auto state = std::make_shared<MockPipelineState>();
|
||||
state->renderResult = false;
|
||||
CameraRenderer renderer(std::make_unique<MockPipeline>(state));
|
||||
|
||||
RenderPassSequence prePasses;
|
||||
prePasses.AddPass(std::make_unique<TrackingPass>(state, "pre"));
|
||||
|
||||
CameraRenderRequest request;
|
||||
request.scene = &scene;
|
||||
request.camera = camera;
|
||||
request.context = CreateValidContext();
|
||||
request.surface = RenderSurface(320, 180);
|
||||
request.cameraDepth = camera->GetDepth();
|
||||
request.preScenePasses = &prePasses;
|
||||
|
||||
EXPECT_FALSE(renderer.Render(request));
|
||||
EXPECT_EQ(
|
||||
state->eventLog,
|
||||
(std::vector<std::string>{ "init:pre", "pre", "pipeline", "shutdown:pre" }));
|
||||
}
|
||||
|
||||
TEST(CameraRenderer_Test, ShutsDownSequencesWhenPostPassInitializationFails) {
|
||||
Scene scene("CameraRendererPostPassInitFailureScene");
|
||||
|
||||
GameObject* cameraObject = scene.CreateGameObject("Camera");
|
||||
auto* camera = cameraObject->AddComponent<CameraComponent>();
|
||||
camera->SetPrimary(true);
|
||||
camera->SetDepth(4.0f);
|
||||
|
||||
auto state = std::make_shared<MockPipelineState>();
|
||||
CameraRenderer renderer(std::make_unique<MockPipeline>(state));
|
||||
|
||||
RenderPassSequence prePasses;
|
||||
prePasses.AddPass(std::make_unique<TrackingPass>(state, "pre"));
|
||||
|
||||
RenderPassSequence postPasses;
|
||||
postPasses.AddPass(std::make_unique<TrackingPass>(state, "post", false, true));
|
||||
|
||||
CameraRenderRequest request;
|
||||
request.scene = &scene;
|
||||
request.camera = camera;
|
||||
request.context = CreateValidContext();
|
||||
request.surface = RenderSurface(512, 512);
|
||||
request.cameraDepth = camera->GetDepth();
|
||||
request.preScenePasses = &prePasses;
|
||||
request.postScenePasses = &postPasses;
|
||||
|
||||
EXPECT_FALSE(renderer.Render(request));
|
||||
EXPECT_EQ(
|
||||
state->eventLog,
|
||||
(std::vector<std::string>{
|
||||
"init:pre",
|
||||
"pre",
|
||||
"pipeline",
|
||||
"init:post",
|
||||
"shutdown:post",
|
||||
"shutdown:pre" }));
|
||||
}
|
||||
|
||||
TEST(SceneRenderer_Test, BuildsSingleExplicitRequestFromSelectedCamera) {
|
||||
|
||||
@@ -6,6 +6,8 @@ set(EDITOR_TEST_SOURCES
|
||||
test_action_routing.cpp
|
||||
test_scene_viewport_camera_controller.cpp
|
||||
test_scene_viewport_move_gizmo.cpp
|
||||
test_scene_viewport_rotate_gizmo.cpp
|
||||
test_scene_viewport_post_pass_plan.cpp
|
||||
test_scene_viewport_picker.cpp
|
||||
test_scene_viewport_overlay_renderer.cpp
|
||||
test_scene_viewport_selection_utils.cpp
|
||||
@@ -14,6 +16,7 @@ set(EDITOR_TEST_SOURCES
|
||||
${CMAKE_SOURCE_DIR}/editor/src/Managers/ProjectManager.cpp
|
||||
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportPicker.cpp
|
||||
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportMoveGizmo.cpp
|
||||
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportRotateGizmo.cpp
|
||||
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportGrid.cpp
|
||||
)
|
||||
|
||||
|
||||
104
tests/editor/test_scene_viewport_post_pass_plan.cpp
Normal file
104
tests/editor/test_scene_viewport_post_pass_plan.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "Viewport/SceneViewportPostPassPlan.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using XCEngine::Editor::BuildSceneViewportPostPassPlan;
|
||||
using XCEngine::Editor::SceneViewportPostPassPlanInput;
|
||||
using XCEngine::Editor::SceneViewportPostPassStep;
|
||||
|
||||
TEST(SceneViewportPostPassPlan_Test, ReturnsInvalidPlanWhenOverlayIsUnavailable) {
|
||||
const auto plan = BuildSceneViewportPostPassPlan({});
|
||||
|
||||
EXPECT_FALSE(plan.valid);
|
||||
EXPECT_TRUE(plan.steps.empty());
|
||||
EXPECT_FALSE(plan.usesSelectionMaskSurface);
|
||||
EXPECT_FALSE(plan.usesSelectionMaskShaderView);
|
||||
}
|
||||
|
||||
TEST(SceneViewportPostPassPlan_Test, BuildsGridOnlyPlanWhenNothingIsSelected) {
|
||||
SceneViewportPostPassPlanInput input = {};
|
||||
input.overlayValid = true;
|
||||
|
||||
const auto plan = BuildSceneViewportPostPassPlan(input);
|
||||
|
||||
ASSERT_TRUE(plan.valid);
|
||||
EXPECT_EQ(
|
||||
plan.steps,
|
||||
(std::vector<SceneViewportPostPassStep>{
|
||||
SceneViewportPostPassStep::ColorToRenderTarget,
|
||||
SceneViewportPostPassStep::InfiniteGrid,
|
||||
SceneViewportPostPassStep::ColorToShaderResource
|
||||
}));
|
||||
EXPECT_FALSE(plan.usesSelectionMaskSurface);
|
||||
EXPECT_FALSE(plan.usesSelectionMaskShaderView);
|
||||
}
|
||||
|
||||
TEST(SceneViewportPostPassPlan_Test, BuildsSelectionOutlinePlanWhenSelectionResourcesExist) {
|
||||
SceneViewportPostPassPlanInput input = {};
|
||||
input.overlayValid = true;
|
||||
input.hasSelection = true;
|
||||
input.hasSelectionMaskRenderTarget = true;
|
||||
input.hasSelectionMaskShaderView = true;
|
||||
|
||||
const auto plan = BuildSceneViewportPostPassPlan(input);
|
||||
|
||||
ASSERT_TRUE(plan.valid);
|
||||
EXPECT_EQ(
|
||||
plan.steps,
|
||||
(std::vector<SceneViewportPostPassStep>{
|
||||
SceneViewportPostPassStep::SelectionMask,
|
||||
SceneViewportPostPassStep::ColorToRenderTarget,
|
||||
SceneViewportPostPassStep::InfiniteGrid,
|
||||
SceneViewportPostPassStep::SelectionOutline,
|
||||
SceneViewportPostPassStep::ColorToShaderResource
|
||||
}));
|
||||
EXPECT_TRUE(plan.usesSelectionMaskSurface);
|
||||
EXPECT_TRUE(plan.usesSelectionMaskShaderView);
|
||||
}
|
||||
|
||||
TEST(SceneViewportPostPassPlan_Test, SkipsSelectionSpecificPassesWhenMaskResourcesAreMissing) {
|
||||
SceneViewportPostPassPlanInput input = {};
|
||||
input.overlayValid = true;
|
||||
input.hasSelection = true;
|
||||
input.hasSelectionMaskRenderTarget = true;
|
||||
input.hasSelectionMaskShaderView = false;
|
||||
|
||||
const auto plan = BuildSceneViewportPostPassPlan(input);
|
||||
|
||||
ASSERT_TRUE(plan.valid);
|
||||
EXPECT_EQ(
|
||||
plan.steps,
|
||||
(std::vector<SceneViewportPostPassStep>{
|
||||
SceneViewportPostPassStep::ColorToRenderTarget,
|
||||
SceneViewportPostPassStep::InfiniteGrid,
|
||||
SceneViewportPostPassStep::ColorToShaderResource
|
||||
}));
|
||||
EXPECT_FALSE(plan.usesSelectionMaskSurface);
|
||||
EXPECT_FALSE(plan.usesSelectionMaskShaderView);
|
||||
}
|
||||
|
||||
TEST(SceneViewportPostPassPlan_Test, BuildsDebugMaskPlanWithoutSelectionMaskTarget) {
|
||||
SceneViewportPostPassPlanInput input = {};
|
||||
input.overlayValid = true;
|
||||
input.hasSelection = true;
|
||||
input.debugSelectionMask = true;
|
||||
|
||||
const auto plan = BuildSceneViewportPostPassPlan(input);
|
||||
|
||||
ASSERT_TRUE(plan.valid);
|
||||
EXPECT_EQ(
|
||||
plan.steps,
|
||||
(std::vector<SceneViewportPostPassStep>{
|
||||
SceneViewportPostPassStep::ColorToRenderTarget,
|
||||
SceneViewportPostPassStep::SelectionMaskDebug,
|
||||
SceneViewportPostPassStep::ColorToShaderResource
|
||||
}));
|
||||
EXPECT_FALSE(plan.usesSelectionMaskSurface);
|
||||
EXPECT_FALSE(plan.usesSelectionMaskShaderView);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user