@@ -35,6 +35,9 @@ internal struct RenderGraphInputInfo
3535
3636 NativeList < AttachmentDescriptor > m_BeginRenderPassAttachments ;
3737
38+ // Contains the index of the non culled passes for native render passes that has at least one pass culled.
39+ NativeList < int > m_NonCulledPassIndicesForRasterPasses ;
40+
3841 internal static bool s_ForceGenerateAuditsForTests = false ;
3942
4043 public NativePassCompiler ( RenderGraphCompilationCache cache )
@@ -76,6 +79,11 @@ public void Cleanup()
7679 {
7780 m_BeginRenderPassAttachments . Dispose ( ) ;
7881 }
82+
83+ if ( m_NonCulledPassIndicesForRasterPasses . IsCreated )
84+ {
85+ m_NonCulledPassIndicesForRasterPasses . Dispose ( ) ;
86+ }
7987 }
8088
8189 public bool Initialize ( RenderGraphResourceRegistry resources , List < RenderGraphPass > renderPasses , RenderGraphDebugParams debugParams , string debugName , bool useCompilationCaching ,
@@ -155,6 +163,8 @@ public void Compile(RenderGraphResourceRegistry resources)
155163
156164 if ( graph . renderTextureUVOriginStrategy == RenderTextureUVOriginStrategy . PropagateAttachmentOrientation )
157165 PropagateTextureUVOrigin ( ) ;
166+
167+ CompactNonCulledPassesForRasterPasses ( ) ;
158168 }
159169
160170 public void Clear ( bool clearContextData )
@@ -632,6 +642,9 @@ void TryMergeNativePasses()
632642#if UNITY_EDITOR || DEVELOPMENT_BUILD
633643 bool generatePassBreakAudits = RenderGraphDebugSession . hasActiveDebugSession || s_ForceGenerateAuditsForTests ;
634644#endif
645+ int indexSinceLastCulledPass = 0 ;
646+ bool passWasCulled = false ;
647+ bool nonCulledPassIndicesListWasCleared = false ;
635648
636649 for ( var passIdx = 0 ; passIdx < ctx . passData . Length ; ++ passIdx )
637650 {
@@ -640,6 +653,7 @@ void TryMergeNativePasses()
640653 // If the pass has been culled, just ignore it
641654 if ( passToAdd . culled )
642655 {
656+ passWasCulled = true ;
643657 continue ;
644658 }
645659
@@ -653,6 +667,9 @@ void TryMergeNativePasses()
653667 ctx . nativePassData . Add ( new NativePassData ( ref passToAdd , ctx ) ) ;
654668 passToAdd . nativePassIndex = ctx . nativePassData . LastIndex ( ) ;
655669 activeNativePassId = passToAdd . nativePassIndex ;
670+
671+ indexSinceLastCulledPass = passIdx ;
672+ passWasCulled = false ;
656673 }
657674 }
658675 // There is an native pass currently open, try to add the current graph pass to it
@@ -684,10 +701,25 @@ void TryMergeNativePasses()
684701 passToAdd . nativePassIndex = ctx . nativePassData . LastIndex ( ) ;
685702 activeNativePassId = passToAdd . nativePassIndex ;
686703 }
704+
705+ if ( passWasCulled )
706+ {
707+ CollectNonCulledPassIndicesForRasterPasses ( passIdx , indexSinceLastCulledPass , mergeTestResult . reason != PassBreakReason . NonRasterPass , ! nonCulledPassIndicesListWasCleared ) ;
708+ passWasCulled = false ;
709+ nonCulledPassIndicesListWasCleared = true ;
710+ }
711+
712+ indexSinceLastCulledPass = passIdx ;
687713 }
688714 }
689715 }
690716
717+ // Handle the last native pass
718+ if ( passWasCulled )
719+ {
720+ CollectNonCulledPassIndicesForRasterPasses ( ctx . passData . Length , indexSinceLastCulledPass , clearList : ! nonCulledPassIndicesListWasCleared ) ;
721+ }
722+
691723 if ( activeNativePassId >= 0 )
692724 {
693725 // "Close" the last native pass by marking the last graph pass as end
@@ -703,6 +735,66 @@ void TryMergeNativePasses()
703735 }
704736 }
705737
738+ void CollectNonCulledPassIndicesForRasterPasses ( int currentPassIdx , int indexSinceLastCulledPass , bool usePreviousNativePass = false , bool clearList = false )
739+ {
740+ var ctx = contextData ;
741+
742+ // In some cases, we create a new native render pass (we allocate a new stand-alone native renderpass based on the current pass)
743+ // but we need to update the data of the previous native pass and not the newly one created.
744+ var indexLastNativePassData = ( usePreviousNativePass ) ? ctx . nativePassData . LastIndex ( ) - 1 : ctx . nativePassData . LastIndex ( ) ;
745+
746+ // In case we have a graph without any render pass.
747+ if ( indexLastNativePassData == - 1 )
748+ return ;
749+
750+ // Filling the attachments array to be sent to the rendering command buffer
751+ if ( ! m_NonCulledPassIndicesForRasterPasses . IsCreated )
752+ {
753+ m_NonCulledPassIndicesForRasterPasses = new NativeList < int > ( ctx . passData . Length , Allocator . Persistent ) ;
754+ }
755+ else if ( clearList )
756+ {
757+ m_NonCulledPassIndicesForRasterPasses . Clear ( ) ;
758+ m_NonCulledPassIndicesForRasterPasses . SetCapacity ( ctx . passData . Length ) ;
759+ }
760+
761+ ref var lastNativePassData = ref ctx . nativePassData . ElementAt ( indexLastNativePassData ) ;
762+ lastNativePassData . firstCompactedNonCulledRasterPass = m_NonCulledPassIndicesForRasterPasses . Length ;
763+
764+ // The native pass has at least one pass culled, so we iterate over each pass to retrieve
765+ // the index of the non culled pass, so they can be copied later on in a new NativeList that
766+ // will be contiguous in memory.
767+ for ( var nonCulledPassIdx = 0 ; nonCulledPassIdx < currentPassIdx - indexSinceLastCulledPass ; ++ nonCulledPassIdx )
768+ {
769+ ref var passToCopy = ref ctx . passData . ElementAt ( indexSinceLastCulledPass + nonCulledPassIdx ) ;
770+
771+ if ( ! passToCopy . culled )
772+ {
773+ m_NonCulledPassIndicesForRasterPasses . Add ( indexSinceLastCulledPass + nonCulledPassIdx ) ;
774+ }
775+ }
776+
777+ lastNativePassData . lastCompactedNonCulledRasterPass = m_NonCulledPassIndicesForRasterPasses . Length - 1 ;
778+ }
779+
780+ // Must be called at the end of the compilation, when PassData is not modified anymore.
781+ void CompactNonCulledPassesForRasterPasses ( )
782+ {
783+ if ( ! m_NonCulledPassIndicesForRasterPasses . IsCreated || m_NonCulledPassIndicesForRasterPasses . Length == 0 )
784+ return ;
785+
786+ var ctx = contextData ;
787+ ctx . compactedNonCulledRasterPasses . ResizeUninitialized ( m_NonCulledPassIndicesForRasterPasses . Length ) ;
788+
789+ // Copy and cache only the PassData that were not contiguous in memory because of culling.
790+ // They are copied in a new NativeArray that is contiguous in memory so we avoid further copies
791+ // later at many places (Initialize, Destroy, etc.) by using directly a ReadOnlySpan of this array.
792+ for ( int i = 0 ; i < m_NonCulledPassIndicesForRasterPasses . Length ; ++ i )
793+ {
794+ ctx . compactedNonCulledRasterPasses [ i ] = ctx . passData . ElementAt ( m_NonCulledPassIndicesForRasterPasses [ i ] ) ;
795+ }
796+ }
797+
706798 bool FindFirstPassIdOnGraphicsQueueAwaitingFenceGoingForward ( ref PassData startAsyncPass , out int firstPassIdAwaiting )
707799 {
708800 var ctx = contextData ;
0 commit comments