#include "Rendering/Execution/SceneRenderer.h" #include "Components/CameraComponent.h" #include "Rendering/Caches/FullscreenPassSurfaceCache.h" #include "Rendering/Planning/CameraPostProcessPassFactory.h" #include "Rendering/Planning/FinalColorPassFactory.h" #include "Rendering/Planning/SceneRenderRequestUtils.h" #include "Rendering/RenderPipelineAsset.h" namespace XCEngine { namespace Rendering { namespace { RenderSurface ConfigureFullscreenStageSurface( const FullscreenPassSurfaceCache::SurfaceEntry& entry, const RenderSurface& templateSurface, bool copyDepthAttachment) { RenderSurface surface = entry.surface; if (copyDepthAttachment) { surface.SetDepthAttachment(templateSurface.GetDepthAttachment()); if (templateSurface.HasClearColorOverride()) { surface.SetClearColorOverride(templateSurface.GetClearColorOverride()); } } if (templateSurface.HasCustomRenderArea()) { surface.SetRenderArea(templateSurface.GetRenderArea()); } else { surface.ResetRenderArea(); } surface.SetColorStateBefore(RHI::ResourceStates::Common); surface.SetColorStateAfter(RHI::ResourceStates::PixelShaderResource); return surface; } } // namespace SceneRenderer::SceneRenderer() = default; SceneRenderer::SceneRenderer(std::unique_ptr pipeline) : m_cameraRenderer(std::move(pipeline)) { } SceneRenderer::SceneRenderer(std::shared_ptr pipelineAsset) : m_cameraRenderer(std::move(pipelineAsset)) { } SceneRenderer::~SceneRenderer() = default; void SceneRenderer::SetPipeline(std::unique_ptr pipeline) { m_cameraRenderer.SetPipeline(std::move(pipeline)); } void SceneRenderer::SetPipelineAsset(std::shared_ptr pipelineAsset) { m_cameraRenderer.SetPipelineAsset(std::move(pipelineAsset)); } std::vector SceneRenderer::BuildRenderRequests( const Components::Scene& scene, Components::CameraComponent* overrideCamera, const RenderContext& context, const RenderSurface& surface) { std::vector requests = m_requestPlanner.BuildRequests(scene, overrideCamera, context, surface); ResolveCameraFinalColorPolicies(requests); AttachFullscreenStageRequests(context, requests); return requests; } bool SceneRenderer::Render(const CameraRenderRequest& request) { return m_cameraRenderer.Render(request); } bool SceneRenderer::Render(const std::vector& requests) { if (requests.empty()) { return false; } for (const CameraRenderRequest& request : requests) { if (!request.IsValid()) { return false; } } std::vector sortedRequests = requests; SceneRenderRequestUtils::SortCameraRenderRequests(sortedRequests); bool rendered = false; for (const CameraRenderRequest& request : sortedRequests) { if (!m_cameraRenderer.Render(request)) { return false; } rendered = true; } return rendered; } bool SceneRenderer::Render( const Components::Scene& scene, Components::CameraComponent* overrideCamera, const RenderContext& context, const RenderSurface& surface) { return Render(BuildRenderRequests(scene, overrideCamera, context, surface)); } void SceneRenderer::PrepareOwnedFullscreenStageState(size_t requestCount) { m_ownedPostProcessSequences.clear(); m_ownedPostProcessSequences.resize(requestCount); m_ownedFinalOutputSequences.clear(); m_ownedFinalOutputSequences.resize(requestCount); if (m_ownedFullscreenStageSurfaces.size() < requestCount) { m_ownedFullscreenStageSurfaces.resize(requestCount); } for (size_t index = 0; index < requestCount; ++index) { if (m_ownedFullscreenStageSurfaces[index] == nullptr) { m_ownedFullscreenStageSurfaces[index] = std::make_unique(); } } } void SceneRenderer::ResolveCameraFinalColorPolicies( std::vector& requests) const { const RenderPipelineAsset* pipelineAsset = GetPipelineAsset(); const FinalColorSettings pipelineDefaults = pipelineAsset != nullptr ? pipelineAsset->GetDefaultFinalColorSettings() : FinalColorSettings(); for (CameraRenderRequest& request : requests) { if (request.camera == nullptr) { continue; } request.finalColorPolicy = ResolveFinalColorPolicy( pipelineDefaults, &request.camera->GetFinalColorOverrides(), nullptr); } } void SceneRenderer::AttachFullscreenStageRequests( const RenderContext& context, std::vector& requests) { PrepareOwnedFullscreenStageState(requests.size()); for (size_t index = 0; index < requests.size(); ++index) { CameraRenderRequest& request = requests[index]; if (request.camera == nullptr || request.context.device == nullptr || !HasValidColorTarget(request.surface)) { continue; } std::unique_ptr postProcessSequence = BuildCameraPostProcessPassSequence(request.camera->GetPostProcessPasses()); std::unique_ptr finalOutputSequence = BuildFinalColorPassSequence(request.finalColorPolicy); const bool hasPostProcess = postProcessSequence != nullptr && postProcessSequence->GetPassCount() > 0u; const bool hasFinalOutput = finalOutputSequence != nullptr && finalOutputSequence->GetPassCount() > 0u; if (!hasPostProcess && !hasFinalOutput) { continue; } const std::vector& colorAttachments = request.surface.GetColorAttachments(); const RHI::Format colorFormat = colorAttachments[0]->GetFormat(); if (colorFormat == RHI::Format::Unknown) { continue; } const size_t fullscreenSurfaceCount = hasPostProcess && hasFinalOutput ? 2u : 1u; FullscreenPassSurfaceCache* surfaceCache = m_ownedFullscreenStageSurfaces[index].get(); if (surfaceCache == nullptr || !surfaceCache->EnsureSurfaces( context, request.surface.GetWidth(), request.surface.GetHeight(), colorFormat, fullscreenSurfaceCount)) { continue; } const FullscreenPassSurfaceCache::SurfaceEntry* sceneColorEntry = surfaceCache->GetSurfaceEntry(0u); if (sceneColorEntry == nullptr || sceneColorEntry->shaderResourceView == nullptr) { continue; } const FullscreenPassSurfaceCache::SurfaceEntry* postProcessOutputEntry = hasPostProcess && hasFinalOutput ? surfaceCache->GetSurfaceEntry(1u) : nullptr; if (hasPostProcess && hasFinalOutput && (postProcessOutputEntry == nullptr || postProcessOutputEntry->shaderResourceView == nullptr)) { continue; } if (hasPostProcess) { request.postProcess.sourceSurface = ConfigureFullscreenStageSurface(*sceneColorEntry, request.surface, true); request.postProcess.sourceColorView = sceneColorEntry->shaderResourceView; request.postProcess.destinationSurface = hasFinalOutput ? ConfigureFullscreenStageSurface(*postProcessOutputEntry, request.surface, false) : request.surface; m_ownedPostProcessSequences[index] = std::move(postProcessSequence); request.postProcess.passes = m_ownedPostProcessSequences[index].get(); } if (hasFinalOutput) { const FullscreenPassSurfaceCache::SurfaceEntry* finalOutputSourceEntry = hasPostProcess ? postProcessOutputEntry : sceneColorEntry; request.finalOutput.sourceSurface = hasPostProcess ? request.postProcess.destinationSurface : ConfigureFullscreenStageSurface(*sceneColorEntry, request.surface, true); request.finalOutput.sourceColorView = finalOutputSourceEntry->shaderResourceView; request.finalOutput.destinationSurface = request.surface; m_ownedFinalOutputSequences[index] = std::move(finalOutputSequence); request.finalOutput.passes = m_ownedFinalOutputSequences[index].get(); } } } } // namespace Rendering } // namespace XCEngine