refactor: extract scene viewport post-pass planning

This commit is contained in:
2026-03-31 21:54:00 +08:00
parent ad237cb81e
commit f85fa78dd1
6 changed files with 435 additions and 114 deletions

View File

@@ -0,0 +1,77 @@
#pragma once
#include <cstdint>
#include <vector>
namespace XCEngine {
namespace Editor {
enum class SceneViewportPostPassStep : uint8_t {
SelectionMask,
ColorToRenderTarget,
InfiniteGrid,
SelectionOutline,
ColorToShaderResource,
SelectionMaskDebug
};
struct SceneViewportPostPassPlanInput {
bool overlayValid = false;
bool hasSelection = false;
bool debugSelectionMask = false;
bool hasSelectionMaskRenderTarget = false;
bool hasSelectionMaskShaderView = false;
};
struct SceneViewportPostPassPlan {
bool valid = false;
bool usesSelectionMaskSurface = false;
bool usesSelectionMaskShaderView = false;
std::vector<SceneViewportPostPassStep> steps;
};
inline SceneViewportPostPassPlan BuildSceneViewportPostPassPlan(
const SceneViewportPostPassPlanInput& input) {
SceneViewportPostPassPlan plan = {};
if (!input.overlayValid) {
return plan;
}
plan.valid = true;
if (input.hasSelection && input.debugSelectionMask) {
plan.steps = {
SceneViewportPostPassStep::ColorToRenderTarget,
SceneViewportPostPassStep::SelectionMaskDebug,
SceneViewportPostPassStep::ColorToShaderResource
};
return plan;
}
const bool canRenderSelectionMask =
input.hasSelection &&
input.hasSelectionMaskRenderTarget &&
input.hasSelectionMaskShaderView;
const bool canRenderSelectionOutline =
canRenderSelectionMask &&
input.hasSelectionMaskShaderView;
if (canRenderSelectionMask) {
plan.usesSelectionMaskSurface = true;
plan.usesSelectionMaskShaderView = true;
plan.steps.push_back(SceneViewportPostPassStep::SelectionMask);
}
plan.steps.push_back(SceneViewportPostPassStep::ColorToRenderTarget);
plan.steps.push_back(SceneViewportPostPassStep::InfiniteGrid);
if (canRenderSelectionOutline) {
plan.steps.push_back(SceneViewportPostPassStep::SelectionOutline);
}
plan.steps.push_back(SceneViewportPostPassStep::ColorToShaderResource);
return plan;
}
} // namespace Editor
} // namespace XCEngine

View File

@@ -7,6 +7,7 @@
#include "SceneViewportPicker.h"
#include "SceneViewportCameraController.h"
#include "SceneViewportInfiniteGridPass.h"
#include "SceneViewportPostPassPlan.h"
#include "SceneViewportSelectionMaskPass.h"
#include "SceneViewportSelectionOutlinePass.h"
#include "SceneViewportSelectionUtils.h"
@@ -534,59 +535,35 @@ private:
const Rendering::RenderCameraData& cameraData,
const std::vector<Rendering::VisibleRenderItem>& selectionRenderables,
Rendering::RenderPassSequence& outPostPasses) {
if (!overlay.valid) {
const bool hasSelection = !selectionRenderables.empty();
const bool hasSelectionMaskRenderTarget = entry.selectionMaskView != nullptr;
const bool hasSelectionMaskShaderView = entry.selectionMaskShaderView != nullptr;
if (hasSelection &&
!kDebugSceneSelectionMask &&
(!hasSelectionMaskRenderTarget || !hasSelectionMaskShaderView)) {
SetViewportStatusIfEmpty(entry.statusText, "Scene selection mask target is unavailable");
}
const SceneViewportPostPassPlan plan = BuildSceneViewportPostPassPlan({
overlay.valid,
hasSelection,
kDebugSceneSelectionMask,
hasSelectionMaskRenderTarget,
hasSelectionMaskShaderView
});
if (!plan.valid) {
return false;
}
const bool hasSelection = !selectionRenderables.empty();
if (hasSelection && kDebugSceneSelectionMask) {
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneColorToRenderTarget",
[&entry](const Rendering::RenderPassContext& context) {
context.renderContext.commandList->TransitionBarrier(
entry.colorView,
context.surface.GetColorStateAfter(),
RHI::ResourceStates::RenderTarget);
entry.colorState = RHI::ResourceStates::RenderTarget;
return true;
}));
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneSelectionMaskDebug",
[this, &entry, &cameraData, &selectionRenderables](
const Rendering::RenderPassContext& context) {
const float debugClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
RHI::RHIResourceView* colorView = entry.colorView;
context.renderContext.commandList->SetRenderTargets(1, &colorView, entry.depthView);
context.renderContext.commandList->ClearRenderTarget(colorView, debugClearColor);
const bool rendered = m_sceneSelectionMaskPass.Render(
context.renderContext,
context.surface,
cameraData,
selectionRenderables);
if (!rendered) {
SetViewportStatusIfEmpty(entry.statusText, "Scene selection mask debug pass failed");
}
return rendered;
}));
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneColorToShaderResource",
[&entry](const Rendering::RenderPassContext& context) {
context.renderContext.commandList->TransitionBarrier(
entry.colorView,
RHI::ResourceStates::RenderTarget,
context.surface.GetColorStateAfter());
entry.colorState = context.surface.GetColorStateAfter();
return true;
}));
return true;
Rendering::RenderSurface selectionMaskSurface = {};
if (plan.usesSelectionMaskSurface) {
selectionMaskSurface = BuildSelectionMaskSurface(entry);
}
if (hasSelection) {
if (entry.selectionMaskView == nullptr || entry.selectionMaskShaderView == nullptr) {
SetViewportStatusIfEmpty(entry.statusText, "Scene selection mask target is unavailable");
} else {
Rendering::RenderSurface selectionMaskSurface = BuildSelectionMaskSurface(entry);
for (const SceneViewportPostPassStep step : plan.steps) {
switch (step) {
case SceneViewportPostPassStep::SelectionMask:
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneSelectionMask",
[this, &entry, selectionMaskSurface, &cameraData, &selectionRenderables](
@@ -618,57 +595,85 @@ private:
entry.selectionMaskState = RHI::ResourceStates::PixelShaderResource;
return rendered;
}));
break;
case SceneViewportPostPassStep::ColorToRenderTarget:
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneColorToRenderTarget",
[&entry](const Rendering::RenderPassContext& context) {
context.renderContext.commandList->TransitionBarrier(
entry.colorView,
context.surface.GetColorStateAfter(),
RHI::ResourceStates::RenderTarget);
entry.colorState = RHI::ResourceStates::RenderTarget;
return true;
}));
break;
case SceneViewportPostPassStep::InfiniteGrid:
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneInfiniteGrid",
[this, overlay, &entry](const Rendering::RenderPassContext& context) {
const bool rendered = m_sceneGridPass.Render(
context.renderContext,
context.surface,
overlay);
if (!rendered) {
SetViewportStatusIfEmpty(entry.statusText, "Scene grid pass failed");
}
return rendered;
}));
break;
case SceneViewportPostPassStep::SelectionOutline:
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneSelectionOutline",
[this, &entry](const Rendering::RenderPassContext& context) {
const bool rendered = m_sceneSelectionOutlinePass.Render(
context.renderContext,
context.surface,
entry.selectionMaskShaderView);
if (!rendered) {
SetViewportStatusIfEmpty(entry.statusText, "Scene selection outline pass failed");
}
return rendered;
}));
break;
case SceneViewportPostPassStep::ColorToShaderResource:
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneColorToShaderResource",
[&entry](const Rendering::RenderPassContext& context) {
context.renderContext.commandList->TransitionBarrier(
entry.colorView,
RHI::ResourceStates::RenderTarget,
context.surface.GetColorStateAfter());
entry.colorState = context.surface.GetColorStateAfter();
return true;
}));
break;
case SceneViewportPostPassStep::SelectionMaskDebug:
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneSelectionMaskDebug",
[this, &entry, &cameraData, &selectionRenderables](
const Rendering::RenderPassContext& context) {
const float debugClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
RHI::RHIResourceView* colorView = entry.colorView;
context.renderContext.commandList->SetRenderTargets(1, &colorView, entry.depthView);
context.renderContext.commandList->ClearRenderTarget(colorView, debugClearColor);
const bool rendered = m_sceneSelectionMaskPass.Render(
context.renderContext,
context.surface,
cameraData,
selectionRenderables);
if (!rendered) {
SetViewportStatusIfEmpty(entry.statusText, "Scene selection mask debug pass failed");
}
return rendered;
}));
break;
default:
break;
}
}
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneColorToRenderTarget",
[&entry](const Rendering::RenderPassContext& context) {
context.renderContext.commandList->TransitionBarrier(
entry.colorView,
context.surface.GetColorStateAfter(),
RHI::ResourceStates::RenderTarget);
entry.colorState = RHI::ResourceStates::RenderTarget;
return true;
}));
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneInfiniteGrid",
[this, overlay, &entry](const Rendering::RenderPassContext& context) {
const bool rendered = m_sceneGridPass.Render(
context.renderContext,
context.surface,
overlay);
if (!rendered) {
SetViewportStatusIfEmpty(entry.statusText, "Scene grid pass failed");
}
return rendered;
}));
if (hasSelection && entry.selectionMaskShaderView != nullptr) {
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneSelectionOutline",
[this, &entry](const Rendering::RenderPassContext& context) {
const bool rendered = m_sceneSelectionOutlinePass.Render(
context.renderContext,
context.surface,
entry.selectionMaskShaderView);
if (!rendered) {
SetViewportStatusIfEmpty(entry.statusText, "Scene selection outline pass failed");
}
return rendered;
}));
}
outPostPasses.AddPass(MakeLambdaRenderPass(
"SceneColorToShaderResource",
[&entry](const Rendering::RenderPassContext& context) {
context.renderContext.commandList->TransitionBarrier(
entry.colorView,
RHI::ResourceStates::RenderTarget,
context.surface.GetColorStateAfter());
entry.colorState = context.surface.GetColorStateAfter();
return true;
}));
return true;
}