#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 CollectSurfaceColorAttachments(const RenderSurface& surface) { std::vector 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 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(renderTargets.size()), renderTargets.data(), depthAttachment); const RHI::Viewport viewport = { static_cast(renderArea.x), static_cast(renderArea.y), static_cast(renderArea.width), static_cast(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 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