Add render-graph main-scene pipeline recording
This commit is contained in:
@@ -0,0 +1,319 @@
|
||||
#include "Rendering/Pipelines/BuiltinForwardPipeline.h"
|
||||
|
||||
#include "Debug/Logger.h"
|
||||
#include "Rendering/Graph/RenderGraph.h"
|
||||
#include "RHI/RHICommandList.h"
|
||||
#include "Rendering/Internal/RenderSurfacePipelineUtils.h"
|
||||
#include "Rendering/RenderSurface.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Rendering {
|
||||
namespace Pipelines {
|
||||
namespace {
|
||||
|
||||
bool IsDepthFormat(RHI::Format format) {
|
||||
return format == RHI::Format::D24_UNorm_S8_UInt ||
|
||||
format == RHI::Format::D32_Float;
|
||||
}
|
||||
|
||||
void TransitionMainDirectionalShadowForSampling(
|
||||
const RenderContext& context,
|
||||
const RenderSceneData& sceneData) {
|
||||
context.commandList->TransitionBarrier(
|
||||
sceneData.lighting.mainDirectionalShadow.shadowMap,
|
||||
RHI::ResourceStates::DepthWrite,
|
||||
RHI::ResourceStates::PixelShaderResource);
|
||||
}
|
||||
|
||||
void RestoreMainDirectionalShadowAfterSampling(
|
||||
const RenderContext& context,
|
||||
const RenderSceneData& sceneData) {
|
||||
context.commandList->TransitionBarrier(
|
||||
sceneData.lighting.mainDirectionalShadow.shadowMap,
|
||||
RHI::ResourceStates::PixelShaderResource,
|
||||
RHI::ResourceStates::DepthWrite);
|
||||
}
|
||||
|
||||
std::vector<RHI::RHIResourceView*> CollectSurfaceColorAttachments(const RenderSurface& surface) {
|
||||
std::vector<RHI::RHIResourceView*> renderTargets;
|
||||
const Core::uint32 colorAttachmentCount =
|
||||
::XCEngine::Rendering::Internal::ResolveSurfaceColorAttachmentCount(surface);
|
||||
renderTargets.reserve(colorAttachmentCount);
|
||||
for (Core::uint32 attachmentIndex = 0; attachmentIndex < colorAttachmentCount; ++attachmentIndex) {
|
||||
RHI::RHIResourceView* renderTarget = surface.GetColorAttachments()[attachmentIndex];
|
||||
if (renderTarget == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
renderTargets.push_back(renderTarget);
|
||||
}
|
||||
|
||||
return renderTargets;
|
||||
}
|
||||
|
||||
RenderSurface BuildGraphManagedForwardSceneSurface(const RenderSurface& templateSurface) {
|
||||
RenderSurface surface = templateSurface;
|
||||
surface.SetAutoTransitionEnabled(false);
|
||||
return surface;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool BuiltinForwardPipeline::ShouldSampleMainDirectionalShadowMap(const RenderSceneData& sceneData) {
|
||||
return sceneData.lighting.HasMainDirectionalShadow() &&
|
||||
sceneData.lighting.mainDirectionalShadow.shadowMap != nullptr &&
|
||||
IsDepthFormat(sceneData.lighting.mainDirectionalShadow.shadowMap->GetFormat());
|
||||
}
|
||||
|
||||
bool BuiltinForwardPipeline::SupportsMainSceneRenderGraph() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuiltinForwardPipeline::RecordMainSceneRenderGraph(
|
||||
const RenderPipelineMainSceneRenderGraphContext& context) {
|
||||
const Containers::String passName = context.passName;
|
||||
const RenderContext* const renderContext = &context.renderContext;
|
||||
const RenderSceneData* const sceneData = &context.sceneData;
|
||||
const RenderSurface surfaceTemplate =
|
||||
BuildGraphManagedForwardSceneSurface(context.surfaceTemplate);
|
||||
const RenderSurface* const sourceSurface = context.sourceSurface;
|
||||
RHI::RHIResourceView* const sourceColorView = context.sourceColorView;
|
||||
const RHI::ResourceStates sourceColorState = context.sourceColorState;
|
||||
const std::vector<RenderGraphTextureHandle> colorTargets = context.colorTargets;
|
||||
const RenderGraphTextureHandle depthTarget = context.depthTarget;
|
||||
const RenderGraphTextureHandle mainDirectionalShadowTexture =
|
||||
context.mainDirectionalShadowTexture;
|
||||
bool* const executionSucceeded = context.executionSucceeded;
|
||||
|
||||
context.graphBuilder.AddRasterPass(
|
||||
passName,
|
||||
[this,
|
||||
surfaceTemplate,
|
||||
renderContext,
|
||||
sceneData,
|
||||
sourceSurface,
|
||||
sourceColorView,
|
||||
sourceColorState,
|
||||
colorTargets,
|
||||
depthTarget,
|
||||
mainDirectionalShadowTexture,
|
||||
executionSucceeded](
|
||||
RenderGraphPassBuilder& passBuilder) {
|
||||
for (RenderGraphTextureHandle colorTarget : colorTargets) {
|
||||
if (colorTarget.IsValid()) {
|
||||
passBuilder.WriteTexture(colorTarget);
|
||||
}
|
||||
}
|
||||
|
||||
if (depthTarget.IsValid()) {
|
||||
passBuilder.WriteDepthTexture(depthTarget);
|
||||
}
|
||||
if (mainDirectionalShadowTexture.IsValid()) {
|
||||
passBuilder.ReadTexture(mainDirectionalShadowTexture);
|
||||
}
|
||||
|
||||
passBuilder.SetExecuteCallback(
|
||||
[this,
|
||||
surfaceTemplate,
|
||||
renderContext,
|
||||
sceneData,
|
||||
sourceSurface,
|
||||
sourceColorView,
|
||||
sourceColorState,
|
||||
mainDirectionalShadowTexture,
|
||||
executionSucceeded](
|
||||
const RenderGraphExecutionContext&) {
|
||||
if (executionSucceeded != nullptr && !(*executionSucceeded)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const FrameExecutionContext executionContext(
|
||||
*renderContext,
|
||||
surfaceTemplate,
|
||||
*sceneData,
|
||||
sourceSurface,
|
||||
sourceColorView,
|
||||
sourceColorState);
|
||||
const bool renderResult =
|
||||
ExecuteForwardSceneFrame(
|
||||
executionContext,
|
||||
!mainDirectionalShadowTexture.IsValid());
|
||||
if (executionSucceeded != nullptr) {
|
||||
*executionSucceeded = renderResult;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuiltinForwardPipeline::Render(
|
||||
const FrameExecutionContext& executionContext) {
|
||||
return ExecuteForwardSceneFrame(executionContext, true);
|
||||
}
|
||||
|
||||
bool BuiltinForwardPipeline::ExecuteForwardSceneFrame(
|
||||
const FrameExecutionContext& executionContext,
|
||||
bool manageMainDirectionalShadowTransitions) {
|
||||
if (!Initialize(executionContext.renderContext)) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
"BuiltinForwardPipeline::Render failed: Initialize returned false");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_forwardSceneFeatureHost.Prepare(executionContext)) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
"BuiltinForwardPipeline::Render failed: SceneRenderFeatureHost::Prepare returned false");
|
||||
return false;
|
||||
}
|
||||
|
||||
const RenderPassContext passContext = BuildRenderPassContext(executionContext);
|
||||
|
||||
if (!BeginForwardScenePass(passContext)) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
"BuiltinForwardPipeline::Render failed: BeginForwardScenePass returned false");
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool sampledDirectionalShadow =
|
||||
manageMainDirectionalShadowTransitions &&
|
||||
ShouldSampleMainDirectionalShadowMap(executionContext.sceneData);
|
||||
if (sampledDirectionalShadow) {
|
||||
TransitionMainDirectionalShadowForSampling(
|
||||
executionContext.renderContext,
|
||||
executionContext.sceneData);
|
||||
}
|
||||
|
||||
const bool renderResult = ExecuteForwardScene(executionContext);
|
||||
|
||||
if (sampledDirectionalShadow) {
|
||||
RestoreMainDirectionalShadowAfterSampling(
|
||||
executionContext.renderContext,
|
||||
executionContext.sceneData);
|
||||
}
|
||||
EndForwardScenePass(passContext);
|
||||
|
||||
return renderResult;
|
||||
}
|
||||
|
||||
bool BuiltinForwardPipeline::BeginForwardScenePass(const RenderPassContext& passContext) {
|
||||
const RenderContext& context = passContext.renderContext;
|
||||
const RenderSurface& surface = passContext.surface;
|
||||
const RenderSceneData& sceneData = passContext.sceneData;
|
||||
RHI::RHIResourceView* depthAttachment = surface.GetDepthAttachment();
|
||||
|
||||
std::vector<RHI::RHIResourceView*> renderTargets = CollectSurfaceColorAttachments(surface);
|
||||
if (renderTargets.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Math::RectInt renderArea = surface.GetRenderArea();
|
||||
if (renderArea.width <= 0 || renderArea.height <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::RHICommandList* commandList = context.commandList;
|
||||
if (surface.IsAutoTransitionEnabled()) {
|
||||
for (RHI::RHIResourceView* renderTarget : renderTargets) {
|
||||
if (renderTarget != nullptr) {
|
||||
commandList->TransitionBarrier(
|
||||
renderTarget,
|
||||
surface.GetColorStateBefore(),
|
||||
RHI::ResourceStates::RenderTarget);
|
||||
}
|
||||
}
|
||||
|
||||
if (depthAttachment != nullptr) {
|
||||
commandList->TransitionBarrier(
|
||||
depthAttachment,
|
||||
surface.GetDepthStateBefore(),
|
||||
RHI::ResourceStates::DepthWrite);
|
||||
}
|
||||
}
|
||||
|
||||
commandList->SetRenderTargets(
|
||||
static_cast<uint32_t>(renderTargets.size()),
|
||||
renderTargets.data(),
|
||||
depthAttachment);
|
||||
|
||||
const RHI::Viewport viewport = {
|
||||
static_cast<float>(renderArea.x),
|
||||
static_cast<float>(renderArea.y),
|
||||
static_cast<float>(renderArea.width),
|
||||
static_cast<float>(renderArea.height),
|
||||
0.0f,
|
||||
1.0f
|
||||
};
|
||||
const RHI::Rect scissorRect = {
|
||||
renderArea.x,
|
||||
renderArea.y,
|
||||
renderArea.x + renderArea.width,
|
||||
renderArea.y + renderArea.height
|
||||
};
|
||||
const RHI::Rect clearRects[] = { scissorRect };
|
||||
commandList->SetViewport(viewport);
|
||||
commandList->SetScissorRect(scissorRect);
|
||||
|
||||
const Math::Color clearColor = surface.HasClearColorOverride()
|
||||
? surface.GetClearColorOverride()
|
||||
: sceneData.cameraData.clearColor;
|
||||
const float clearValues[4] = { clearColor.r, clearColor.g, clearColor.b, clearColor.a };
|
||||
if (HasRenderClearFlag(sceneData.cameraData.clearFlags, RenderClearFlags::Color) &&
|
||||
!HasSkybox(sceneData)) {
|
||||
for (RHI::RHIResourceView* renderTarget : renderTargets) {
|
||||
if (renderTarget != nullptr) {
|
||||
commandList->ClearRenderTarget(renderTarget, clearValues, 1, clearRects);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (depthAttachment != nullptr &&
|
||||
HasRenderClearFlag(sceneData.cameraData.clearFlags, RenderClearFlags::Depth)) {
|
||||
commandList->ClearDepthStencil(depthAttachment, 1.0f, 0, 1, clearRects);
|
||||
}
|
||||
|
||||
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuiltinForwardPipeline::Render(
|
||||
const RenderContext& context,
|
||||
const RenderSurface& surface,
|
||||
const RenderSceneData& sceneData) {
|
||||
return Render(FrameExecutionContext(context, surface, sceneData));
|
||||
}
|
||||
|
||||
void BuiltinForwardPipeline::EndForwardScenePass(const RenderPassContext& passContext) {
|
||||
const RenderContext& context = passContext.renderContext;
|
||||
const RenderSurface& surface = passContext.surface;
|
||||
RHI::RHIResourceView* depthAttachment = surface.GetDepthAttachment();
|
||||
std::vector<RHI::RHIResourceView*> renderTargets = CollectSurfaceColorAttachments(surface);
|
||||
RHI::RHICommandList* commandList = context.commandList;
|
||||
|
||||
commandList->EndRenderPass();
|
||||
if (!surface.IsAutoTransitionEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (RHI::RHIResourceView* renderTarget : renderTargets) {
|
||||
if (renderTarget != nullptr) {
|
||||
commandList->TransitionBarrier(
|
||||
renderTarget,
|
||||
RHI::ResourceStates::RenderTarget,
|
||||
surface.GetColorStateAfter());
|
||||
}
|
||||
}
|
||||
|
||||
if (depthAttachment != nullptr) {
|
||||
commandList->TransitionBarrier(
|
||||
depthAttachment,
|
||||
RHI::ResourceStates::DepthWrite,
|
||||
surface.GetDepthStateAfter());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Pipelines
|
||||
} // namespace Rendering
|
||||
} // namespace XCEngine
|
||||
Reference in New Issue
Block a user