refactor: move scene view post passes into rendering

This commit is contained in:
2026-04-02 04:42:35 +08:00
parent c080890c9d
commit 0d3851204f
6 changed files with 383 additions and 198 deletions

View File

@@ -13,13 +13,13 @@
#include <XCEngine/Components/CameraComponent.h>
#include <XCEngine/Components/GameObject.h>
#include <XCEngine/Core/Asset/ResourceManager.h>
#include <XCEngine/RHI/RHIDevice.h>
#include <XCEngine/RHI/RHIEnums.h>
#include <XCEngine/RHI/RHIResourceView.h>
#include <XCEngine/RHI/RHITexture.h>
#include <XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h>
#include <XCEngine/Rendering/Passes/BuiltinSceneViewPostPassPlan.h>
#include <XCEngine/Rendering/Passes/BuiltinObjectIdOutlinePass.h>
#include <XCEngine/Rendering/Passes/BuiltinSceneViewPostPassSequenceBuilder.h>
#include <XCEngine/Rendering/RenderContext.h>
#include <XCEngine/Rendering/RenderSurface.h>
#include <XCEngine/Rendering/SceneRenderer.h>
@@ -27,10 +27,8 @@
#include <array>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>
namespace XCEngine {
@@ -40,35 +38,6 @@ namespace {
constexpr bool kDebugSceneSelectionMask = false;
class LambdaRenderPass final : public Rendering::RenderPass {
public:
using ExecuteCallback = std::function<bool(const Rendering::RenderPassContext&)>;
LambdaRenderPass(std::string name, ExecuteCallback executeCallback)
: m_name(std::move(name))
, m_executeCallback(std::move(executeCallback)) {
}
const char* GetName() const override {
return m_name.c_str();
}
bool Execute(const Rendering::RenderPassContext& context) override {
return m_executeCallback != nullptr && m_executeCallback(context);
}
private:
std::string m_name;
ExecuteCallback m_executeCallback;
};
template <typename Callback>
std::unique_ptr<Rendering::RenderPass> MakeLambdaRenderPass(const char* name, Callback&& callback) {
return std::make_unique<LambdaRenderPass>(
name,
LambdaRenderPass::ExecuteCallback(std::forward<Callback>(callback)));
}
Rendering::Passes::InfiniteGridPassData BuildInfiniteGridPassData(
const SceneViewportOverlayData& overlay) {
Rendering::Passes::InfiniteGridPassData data = {};
@@ -123,8 +92,7 @@ public:
m_sceneViewLastRenderContext = {};
m_device = nullptr;
m_backend = nullptr;
m_sceneGridPass.Shutdown();
m_sceneSelectionOutlinePass.Shutdown();
m_sceneViewPostPassBuilder.Shutdown();
m_sceneRenderer.reset();
}
@@ -444,176 +412,32 @@ private:
policy.clearColor.a);
}
void AddSceneColorToRenderTargetPass(
ViewportEntry& entry,
Rendering::RenderPassSequence& outPostPasses) {
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneColorToRenderTarget",
[&entry](const Rendering::RenderPassContext& context) {
context.renderContext.commandList->TransitionBarrier(
entry.renderTargets.colorView,
context.surface.GetColorStateAfter(),
RHI::ResourceStates::RenderTarget);
entry.renderTargets.colorState = RHI::ResourceStates::RenderTarget;
return true;
}));
}
void AddSceneInfiniteGridPass(
ViewportEntry& entry,
const SceneViewportOverlayData& overlay,
Rendering::RenderPassSequence& outPostPasses) {
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneInfiniteGrid",
[this, overlay, &entry](const Rendering::RenderPassContext& context) {
const bool rendered = m_sceneGridPass.Render(
context.renderContext,
context.surface,
BuildInfiniteGridPassData(overlay));
if (!rendered) {
SetViewportStatusIfEmpty(entry.statusText, "Scene grid pass failed");
}
return rendered;
}));
}
void AddSceneSelectionOutlinePass(
ViewportEntry& entry,
const std::vector<uint64_t>& selectedObjectIds,
Rendering::RenderPassSequence& outPostPasses) {
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneSelectionOutline",
[this, &entry, selectedObjectIds](const Rendering::RenderPassContext& context) {
const bool rendered = m_sceneSelectionOutlinePass.Render(
context.renderContext,
context.surface,
entry.renderTargets.objectIdShaderView,
selectedObjectIds,
Rendering::Passes::ObjectIdOutlineStyle{
Math::Color(1.0f, 0.4f, 0.0f, 1.0f),
2.0f,
false
});
if (!rendered) {
SetViewportStatusIfEmpty(entry.statusText, "Scene selection outline pass failed");
}
return rendered;
}));
}
void AddSceneColorToShaderResourcePass(
ViewportEntry& entry,
Rendering::RenderPassSequence& outPostPasses) {
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneColorToShaderResource",
[&entry](const Rendering::RenderPassContext& context) {
context.renderContext.commandList->TransitionBarrier(
entry.renderTargets.colorView,
RHI::ResourceStates::RenderTarget,
context.surface.GetColorStateAfter());
entry.renderTargets.colorState = context.surface.GetColorStateAfter();
return true;
}));
}
void AddSceneSelectionMaskDebugPass(
ViewportEntry& entry,
const std::vector<uint64_t>& selectedObjectIds,
Rendering::RenderPassSequence& outPostPasses) {
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneSelectionMaskDebug",
[this, &entry, selectedObjectIds](
const Rendering::RenderPassContext& context) {
const float debugClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
RHI::RHIResourceView* colorView = entry.renderTargets.colorView;
context.renderContext.commandList->SetRenderTargets(
1,
&colorView,
entry.renderTargets.depthView);
context.renderContext.commandList->ClearRenderTarget(colorView, debugClearColor);
const bool rendered = m_sceneSelectionOutlinePass.Render(
context.renderContext,
context.surface,
entry.renderTargets.objectIdShaderView,
selectedObjectIds,
Rendering::Passes::ObjectIdOutlineStyle{
Math::Color(1.0f, 0.4f, 0.0f, 1.0f),
2.0f,
true
});
if (!rendered) {
SetViewportStatusIfEmpty(entry.statusText, "Scene selection mask debug pass failed");
}
return rendered;
}));
}
void AddSceneViewPostPassStep(
Rendering::Passes::BuiltinSceneViewPostPassStep step,
ViewportEntry& entry,
const SceneViewportOverlayData& overlay,
const std::vector<uint64_t>& selectedObjectIds,
Rendering::RenderPassSequence& outPostPasses) {
switch (step) {
case Rendering::Passes::BuiltinSceneViewPostPassStep::ColorToRenderTarget:
AddSceneColorToRenderTargetPass(entry, outPostPasses);
break;
case Rendering::Passes::BuiltinSceneViewPostPassStep::InfiniteGrid:
AddSceneInfiniteGridPass(entry, overlay, outPostPasses);
break;
case Rendering::Passes::BuiltinSceneViewPostPassStep::SelectionOutline:
AddSceneSelectionOutlinePass(entry, selectedObjectIds, outPostPasses);
break;
case Rendering::Passes::BuiltinSceneViewPostPassStep::ColorToShaderResource:
AddSceneColorToShaderResourcePass(entry, outPostPasses);
break;
case Rendering::Passes::BuiltinSceneViewPostPassStep::SelectionMaskDebug:
AddSceneSelectionMaskDebugPass(
entry,
selectedObjectIds,
outPostPasses);
break;
default:
break;
}
}
bool BuildSceneViewPostPassSequence(
ViewportEntry& entry,
const SceneViewportOverlayData& overlay,
const std::vector<uint64_t>& selectedObjectIds,
Rendering::RenderPassSequence& outPostPasses) {
const bool hasSelection = !selectedObjectIds.empty();
const bool hasObjectIdShaderView = entry.renderTargets.objectIdShaderView != nullptr;
Rendering::Passes::ObjectIdOutlineStyle outlineStyle = {};
outlineStyle.outlineColor = Math::Color(1.0f, 0.4f, 0.0f, 1.0f);
outlineStyle.outlineWidthPixels = 2.0f;
outlineStyle.debugSelectionMask = kDebugSceneSelectionMask;
if (hasSelection &&
!kDebugSceneSelectionMask &&
!hasObjectIdShaderView) {
const Rendering::Passes::BuiltinSceneViewPostPassSequenceBuildResult result =
m_sceneViewPostPassBuilder.Build(
{
BuildInfiniteGridPassData(overlay),
entry.renderTargets.objectIdShaderView,
selectedObjectIds,
outlineStyle
},
outPostPasses);
if (result.missingObjectIdTextureViewForSelection &&
!kDebugSceneSelectionMask) {
SetViewportStatusIfEmpty(entry.statusText, "Scene object id shader view is unavailable");
}
const Rendering::Passes::BuiltinSceneViewPostPassPlan plan =
Rendering::Passes::BuildBuiltinSceneViewPostPassPlan({
overlay.valid,
hasSelection,
kDebugSceneSelectionMask,
hasObjectIdShaderView
});
if (!plan.valid) {
return false;
}
for (const Rendering::Passes::BuiltinSceneViewPostPassStep step : plan.steps) {
AddSceneViewPostPassStep(
step,
entry,
overlay,
selectedObjectIds,
outPostPasses);
}
return true;
return result.valid;
}
void BuildSceneViewportRenderState(
@@ -693,6 +517,10 @@ private:
}
MarkSceneViewportRenderSuccess(entry.renderTargets, requests[0]);
const Core::uint32 pendingAsyncLoads = Resources::ResourceManager::Get().GetAsyncPendingCount();
if (pendingAsyncLoads > 0) {
entry.statusText = "Loading scene assets... (" + std::to_string(pendingAsyncLoads) + ")";
}
return true;
}
@@ -829,8 +657,7 @@ private:
Rendering::RenderContext m_sceneViewLastRenderContext = {};
std::array<ViewportEntry, 2> m_entries = {};
SceneViewCameraState m_sceneViewCamera;
Rendering::Passes::BuiltinInfiniteGridPass m_sceneGridPass;
Rendering::Passes::BuiltinObjectIdOutlinePass m_sceneSelectionOutlinePass;
Rendering::Passes::BuiltinSceneViewPostPassSequenceBuilder m_sceneViewPostPassBuilder;
};
} // namespace Editor

View File

@@ -358,11 +358,13 @@ add_library(XCEngine STATIC
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinObjectIdPass.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinSceneViewPostPassPlan.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinSceneViewPostPassSequenceBuilder.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinObjectIdOutlinePass.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/CameraRenderer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinObjectIdPass.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinInfiniteGridPass.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinSceneViewPostPassSequenceBuilder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinObjectIdOutlinePass.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/RenderSurface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/RenderSceneExtractor.cpp

View File

@@ -0,0 +1,59 @@
#pragma once
#include <XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h>
#include <XCEngine/Rendering/Passes/BuiltinObjectIdOutlinePass.h>
#include <XCEngine/Rendering/RenderPass.h>
#include <cstdint>
#include <vector>
namespace XCEngine {
namespace Rendering {
namespace Passes {
struct BuiltinSceneViewPostPassSequenceInput {
InfiniteGridPassData gridPassData = {};
RHI::RHIResourceView* objectIdTextureView = nullptr;
std::vector<uint64_t> selectedObjectIds = {};
ObjectIdOutlineStyle outlineStyle = {};
};
struct BuiltinSceneViewPostPassSequenceBuildResult {
bool valid = false;
bool missingObjectIdTextureViewForSelection = false;
};
class BuiltinSceneViewPostPassSequenceBuilder {
public:
~BuiltinSceneViewPostPassSequenceBuilder();
void Shutdown();
BuiltinSceneViewPostPassSequenceBuildResult Build(
const BuiltinSceneViewPostPassSequenceInput& input,
RenderPassSequence& outSequence);
private:
void AddColorToRenderTargetPass(RenderPassSequence& outSequence);
void AddInfiniteGridPass(
const InfiniteGridPassData& gridPassData,
RenderPassSequence& outSequence);
void AddSelectionOutlinePass(
RHI::RHIResourceView* objectIdTextureView,
const std::vector<uint64_t>& selectedObjectIds,
const ObjectIdOutlineStyle& outlineStyle,
RenderPassSequence& outSequence);
void AddColorToShaderResourcePass(RenderPassSequence& outSequence);
void AddSelectionMaskDebugPass(
RHI::RHIResourceView* objectIdTextureView,
const std::vector<uint64_t>& selectedObjectIds,
const ObjectIdOutlineStyle& outlineStyle,
RenderPassSequence& outSequence);
BuiltinInfiniteGridPass m_gridPass;
BuiltinObjectIdOutlinePass m_outlinePass;
};
} // namespace Passes
} // namespace Rendering
} // namespace XCEngine

View File

@@ -0,0 +1,214 @@
#include "Rendering/Passes/BuiltinSceneViewPostPassSequenceBuilder.h"
#include "Rendering/Passes/BuiltinSceneViewPostPassPlan.h"
#include <XCEngine/Core/Math/Color.h>
#include <XCEngine/RHI/RHICommandList.h>
#include <functional>
#include <memory>
#include <string>
#include <utility>
namespace XCEngine {
namespace Rendering {
namespace Passes {
namespace {
class LambdaRenderPass final : public RenderPass {
public:
using ExecuteCallback = std::function<bool(const RenderPassContext&)>;
LambdaRenderPass(std::string name, ExecuteCallback executeCallback)
: m_name(std::move(name))
, m_executeCallback(std::move(executeCallback)) {
}
const char* GetName() const override {
return m_name.c_str();
}
bool Execute(const RenderPassContext& context) override {
return m_executeCallback != nullptr && m_executeCallback(context);
}
private:
std::string m_name;
ExecuteCallback m_executeCallback;
};
template <typename Callback>
std::unique_ptr<RenderPass> MakeLambdaRenderPass(const char* name, Callback&& callback) {
return std::make_unique<LambdaRenderPass>(
name,
LambdaRenderPass::ExecuteCallback(std::forward<Callback>(callback)));
}
} // namespace
BuiltinSceneViewPostPassSequenceBuilder::~BuiltinSceneViewPostPassSequenceBuilder() {
Shutdown();
}
void BuiltinSceneViewPostPassSequenceBuilder::Shutdown() {
m_outlinePass.Shutdown();
m_gridPass.Shutdown();
}
BuiltinSceneViewPostPassSequenceBuildResult BuiltinSceneViewPostPassSequenceBuilder::Build(
const BuiltinSceneViewPostPassSequenceInput& input,
RenderPassSequence& outSequence) {
BuiltinSceneViewPostPassSequenceBuildResult result = {};
const bool hasSelection = !input.selectedObjectIds.empty();
const bool hasObjectIdTextureView = input.objectIdTextureView != nullptr;
if (hasSelection && !hasObjectIdTextureView) {
result.missingObjectIdTextureViewForSelection = true;
}
const BuiltinSceneViewPostPassPlan plan = BuildBuiltinSceneViewPostPassPlan({
input.gridPassData.valid,
hasSelection,
input.outlineStyle.debugSelectionMask,
hasObjectIdTextureView
});
if (!plan.valid) {
return result;
}
result.valid = true;
for (const BuiltinSceneViewPostPassStep step : plan.steps) {
switch (step) {
case BuiltinSceneViewPostPassStep::ColorToRenderTarget:
AddColorToRenderTargetPass(outSequence);
break;
case BuiltinSceneViewPostPassStep::InfiniteGrid:
AddInfiniteGridPass(input.gridPassData, outSequence);
break;
case BuiltinSceneViewPostPassStep::SelectionOutline:
AddSelectionOutlinePass(
input.objectIdTextureView,
input.selectedObjectIds,
input.outlineStyle,
outSequence);
break;
case BuiltinSceneViewPostPassStep::ColorToShaderResource:
AddColorToShaderResourcePass(outSequence);
break;
case BuiltinSceneViewPostPassStep::SelectionMaskDebug:
AddSelectionMaskDebugPass(
input.objectIdTextureView,
input.selectedObjectIds,
input.outlineStyle,
outSequence);
break;
default:
break;
}
}
return result;
}
void BuiltinSceneViewPostPassSequenceBuilder::AddColorToRenderTargetPass(
RenderPassSequence& outSequence) {
outSequence.AddPass(MakeLambdaRenderPass(
"SceneColorToRenderTarget",
[](const RenderPassContext& context) {
const std::vector<RHI::RHIResourceView*>& colorAttachments = context.surface.GetColorAttachments();
if (colorAttachments.empty() || colorAttachments[0] == nullptr || context.renderContext.commandList == nullptr) {
return false;
}
context.renderContext.commandList->TransitionBarrier(
colorAttachments[0],
context.surface.GetColorStateAfter(),
RHI::ResourceStates::RenderTarget);
return true;
}));
}
void BuiltinSceneViewPostPassSequenceBuilder::AddInfiniteGridPass(
const InfiniteGridPassData& gridPassData,
RenderPassSequence& outSequence) {
outSequence.AddPass(MakeLambdaRenderPass(
"SceneInfiniteGrid",
[this, gridPassData](const RenderPassContext& context) {
return m_gridPass.Render(
context.renderContext,
context.surface,
gridPassData);
}));
}
void BuiltinSceneViewPostPassSequenceBuilder::AddSelectionOutlinePass(
RHI::RHIResourceView* objectIdTextureView,
const std::vector<uint64_t>& selectedObjectIds,
const ObjectIdOutlineStyle& outlineStyle,
RenderPassSequence& outSequence) {
outSequence.AddPass(MakeLambdaRenderPass(
"SceneSelectionOutline",
[this, objectIdTextureView, selectedObjectIds, outlineStyle](const RenderPassContext& context) {
return m_outlinePass.Render(
context.renderContext,
context.surface,
objectIdTextureView,
selectedObjectIds,
outlineStyle);
}));
}
void BuiltinSceneViewPostPassSequenceBuilder::AddColorToShaderResourcePass(
RenderPassSequence& outSequence) {
outSequence.AddPass(MakeLambdaRenderPass(
"SceneColorToShaderResource",
[](const RenderPassContext& context) {
const std::vector<RHI::RHIResourceView*>& colorAttachments = context.surface.GetColorAttachments();
if (colorAttachments.empty() || colorAttachments[0] == nullptr || context.renderContext.commandList == nullptr) {
return false;
}
context.renderContext.commandList->TransitionBarrier(
colorAttachments[0],
RHI::ResourceStates::RenderTarget,
context.surface.GetColorStateAfter());
return true;
}));
}
void BuiltinSceneViewPostPassSequenceBuilder::AddSelectionMaskDebugPass(
RHI::RHIResourceView* objectIdTextureView,
const std::vector<uint64_t>& selectedObjectIds,
const ObjectIdOutlineStyle& outlineStyle,
RenderPassSequence& outSequence) {
outSequence.AddPass(MakeLambdaRenderPass(
"SceneSelectionMaskDebug",
[this, objectIdTextureView, selectedObjectIds, outlineStyle](const RenderPassContext& context) {
const std::vector<RHI::RHIResourceView*>& colorAttachments = context.surface.GetColorAttachments();
if (colorAttachments.empty() || colorAttachments[0] == nullptr || context.renderContext.commandList == nullptr) {
return false;
}
const float debugClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
RHI::RHIResourceView* colorView = colorAttachments[0];
context.renderContext.commandList->SetRenderTargets(
1,
&colorView,
context.surface.GetDepthAttachment());
context.renderContext.commandList->ClearRenderTarget(colorView, debugClearColor);
ObjectIdOutlineStyle debugStyle = outlineStyle;
debugStyle.debugSelectionMask = true;
return m_outlinePass.Render(
context.renderContext,
context.surface,
objectIdTextureView,
selectedObjectIds,
debugStyle);
}));
}
} // namespace Passes
} // namespace Rendering
} // namespace XCEngine

View File

@@ -6,6 +6,7 @@ set(RENDERING_UNIT_TEST_SOURCES
test_render_pass.cpp
test_builtin_forward_pipeline.cpp
test_builtin_scene_view_post_pass_plan.cpp
test_builtin_scene_view_post_pass_sequence_builder.cpp
test_camera_scene_renderer.cpp
test_scene_render_request_planner.cpp
test_scene_render_request_utils.cpp

View File

@@ -0,0 +1,82 @@
#include <gtest/gtest.h>
#include <XCEngine/Rendering/Passes/BuiltinSceneViewPostPassSequenceBuilder.h>
namespace {
using XCEngine::Rendering::Passes::BuiltinSceneViewPostPassSequenceBuilder;
using XCEngine::Rendering::Passes::BuiltinSceneViewPostPassSequenceInput;
using XCEngine::Rendering::Passes::ObjectIdOutlineStyle;
using XCEngine::Rendering::RenderPassSequence;
TEST(BuiltinSceneViewPostPassSequenceBuilder_Test, ReturnsInvalidSequenceWhenGridDataIsUnavailable) {
BuiltinSceneViewPostPassSequenceBuilder builder;
RenderPassSequence sequence;
const auto result = builder.Build({}, sequence);
EXPECT_FALSE(result.valid);
EXPECT_FALSE(result.missingObjectIdTextureViewForSelection);
EXPECT_EQ(sequence.GetPassCount(), 0u);
}
TEST(BuiltinSceneViewPostPassSequenceBuilder_Test, BuildsGridOnlySequenceWhenNothingIsSelected) {
BuiltinSceneViewPostPassSequenceBuilder builder;
RenderPassSequence sequence;
BuiltinSceneViewPostPassSequenceInput input = {};
input.gridPassData.valid = true;
const auto result = builder.Build(input, sequence);
EXPECT_TRUE(result.valid);
EXPECT_FALSE(result.missingObjectIdTextureViewForSelection);
EXPECT_EQ(sequence.GetPassCount(), 3u);
}
TEST(BuiltinSceneViewPostPassSequenceBuilder_Test, BuildsSelectionOutlineSequenceWhenObjectIdTextureViewExists) {
BuiltinSceneViewPostPassSequenceBuilder builder;
RenderPassSequence sequence;
BuiltinSceneViewPostPassSequenceInput input = {};
input.gridPassData.valid = true;
input.objectIdTextureView = reinterpret_cast<XCEngine::RHI::RHIResourceView*>(1);
input.selectedObjectIds = { 7u, 11u };
const auto result = builder.Build(input, sequence);
EXPECT_TRUE(result.valid);
EXPECT_FALSE(result.missingObjectIdTextureViewForSelection);
EXPECT_EQ(sequence.GetPassCount(), 4u);
}
TEST(BuiltinSceneViewPostPassSequenceBuilder_Test, ReportsMissingObjectIdTextureViewAndFallsBackToGridOnlySequence) {
BuiltinSceneViewPostPassSequenceBuilder builder;
RenderPassSequence sequence;
BuiltinSceneViewPostPassSequenceInput input = {};
input.gridPassData.valid = true;
input.selectedObjectIds = { 42u };
const auto result = builder.Build(input, sequence);
EXPECT_TRUE(result.valid);
EXPECT_TRUE(result.missingObjectIdTextureViewForSelection);
EXPECT_EQ(sequence.GetPassCount(), 3u);
}
TEST(BuiltinSceneViewPostPassSequenceBuilder_Test, BuildsDebugMaskSequenceWhenRequested) {
BuiltinSceneViewPostPassSequenceBuilder builder;
RenderPassSequence sequence;
BuiltinSceneViewPostPassSequenceInput input = {};
input.gridPassData.valid = true;
input.objectIdTextureView = reinterpret_cast<XCEngine::RHI::RHIResourceView*>(1);
input.selectedObjectIds = { 5u };
input.outlineStyle = ObjectIdOutlineStyle{};
input.outlineStyle.debugSelectionMask = true;
const auto result = builder.Build(input, sequence);
EXPECT_TRUE(result.valid);
EXPECT_FALSE(result.missingObjectIdTextureViewForSelection);
EXPECT_EQ(sequence.GetPassCount(), 3u);
}
} // namespace