using System; using System.Runtime.CompilerServices; using XCEngine; using XCEngine.Rendering; namespace XCEngine.Rendering.Universal { public abstract class ScriptableRendererData : Object { public ScriptableRendererFeature[] rendererFeatures; private ScriptableRendererFeature[] m_rendererFeatures; private ScriptableRenderer m_rendererInstance; private bool m_rendererInvalidated; private int m_runtimeStateVersion = 1; private int m_rendererFeatureCollectionHash; private bool m_rendererFeatureCollectionHashResolved; protected ScriptableRendererData() { rendererFeatures = Array.Empty(); } internal ScriptableRenderer CreateRendererInstance() { return GetRendererInstance(); } internal ScriptableRenderer GetRendererInstance() { if (m_rendererInstance == null) { m_rendererInstance = CreateRenderer(); if (m_rendererInstance != null) { SetupRendererInstance(m_rendererInstance); m_rendererInvalidated = false; } } return m_rendererInstance; } internal ScriptableRendererFeature[] CreateRendererFeaturesInstance() { return GetRendererFeatures(); } internal void SetupRendererInstance( ScriptableRenderer renderer) { if (renderer == null) { return; } SetupRenderer(renderer); } internal void SetDirtyInstance() { SetDirty(); } internal void InvalidateRendererFeaturesInstance() { m_rendererFeatureCollectionHash = ComputeRendererFeatureCollectionHash( rendererFeatures ?? Array.Empty()); m_rendererFeatureCollectionHashResolved = true; SetDirty(); } internal int GetRuntimeStateVersionInstance() { SynchronizeRendererFeatureCollectionState(); return m_runtimeStateVersion; } internal void ReleaseRuntimeResourcesInstance() { ReleaseRendererSetupCache(); ReleaseRuntimeResources(); m_rendererInvalidated = false; } internal void ConfigureCameraRenderRequestInstance( CameraRenderRequestContext context) { ConfigureCameraRenderRequest(context); ScriptableRendererFeature[] rendererFeatures = GetRendererFeatures(); for (int i = 0; i < rendererFeatures.Length; ++i) { ScriptableRendererFeature rendererFeature = rendererFeatures[i]; if (rendererFeature == null || !rendererFeature.isActive) { continue; } rendererFeature.ConfigureCameraRenderRequest( context); } } internal void ConfigureCameraFramePlanInstance( ScriptableRenderPipelinePlanningContext context) { ConfigureCameraFramePlan(context); ScriptableRenderer renderer = GetRendererInstance(); if (renderer != null) { renderer.ConfigureCameraFramePlanInstance( context); } ScriptableRendererFeature[] rendererFeatures = GetRendererFeatures(); for (int i = 0; i < rendererFeatures.Length; ++i) { ScriptableRendererFeature rendererFeature = rendererFeatures[i]; if (rendererFeature == null || !rendererFeature.isActive) { continue; } rendererFeature.ConfigureCameraFramePlan( context); } if (renderer != null) { renderer.FinalizeCameraFramePlanInstance( context); } } internal bool ConfigureRenderSceneSetupInstance( RenderSceneSetupContext context) { ConfigureRenderSceneSetup(context); ScriptableRenderer renderer = GetRendererInstance(); if (renderer != null) { renderer.ConfigureRenderSceneSetupInstance( context); } ScriptableRendererFeature[] rendererFeatures = GetRendererFeatures(); for (int i = 0; i < rendererFeatures.Length; ++i) { ScriptableRendererFeature rendererFeature = rendererFeatures[i]; if (rendererFeature == null || !rendererFeature.isActive) { continue; } rendererFeature.ConfigureRenderSceneSetup( context); } return context != null && context.isConfigured; } internal bool ConfigureDirectionalShadowExecutionStateInstance( DirectionalShadowExecutionContext context) { ConfigureDirectionalShadowExecutionState( context); ScriptableRenderer renderer = GetRendererInstance(); if (renderer != null) { renderer .ConfigureDirectionalShadowExecutionStateInstance( context); } ScriptableRendererFeature[] rendererFeatures = GetRendererFeatures(); for (int i = 0; i < rendererFeatures.Length; ++i) { ScriptableRendererFeature rendererFeature = rendererFeatures[i]; if (rendererFeature == null || !rendererFeature.isActive) { continue; } rendererFeature .ConfigureDirectionalShadowExecutionState( context); } return context != null && context.isConfigured; } protected virtual ScriptableRenderer CreateRenderer() { return null; } protected virtual void SetupRenderer( ScriptableRenderer renderer) { AddRendererFeatures( renderer, GetRendererFeatures()); } protected virtual void ConfigureCameraRenderRequest( CameraRenderRequestContext context) { } protected virtual void ConfigureCameraFramePlan( ScriptableRenderPipelinePlanningContext context) { } protected virtual void ConfigureRenderSceneSetup( RenderSceneSetupContext context) { } protected virtual void ConfigureDirectionalShadowExecutionState( DirectionalShadowExecutionContext context) { } protected virtual ScriptableRendererFeature[] CreateRendererFeatures() { return rendererFeatures ?? Array.Empty(); } protected virtual void ReleaseRuntimeResources() { } protected virtual ScriptableRendererFeature[] CreateDefaultRendererFeatures() { return Array.Empty(); } protected bool isInvalidated { get { return m_rendererInvalidated; } } protected bool HasDirectionalShadow( CameraRenderRequestContext context) { return context != null && InternalCalls .Rendering_CameraRenderRequestContext_GetHasDirectionalShadow( context.nativeHandle); } protected void ClearDirectionalShadow( CameraRenderRequestContext context) { if (context == null) { return; } InternalCalls .Rendering_CameraRenderRequestContext_ClearDirectionalShadow( context.nativeHandle); } protected void SetDirty() { ReleaseRendererSetupCache(); m_rendererInvalidated = true; unchecked { ++m_runtimeStateVersion; } if (m_runtimeStateVersion <= 0) { m_runtimeStateVersion = 1; } } protected void AddRendererFeature( ScriptableRenderer renderer, ScriptableRendererFeature rendererFeature) { if (renderer == null || rendererFeature == null) { return; } renderer.AddFeatureInstance(rendererFeature); } protected void AddRendererFeatures( ScriptableRenderer renderer, ScriptableRendererFeature[] rendererFeatures) { if (renderer == null || rendererFeatures == null) { return; } for (int i = 0; i < rendererFeatures.Length; ++i) { AddRendererFeature( renderer, rendererFeatures[i]); } } protected void ResetRendererFeaturesToDefault() { rendererFeatures = CreateDefaultRendererFeatures() ?? Array.Empty(); } private ScriptableRendererFeature[] GetRendererFeatures() { if (m_rendererFeatures == null) { m_rendererFeatures = CreateRendererFeatures() ?? Array.Empty(); } BindRendererFeatureOwners(m_rendererFeatures); return m_rendererFeatures; } private void SynchronizeRendererFeatureCollectionState() { ScriptableRendererFeature[] configuredRendererFeatures = rendererFeatures ?? Array.Empty(); BindRendererFeatureOwners(configuredRendererFeatures); int collectionHash = ComputeRendererFeatureCollectionHash( configuredRendererFeatures); if (!m_rendererFeatureCollectionHashResolved) { m_rendererFeatureCollectionHash = collectionHash; m_rendererFeatureCollectionHashResolved = true; return; } if (collectionHash == m_rendererFeatureCollectionHash) { return; } m_rendererFeatureCollectionHash = collectionHash; SetDirty(); } private void BindRendererFeatureOwners( ScriptableRendererFeature[] rendererFeatureCollection) { if (rendererFeatureCollection == null) { return; } for (int i = 0; i < rendererFeatureCollection.Length; ++i) { ScriptableRendererFeature rendererFeature = rendererFeatureCollection[i]; if (rendererFeature != null) { rendererFeature.BindOwnerInstance(this); } } } private static int ComputeRendererFeatureCollectionHash( ScriptableRendererFeature[] rendererFeatureCollection) { unchecked { int hash = 17; if (rendererFeatureCollection == null) { return hash; } hash = (hash * 31) + rendererFeatureCollection.Length; for (int i = 0; i < rendererFeatureCollection.Length; ++i) { ScriptableRendererFeature rendererFeature = rendererFeatureCollection[i]; if (rendererFeature == null) { hash = (hash * 31) + 1; continue; } hash = (hash * 31) + RuntimeHelpers.GetHashCode(rendererFeature); hash = (hash * 31) + rendererFeature .GetRuntimeStateVersionInstance(); } return hash; } } private void ReleaseRendererSetupCache() { if (m_rendererInstance != null) { m_rendererInstance.ReleaseRuntimeResourcesInstance(); m_rendererInstance = null; m_rendererFeatures = null; return; } if (m_rendererFeatures == null) { return; } for (int i = 0; i < m_rendererFeatures.Length; ++i) { ScriptableRendererFeature rendererFeature = m_rendererFeatures[i]; if (rendererFeature != null) { rendererFeature.ReleaseRuntimeResourcesInstance(); } } m_rendererFeatures = null; } } }