diff --git a/src/Runtime/Ghost.Graphics/Meshlet/ClodBoundsHelper.cs b/src/Runtime/Ghost.Graphics/Meshlet/ClodBoundsHelper.cs index d0045cc..6204dd1 100644 --- a/src/Runtime/Ghost.Graphics/Meshlet/ClodBoundsHelper.cs +++ b/src/Runtime/Ghost.Graphics/Meshlet/ClodBoundsHelper.cs @@ -20,8 +20,8 @@ internal static class ClodBoundsHelper public static ClodBounds MergeBounds(UnsafeList clusters, UnsafeList group) { - using var scope = AllocationManager.CreateStackScope(); - var boundsList = new UnsafeList((nuint)group.Length, scope.AllocationHandle); + // Use Temp for the bounds list to support mega-meshes without stack overflow + var boundsList = new UnsafeList((nuint)group.Length, Allocator.Temp); for (int j = 0; j < (int)group.Length; j++) { @@ -46,6 +46,7 @@ internal static class ClodBoundsHelper result.error = Math.Max(result.error, clusters[group[j]].bounds.error); } + boundsList.Dispose(); return result; } } diff --git a/src/Runtime/Ghost.Graphics/Meshlet/ClodBuilder.cs b/src/Runtime/Ghost.Graphics/Meshlet/ClodBuilder.cs index 8e4367b..0bf5bce 100644 --- a/src/Runtime/Ghost.Graphics/Meshlet/ClodBuilder.cs +++ b/src/Runtime/Ghost.Graphics/Meshlet/ClodBuilder.cs @@ -21,16 +21,12 @@ public unsafe static class ClodBuilder { Debug.Assert(mesh.vertexAttributesStride % (nuint)sizeof(float) == 0, "vertexAttributesStride must be a multiple of sizeof(float)"); - using var scope = AllocationManager.CreateStackScope(); - - var locks = new UnsafeList(mesh.vertexCount, scope.AllocationHandle); - locks.Resize(mesh.vertexCount); - for (int i = 0; i < (int)mesh.vertexCount; i++) - locks[i] = 0; + // Use Persistent or Temp for large mesh data to avoid stack overflow + var locks = new UnsafeList(mesh.vertexCount, Allocator.Temp); + locks.AsSpan().Fill(0); // Generate position-only remap - var remap = new UnsafeList(mesh.vertexCount, scope.AllocationHandle); - remap.Resize(mesh.vertexCount); + var remap = new UnsafeList(mesh.vertexCount, Allocator.Temp); MeshOptApi.GeneratePositionRemap(remap.GetUnsafePtr(), mesh.vertexPositions, mesh.vertexCount, mesh.vertexPositionsStride); // Set up protect bits on UV seams @@ -62,16 +58,16 @@ public unsafe static class ClodBuilder clusters[i].bounds = ClodBoundsHelper.ComputeBounds(mesh, clusters[i].indices, 0.0f); } - var pending = new UnsafeList(clusters.Length, scope.AllocationHandle); - pending.Resize(clusters.Length); + var pending = new UnsafeList(clusters.Length, Allocator.Temp); for (int i = 0; i < (int)clusters.Length; i++) - pending[i] = i; + pending.Add(i); int depth = 0; while (pending.Length > 1) { - var groups = ClodPartition.Partition(config, mesh, clusters, pending, remap, scope.AllocationHandle); + // Partition results are temporary but returned, using Temp allocator + var groups = ClodPartition.Partition(config, mesh, clusters, pending, remap, Allocator.Temp); pending.Clear(); @@ -80,7 +76,8 @@ public unsafe static class ClodBuilder for (int i = 0; i < (int)groups.Length; i++) { - var merged = new UnsafeList((nuint)groups[i].Length * config.maxTriangles * 3, scope.AllocationHandle); + // Merged indices for a group of clusters + var merged = new UnsafeList((nuint)groups[i].Length * config.maxTriangles * 3, Allocator.Temp); for (int j = 0; j < (int)groups[i].Length; j++) { var clusterIndices = clusters[groups[i][j]].indices; @@ -99,6 +96,7 @@ public unsafe static class ClodBuilder { bounds.error = float.MaxValue; OutputGroup(config, mesh, clusters, groups[i], bounds, depth, outputContext, outputCallback); + merged.Dispose(); continue; } @@ -123,6 +121,7 @@ public unsafe static class ClodBuilder } split.Dispose(); + merged.Dispose(); } // Cleanup groups @@ -147,6 +146,10 @@ public unsafe static class ClodBuilder for (int i = 0; i < (int)clusters.Length; i++) clusters[i].indices.Dispose(); clusters.Dispose(); + + locks.Dispose(); + remap.Dispose(); + pending.Dispose(); return finalClusterCount; } @@ -162,22 +165,23 @@ public unsafe static class ClodBuilder ClodOutputDelegate outputCallback ) { - using var scope = AllocationManager.CreateStackScope(); - var groupClusters = new UnsafeList(group.Length, scope.AllocationHandle); - groupClusters.Resize((nuint)group.Length); + // Use Temp for the output array to avoid stack pressure + var groupClusters = new UnsafeList(group.Length, Allocator.Temp); for (int i = 0; i < (int)group.Length; i++) { ref var srcCluster = ref clusters[group[i]]; - ref var dstCluster = ref groupClusters[i]; - - dstCluster.refined = srcCluster.refined; - dstCluster.bounds = (config.optimizeBounds && srcCluster.refined != -1) - ? ClodBoundsHelper.ComputeBounds(mesh, srcCluster.indices, srcCluster.bounds.error) - : srcCluster.bounds; - dstCluster.indices = srcCluster.indices.GetUnsafePtr(); - dstCluster.indexCount = (nuint)srcCluster.indices.Length; - dstCluster.vertexCount = srcCluster.vertices; + var dstCluster = new ClodCluster + { + refined = srcCluster.refined, + bounds = (config.optimizeBounds && srcCluster.refined != -1) + ? ClodBoundsHelper.ComputeBounds(mesh, srcCluster.indices, srcCluster.bounds.error) + : srcCluster.bounds, + indices = srcCluster.indices.GetUnsafePtr(), + indexCount = (nuint)srcCluster.indices.Length, + vertexCount = srcCluster.vertices + }; + groupClusters.Add(dstCluster); } var clodGroup = new ClodGroup { depth = depth, simplified = simplified }; @@ -185,6 +189,7 @@ public unsafe static class ClodBuilder ? outputCallback(outputContext, clodGroup, (ClodCluster*)groupClusters.GetUnsafePtr(), (nuint)groupClusters.Length) : -1; + groupClusters.Dispose(); return result; } } diff --git a/src/Runtime/Ghost.Graphics/Meshlet/ClodInternal_Partition.cs b/src/Runtime/Ghost.Graphics/Meshlet/ClodInternal_Partition.cs index 2fb0c3f..55bf8b3 100644 --- a/src/Runtime/Ghost.Graphics/Meshlet/ClodInternal_Partition.cs +++ b/src/Runtime/Ghost.Graphics/Meshlet/ClodInternal_Partition.cs @@ -6,7 +6,7 @@ namespace Ghost.Graphics.Meshlet; internal static class ClodPartition { - public static UnsafeList> Partition(ClodConfig config, ClodMesh mesh, UnsafeList clusters, UnsafeList pending, UnsafeList remap, AllocationHandle allocator) + public static UnsafeList> Partition(ClodConfig config, ClodMesh mesh, UnsafeList clusters, UnsafeList pending, UnsafeList remap, Allocator allocator) { if (pending.Length <= (int)config.partitionSize) { @@ -15,9 +15,9 @@ internal static class ClodPartition return partitions; } - using var stackScope = AllocationManager.CreateStackScope(); - var clusterIndices = new UnsafeList(1024, stackScope.AllocationHandle); - var clusterCounts = new UnsafeList((nuint)pending.Length, stackScope.AllocationHandle); + // Internal counters/indices can stay on Temp to avoid stack overflow for huge meshes + var clusterIndices = new UnsafeList(1024, Allocator.Temp); + var clusterCounts = new UnsafeList((nuint)pending.Length, Allocator.Temp); nuint totalIndexCount = 0; for (int i = 0; i < pending.Length; i++) @@ -41,7 +41,7 @@ internal static class ClodPartition offset += (nuint)cluster.indices.Length; } - var clusterPart = new UnsafeList((nuint)pending.Length, stackScope.AllocationHandle); + var clusterPart = new UnsafeList((nuint)pending.Length, Allocator.Temp); clusterPart.Resize((nuint)pending.Length); nuint partitionCount = MeshOptApi.PartitionClusters( @@ -67,6 +67,10 @@ internal static class ClodPartition partitions[(int)clusterPart[i]].Add(pending[i]); } + clusterIndices.Dispose(); + clusterCounts.Dispose(); + clusterPart.Dispose(); + return partitions; } } diff --git a/src/Runtime/Ghost.Graphics/Meshlet/ClodSimplify.cs b/src/Runtime/Ghost.Graphics/Meshlet/ClodSimplify.cs index f0b8a70..09e9f86 100644 --- a/src/Runtime/Ghost.Graphics/Meshlet/ClodSimplify.cs +++ b/src/Runtime/Ghost.Graphics/Meshlet/ClodSimplify.cs @@ -20,8 +20,8 @@ internal static class ClodSimplify return indices; } - using var scope = AllocationManager.CreateStackScope(); - var lod = new UnsafeList(indices.Length, scope.AllocationHandle); + // Use Allocator.Temp for LOD results to avoid stack overflow on mega-meshes + var lod = new UnsafeList((nuint)indices.Length, Allocator.Temp); lod.Resize((nuint)indices.Length); uint options = MeshOptApi.SimplifySparse | MeshOptApi.SimplifyErrorAbsolute; @@ -124,7 +124,6 @@ internal static class ClodSimplify float* error ) { - // Simplified version - deindex and use sloppy simplification - // Implementation details would involve creating a subset for sparse simplification + // Placeholder for sloppy simplification fallback logic } }