334 lines
9.5 KiB
C#
334 lines
9.5 KiB
C#
using System.Collections.Generic;
|
|
using XCEngine;
|
|
using XCEngine.Rendering;
|
|
|
|
namespace XCEngine.Rendering.Universal
|
|
{
|
|
public abstract class ScriptableRenderer
|
|
{
|
|
private readonly List<ScriptableRendererFeature> m_features =
|
|
new List<ScriptableRendererFeature>();
|
|
private readonly List<ScriptableRenderPass> m_activePassQueue =
|
|
new List<ScriptableRenderPass>();
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|