Split render-graph main scene into forward segments
This commit is contained in:
@@ -331,7 +331,18 @@ private:
|
||||
bool ExecuteForwardSceneFrame(
|
||||
const FrameExecutionContext& executionContext,
|
||||
bool manageMainDirectionalShadowTransitions);
|
||||
bool BeginForwardScenePass(const RenderPassContext& context);
|
||||
bool ExecuteForwardSceneSteps(
|
||||
const FrameExecutionContext& executionContext,
|
||||
size_t beginStepIndex,
|
||||
size_t endStepIndex);
|
||||
bool ExecuteForwardSceneSegmentPass(
|
||||
const FrameExecutionContext& executionContext,
|
||||
size_t beginStepIndex,
|
||||
size_t endStepIndex,
|
||||
bool clearAttachments);
|
||||
bool BeginForwardScenePass(
|
||||
const RenderPassContext& context,
|
||||
bool clearAttachments = true);
|
||||
void EndForwardScenePass(const RenderPassContext& context);
|
||||
bool ExecuteForwardOpaquePass(const ScenePhaseExecutionContext& context);
|
||||
bool ExecuteForwardSkyboxPass(const RenderPassContext& context);
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include "Rendering/Internal/RenderSurfacePipelineUtils.h"
|
||||
#include "Rendering/RenderSurface.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Rendering {
|
||||
namespace Pipelines {
|
||||
@@ -57,6 +60,36 @@ RenderSurface BuildGraphManagedForwardSceneSurface(const RenderSurface& template
|
||||
return surface;
|
||||
}
|
||||
|
||||
struct ForwardSceneGraphSegmentDesc {
|
||||
const char* suffix = "";
|
||||
size_t beginStepIndex = 0u;
|
||||
size_t endStepIndex = 0u;
|
||||
bool clearAttachments = false;
|
||||
bool samplesMainDirectionalShadow = false;
|
||||
};
|
||||
|
||||
struct ForwardSceneGraphExecutionState {
|
||||
bool initialized = false;
|
||||
};
|
||||
|
||||
const std::array<ForwardSceneGraphSegmentDesc, 3>& GetForwardSceneGraphSegments() {
|
||||
static constexpr std::array<ForwardSceneGraphSegmentDesc, 3> kSegments = {{
|
||||
{ "Opaque", 0u, 3u, true, true },
|
||||
{ "Skybox", 3u, 6u, false, false },
|
||||
{ "Transparent", 6u, 9u, false, true }
|
||||
}};
|
||||
return kSegments;
|
||||
}
|
||||
|
||||
Containers::String BuildForwardSceneSegmentPassName(
|
||||
const Containers::String& baseName,
|
||||
const char* suffix) {
|
||||
std::string name = baseName.CStr();
|
||||
name += '.';
|
||||
name += suffix != nullptr ? suffix : "Segment";
|
||||
return Containers::String(name.c_str());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool BuiltinForwardPipeline::ShouldSampleMainDirectionalShadowMap(const RenderSceneData& sceneData) {
|
||||
@@ -84,21 +117,28 @@ bool BuiltinForwardPipeline::RecordMainSceneRenderGraph(
|
||||
const RenderGraphTextureHandle mainDirectionalShadowTexture =
|
||||
context.mainDirectionalShadowTexture;
|
||||
bool* const executionSucceeded = context.executionSucceeded;
|
||||
const std::shared_ptr<ForwardSceneGraphExecutionState> graphExecutionState =
|
||||
std::make_shared<ForwardSceneGraphExecutionState>();
|
||||
|
||||
context.graphBuilder.AddRasterPass(
|
||||
passName,
|
||||
[this,
|
||||
surfaceTemplate,
|
||||
renderContext,
|
||||
sceneData,
|
||||
sourceSurface,
|
||||
sourceColorView,
|
||||
sourceColorState,
|
||||
colorTargets,
|
||||
depthTarget,
|
||||
mainDirectionalShadowTexture,
|
||||
executionSucceeded](
|
||||
RenderGraphPassBuilder& passBuilder) {
|
||||
for (const ForwardSceneGraphSegmentDesc& segment : GetForwardSceneGraphSegments()) {
|
||||
const Containers::String segmentPassName =
|
||||
BuildForwardSceneSegmentPassName(passName, segment.suffix);
|
||||
context.graphBuilder.AddRasterPass(
|
||||
segmentPassName,
|
||||
[this,
|
||||
graphExecutionState,
|
||||
surfaceTemplate,
|
||||
renderContext,
|
||||
sceneData,
|
||||
sourceSurface,
|
||||
sourceColorView,
|
||||
sourceColorState,
|
||||
colorTargets,
|
||||
depthTarget,
|
||||
mainDirectionalShadowTexture,
|
||||
executionSucceeded,
|
||||
segment](
|
||||
RenderGraphPassBuilder& passBuilder) {
|
||||
for (RenderGraphTextureHandle colorTarget : colorTargets) {
|
||||
if (colorTarget.IsValid()) {
|
||||
passBuilder.WriteTexture(colorTarget);
|
||||
@@ -108,20 +148,22 @@ bool BuiltinForwardPipeline::RecordMainSceneRenderGraph(
|
||||
if (depthTarget.IsValid()) {
|
||||
passBuilder.WriteDepthTexture(depthTarget);
|
||||
}
|
||||
if (mainDirectionalShadowTexture.IsValid()) {
|
||||
if (segment.samplesMainDirectionalShadow &&
|
||||
mainDirectionalShadowTexture.IsValid()) {
|
||||
passBuilder.ReadTexture(mainDirectionalShadowTexture);
|
||||
}
|
||||
|
||||
passBuilder.SetExecuteCallback(
|
||||
[this,
|
||||
graphExecutionState,
|
||||
surfaceTemplate,
|
||||
renderContext,
|
||||
sceneData,
|
||||
sourceSurface,
|
||||
sourceColorView,
|
||||
sourceColorState,
|
||||
mainDirectionalShadowTexture,
|
||||
executionSucceeded](
|
||||
executionSucceeded,
|
||||
segment](
|
||||
const RenderGraphExecutionContext&) {
|
||||
if (executionSucceeded != nullptr && !(*executionSucceeded)) {
|
||||
return;
|
||||
@@ -134,15 +176,40 @@ bool BuiltinForwardPipeline::RecordMainSceneRenderGraph(
|
||||
sourceSurface,
|
||||
sourceColorView,
|
||||
sourceColorState);
|
||||
if (!graphExecutionState->initialized) {
|
||||
if (!Initialize(*renderContext)) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
"BuiltinForwardPipeline::RecordMainSceneRenderGraph failed during execution: Initialize returned false");
|
||||
if (executionSucceeded != nullptr) {
|
||||
*executionSucceeded = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!m_forwardSceneFeatureHost.Prepare(executionContext)) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
"BuiltinForwardPipeline::RecordMainSceneRenderGraph failed during execution: SceneRenderFeatureHost::Prepare returned false");
|
||||
if (executionSucceeded != nullptr) {
|
||||
*executionSucceeded = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
graphExecutionState->initialized = true;
|
||||
}
|
||||
|
||||
const bool renderResult =
|
||||
ExecuteForwardSceneFrame(
|
||||
ExecuteForwardSceneSegmentPass(
|
||||
executionContext,
|
||||
!mainDirectionalShadowTexture.IsValid());
|
||||
segment.beginStepIndex,
|
||||
segment.endStepIndex,
|
||||
segment.clearAttachments);
|
||||
if (executionSucceeded != nullptr) {
|
||||
*executionSucceeded = renderResult;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -199,7 +266,9 @@ bool BuiltinForwardPipeline::ExecuteForwardSceneFrame(
|
||||
return renderResult;
|
||||
}
|
||||
|
||||
bool BuiltinForwardPipeline::BeginForwardScenePass(const RenderPassContext& passContext) {
|
||||
bool BuiltinForwardPipeline::BeginForwardScenePass(
|
||||
const RenderPassContext& passContext,
|
||||
bool clearAttachments) {
|
||||
const RenderContext& context = passContext.renderContext;
|
||||
const RenderSurface& surface = passContext.surface;
|
||||
const RenderSceneData& sceneData = passContext.sceneData;
|
||||
@@ -261,7 +330,8 @@ bool BuiltinForwardPipeline::BeginForwardScenePass(const RenderPassContext& pass
|
||||
? surface.GetClearColorOverride()
|
||||
: sceneData.cameraData.clearColor;
|
||||
const float clearValues[4] = { clearColor.r, clearColor.g, clearColor.b, clearColor.a };
|
||||
if (HasRenderClearFlag(sceneData.cameraData.clearFlags, RenderClearFlags::Color) &&
|
||||
if (clearAttachments &&
|
||||
HasRenderClearFlag(sceneData.cameraData.clearFlags, RenderClearFlags::Color) &&
|
||||
!HasSkybox(sceneData)) {
|
||||
for (RHI::RHIResourceView* renderTarget : renderTargets) {
|
||||
if (renderTarget != nullptr) {
|
||||
@@ -269,7 +339,8 @@ bool BuiltinForwardPipeline::BeginForwardScenePass(const RenderPassContext& pass
|
||||
}
|
||||
}
|
||||
}
|
||||
if (depthAttachment != nullptr &&
|
||||
if (clearAttachments &&
|
||||
depthAttachment != nullptr &&
|
||||
HasRenderClearFlag(sceneData.cameraData.clearFlags, RenderClearFlags::Depth)) {
|
||||
commandList->ClearDepthStencil(depthAttachment, 1.0f, 0, 1, clearRects);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
#include "Rendering/Pipelines/BuiltinForwardPipeline.h"
|
||||
|
||||
#include "Debug/Logger.h"
|
||||
#include "Rendering/Pipelines/Internal/BuiltinForwardSceneSetup.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Rendering {
|
||||
namespace Pipelines {
|
||||
|
||||
ScenePhaseExecutionContext BuiltinForwardPipeline::BuildScenePhaseExecutionContext(
|
||||
const FrameExecutionContext& executionContext,
|
||||
ScenePhase scenePhase) const {
|
||||
return ScenePhaseExecutionContext(
|
||||
executionContext,
|
||||
scenePhase,
|
||||
ShouldSampleMainDirectionalShadowMap(executionContext.sceneData));
|
||||
}
|
||||
|
||||
DrawSettings BuiltinForwardPipeline::BuildDrawSettings(ScenePhase scenePhase) const {
|
||||
DrawSettings drawSettings = {};
|
||||
drawSettings.scenePhase = scenePhase;
|
||||
switch (scenePhase) {
|
||||
case ScenePhase::Opaque:
|
||||
drawSettings.rendererListType = RendererListType::Opaque;
|
||||
break;
|
||||
case ScenePhase::Transparent:
|
||||
drawSettings.rendererListType = RendererListType::Transparent;
|
||||
break;
|
||||
default:
|
||||
drawSettings.rendererListType = RendererListType::AllVisible;
|
||||
break;
|
||||
}
|
||||
|
||||
return drawSettings;
|
||||
}
|
||||
|
||||
bool BuiltinForwardPipeline::ExecuteBuiltinScenePhase(
|
||||
const ScenePhaseExecutionContext& executionContext) {
|
||||
switch (executionContext.scenePhase) {
|
||||
case ScenePhase::Opaque:
|
||||
return ExecuteForwardOpaquePass(executionContext);
|
||||
case ScenePhase::Skybox:
|
||||
return ExecuteForwardSkyboxPass(BuildRenderPassContext(executionContext));
|
||||
case ScenePhase::Transparent:
|
||||
return ExecuteForwardTransparentPass(executionContext);
|
||||
default:
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
(Containers::String("BuiltinForwardPipeline::ExecuteBuiltinScenePhase does not support scene phase: ") +
|
||||
ToString(executionContext.scenePhase)).CStr());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool BuiltinForwardPipeline::ExecuteForwardScene(
|
||||
const FrameExecutionContext& executionContext) {
|
||||
return ExecuteForwardSceneSteps(
|
||||
executionContext,
|
||||
0u,
|
||||
Internal::GetBuiltinForwardSceneSteps().size());
|
||||
}
|
||||
|
||||
bool BuiltinForwardPipeline::ExecuteForwardSceneSteps(
|
||||
const FrameExecutionContext& executionContext,
|
||||
size_t beginStepIndex,
|
||||
size_t endStepIndex) {
|
||||
const auto& steps = Internal::GetBuiltinForwardSceneSteps();
|
||||
if (beginStepIndex > endStepIndex ||
|
||||
endStepIndex > steps.size()) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
"BuiltinForwardPipeline::ExecuteForwardSceneSteps received an invalid step range");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t stepIndex = beginStepIndex; stepIndex < endStepIndex; ++stepIndex) {
|
||||
const Internal::ForwardSceneStep& step = steps[stepIndex];
|
||||
if (step.type == Internal::ForwardSceneStepType::InjectionPoint) {
|
||||
if (m_forwardSceneFeatureHost.Execute(executionContext, step.injectionPoint)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
(Containers::String("BuiltinForwardPipeline::ExecuteForwardScene failed at injection point: ") +
|
||||
ToString(step.injectionPoint)).CStr());
|
||||
return false;
|
||||
}
|
||||
|
||||
const ScenePhaseExecutionContext scenePhaseExecutionContext =
|
||||
BuildScenePhaseExecutionContext(executionContext, step.scenePhase);
|
||||
if (!ExecuteBuiltinScenePhase(scenePhaseExecutionContext)) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
(Containers::String("BuiltinForwardPipeline::ExecuteForwardScene failed during builtin phase: ") +
|
||||
ToString(step.scenePhase)).CStr());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuiltinForwardPipeline::ExecuteForwardSceneSegmentPass(
|
||||
const FrameExecutionContext& executionContext,
|
||||
size_t beginStepIndex,
|
||||
size_t endStepIndex,
|
||||
bool clearAttachments) {
|
||||
const RenderPassContext passContext = BuildRenderPassContext(executionContext);
|
||||
if (!BeginForwardScenePass(passContext, clearAttachments)) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
"BuiltinForwardPipeline::ExecuteForwardSceneSegmentPass failed: BeginForwardScenePass returned false");
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool executeResult =
|
||||
ExecuteForwardSceneSteps(
|
||||
executionContext,
|
||||
beginStepIndex,
|
||||
endStepIndex);
|
||||
EndForwardScenePass(passContext);
|
||||
return executeResult;
|
||||
}
|
||||
|
||||
} // namespace Pipelines
|
||||
} // namespace Rendering
|
||||
} // namespace XCEngine
|
||||
@@ -609,9 +609,19 @@ TEST(BuiltinForwardPipeline_Test, RecordsMainSceneGraphPassWithSampledShadowDepe
|
||||
String errorMessage;
|
||||
ASSERT_TRUE(RenderGraphCompiler::Compile(graph, compiledGraph, &errorMessage))
|
||||
<< errorMessage.CStr();
|
||||
EXPECT_EQ(compiledGraph.GetPassCount(), 1u);
|
||||
EXPECT_STREQ(compiledGraph.GetPassName(0).CStr(), "MainScene");
|
||||
EXPECT_EQ(compiledGraph.GetPassCount(), 3u);
|
||||
EXPECT_STREQ(compiledGraph.GetPassName(0).CStr(), "MainScene.Opaque");
|
||||
EXPECT_STREQ(compiledGraph.GetPassName(1).CStr(), "MainScene.Skybox");
|
||||
EXPECT_STREQ(compiledGraph.GetPassName(2).CStr(), "MainScene.Transparent");
|
||||
EXPECT_EQ(compiledGraph.GetPassType(0), RenderGraphPassType::Raster);
|
||||
EXPECT_EQ(compiledGraph.GetPassType(1), RenderGraphPassType::Raster);
|
||||
EXPECT_EQ(compiledGraph.GetPassType(2), RenderGraphPassType::Raster);
|
||||
|
||||
RenderGraphTextureLifetime shadowLifetime = {};
|
||||
ASSERT_TRUE(compiledGraph.TryGetTextureLifetime(shadowTarget, shadowLifetime));
|
||||
EXPECT_TRUE(shadowLifetime.used);
|
||||
EXPECT_EQ(shadowLifetime.firstPassIndex, 0u);
|
||||
EXPECT_EQ(shadowLifetime.lastPassIndex, 2u);
|
||||
|
||||
RenderGraphTextureTransitionPlan shadowPlan = {};
|
||||
ASSERT_TRUE(compiledGraph.TryGetTextureTransitionPlan(shadowTarget, shadowPlan));
|
||||
|
||||
Reference in New Issue
Block a user