refactor: move scene view post passes into rendering
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user