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<int> 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
This commit is contained in:
@@ -261,17 +261,16 @@ internal class MeshAssetHandler : IImportableAssetHandler, IPackableAssetHandler
|
|||||||
return Result.Failure<ImportedSubAsset[]>("Source file does not exist.");
|
return Result.Failure<ImportedSubAsset[]>("Source file does not exist.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var meshSettings = ResolveSettings(sourcePath, settings);
|
|
||||||
var root = new MeshNode();
|
|
||||||
try
|
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 parseJob = new MeshParsingJob(root, sourcePath, AllocationHandle.Persistent, meshSettings);
|
||||||
var context = default(Misaki.HighPerformance.Jobs.JobExecutionContext);
|
var context = default(Misaki.HighPerformance.Jobs.JobExecutionContext);
|
||||||
parseJob.Execute(in context);
|
parseJob.Execute(in context);
|
||||||
|
|
||||||
var heapSize2 = AllocationManager.TotalAllocatedMemory;
|
|
||||||
|
|
||||||
var manifest = new ModelManifest
|
var manifest = new ModelManifest
|
||||||
{
|
{
|
||||||
AssetId = id,
|
AssetId = id,
|
||||||
@@ -291,10 +290,6 @@ internal class MeshAssetHandler : IImportableAssetHandler, IPackableAssetHandler
|
|||||||
{
|
{
|
||||||
return Result.Failure<ImportedSubAsset[]>($"Failed to import mesh asset: {ex.Message}");
|
return Result.Failure<ImportedSubAsset[]>($"Failed to import mesh asset: {ex.Message}");
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
root.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask<Result> ExportAsync(string assetPath, string targetPath, IAssetExportOptions? options, CancellationToken token = default)
|
public ValueTask<Result> ExportAsync(string assetPath, string targetPath, IAssetExportOptions? options, CancellationToken token = default)
|
||||||
|
|||||||
@@ -864,7 +864,7 @@ internal static unsafe partial class MeshProcessor
|
|||||||
public int meshletIndex;
|
public int meshletIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int BuildBinaryTree(UnsafeList<TempBinaryNode> nodes, UnsafeArray<int> meshletIndices, int start, int end, ReadOnlySpan<Meshlet> meshlets)
|
private static int BuildBinaryTree(ref UnsafeList<TempBinaryNode> nodes, UnsafeArray<int> meshletIndices, int start, int end, ReadOnlySpan<Meshlet> meshlets)
|
||||||
{
|
{
|
||||||
if (start == end - 1)
|
if (start == end - 1)
|
||||||
{
|
{
|
||||||
@@ -921,8 +921,8 @@ internal static unsafe partial class MeshProcessor
|
|||||||
mid = start + (end - start) / 2;
|
mid = start + (end - start) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
var left = BuildBinaryTree(nodes, meshletIndices, start, mid, meshlets);
|
var left = BuildBinaryTree(ref nodes, meshletIndices, start, mid, meshlets);
|
||||||
var right = BuildBinaryTree(nodes, meshletIndices, mid, end, meshlets);
|
var right = BuildBinaryTree(ref nodes, meshletIndices, mid, end, meshlets);
|
||||||
|
|
||||||
var leftNode = nodes[left];
|
var leftNode = nodes[left];
|
||||||
var rightNode = nodes[right];
|
var rightNode = nodes[right];
|
||||||
@@ -945,7 +945,7 @@ internal static unsafe partial class MeshProcessor
|
|||||||
return internalNodeIndex;
|
return internalNodeIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GatherChildren(UnsafeList<TempBinaryNode> binaryNodes, int nodeIndex, UnsafeList<int> gathered)
|
private static void GatherChildren(UnsafeList<TempBinaryNode> binaryNodes, int nodeIndex, ref UnsafeList<int> gathered)
|
||||||
{
|
{
|
||||||
gathered.Clear();
|
gathered.Clear();
|
||||||
var node = binaryNodes[nodeIndex];
|
var node = binaryNodes[nodeIndex];
|
||||||
@@ -992,80 +992,88 @@ internal static unsafe partial class MeshProcessor
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
using var gathered = new UnsafeList<int>(4, AllocationHandle.Persistent);
|
var gathered = new UnsafeList<int>(4, AllocationHandle.Persistent);
|
||||||
GatherChildren(binaryNodes, binaryNodeIndex, gathered);
|
|
||||||
|
|
||||||
var bvhNode = new MeshletHierarchyNode();
|
try
|
||||||
|
|
||||||
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++)
|
|
||||||
{
|
{
|
||||||
var childIdx = gathered[i];
|
GatherChildren(binaryNodes, binaryNodeIndex, ref gathered);
|
||||||
var childNode = binaryNodes[childIdx];
|
|
||||||
|
|
||||||
uint data = 0;
|
var bvhNode = new MeshletHierarchyNode();
|
||||||
if (childNode.leftChild == -1)
|
|
||||||
|
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;
|
var childIdx = gathered[i];
|
||||||
}
|
var childNode = binaryNodes[childIdx];
|
||||||
else
|
|
||||||
{
|
uint data = 0;
|
||||||
var child4AryIndex = CollapseTo4Ary(binaryNodes, childIdx, hierarchyNodes);
|
if (childNode.leftChild == -1)
|
||||||
data = (1u << 31) | (uint)child4AryIndex;
|
{
|
||||||
|
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)
|
bvhNode.minX = minX;
|
||||||
{
|
bvhNode.minY = minY;
|
||||||
minX.x = childNode.bounds.Min.x; minY.x = childNode.bounds.Min.y; minZ.x = childNode.bounds.Min.z;
|
bvhNode.minZ = minZ;
|
||||||
maxX.x = childNode.bounds.Max.x; maxY.x = childNode.bounds.Max.y; maxZ.x = childNode.bounds.Max.z;
|
bvhNode.maxX = maxX;
|
||||||
maxParentError.x = childNode.maxParentError;
|
bvhNode.maxY = maxY;
|
||||||
nodeData.x = data;
|
bvhNode.maxZ = maxZ;
|
||||||
}
|
bvhNode.maxParentError = maxParentError;
|
||||||
else if (i == 1)
|
bvhNode.nodeData = nodeData;
|
||||||
{
|
|
||||||
minX.y = childNode.bounds.Min.x; minY.y = childNode.bounds.Min.y; minZ.y = childNode.bounds.Min.z;
|
hierarchyNodes[outNodeIndex] = bvhNode;
|
||||||
maxX.y = childNode.bounds.Max.x; maxY.y = childNode.bounds.Max.y; maxZ.y = childNode.bounds.Max.z;
|
return outNodeIndex;
|
||||||
maxParentError.y = childNode.maxParentError;
|
}
|
||||||
nodeData.y = data;
|
finally
|
||||||
}
|
{
|
||||||
else if (i == 2)
|
gathered.Dispose();
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1082,43 +1090,49 @@ internal static unsafe partial class MeshProcessor
|
|||||||
meshletIndices[i] = i;
|
meshletIndices[i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
var meshletsSpan = new ReadOnlySpan<Meshlet>(meshletData.meshlets.GetUnsafePtr(), meshletData.meshlets.Count);
|
var binaryNodes = new UnsafeList<TempBinaryNode>(meshletData.meshletCount * 2, AllocationHandle.Persistent);
|
||||||
|
|
||||||
using var binaryNodes = new UnsafeList<TempBinaryNode>(meshletData.meshletCount * 2, AllocationHandle.Persistent);
|
try
|
||||||
var rootIndex = BuildBinaryTree(binaryNodes, meshletIndices, 0, meshletIndices.Length, meshletsSpan);
|
|
||||||
|
|
||||||
if (!meshletData.hierarchyNodes.IsCreated)
|
|
||||||
{
|
{
|
||||||
meshletData.hierarchyNodes = new UnsafeList<MeshletHierarchyNode>(meshletData.meshletCount, allocationHandle);
|
var rootIndex = BuildBinaryTree(ref binaryNodes, meshletIndices, 0, meshletIndices.Length, meshletData.meshlets);
|
||||||
|
|
||||||
|
if (!meshletData.hierarchyNodes.IsCreated)
|
||||||
|
{
|
||||||
|
meshletData.hierarchyNodes = new UnsafeList<MeshletHierarchyNode>(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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
if (binaryNodes[rootIndex].leftChild == -1)
|
|
||||||
{
|
{
|
||||||
var bvhNode = new MeshletHierarchyNode();
|
binaryNodes.Dispose();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"Ghost.Editor.Core": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"debugEngines": "managed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,9 @@
|
|||||||
<Folder Name="/Editor/">
|
<Folder Name="/Editor/">
|
||||||
<Project Path="Editor/Ghost.DSL/Ghost.DSL.csproj" />
|
<Project Path="Editor/Ghost.DSL/Ghost.DSL.csproj" />
|
||||||
<Project Path="Editor/Ghost.Editor.Core/Ghost.Editor.Core.csproj">
|
<Project Path="Editor/Ghost.Editor.Core/Ghost.Editor.Core.csproj">
|
||||||
<Platform Solution="Debug|x64" Project="x64" />
|
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||||
|
<Platform Solution="*|x64" Project="x64" />
|
||||||
|
<Platform Solution="*|x86" Project="x86" />
|
||||||
</Project>
|
</Project>
|
||||||
<Project Path="Editor/Ghost.Editor/Ghost.Editor.csproj">
|
<Project Path="Editor/Ghost.Editor/Ghost.Editor.csproj">
|
||||||
<Platform Solution="*|ARM64" Project="ARM64" />
|
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<DefineConstants>$(DefineConstants);MHP_ENABLE_SAFETY_CHECKS;MHP_ENABLE_MIMALLOC;MHP_FASTMATH</DefineConstants>
|
<DefineConstants>$(DefineConstants);MHP_ENABLE_MIMALLOC;MHP_FASTMATH</DefineConstants>
|
||||||
<IsAotCompatible>True</IsAotCompatible>
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
<IsTrimmable>True</IsTrimmable>
|
<IsTrimmable>True</IsTrimmable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user