Skip to content

Commit b911cd2

Browse files
YohannVaastUnityEvergreen
authored andcommitted
RenderGraph - Fix "Cannot return local 'actualPasses'" error
1 parent 6439b4e commit b911cd2

File tree

5 files changed

+360
-27
lines changed

5 files changed

+360
-27
lines changed

Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/CompilerContextData.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ void AllocateNativeDataStructuresIfNeeded(int estimatedNumPasses)
5858
// These are risky heuristics that only work because we purposely estimate a very high number of passes
5959
// We need to fix this with a proper size computation
6060
passData = new NativeList<PassData>(estimatedNumPasses, AllocatorManager.Persistent);
61+
compactedNonCulledRasterPasses = new NativeList<PassData>(0, AllocatorManager.Persistent); // Will be resized during the compilation
6162
inputData = new NativeList<PassInputData>(estimatedNumPasses * 2, AllocatorManager.Persistent);
6263
outputData = new NativeList<PassOutputData>(estimatedNumPasses * 2, AllocatorManager.Persistent);
6364
fragmentData = new NativeList<PassFragmentData>(estimatedNumPasses * 4, AllocatorManager.Persistent);
@@ -87,6 +88,7 @@ public void Clear()
8788
if (m_AreNativeListsAllocated)
8889
{
8990
passData.Clear();
91+
compactedNonCulledRasterPasses.Clear();
9092
fences.Clear();
9193
inputData.Clear();
9294
outputData.Clear();
@@ -139,6 +141,7 @@ public ref ResourceReaderData ResourceReader(in ResourceHandle h, int i)
139141

140142
// Data per graph level renderpass
141143
public NativeList<PassData> passData;
144+
public NativeList<PassData> compactedNonCulledRasterPasses;
142145
public Dictionary<int, GraphicsFence> fences;
143146
public DynamicArray<Name> passNames;
144147

@@ -369,6 +372,7 @@ void Cleanup()
369372
if (m_AreNativeListsAllocated)
370373
{
371374
passData.Dispose();
375+
compactedNonCulledRasterPasses.Dispose();
372376
inputData.Dispose();
373377
outputData.Dispose();
374378
fragmentData.Dispose();

Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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;

Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/PassesData.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,9 @@ internal struct NativePassData
668668
public int lastGraphPass;
669669
public int numGraphPasses;
670670

671+
public int firstCompactedNonCulledRasterPass;
672+
public int lastCompactedNonCulledRasterPass;
673+
671674
public int firstNativeSubPass; // Offset+count in context subpass array
672675
public int numNativeSubPasses;
673676
public int width;
@@ -693,6 +696,8 @@ public NativePassData(ref PassData pass, CompilerContextData ctx)
693696
numGraphPasses = 1;
694697
firstNativeSubPass = -1; // Set up during compile
695698
numNativeSubPasses = 0;
699+
firstCompactedNonCulledRasterPass = -1;
700+
lastCompactedNonCulledRasterPass = -1;
696701

697702
fragments = new FixedAttachmentArray<PassFragmentData>();
698703
attachments = new FixedAttachmentArray<NativePassAttachment>();
@@ -768,6 +773,8 @@ public void Clear()
768773
{
769774
firstGraphPass = 0;
770775
numGraphPasses = 0;
776+
firstCompactedNonCulledRasterPass = -1;
777+
lastCompactedNonCulledRasterPass = -1;
771778
attachments.Clear();
772779
fragments.Clear();
773780
loadAudit.Clear();
@@ -780,6 +787,7 @@ public readonly bool IsValid()
780787
return numGraphPasses > 0;
781788
}
782789

790+
// This method cannot be called during the Compile step.
783791
[MethodImpl(MethodImplOptions.AggressiveInlining)]
784792
public readonly ReadOnlySpan<PassData> GraphPasses(CompilerContextData ctx)
785793
{
@@ -789,20 +797,9 @@ public readonly ReadOnlySpan<PassData> GraphPasses(CompilerContextData ctx)
789797
return ctx.passData.MakeReadOnlySpan(firstGraphPass, numGraphPasses);
790798
}
791799

792-
var actualPasses =
793-
new NativeArray<PassData>(numGraphPasses, Allocator.Temp,
794-
NativeArrayOptions.UninitializedMemory);
800+
Debug.Assert(!ctx.compactedNonCulledRasterPasses.IsEmpty);
795801

796-
for (int i = firstGraphPass, index = 0; i < lastGraphPass + 1; ++i)
797-
{
798-
var pass = ctx.passData[i];
799-
if (!pass.culled)
800-
{
801-
actualPasses[index++] = pass;
802-
}
803-
}
804-
805-
return actualPasses;
802+
return ctx.compactedNonCulledRasterPasses.MakeReadOnlySpan(firstCompactedNonCulledRasterPass, lastCompactedNonCulledRasterPass - firstCompactedNonCulledRasterPass + 1);
806803
}
807804

808805
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -953,9 +950,12 @@ public static PassBreakAudit CanMerge(CompilerContextData contextData, int activ
953950
// Temporary cache of sampled textures in current Native Render Pass for conflict detection against fragments
954951
using (HashSetPool<int>.Get(out var tempSampledTextures))
955952
{
956-
var graphPasses = nativePass.GraphPasses(contextData);
957-
foreach (ref readonly var graphPass in graphPasses)
953+
for (int i = nativePass.firstGraphPass; i < nativePass.lastGraphPass + 1; ++i)
958954
{
955+
ref var graphPass = ref contextData.passData.ElementAt(i);
956+
if (graphPass.culled)
957+
continue;
958+
959959
if (graphPass.numSampledOnlyRaster > 0) // Skip passes with no sampled textures
960960
{
961961
foreach (ref readonly var earlierInput in graphPass.SampledTexturesIfRaster(contextData))

0 commit comments

Comments
 (0)