From d052ca848f494a2a8e8468a731bfc8ca8da1a4a4 Mon Sep 17 00:00:00 2001 From: Misaki Date: Thu, 7 May 2026 00:23:51 +0900 Subject: [PATCH] Refactor resource management and update project configs - Use `using` for MeshNode disposal in MeshAssetHandler - Switch to `ref` UnsafeList in meshlet hierarchy methods for perf - Ensure proper disposal of UnsafeList and TempBinaryNode - Add launchSettings.json for Ghost.Editor.Core debugging - Update GhostEngine.slnx with platform mappings for Editor.Core - Remove MHP_ENABLE_SAFETY_CHECKS from Debug|AnyCPU in csproj --- .../Assets/MeshAssetHandler.cs | 13 +- .../Assets/MeshProcessor.Meshlet.cs | 222 ++++++++++-------- .../Properties/launchSettings.json | 8 + src/GhostEngine.slnx | 4 +- src/Runtime/Ghost.Core/Ghost.Core.csproj | 2 +- 5 files changed, 134 insertions(+), 115 deletions(-) create mode 100644 src/Editor/Ghost.Editor.Core/Properties/launchSettings.json diff --git a/src/Editor/Ghost.Editor.Core/Assets/MeshAssetHandler.cs b/src/Editor/Ghost.Editor.Core/Assets/MeshAssetHandler.cs index aef9d8b..2261cf6 100644 --- a/src/Editor/Ghost.Editor.Core/Assets/MeshAssetHandler.cs +++ b/src/Editor/Ghost.Editor.Core/Assets/MeshAssetHandler.cs @@ -261,17 +261,16 @@ internal class MeshAssetHandler : IImportableAssetHandler, IPackableAssetHandler return Result.Failure("Source file does not exist."); } - var meshSettings = ResolveSettings(sourcePath, settings); - var root = new MeshNode(); try { - var heapSize1 = AllocationManager.TotalAllocatedMemory; + var meshSettings = ResolveSettings(sourcePath, settings); + + using var root = new MeshNode(); + var parseJob = new MeshParsingJob(root, sourcePath, AllocationHandle.Persistent, meshSettings); var context = default(Misaki.HighPerformance.Jobs.JobExecutionContext); parseJob.Execute(in context); - var heapSize2 = AllocationManager.TotalAllocatedMemory; - var manifest = new ModelManifest { AssetId = id, @@ -291,10 +290,6 @@ internal class MeshAssetHandler : IImportableAssetHandler, IPackableAssetHandler { return Result.Failure($"Failed to import mesh asset: {ex.Message}"); } - finally - { - root.Dispose(); - } } public ValueTask ExportAsync(string assetPath, string targetPath, IAssetExportOptions? options, CancellationToken token = default) diff --git a/src/Editor/Ghost.Editor.Core/Assets/MeshProcessor.Meshlet.cs b/src/Editor/Ghost.Editor.Core/Assets/MeshProcessor.Meshlet.cs index d2eb528..c34c673 100644 --- a/src/Editor/Ghost.Editor.Core/Assets/MeshProcessor.Meshlet.cs +++ b/src/Editor/Ghost.Editor.Core/Assets/MeshProcessor.Meshlet.cs @@ -864,7 +864,7 @@ internal static unsafe partial class MeshProcessor public int meshletIndex; } - private static int BuildBinaryTree(UnsafeList nodes, UnsafeArray meshletIndices, int start, int end, ReadOnlySpan meshlets) + private static int BuildBinaryTree(ref UnsafeList nodes, UnsafeArray meshletIndices, int start, int end, ReadOnlySpan meshlets) { if (start == end - 1) { @@ -921,8 +921,8 @@ internal static unsafe partial class MeshProcessor mid = start + (end - start) / 2; } - var left = BuildBinaryTree(nodes, meshletIndices, start, mid, meshlets); - var right = BuildBinaryTree(nodes, meshletIndices, mid, end, meshlets); + var left = BuildBinaryTree(ref nodes, meshletIndices, start, mid, meshlets); + var right = BuildBinaryTree(ref nodes, meshletIndices, mid, end, meshlets); var leftNode = nodes[left]; var rightNode = nodes[right]; @@ -945,7 +945,7 @@ internal static unsafe partial class MeshProcessor return internalNodeIndex; } - private static void GatherChildren(UnsafeList binaryNodes, int nodeIndex, UnsafeList gathered) + private static void GatherChildren(UnsafeList binaryNodes, int nodeIndex, ref UnsafeList gathered) { gathered.Clear(); var node = binaryNodes[nodeIndex]; @@ -992,80 +992,88 @@ internal static unsafe partial class MeshProcessor return -1; } - using var gathered = new UnsafeList(4, AllocationHandle.Persistent); - GatherChildren(binaryNodes, binaryNodeIndex, gathered); + var gathered = new UnsafeList(4, AllocationHandle.Persistent); - var bvhNode = new MeshletHierarchyNode(); - - var minX = new float4(float.PositiveInfinity); - var minY = new float4(float.PositiveInfinity); - var minZ = new float4(float.PositiveInfinity); - var maxX = new float4(float.NegativeInfinity); - var maxY = new float4(float.NegativeInfinity); - var maxZ = new float4(float.NegativeInfinity); - var maxParentError = new float4(0); - var nodeData = new uint4(0xFFFFFFFF); - - var outNodeIndex = hierarchyNodes.Count; - hierarchyNodes.Add(bvhNode); // Reserve slot - - for (var i = 0; i < gathered.Count; i++) + try { - var childIdx = gathered[i]; - var childNode = binaryNodes[childIdx]; + GatherChildren(binaryNodes, binaryNodeIndex, ref gathered); - uint data = 0; - if (childNode.leftChild == -1) + var bvhNode = new MeshletHierarchyNode(); + + var minX = new float4(float.PositiveInfinity); + var minY = new float4(float.PositiveInfinity); + var minZ = new float4(float.PositiveInfinity); + var maxX = new float4(float.NegativeInfinity); + var maxY = new float4(float.NegativeInfinity); + var maxZ = new float4(float.NegativeInfinity); + var maxParentError = new float4(0); + var nodeData = new uint4(0xFFFFFFFF); + + var outNodeIndex = hierarchyNodes.Count; + hierarchyNodes.Add(bvhNode); // Reserve slot + + for (var i = 0; i < gathered.Count; i++) { - data = (uint)childNode.meshletIndex; - } - else - { - var child4AryIndex = CollapseTo4Ary(binaryNodes, childIdx, hierarchyNodes); - data = (1u << 31) | (uint)child4AryIndex; + var childIdx = gathered[i]; + var childNode = binaryNodes[childIdx]; + + uint data = 0; + if (childNode.leftChild == -1) + { + data = (uint)childNode.meshletIndex; + } + else + { + var child4AryIndex = CollapseTo4Ary(binaryNodes, childIdx, hierarchyNodes); + data = (1u << 31) | (uint)child4AryIndex; + } + + if (i == 0) + { + minX.x = childNode.bounds.Min.x; minY.x = childNode.bounds.Min.y; minZ.x = childNode.bounds.Min.z; + maxX.x = childNode.bounds.Max.x; maxY.x = childNode.bounds.Max.y; maxZ.x = childNode.bounds.Max.z; + maxParentError.x = childNode.maxParentError; + nodeData.x = data; + } + else if (i == 1) + { + minX.y = childNode.bounds.Min.x; minY.y = childNode.bounds.Min.y; minZ.y = childNode.bounds.Min.z; + maxX.y = childNode.bounds.Max.x; maxY.y = childNode.bounds.Max.y; maxZ.y = childNode.bounds.Max.z; + maxParentError.y = childNode.maxParentError; + nodeData.y = data; + } + else if (i == 2) + { + minX.z = childNode.bounds.Min.x; minY.z = childNode.bounds.Min.y; minZ.z = childNode.bounds.Min.z; + maxX.z = childNode.bounds.Max.x; maxY.z = childNode.bounds.Max.y; maxZ.z = childNode.bounds.Max.z; + maxParentError.z = childNode.maxParentError; + nodeData.z = data; + } + else if (i == 3) + { + minX.w = childNode.bounds.Min.x; minY.w = childNode.bounds.Min.y; minZ.w = childNode.bounds.Min.z; + maxX.w = childNode.bounds.Max.x; maxY.w = childNode.bounds.Max.y; maxZ.w = childNode.bounds.Max.z; + maxParentError.w = childNode.maxParentError; + nodeData.w = data; + } } - if (i == 0) - { - minX.x = childNode.bounds.Min.x; minY.x = childNode.bounds.Min.y; minZ.x = childNode.bounds.Min.z; - maxX.x = childNode.bounds.Max.x; maxY.x = childNode.bounds.Max.y; maxZ.x = childNode.bounds.Max.z; - maxParentError.x = childNode.maxParentError; - nodeData.x = data; - } - else if (i == 1) - { - minX.y = childNode.bounds.Min.x; minY.y = childNode.bounds.Min.y; minZ.y = childNode.bounds.Min.z; - maxX.y = childNode.bounds.Max.x; maxY.y = childNode.bounds.Max.y; maxZ.y = childNode.bounds.Max.z; - maxParentError.y = childNode.maxParentError; - nodeData.y = data; - } - else if (i == 2) - { - minX.z = childNode.bounds.Min.x; minY.z = childNode.bounds.Min.y; minZ.z = childNode.bounds.Min.z; - maxX.z = childNode.bounds.Max.x; maxY.z = childNode.bounds.Max.y; maxZ.z = childNode.bounds.Max.z; - maxParentError.z = childNode.maxParentError; - nodeData.z = data; - } - else if (i == 3) - { - minX.w = childNode.bounds.Min.x; minY.w = childNode.bounds.Min.y; minZ.w = childNode.bounds.Min.z; - maxX.w = childNode.bounds.Max.x; maxY.w = childNode.bounds.Max.y; maxZ.w = childNode.bounds.Max.z; - maxParentError.w = childNode.maxParentError; - nodeData.w = data; - } + bvhNode.minX = minX; + bvhNode.minY = minY; + bvhNode.minZ = minZ; + bvhNode.maxX = maxX; + bvhNode.maxY = maxY; + bvhNode.maxZ = maxZ; + bvhNode.maxParentError = maxParentError; + bvhNode.nodeData = nodeData; + + hierarchyNodes[outNodeIndex] = bvhNode; + return outNodeIndex; + } + finally + { + gathered.Dispose(); } - - bvhNode.minX = minX; - bvhNode.minY = minY; - bvhNode.minZ = minZ; - bvhNode.maxX = maxX; - bvhNode.maxY = maxY; - bvhNode.maxZ = maxZ; - bvhNode.maxParentError = maxParentError; - bvhNode.nodeData = nodeData; - - hierarchyNodes[outNodeIndex] = bvhNode; - return outNodeIndex; } /// @@ -1082,43 +1090,49 @@ internal static unsafe partial class MeshProcessor meshletIndices[i] = i; } - var meshletsSpan = new ReadOnlySpan(meshletData.meshlets.GetUnsafePtr(), meshletData.meshlets.Count); + var binaryNodes = new UnsafeList(meshletData.meshletCount * 2, AllocationHandle.Persistent); - using var binaryNodes = new UnsafeList(meshletData.meshletCount * 2, AllocationHandle.Persistent); - var rootIndex = BuildBinaryTree(binaryNodes, meshletIndices, 0, meshletIndices.Length, meshletsSpan); - - if (!meshletData.hierarchyNodes.IsCreated) + try { - meshletData.hierarchyNodes = new UnsafeList(meshletData.meshletCount, allocationHandle); + var rootIndex = BuildBinaryTree(ref binaryNodes, meshletIndices, 0, meshletIndices.Length, meshletData.meshlets); + + if (!meshletData.hierarchyNodes.IsCreated) + { + meshletData.hierarchyNodes = new UnsafeList(meshletData.meshletCount, allocationHandle); + } + + if (binaryNodes[rootIndex].leftChild == -1) + { + var bvhNode = new MeshletHierarchyNode(); + bvhNode.minX = new float4(float.PositiveInfinity); + bvhNode.minY = new float4(float.PositiveInfinity); + bvhNode.minZ = new float4(float.PositiveInfinity); + bvhNode.maxX = new float4(float.NegativeInfinity); + bvhNode.maxY = new float4(float.NegativeInfinity); + bvhNode.maxZ = new float4(float.NegativeInfinity); + bvhNode.maxParentError = new float4(0); + bvhNode.nodeData = new uint4(0xFFFFFFFF); + + var childNode = binaryNodes[rootIndex]; + bvhNode.minX.x = childNode.bounds.Min.x; + bvhNode.minY.x = childNode.bounds.Min.y; + bvhNode.minZ.x = childNode.bounds.Min.z; + bvhNode.maxX.x = childNode.bounds.Max.x; + bvhNode.maxY.x = childNode.bounds.Max.y; + bvhNode.maxZ.x = childNode.bounds.Max.z; + bvhNode.maxParentError.x = childNode.maxParentError; + bvhNode.nodeData.x = (uint)childNode.meshletIndex; + + meshletData.hierarchyNodes.Add(bvhNode); + } + else + { + CollapseTo4Ary(binaryNodes, rootIndex, meshletData.hierarchyNodes); + } } - - if (binaryNodes[rootIndex].leftChild == -1) + finally { - var bvhNode = new MeshletHierarchyNode(); - bvhNode.minX = new float4(float.PositiveInfinity); - bvhNode.minY = new float4(float.PositiveInfinity); - bvhNode.minZ = new float4(float.PositiveInfinity); - bvhNode.maxX = new float4(float.NegativeInfinity); - bvhNode.maxY = new float4(float.NegativeInfinity); - bvhNode.maxZ = new float4(float.NegativeInfinity); - bvhNode.maxParentError = new float4(0); - bvhNode.nodeData = new uint4(0xFFFFFFFF); - - var childNode = binaryNodes[rootIndex]; - bvhNode.minX.x = childNode.bounds.Min.x; - bvhNode.minY.x = childNode.bounds.Min.y; - bvhNode.minZ.x = childNode.bounds.Min.z; - bvhNode.maxX.x = childNode.bounds.Max.x; - bvhNode.maxY.x = childNode.bounds.Max.y; - bvhNode.maxZ.x = childNode.bounds.Max.z; - bvhNode.maxParentError.x = childNode.maxParentError; - bvhNode.nodeData.x = (uint)childNode.meshletIndex; - - meshletData.hierarchyNodes.Add(bvhNode); - } - else - { - CollapseTo4Ary(binaryNodes, rootIndex, meshletData.hierarchyNodes); + binaryNodes.Dispose(); } } } diff --git a/src/Editor/Ghost.Editor.Core/Properties/launchSettings.json b/src/Editor/Ghost.Editor.Core/Properties/launchSettings.json new file mode 100644 index 0000000..cd2550d --- /dev/null +++ b/src/Editor/Ghost.Editor.Core/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Ghost.Editor.Core": { + "commandName": "Project", + "debugEngines": "managed" + } + } +} \ No newline at end of file diff --git a/src/GhostEngine.slnx b/src/GhostEngine.slnx index 55701f9..87d5a1b 100644 --- a/src/GhostEngine.slnx +++ b/src/GhostEngine.slnx @@ -7,7 +7,9 @@ - + + + diff --git a/src/Runtime/Ghost.Core/Ghost.Core.csproj b/src/Runtime/Ghost.Core/Ghost.Core.csproj index 15cc064..e773cbc 100644 --- a/src/Runtime/Ghost.Core/Ghost.Core.csproj +++ b/src/Runtime/Ghost.Core/Ghost.Core.csproj @@ -8,7 +8,7 @@ - $(DefineConstants);MHP_ENABLE_SAFETY_CHECKS;MHP_ENABLE_MIMALLOC;MHP_FASTMATH + $(DefineConstants);MHP_ENABLE_MIMALLOC;MHP_FASTMATH True True