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.
parent
5c593f3892
commit
6d52974c5f
|
@ -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);
|
||||
|
|
|
@ -36,23 +36,27 @@ namespace OpenSim.Region.Physics.Meshing
|
|||
{
|
||||
public class Mesh : IMesh
|
||||
{
|
||||
private Dictionary<Vertex, int> vertices;
|
||||
private List<Triangle> triangles;
|
||||
GCHandle pinnedVirtexes;
|
||||
GCHandle pinnedIndex;
|
||||
public float[] normals;
|
||||
private Dictionary<Vertex, int> m_vertices;
|
||||
private List<Triangle> 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<Vertex, int>();
|
||||
triangles = new List<Triangle>();
|
||||
m_vertices = new Dictionary<Vertex, int>();
|
||||
m_triangles = new List<Triangle>();
|
||||
}
|
||||
|
||||
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<PhysicsVector> getVertexList()
|
||||
{
|
||||
List<PhysicsVector> result = new List<PhysicsVector>();
|
||||
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<Vertex, int> kvp in vertices)
|
||||
if(m_vertices == null)
|
||||
throw new NotSupportedException();
|
||||
float[] result = new float[m_vertices.Count * 3];
|
||||
foreach (KeyValuePair<Vertex, int> 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
|
|||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -209,29 +267,29 @@ namespace OpenSim.Region.Physics.Meshing
|
|||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue