From 5c593f3892d3de0bc3dab25c9298a3f31d3d86c1 Mon Sep 17 00:00:00 2001 From: dahlia Date: Sun, 4 Oct 2009 20:01:44 -0700 Subject: [PATCH 1/2] only cache mesh if meshing was successful re-enable sculpt mesh caching --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 0e29cccfa3..1ea08e250c 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -498,12 +498,9 @@ namespace OpenSim.Region.Physics.Meshing // If this mesh has been created already, return it instead of creating another copy // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory - if (! primShape.SculptEntry) - { - key = GetMeshKey(primShape, size, lod); - if (m_uniqueMeshes.TryGetValue(key, out mesh)) - return mesh; - } + key = GetMeshKey(primShape, size, lod); + if (m_uniqueMeshes.TryGetValue(key, out mesh)) + return mesh; if (size.X < 0.01f) size.X = 0.01f; if (size.Y < 0.01f) size.Y = 0.01f; @@ -525,10 +522,9 @@ namespace OpenSim.Region.Physics.Meshing // trim the vertex and triangle lists to free up memory mesh.TrimExcess(); - } - if (!primShape.SculptEntry) m_uniqueMeshes.Add(key, mesh); + } return mesh; } From 6d52974c5f8184c03e3366fdcce03e4ec15c85f6 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Mon, 5 Oct 2009 05:35:56 -0700 Subject: [PATCH 2/2] 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 e26c6234a1..ac14292915 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 aae88710ab..ff1f816c88 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 float[] getVertexListAsFloatLocked() + { + if( m_pinnedVertexes.IsAllocated ) + return (float[])(m_pinnedVertexes.Target); + + 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) + { + 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() { - int[] result; - - result = new int[triangles.Count * 3]; - for (int i = 0; i < triangles.Count; i++) + 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 = triangles[i]; - result[3 * i + 0] = vertices[t.v1]; - result[3 * i + 1] = vertices[t.v2]; - result[3 * i + 2] = vertices[t.v3]; + 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 032b5dff6d..c04124327c 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);