From 6d52974c5f8184c03e3366fdcce03e4ec15c85f6 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Mon, 5 Oct 2009 05:35:56 -0700 Subject: Eliminate pinned Mesh data on managed heap by using IntPtrs to memory allocated on the unmanaged heap. This prevents fragmentation of the managed heap and the resulting stress on GC. A region with ~150,000 prims using ODE and Meshmerizer saw memory remain flat around 1.2GB as opposed to 1.5GB and continually growing due to pinned memory. This patch complements the unique mesh dictionary patch applied to Meshmerizer but is independent. The net effect is a 60-75% reduction in memory for our largest regions. --- OpenSim/Region/Physics/Manager/IMesher.cs | 2 + OpenSim/Region/Physics/Meshing/Mesh.cs | 166 +++++++++++++++++++--------- OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 13 +-- 3 files changed, 120 insertions(+), 61 deletions(-) diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs index e26c623..ac14292 100644 --- a/OpenSim/Region/Physics/Manager/IMesher.cs +++ b/OpenSim/Region/Physics/Manager/IMesher.cs @@ -47,6 +47,8 @@ namespace OpenSim.Region.Physics.Manager int[] getIndexListAsInt(); int[] getIndexListAsIntLocked(); float[] getVertexListAsFloatLocked(); + void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount); + void getVertexListAsPtrToFloatArray( out IntPtr vertexList, out int vertexStride, out int vertexCount ); void releaseSourceMeshData(); void releasePinned(); void Append(IMesh newMesh); diff --git a/OpenSim/Region/Physics/Meshing/Mesh.cs b/OpenSim/Region/Physics/Meshing/Mesh.cs index aae8871..ff1f816 100644 --- a/OpenSim/Region/Physics/Meshing/Mesh.cs +++ b/OpenSim/Region/Physics/Meshing/Mesh.cs @@ -36,23 +36,27 @@ namespace OpenSim.Region.Physics.Meshing { public class Mesh : IMesh { - private Dictionary vertices; - private List triangles; - GCHandle pinnedVirtexes; - GCHandle pinnedIndex; - public float[] normals; + private Dictionary m_vertices; + private List m_triangles; + GCHandle m_pinnedVertexes; + GCHandle m_pinnedIndex; + IntPtr m_verticesPtr = IntPtr.Zero; + int m_vertexCount = 0; + IntPtr m_indicesPtr = IntPtr.Zero; + int m_indexCount = 0; + public float[] m_normals; public Mesh() { - vertices = new Dictionary(); - triangles = new List(); + m_vertices = new Dictionary(); + m_triangles = new List(); } public Mesh Clone() { Mesh result = new Mesh(); - foreach (Triangle t in triangles) + foreach (Triangle t in m_triangles) { result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone())); } @@ -62,27 +66,27 @@ namespace OpenSim.Region.Physics.Meshing public void Add(Triangle triangle) { - if (pinnedIndex.IsAllocated || pinnedVirtexes.IsAllocated) + if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) throw new NotSupportedException("Attempt to Add to a pinned Mesh"); // If a vertex of the triangle is not yet in the vertices list, // add it and set its index to the current index count - if (!vertices.ContainsKey(triangle.v1)) - vertices[triangle.v1] = vertices.Count; - if (!vertices.ContainsKey(triangle.v2)) - vertices[triangle.v2] = vertices.Count; - if (!vertices.ContainsKey(triangle.v3)) - vertices[triangle.v3] = vertices.Count; - triangles.Add(triangle); + if( !m_vertices.ContainsKey(triangle.v1) ) + m_vertices[triangle.v1] = m_vertices.Count; + if (!m_vertices.ContainsKey(triangle.v2)) + m_vertices[triangle.v2] = m_vertices.Count; + if (!m_vertices.ContainsKey(triangle.v3)) + m_vertices[triangle.v3] = m_vertices.Count; + m_triangles.Add(triangle); } public void CalcNormals() { - int iTriangles = triangles.Count; + int iTriangles = m_triangles.Count; - this.normals = new float[iTriangles * 3]; + this.m_normals = new float[iTriangles * 3]; int i = 0; - foreach (Triangle t in triangles) + foreach (Triangle t in m_triangles) { float ux, uy, uz; float vx, vy, vz; @@ -129,9 +133,9 @@ namespace OpenSim.Region.Physics.Meshing //ny /= l; //nz /= l; - normals[i] = nx * lReciprocal; - normals[i + 1] = ny * lReciprocal; - normals[i + 2] = nz * lReciprocal; + m_normals[i] = nx * lReciprocal; + m_normals[i + 1] = ny * lReciprocal; + m_normals[i + 2] = nz * lReciprocal; i += 3; } @@ -140,45 +144,70 @@ namespace OpenSim.Region.Physics.Meshing public List getVertexList() { List result = new List(); - foreach (Vertex v in vertices.Keys) + foreach (Vertex v in m_vertices.Keys) { result.Add(v); } return result; } - public float[] getVertexListAsFloatLocked() + private float[] getVertexListAsFloat() { - if (pinnedVirtexes.IsAllocated) - return (float[])(pinnedVirtexes.Target); - float[] result; - - //m_log.WarnFormat("vertices.Count = {0}", vertices.Count); - result = new float[vertices.Count * 3]; - foreach (KeyValuePair kvp in vertices) + if(m_vertices == null) + throw new NotSupportedException(); + float[] result = new float[m_vertices.Count * 3]; + foreach (KeyValuePair kvp in m_vertices) { Vertex v = kvp.Key; int i = kvp.Value; - //m_log.WarnFormat("kvp.Value = {0}", i); result[3 * i + 0] = v.X; result[3 * i + 1] = v.Y; result[3 * i + 2] = v.Z; } - pinnedVirtexes = GCHandle.Alloc(result, GCHandleType.Pinned); return result; } - public int[] getIndexListAsInt() + public float[] getVertexListAsFloatLocked() { - int[] result; + if( m_pinnedVertexes.IsAllocated ) + return (float[])(m_pinnedVertexes.Target); - result = new int[triangles.Count * 3]; - for (int i = 0; i < triangles.Count; i++) + float[] result = getVertexListAsFloat(); + m_pinnedVertexes = GCHandle.Alloc(result, GCHandleType.Pinned); + + return result; + } + + public void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount) + { + // A vertex is 3 floats + vertexStride = 3 * sizeof(float); + + // If there isn't an unmanaged array allocated yet, do it now + if (m_verticesPtr == IntPtr.Zero) { - Triangle t = triangles[i]; - result[3 * i + 0] = vertices[t.v1]; - result[3 * i + 1] = vertices[t.v2]; - result[3 * i + 2] = vertices[t.v3]; + float[] vertexList = getVertexListAsFloat(); + // Each vertex is 3 elements (floats) + m_vertexCount = vertexList.Length / 3; + int byteCount = m_vertexCount * vertexStride; + m_verticesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); + System.Runtime.InteropServices.Marshal.Copy(vertexList, 0, m_verticesPtr, m_vertexCount * 3); + } + vertices = m_verticesPtr; + vertexCount = m_vertexCount; + } + + public int[] getIndexListAsInt() + { + if (m_triangles == null) + throw new NotSupportedException(); + int[] result = new int[m_triangles.Count * 3]; + for (int i = 0; i < m_triangles.Count; i++) + { + Triangle t = m_triangles[i]; + result[3 * i + 0] = m_vertices[t.v1]; + result[3 * i + 1] = m_vertices[t.v2]; + result[3 * i + 2] = m_vertices[t.v3]; } return result; } @@ -189,19 +218,48 @@ namespace OpenSim.Region.Physics.Meshing /// public int[] getIndexListAsIntLocked() { - if (pinnedIndex.IsAllocated) - return (int[])(pinnedIndex.Target); + if (m_pinnedIndex.IsAllocated) + return (int[])(m_pinnedIndex.Target); int[] result = getIndexListAsInt(); - pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); + m_pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); return result; } + public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount) + { + // If there isn't an unmanaged array allocated yet, do it now + if (m_indicesPtr == IntPtr.Zero) + { + int[] indexList = getIndexListAsInt(); + m_indexCount = indexList.Length; + int byteCount = m_indexCount * sizeof(int); + m_indicesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); + System.Runtime.InteropServices.Marshal.Copy(indexList, 0, m_indicesPtr, m_indexCount); + } + // A triangle is 3 ints (indices) + triStride = 3 * sizeof(int); + indices = m_indicesPtr; + indexCount = m_indexCount; + } + public void releasePinned() { - pinnedVirtexes.Free(); - pinnedIndex.Free(); + if (m_pinnedVertexes.IsAllocated) + m_pinnedVertexes.Free(); + if (m_pinnedIndex.IsAllocated) + m_pinnedIndex.Free(); + if (m_verticesPtr != IntPtr.Zero) + { + System.Runtime.InteropServices.Marshal.FreeHGlobal(m_verticesPtr); + m_verticesPtr = IntPtr.Zero; + } + if (m_indicesPtr != IntPtr.Zero) + { + System.Runtime.InteropServices.Marshal.FreeHGlobal(m_indicesPtr); + m_indicesPtr = IntPtr.Zero; + } } /// @@ -209,29 +267,29 @@ namespace OpenSim.Region.Physics.Meshing /// public void releaseSourceMeshData() { - triangles = null; - vertices = null; + m_triangles = null; + m_vertices = null; } public void Append(IMesh newMesh) { - if (pinnedIndex.IsAllocated || pinnedVirtexes.IsAllocated) + if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) throw new NotSupportedException("Attempt to Append to a pinned Mesh"); if (!(newMesh is Mesh)) return; - foreach (Triangle t in ((Mesh)newMesh).triangles) + foreach (Triangle t in ((Mesh)newMesh).m_triangles) Add(t); } // Do a linear transformation of mesh. public void TransformLinear(float[,] matrix, float[] offset) { - if (pinnedIndex.IsAllocated || pinnedVirtexes.IsAllocated) + if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); - foreach (Vertex v in vertices.Keys) + foreach (Vertex v in m_vertices.Keys) { if (v == null) continue; @@ -252,7 +310,7 @@ namespace OpenSim.Region.Physics.Meshing String fileName = name + "_" + title + ".raw"; String completePath = Path.Combine(path, fileName); StreamWriter sw = new StreamWriter(completePath); - foreach (Triangle t in triangles) + foreach (Triangle t in m_triangles) { String s = t.ToStringRaw(); sw.WriteLine(s); @@ -262,7 +320,7 @@ namespace OpenSim.Region.Physics.Meshing public void TrimExcess() { - triangles.TrimExcess(); + m_triangles.TrimExcess(); } } } diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 032b5df..c041243 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -813,18 +813,17 @@ namespace OpenSim.Region.Physics.OdePlugin } } - float[] vertexList = mesh.getVertexListAsFloatLocked(); // Note, that vertextList is pinned in memory - int[] indexList = mesh.getIndexListAsIntLocked(); // Also pinned, needs release after usage + IntPtr vertices, indices; + int vertexCount, indexCount; + int vertexStride, triStride; + mesh.getVertexListAsPtrToFloatArray( out vertices, out vertexStride, out vertexCount ); // Note, that vertices are fixed in unmanaged heap + mesh.getIndexListAsPtrToIntArray( out indices, out triStride, out indexCount ); // Also fixed, needs release after usage mesh.releaseSourceMeshData(); // free up the original mesh data to save memory - int VertexCount = vertexList.GetLength(0)/3; - int IndexCount = indexList.GetLength(0); - _triMeshData = d.GeomTriMeshDataCreate(); - d.GeomTriMeshDataBuildSimple(_triMeshData, vertexList, 3*sizeof (float), VertexCount, indexList, IndexCount, - 3*sizeof (int)); + d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride); d.GeomTriMeshDataPreprocess(_triMeshData); _parent_scene.waitForSpaceUnlock(m_targetSpace); -- cgit v1.1