389 lines
12 KiB
C#
389 lines
12 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 readonly RendererBlocks m_rendererBlocks =
|
|
new RendererBlocks();
|
|
private bool m_isBuildingPassQueue;
|
|
private CameraFrameStage m_passQueueStage =
|
|
CameraFrameStage.MainScene;
|
|
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_rendererBlocks.Clear();
|
|
m_disposed = true;
|
|
}
|
|
|
|
public void EnqueuePass(
|
|
ScriptableRenderPass renderPass)
|
|
{
|
|
if (renderPass == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_isBuildingPassQueue &&
|
|
!renderPass.SupportsStage(m_passQueueStage))
|
|
{
|
|
return;
|
|
}
|
|
|
|
InsertActivePass(
|
|
renderPass);
|
|
}
|
|
|
|
private void InsertActivePass(
|
|
ScriptableRenderPass renderPass)
|
|
{
|
|
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 void ConfigureRenderSceneSetupInstance(
|
|
RenderSceneSetupContext context)
|
|
{
|
|
ConfigureRenderSceneSetup(context);
|
|
}
|
|
|
|
internal void ConfigureDirectionalShadowExecutionStateInstance(
|
|
DirectionalShadowExecutionContext context)
|
|
{
|
|
ConfigureDirectionalShadowExecutionState(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);
|
|
return SupportsRendererStage(context);
|
|
}
|
|
|
|
protected virtual bool RecordRenderer(
|
|
RendererRecordingContext context)
|
|
{
|
|
if (context == null ||
|
|
context.renderContext == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
RenderingData renderingData =
|
|
context.renderingData;
|
|
BuildPassQueue(renderingData);
|
|
return RecordRendererStage(context);
|
|
}
|
|
|
|
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)
|
|
{
|
|
}
|
|
|
|
protected virtual void ConfigureRenderSceneSetup(
|
|
RenderSceneSetupContext context)
|
|
{
|
|
}
|
|
|
|
protected virtual void ConfigureDirectionalShadowExecutionState(
|
|
DirectionalShadowExecutionContext context)
|
|
{
|
|
}
|
|
|
|
private bool HasRendererBlock(
|
|
RendererBlock block)
|
|
{
|
|
return m_rendererBlocks.HasPasses(block);
|
|
}
|
|
|
|
protected virtual bool SupportsRendererStage(
|
|
RendererRecordingContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
switch (context.stage)
|
|
{
|
|
case CameraFrameStage.ShadowCaster:
|
|
return HasRendererBlock(
|
|
RendererBlock.ShadowCaster);
|
|
case CameraFrameStage.DepthOnly:
|
|
return HasRendererBlock(
|
|
RendererBlock.DepthPrepass);
|
|
case CameraFrameStage.MainScene:
|
|
return HasRendererBlock(
|
|
RendererBlock.MainOpaque) ||
|
|
HasRendererBlock(
|
|
RendererBlock.MainSkybox) ||
|
|
HasRendererBlock(
|
|
RendererBlock.MainTransparent);
|
|
case CameraFrameStage.PostProcess:
|
|
return HasRendererBlock(
|
|
RendererBlock.PostProcess);
|
|
case CameraFrameStage.FinalOutput:
|
|
return HasRendererBlock(
|
|
RendererBlock.FinalOutput);
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
protected virtual bool RecordRendererStage(
|
|
RendererRecordingContext context)
|
|
{
|
|
if (context == null ||
|
|
context.renderContext == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool recordedAnyPass = false;
|
|
switch (context.stage)
|
|
{
|
|
case CameraFrameStage.ShadowCaster:
|
|
return RecordRendererBlock(
|
|
RendererBlock.ShadowCaster,
|
|
context,
|
|
ref recordedAnyPass) &&
|
|
recordedAnyPass;
|
|
case CameraFrameStage.DepthOnly:
|
|
return RecordRendererBlock(
|
|
RendererBlock.DepthPrepass,
|
|
context,
|
|
ref recordedAnyPass) &&
|
|
recordedAnyPass;
|
|
case CameraFrameStage.MainScene:
|
|
return RecordRendererBlock(
|
|
RendererBlock.MainOpaque,
|
|
context,
|
|
ref recordedAnyPass) &&
|
|
RecordRendererBlock(
|
|
RendererBlock.MainSkybox,
|
|
context,
|
|
ref recordedAnyPass) &&
|
|
RecordRendererBlock(
|
|
RendererBlock.MainTransparent,
|
|
context,
|
|
ref recordedAnyPass) &&
|
|
recordedAnyPass;
|
|
case CameraFrameStage.PostProcess:
|
|
return RecordRendererBlock(
|
|
RendererBlock.PostProcess,
|
|
context,
|
|
ref recordedAnyPass) &&
|
|
recordedAnyPass;
|
|
case CameraFrameStage.FinalOutput:
|
|
return RecordRendererBlock(
|
|
RendererBlock.FinalOutput,
|
|
context,
|
|
ref recordedAnyPass) &&
|
|
recordedAnyPass;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private bool RecordRendererBlock(
|
|
RendererBlock block,
|
|
RendererRecordingContext context,
|
|
ref bool recordedAnyPass)
|
|
{
|
|
if (context == null ||
|
|
context.renderContext == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int firstPassIndex;
|
|
int lastPassIndex;
|
|
if (!m_rendererBlocks.TryGetPassRange(
|
|
block,
|
|
out firstPassIndex,
|
|
out lastPassIndex))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
for (int i = firstPassIndex;
|
|
i <= lastPassIndex;
|
|
++i)
|
|
{
|
|
ScriptableRenderPass renderPass =
|
|
m_activePassQueue[i];
|
|
if (renderPass == null ||
|
|
!renderPass.SupportsRendererBlock(block))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!renderPass.Record(
|
|
context.renderContext,
|
|
context.renderingData))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
recordedAnyPass = true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void BuildPassQueue(
|
|
RenderingData renderingData)
|
|
{
|
|
m_activePassQueue.Clear();
|
|
m_rendererBlocks.Clear();
|
|
m_isBuildingPassQueue = true;
|
|
m_passQueueStage =
|
|
renderingData != null
|
|
? renderingData.stage
|
|
: CameraFrameStage.MainScene;
|
|
|
|
try
|
|
{
|
|
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);
|
|
m_rendererBlocks.Build(m_activePassQueue);
|
|
}
|
|
finally
|
|
{
|
|
m_isBuildingPassQueue = false;
|
|
m_passQueueStage =
|
|
CameraFrameStage.MainScene;
|
|
}
|
|
}
|
|
|
|
protected virtual void ReleaseRuntimeResources()
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|