#include namespace XCEngine { namespace Rendering { namespace { CameraFrameFullscreenStagePlan* GetMutableFullscreenStagePlan( CameraFramePlan& plan, CameraFrameStage stage) { switch (stage) { case CameraFrameStage::PostProcess: return &plan.colorChain.postProcess; case CameraFrameStage::FinalOutput: return &plan.colorChain.finalOutput; default: return nullptr; } } FullscreenPassRenderRequest* GetMutableFullscreenPassRequest( CameraFramePlan& plan, CameraFrameStage stage) { switch (stage) { case CameraFrameStage::PostProcess: return &plan.postProcess; case CameraFrameStage::FinalOutput: return &plan.finalOutput; default: return nullptr; } } bool DoesStageNeedGraphManagedSceneColor( const CameraFrameFullscreenStagePlan& stagePlan) { return stagePlan.requested && stagePlan.source == CameraFrameColorSource::MainSceneColor; } } // namespace RenderSurface CameraFramePlan::BuildGraphManagedIntermediateSurfaceTemplate( const RenderSurface& surface) { RenderSurface graphManagedSurface = surface; graphManagedSurface.SetColorAttachments({}); graphManagedSurface.SetAutoTransitionEnabled(false); graphManagedSurface.SetColorStateBefore(RHI::ResourceStates::Common); graphManagedSurface.SetColorStateAfter(RHI::ResourceStates::Common); return graphManagedSurface; } RenderSurface CameraFramePlan::BuildCameraDepthOnlySurfaceTemplate( const RenderSurface& surface) { RenderSurface depthOnlySurface = surface; depthOnlySurface.SetColorAttachments({}); depthOnlySurface.ClearClearColorOverride(); return depthOnlySurface; } CameraFramePlan CameraFramePlan::FromRequest(const CameraRenderRequest& request) { CameraFramePlan plan = {}; plan.request = request; plan.shadowCaster = request.shadowCaster; plan.directionalShadow = request.directionalShadow; plan.postProcess = request.postProcess; plan.finalOutput = request.finalOutput; plan.finalColorPolicy = request.finalColorPolicy; plan.preScenePasses = request.preScenePasses; plan.postScenePasses = request.postScenePasses; plan.overlayPasses = request.overlayPasses; plan.shadowCasterStage.requested = request.shadowCaster.IsRequested() || request.directionalShadow.IsValid(); plan.depthOnlyStage.requested = request.depthOnly.IsRequested(); plan.colorChain.postProcess.requested = request.postProcess.IsRequested(); plan.colorChain.finalOutput.requested = request.finalOutput.IsRequested(); return plan; } bool CameraFramePlan::IsValid() const { return request.IsValid(); } void CameraFramePlan::ConfigureGraphManagedSceneSurface() { graphManagedSceneSurface = BuildGraphManagedIntermediateSurfaceTemplate(request.surface); } void CameraFramePlan::ClearOwnedPostProcessSequence() { if (postProcess.passes == m_ownedPostProcessSequence.get()) { postProcess.passes = nullptr; } m_ownedPostProcessSequence.reset(); } void CameraFramePlan::SetOwnedPostProcessSequence( std::shared_ptr sequence) { ClearOwnedPostProcessSequence(); m_ownedPostProcessSequence = std::move(sequence); if (m_ownedPostProcessSequence != nullptr) { postProcess.passes = m_ownedPostProcessSequence.get(); } } void CameraFramePlan::ClearOwnedFinalOutputSequence() { if (finalOutput.passes == m_ownedFinalOutputSequence.get()) { finalOutput.passes = nullptr; } m_ownedFinalOutputSequence.reset(); } void CameraFramePlan::SetOwnedFinalOutputSequence( std::shared_ptr sequence) { ClearOwnedFinalOutputSequence(); m_ownedFinalOutputSequence = std::move(sequence); if (m_ownedFinalOutputSequence != nullptr) { finalOutput.passes = m_ownedFinalOutputSequence.get(); } } bool CameraFramePlan::UsesGraphManagedSceneColor() const { return colorChain.usesGraphManagedSceneColor; } bool CameraFramePlan::UsesGraphManagedOutputColor(CameraFrameStage stage) const { if (SupportsCameraFramePipelineGraphRecording(stage)) { return UsesGraphManagedSceneColor(); } if (const CameraFrameFullscreenStagePlan* fullscreenStagePlan = GetFullscreenStagePlan(stage); fullscreenStagePlan != nullptr) { return fullscreenStagePlan->usesGraphManagedOutputColor; } return false; } CameraFrameColorSource CameraFramePlan::ResolveStageColorSource(CameraFrameStage stage) const { if (const CameraFrameFullscreenStagePlan* fullscreenStagePlan = GetFullscreenStagePlan(stage); fullscreenStagePlan != nullptr) { return fullscreenStagePlan->source; } return CameraFrameColorSource::ExplicitSurface; } bool CameraFramePlan::IsFullscreenStageRequested(CameraFrameStage stage) const { if (const CameraFrameFullscreenStagePlan* fullscreenStagePlan = GetFullscreenStagePlan(stage); fullscreenStagePlan != nullptr) { return fullscreenStagePlan->requested; } return false; } bool CameraFramePlan::RequestFullscreenStage( CameraFrameStage stage, CameraFrameColorSource source, bool usesGraphManagedOutputColor, bool explicitlyConfigured) { CameraFrameFullscreenStagePlan* const fullscreenStagePlan = GetMutableFullscreenStagePlan(*this, stage); FullscreenPassRenderRequest* const fullscreenRequest = GetMutableFullscreenPassRequest(*this, stage); if (fullscreenStagePlan == nullptr || fullscreenRequest == nullptr) { return false; } fullscreenStagePlan->requested = true; fullscreenStagePlan->source = source; fullscreenStagePlan->usesGraphManagedOutputColor = stage == CameraFrameStage::PostProcess ? usesGraphManagedOutputColor : false; fullscreenStagePlan->explicitlyConfigured = fullscreenStagePlan->explicitlyConfigured || explicitlyConfigured; if (source != CameraFrameColorSource::ExplicitSurface) { fullscreenRequest->sourceSurface = {}; fullscreenRequest->sourceColorView = nullptr; fullscreenRequest->sourceColorState = RHI::ResourceStates::Common; } if (stage == CameraFrameStage::PostProcess) { fullscreenRequest->destinationSurface = fullscreenStagePlan->usesGraphManagedOutputColor ? RenderSurface{} : request.surface; } else { fullscreenRequest->destinationSurface = request.surface; } RefreshGraphManagedSceneSurfaceState(); return true; } void CameraFramePlan::ClearFullscreenStage( CameraFrameStage stage, bool explicitlyConfigured) { if (stage == CameraFrameStage::PostProcess) { ClearOwnedPostProcessSequence(); postProcess = {}; colorChain.postProcess = {}; colorChain.postProcess.explicitlyConfigured = explicitlyConfigured; } else if (stage == CameraFrameStage::FinalOutput) { ClearOwnedFinalOutputSequence(); finalOutput = {}; colorChain.finalOutput = {}; colorChain.finalOutput.explicitlyConfigured = explicitlyConfigured; } else { return; } RefreshGraphManagedSceneSurfaceState(); } bool CameraFramePlan::RequestShadowCasterStage( bool explicitlyConfigured) { shadowCasterStage.requested = shadowCaster.IsRequested() || directionalShadow.IsValid(); shadowCasterStage.explicitlyConfigured = shadowCasterStage.explicitlyConfigured || explicitlyConfigured; return shadowCasterStage.requested; } void CameraFramePlan::ClearShadowCasterStage( bool explicitlyConfigured) { shadowCasterStage.requested = false; shadowCasterStage.explicitlyConfigured = shadowCasterStage.explicitlyConfigured || explicitlyConfigured; } bool CameraFramePlan::RequestDepthOnlyStage( bool explicitlyConfigured) { depthOnlyStage.requested = request.depthOnly.IsRequested(); depthOnlyStage.explicitlyConfigured = depthOnlyStage.explicitlyConfigured || explicitlyConfigured; return depthOnlyStage.requested; } void CameraFramePlan::ClearDepthOnlyStage( bool explicitlyConfigured) { depthOnlyStage.requested = false; depthOnlyStage.explicitlyConfigured = depthOnlyStage.explicitlyConfigured || explicitlyConfigured; } bool CameraFramePlan::HasExplicitFullscreenStageConfiguration( CameraFrameStage stage) const { if (const CameraFrameFullscreenStagePlan* fullscreenStagePlan = GetFullscreenStagePlan(stage); fullscreenStagePlan != nullptr) { return fullscreenStagePlan->explicitlyConfigured; } return false; } bool CameraFramePlan::HasExplicitShadowCasterStageConfiguration() const { return shadowCasterStage.explicitlyConfigured; } bool CameraFramePlan::HasExplicitDepthOnlyStageConfiguration() const { return depthOnlyStage.explicitlyConfigured; } bool CameraFramePlan::IsShadowCasterStageRequested() const { return shadowCasterStage.requested; } bool CameraFramePlan::IsDepthOnlyStageRequested() const { return depthOnlyStage.requested; } bool CameraFramePlan::IsPostProcessStageValid() const { if (!IsFullscreenStageRequested(CameraFrameStage::PostProcess)) { return true; } const CameraFrameColorSource postProcessSource = ResolveStageColorSource(CameraFrameStage::PostProcess); if (postProcessSource == CameraFrameColorSource::ExplicitSurface) { return postProcess.IsValid(); } if (postProcessSource != CameraFrameColorSource::MainSceneColor) { return false; } const bool hasUsableDestination = UsesGraphManagedOutputColor(CameraFrameStage::PostProcess) || (HasValidColorTarget(postProcess.destinationSurface) && HasValidSurfaceSampleDescription(postProcess.destinationSurface)); return UsesGraphManagedOutputColor(CameraFrameStage::MainScene) && HasValidSingleSampleColorSource(request.surface) && hasUsableDestination; } bool CameraFramePlan::IsFinalOutputStageValid() const { if (!IsFullscreenStageRequested(CameraFrameStage::FinalOutput)) { return true; } const CameraFrameColorSource finalOutputSource = ResolveStageColorSource(CameraFrameStage::FinalOutput); if (finalOutputSource == CameraFrameColorSource::ExplicitSurface) { return finalOutput.IsValid(); } const bool hasUsableSource = finalOutputSource == CameraFrameColorSource::MainSceneColor ? UsesGraphManagedOutputColor(CameraFrameStage::MainScene) : UsesGraphManagedOutputColor(CameraFrameStage::PostProcess); return hasUsableSource && HasValidColorTarget(finalOutput.destinationSurface) && HasValidSurfaceSampleDescription(finalOutput.destinationSurface); } bool CameraFramePlan::HasFrameStage(CameraFrameStage stage) const { if (SupportsCameraFramePipelineGraphRecording(stage)) { return true; } if (IsCameraFrameSequenceStage(stage)) { if (IsCameraFrameFullscreenSequenceStage(stage)) { return IsFullscreenStageRequested(stage); } if (const FullscreenPassRenderRequest* fullscreenRequest = GetFullscreenPassRequest(stage); fullscreenRequest != nullptr) { return fullscreenRequest->IsRequested(); } return GetPassSequence(stage) != nullptr; } switch (GetCameraFrameStageRequestKind(stage)) { case CameraFrameStageRequestKind::ShadowCaster: return IsShadowCasterStageRequested(); case CameraFrameStageRequestKind::DepthOnly: return IsDepthOnlyStageRequested(); case CameraFrameStageRequestKind::ObjectId: return request.objectId.IsRequested(); default: return false; } } RenderPassSequence* CameraFramePlan::GetPassSequence(CameraFrameStage stage) const { if (!IsCameraFrameSequenceStage(stage)) { return nullptr; } switch (stage) { case CameraFrameStage::PreScenePasses: return preScenePasses; case CameraFrameStage::PostProcess: return postProcess.passes; case CameraFrameStage::FinalOutput: return finalOutput.passes; case CameraFrameStage::PostScenePasses: return postScenePasses; case CameraFrameStage::OverlayPasses: return overlayPasses; default: return nullptr; } } const FullscreenPassRenderRequest* CameraFramePlan::GetFullscreenPassRequest( CameraFrameStage stage) const { switch (stage) { case CameraFrameStage::PostProcess: return &postProcess; case CameraFrameStage::FinalOutput: return &finalOutput; default: return nullptr; } } const CameraFrameFullscreenStagePlan* CameraFramePlan::GetFullscreenStagePlan( CameraFrameStage stage) const { switch (stage) { case CameraFrameStage::PostProcess: return &colorChain.postProcess; case CameraFrameStage::FinalOutput: return &colorChain.finalOutput; default: return nullptr; } } const ScenePassRenderRequest* CameraFramePlan::GetScenePassRequest(CameraFrameStage stage) const { switch (GetCameraFrameStageRequestKind(stage)) { case CameraFrameStageRequestKind::ShadowCaster: return &shadowCaster; case CameraFrameStageRequestKind::DepthOnly: return &request.depthOnly; default: return nullptr; } } const ObjectIdRenderRequest* CameraFramePlan::GetObjectIdRequest(CameraFrameStage stage) const { return GetCameraFrameStageRequestKind(stage) == CameraFrameStageRequestKind::ObjectId ? &request.objectId : nullptr; } const RenderSurface* CameraFramePlan::GetSharedStageOutputSurface( CameraFrameStage stage) const { switch (GetCameraFrameStageSharedOutputSurfaceRole(stage)) { case CameraFrameStageSharedSurfaceRole::MainScene: return &GetMainSceneSurface(); case CameraFrameStageSharedSurfaceRole::FinalComposited: return &GetFinalCompositedSurface(); default: return nullptr; } } const RenderSurface& CameraFramePlan::GetMainSceneSurface() const { if (UsesGraphManagedOutputColor(CameraFrameStage::MainScene) && graphManagedSceneSurface.GetWidth() > 0u && graphManagedSceneSurface.GetHeight() > 0u) { return graphManagedSceneSurface; } if (IsFullscreenStageRequested(CameraFrameStage::PostProcess) && HasValidColorTarget(postProcess.sourceSurface)) { return postProcess.sourceSurface; } if (IsFullscreenStageRequested(CameraFrameStage::FinalOutput) && HasValidColorTarget(finalOutput.sourceSurface)) { return finalOutput.sourceSurface; } return request.surface; } const RenderSurface& CameraFramePlan::GetFinalCompositedSurface() const { if (IsFullscreenStageRequested(CameraFrameStage::FinalOutput) && HasValidColorTarget(finalOutput.destinationSurface)) { return finalOutput.destinationSurface; } if (IsFullscreenStageRequested(CameraFrameStage::PostProcess) && HasValidColorTarget(postProcess.destinationSurface)) { return postProcess.destinationSurface; } return request.surface; } bool CameraFramePlan::RequiresIntermediateSceneColor() const { return IsFullscreenStageRequested(CameraFrameStage::PostProcess) || IsFullscreenStageRequested(CameraFrameStage::FinalOutput); } void CameraFramePlan::RefreshGraphManagedSceneSurfaceState() { colorChain.usesGraphManagedSceneColor = DoesStageNeedGraphManagedSceneColor(colorChain.postProcess) || DoesStageNeedGraphManagedSceneColor(colorChain.finalOutput); if (colorChain.usesGraphManagedSceneColor) { ConfigureGraphManagedSceneSurface(); } else { graphManagedSceneSurface = {}; } } } // namespace Rendering } // namespace XCEngine