Files
XCEngine/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineFrame.cpp

247 lines
8.5 KiB
C++

#include "Rendering/Pipelines/BuiltinForwardPipeline.h"
#include "Debug/Logger.h"
#include "Rendering/Pipelines/Internal/BuiltinForwardMainSceneGraphBuilder.h"
#include "Rendering/Internal/RenderSurfacePipelineUtils.h"
#include "Rendering/RenderSurface.h"
#include "RHI/RHICommandList.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;
}
} // namespace
bool BuiltinForwardPipeline::ShouldSampleMainDirectionalShadowMap(const RenderSceneData& sceneData) {
return sceneData.lighting.HasMainDirectionalShadow() &&
sceneData.lighting.mainDirectionalShadow.shadowMap != nullptr &&
IsDepthFormat(sceneData.lighting.mainDirectionalShadow.shadowMap->GetFormat());
}
bool BuiltinForwardPipeline::SupportsStageRenderGraph(
CameraFrameStage stage) const {
return SupportsCameraFramePipelineGraphRecording(stage);
}
bool BuiltinForwardPipeline::RecordStageRenderGraph(
const RenderPipelineStageRenderGraphContext& context) {
return context.stage == CameraFrameStage::MainScene &&
Internal::BuiltinForwardMainSceneGraphBuilder::Record(*this, context);
}
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,
bool clearAttachments) {
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 (clearAttachments &&
HasRenderClearFlag(sceneData.cameraData.clearFlags, RenderClearFlags::Color) &&
!HasSkybox(sceneData)) {
for (RHI::RHIResourceView* renderTarget : renderTargets) {
if (renderTarget != nullptr) {
commandList->ClearRenderTarget(renderTarget, clearValues, 1, clearRects);
}
}
}
if (clearAttachments &&
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