using System.Collections.Generic; using XCEngine; using XCEngine.Rendering; namespace XCEngine.Rendering.Universal { public abstract class ScriptableRenderer { private readonly List m_features = new List(); private readonly List m_activePassQueue = new List(); private bool m_disposed; protected ScriptableRenderer() { } internal void ReleaseRuntimeResourcesInstance() { if (m_disposed) { return; } ReleaseRuntimeResources(); for (int i = 0; i < m_features.Count; ++i) { ScriptableRendererFeature feature = m_features[i]; if (feature != null) { feature.ReleaseRuntimeResourcesInstance(); } } m_features.Clear(); m_activePassQueue.Clear(); m_disposed = true; } public void EnqueuePass( ScriptableRenderPass renderPass) { if (renderPass == null) { return; } int insertIndex = m_activePassQueue.Count; while (insertIndex > 0 && m_activePassQueue[insertIndex - 1].renderPassEvent > renderPass.renderPassEvent) { insertIndex--; } m_activePassQueue.Insert( insertIndex, renderPass); } protected void AddFeature( ScriptableRendererFeature feature) { if (feature == null) { return; } m_features.Add(feature); feature.CreateInstance(); } protected virtual void AddRenderPasses( RenderingData renderingData) { } internal void AddFeatureInstance( ScriptableRendererFeature feature) { AddFeature(feature); } internal bool SupportsRendererRecordingInstance( RendererRecordingContext context) { return SupportsRendererRecording(context); } internal void ConfigureCameraFramePlanInstance( ScriptableRenderPipelinePlanningContext context) { ConfigureCameraFramePlan(context); } internal void FinalizeCameraFramePlanInstance( ScriptableRenderPipelinePlanningContext context) { FinalizeCameraFramePlan(context); } internal bool RecordRendererInstance( RendererRecordingContext context) { return RecordRenderer(context); } protected virtual bool SupportsRendererRecording( RendererRecordingContext context) { if (context == null) { return false; } RenderingData renderingData = context.renderingData; BuildPassQueue(renderingData); for (int i = 0; i < m_activePassQueue.Count; ++i) { ScriptableRenderPass renderPass = m_activePassQueue[i]; if (renderPass != null && renderPass.SupportsStage(context.stage)) { return true; } } return false; } protected virtual bool RecordRenderer( RendererRecordingContext context) { if (context == null || context.renderContext == null) { return false; } RenderingData renderingData = context.renderingData; BuildPassQueue(renderingData); bool recordedAnyPass = false; for (int i = 0; i < m_activePassQueue.Count; ++i) { ScriptableRenderPass renderPass = m_activePassQueue[i]; if (renderPass == null || !renderPass.SupportsStage(renderingData.stage)) { continue; } if (!renderPass.Record( context.renderContext, renderingData)) { return false; } recordedAnyPass = true; } return recordedAnyPass; } protected internal virtual bool SupportsStageRenderGraph( CameraFrameStage stage) { return SupportsRendererRecording( new RendererRecordingContext(stage)); } protected internal virtual bool RecordStageRenderGraph( ScriptableRenderContext context) { return context != null && RecordRenderer( new RendererRecordingContext(context)); } protected virtual void ConfigureCameraFramePlan( ScriptableRenderPipelinePlanningContext context) { } protected virtual void FinalizeCameraFramePlan( ScriptableRenderPipelinePlanningContext context) { if (context == null) { return; } ApplyInferredFullscreenStageRequests( context); } private void BuildPassQueue( RenderingData renderingData) { m_activePassQueue.Clear(); for (int i = 0; i < m_features.Count; ++i) { ScriptableRendererFeature feature = m_features[i]; if (feature == null || !feature.isActive) { continue; } feature.AddRenderPasses( this, renderingData); } AddRenderPasses(renderingData); } protected virtual void ReleaseRuntimeResources() { } protected virtual RenderingData CreatePlanningRenderingData( ScriptableRenderPipelinePlanningContext context) { return context != null ? new RenderingData( CameraFrameStage.MainScene, context.rendererIndex) : null; } private void ApplyInferredFullscreenStageRequests( ScriptableRenderPipelinePlanningContext context) { RenderingData planningData = CreatePlanningRenderingData(context); if (planningData == null) { return; } BuildPassQueue(planningData); bool hasPostProcessPass = HasQueuedPassForStage( CameraFrameStage.PostProcess); bool hasFinalOutputPass = HasQueuedPassForStage( CameraFrameStage.FinalOutput); bool needsFinalOutputDependency = context.HasFinalColorProcessing() || context.IsStageRequested( CameraFrameStage.FinalOutput) || hasFinalOutputPass; if (hasPostProcessPass) { EnsureInferredPostProcessStage( context, needsFinalOutputDependency); } if (hasFinalOutputPass && !context.IsStageRequested( CameraFrameStage.FinalOutput)) { context.RequestFullscreenStage( CameraFrameStage.FinalOutput, context.IsStageRequested( CameraFrameStage.PostProcess) ? CameraFrameColorSource.PostProcessColor : CameraFrameColorSource.MainSceneColor); } } private bool HasQueuedPassForStage( CameraFrameStage stage) { for (int i = 0; i < m_activePassQueue.Count; ++i) { ScriptableRenderPass renderPass = m_activePassQueue[i]; if (renderPass != null && renderPass.SupportsStage(stage)) { return true; } } return false; } private static void EnsureInferredPostProcessStage( ScriptableRenderPipelinePlanningContext context, bool needsGraphManagedOutputColor) { if (!context.IsStageRequested( CameraFrameStage.PostProcess)) { context.RequestFullscreenStage( CameraFrameStage.PostProcess, CameraFrameColorSource.MainSceneColor, needsGraphManagedOutputColor); return; } CameraFrameColorSource source = context.GetStageColorSource( CameraFrameStage.PostProcess); if (!needsGraphManagedOutputColor || source == CameraFrameColorSource.ExplicitSurface || context.UsesGraphManagedOutputColor( CameraFrameStage.PostProcess)) { return; } context.ClearFullscreenStage( CameraFrameStage.PostProcess); context.RequestFullscreenStage( CameraFrameStage.PostProcess, source, true); } } }