247 lines
8.5 KiB
C++
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
|