diff options
author | Dan Lake | 2009-10-05 05:35:56 -0700 |
---|---|---|
committer | Melanie | 2009-10-05 12:45:41 +0100 |
commit | 6d52974c5f8184c03e3366fdcce03e4ec15c85f6 (patch) | |
tree | 7a1c7a7db8446b9f7bf59fcc367d347c5e00a50a | |
parent | only cache mesh if meshing was successful (diff) | |
download | opensim-SC-6d52974c5f8184c03e3366fdcce03e4ec15c85f6.zip opensim-SC-6d52974c5f8184c03e3366fdcce03e4ec15c85f6.tar.gz opensim-SC-6d52974c5f8184c03e3366fdcce03e4ec15c85f6.tar.bz2 opensim-SC-6d52974c5f8184c03e3366fdcce03e4ec15c85f6.tar.xz |
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.
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/Manager/IMesher.cs | 2 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Mesh.cs | 166 | ||||
-rw-r--r-- | 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 | |||
47 | int[] getIndexListAsInt(); | 47 | int[] getIndexListAsInt(); |
48 | int[] getIndexListAsIntLocked(); | 48 | int[] getIndexListAsIntLocked(); |
49 | float[] getVertexListAsFloatLocked(); | 49 | float[] getVertexListAsFloatLocked(); |
50 | void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount); | ||
51 | void getVertexListAsPtrToFloatArray( out IntPtr vertexList, out int vertexStride, out int vertexCount ); | ||
50 | void releaseSourceMeshData(); | 52 | void releaseSourceMeshData(); |
51 | void releasePinned(); | 53 | void releasePinned(); |
52 | void Append(IMesh newMesh); | 54 | 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 | |||
36 | { | 36 | { |
37 | public class Mesh : IMesh | 37 | public class Mesh : IMesh |
38 | { | 38 | { |
39 | private Dictionary<Vertex, int> vertices; | 39 | private Dictionary<Vertex, int> m_vertices; |
40 | private List<Triangle> triangles; | 40 | private List<Triangle> m_triangles; |
41 | GCHandle pinnedVirtexes; | 41 | GCHandle m_pinnedVertexes; |
42 | GCHandle pinnedIndex; | 42 | GCHandle m_pinnedIndex; |
43 | public float[] normals; | 43 | IntPtr m_verticesPtr = IntPtr.Zero; |
44 | int m_vertexCount = 0; | ||
45 | IntPtr m_indicesPtr = IntPtr.Zero; | ||
46 | int m_indexCount = 0; | ||
47 | public float[] m_normals; | ||
44 | 48 | ||
45 | public Mesh() | 49 | public Mesh() |
46 | { | 50 | { |
47 | vertices = new Dictionary<Vertex, int>(); | 51 | m_vertices = new Dictionary<Vertex, int>(); |
48 | triangles = new List<Triangle>(); | 52 | m_triangles = new List<Triangle>(); |
49 | } | 53 | } |
50 | 54 | ||
51 | public Mesh Clone() | 55 | public Mesh Clone() |
52 | { | 56 | { |
53 | Mesh result = new Mesh(); | 57 | Mesh result = new Mesh(); |
54 | 58 | ||
55 | foreach (Triangle t in triangles) | 59 | foreach (Triangle t in m_triangles) |
56 | { | 60 | { |
57 | result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone())); | 61 | result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone())); |
58 | } | 62 | } |
@@ -62,27 +66,27 @@ namespace OpenSim.Region.Physics.Meshing | |||
62 | 66 | ||
63 | public void Add(Triangle triangle) | 67 | public void Add(Triangle triangle) |
64 | { | 68 | { |
65 | if (pinnedIndex.IsAllocated || pinnedVirtexes.IsAllocated) | 69 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) |
66 | throw new NotSupportedException("Attempt to Add to a pinned Mesh"); | 70 | throw new NotSupportedException("Attempt to Add to a pinned Mesh"); |
67 | // If a vertex of the triangle is not yet in the vertices list, | 71 | // If a vertex of the triangle is not yet in the vertices list, |
68 | // add it and set its index to the current index count | 72 | // add it and set its index to the current index count |
69 | if (!vertices.ContainsKey(triangle.v1)) | 73 | if( !m_vertices.ContainsKey(triangle.v1) ) |
70 | vertices[triangle.v1] = vertices.Count; | 74 | m_vertices[triangle.v1] = m_vertices.Count; |
71 | if (!vertices.ContainsKey(triangle.v2)) | 75 | if (!m_vertices.ContainsKey(triangle.v2)) |
72 | vertices[triangle.v2] = vertices.Count; | 76 | m_vertices[triangle.v2] = m_vertices.Count; |
73 | if (!vertices.ContainsKey(triangle.v3)) | 77 | if (!m_vertices.ContainsKey(triangle.v3)) |
74 | vertices[triangle.v3] = vertices.Count; | 78 | m_vertices[triangle.v3] = m_vertices.Count; |
75 | triangles.Add(triangle); | 79 | m_triangles.Add(triangle); |
76 | } | 80 | } |
77 | 81 | ||
78 | public void CalcNormals() | 82 | public void CalcNormals() |
79 | { | 83 | { |
80 | int iTriangles = triangles.Count; | 84 | int iTriangles = m_triangles.Count; |
81 | 85 | ||
82 | this.normals = new float[iTriangles * 3]; | 86 | this.m_normals = new float[iTriangles * 3]; |
83 | 87 | ||
84 | int i = 0; | 88 | int i = 0; |
85 | foreach (Triangle t in triangles) | 89 | foreach (Triangle t in m_triangles) |
86 | { | 90 | { |
87 | float ux, uy, uz; | 91 | float ux, uy, uz; |
88 | float vx, vy, vz; | 92 | float vx, vy, vz; |
@@ -129,9 +133,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
129 | //ny /= l; | 133 | //ny /= l; |
130 | //nz /= l; | 134 | //nz /= l; |
131 | 135 | ||
132 | normals[i] = nx * lReciprocal; | 136 | m_normals[i] = nx * lReciprocal; |
133 | normals[i + 1] = ny * lReciprocal; | 137 | m_normals[i + 1] = ny * lReciprocal; |
134 | normals[i + 2] = nz * lReciprocal; | 138 | m_normals[i + 2] = nz * lReciprocal; |
135 | 139 | ||
136 | i += 3; | 140 | i += 3; |
137 | } | 141 | } |
@@ -140,45 +144,70 @@ namespace OpenSim.Region.Physics.Meshing | |||
140 | public List<PhysicsVector> getVertexList() | 144 | public List<PhysicsVector> getVertexList() |
141 | { | 145 | { |
142 | List<PhysicsVector> result = new List<PhysicsVector>(); | 146 | List<PhysicsVector> result = new List<PhysicsVector>(); |
143 | foreach (Vertex v in vertices.Keys) | 147 | foreach (Vertex v in m_vertices.Keys) |
144 | { | 148 | { |
145 | result.Add(v); | 149 | result.Add(v); |
146 | } | 150 | } |
147 | return result; | 151 | return result; |
148 | } | 152 | } |
149 | 153 | ||
150 | public float[] getVertexListAsFloatLocked() | 154 | private float[] getVertexListAsFloat() |
151 | { | 155 | { |
152 | if (pinnedVirtexes.IsAllocated) | 156 | if(m_vertices == null) |
153 | return (float[])(pinnedVirtexes.Target); | 157 | throw new NotSupportedException(); |
154 | float[] result; | 158 | float[] result = new float[m_vertices.Count * 3]; |
155 | 159 | foreach (KeyValuePair<Vertex, int> kvp in m_vertices) | |
156 | //m_log.WarnFormat("vertices.Count = {0}", vertices.Count); | ||
157 | result = new float[vertices.Count * 3]; | ||
158 | foreach (KeyValuePair<Vertex, int> kvp in vertices) | ||
159 | { | 160 | { |
160 | Vertex v = kvp.Key; | 161 | Vertex v = kvp.Key; |
161 | int i = kvp.Value; | 162 | int i = kvp.Value; |
162 | //m_log.WarnFormat("kvp.Value = {0}", i); | ||
163 | result[3 * i + 0] = v.X; | 163 | result[3 * i + 0] = v.X; |
164 | result[3 * i + 1] = v.Y; | 164 | result[3 * i + 1] = v.Y; |
165 | result[3 * i + 2] = v.Z; | 165 | result[3 * i + 2] = v.Z; |
166 | } | 166 | } |
167 | pinnedVirtexes = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
168 | return result; | 167 | return result; |
169 | } | 168 | } |
170 | 169 | ||
171 | public int[] getIndexListAsInt() | 170 | public float[] getVertexListAsFloatLocked() |
172 | { | 171 | { |
173 | int[] result; | 172 | if( m_pinnedVertexes.IsAllocated ) |
173 | return (float[])(m_pinnedVertexes.Target); | ||
174 | 174 | ||
175 | result = new int[triangles.Count * 3]; | 175 | float[] result = getVertexListAsFloat(); |
176 | for (int i = 0; i < triangles.Count; i++) | 176 | m_pinnedVertexes = GCHandle.Alloc(result, GCHandleType.Pinned); |
177 | |||
178 | return result; | ||
179 | } | ||
180 | |||
181 | public void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount) | ||
182 | { | ||
183 | // A vertex is 3 floats | ||
184 | vertexStride = 3 * sizeof(float); | ||
185 | |||
186 | // If there isn't an unmanaged array allocated yet, do it now | ||
187 | if (m_verticesPtr == IntPtr.Zero) | ||
177 | { | 188 | { |
178 | Triangle t = triangles[i]; | 189 | float[] vertexList = getVertexListAsFloat(); |
179 | result[3 * i + 0] = vertices[t.v1]; | 190 | // Each vertex is 3 elements (floats) |
180 | result[3 * i + 1] = vertices[t.v2]; | 191 | m_vertexCount = vertexList.Length / 3; |
181 | result[3 * i + 2] = vertices[t.v3]; | 192 | int byteCount = m_vertexCount * vertexStride; |
193 | m_verticesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); | ||
194 | System.Runtime.InteropServices.Marshal.Copy(vertexList, 0, m_verticesPtr, m_vertexCount * 3); | ||
195 | } | ||
196 | vertices = m_verticesPtr; | ||
197 | vertexCount = m_vertexCount; | ||
198 | } | ||
199 | |||
200 | public int[] getIndexListAsInt() | ||
201 | { | ||
202 | if (m_triangles == null) | ||
203 | throw new NotSupportedException(); | ||
204 | int[] result = new int[m_triangles.Count * 3]; | ||
205 | for (int i = 0; i < m_triangles.Count; i++) | ||
206 | { | ||
207 | Triangle t = m_triangles[i]; | ||
208 | result[3 * i + 0] = m_vertices[t.v1]; | ||
209 | result[3 * i + 1] = m_vertices[t.v2]; | ||
210 | result[3 * i + 2] = m_vertices[t.v3]; | ||
182 | } | 211 | } |
183 | return result; | 212 | return result; |
184 | } | 213 | } |
@@ -189,19 +218,48 @@ namespace OpenSim.Region.Physics.Meshing | |||
189 | /// <returns></returns> | 218 | /// <returns></returns> |
190 | public int[] getIndexListAsIntLocked() | 219 | public int[] getIndexListAsIntLocked() |
191 | { | 220 | { |
192 | if (pinnedIndex.IsAllocated) | 221 | if (m_pinnedIndex.IsAllocated) |
193 | return (int[])(pinnedIndex.Target); | 222 | return (int[])(m_pinnedIndex.Target); |
194 | 223 | ||
195 | int[] result = getIndexListAsInt(); | 224 | int[] result = getIndexListAsInt(); |
196 | pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); | 225 | m_pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); |
197 | 226 | ||
198 | return result; | 227 | return result; |
199 | } | 228 | } |
200 | 229 | ||
230 | public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount) | ||
231 | { | ||
232 | // If there isn't an unmanaged array allocated yet, do it now | ||
233 | if (m_indicesPtr == IntPtr.Zero) | ||
234 | { | ||
235 | int[] indexList = getIndexListAsInt(); | ||
236 | m_indexCount = indexList.Length; | ||
237 | int byteCount = m_indexCount * sizeof(int); | ||
238 | m_indicesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); | ||
239 | System.Runtime.InteropServices.Marshal.Copy(indexList, 0, m_indicesPtr, m_indexCount); | ||
240 | } | ||
241 | // A triangle is 3 ints (indices) | ||
242 | triStride = 3 * sizeof(int); | ||
243 | indices = m_indicesPtr; | ||
244 | indexCount = m_indexCount; | ||
245 | } | ||
246 | |||
201 | public void releasePinned() | 247 | public void releasePinned() |
202 | { | 248 | { |
203 | pinnedVirtexes.Free(); | 249 | if (m_pinnedVertexes.IsAllocated) |
204 | pinnedIndex.Free(); | 250 | m_pinnedVertexes.Free(); |
251 | if (m_pinnedIndex.IsAllocated) | ||
252 | m_pinnedIndex.Free(); | ||
253 | if (m_verticesPtr != IntPtr.Zero) | ||
254 | { | ||
255 | System.Runtime.InteropServices.Marshal.FreeHGlobal(m_verticesPtr); | ||
256 | m_verticesPtr = IntPtr.Zero; | ||
257 | } | ||
258 | if (m_indicesPtr != IntPtr.Zero) | ||
259 | { | ||
260 | System.Runtime.InteropServices.Marshal.FreeHGlobal(m_indicesPtr); | ||
261 | m_indicesPtr = IntPtr.Zero; | ||
262 | } | ||
205 | } | 263 | } |
206 | 264 | ||
207 | /// <summary> | 265 | /// <summary> |
@@ -209,29 +267,29 @@ namespace OpenSim.Region.Physics.Meshing | |||
209 | /// </summary> | 267 | /// </summary> |
210 | public void releaseSourceMeshData() | 268 | public void releaseSourceMeshData() |
211 | { | 269 | { |
212 | triangles = null; | 270 | m_triangles = null; |
213 | vertices = null; | 271 | m_vertices = null; |
214 | } | 272 | } |
215 | 273 | ||
216 | public void Append(IMesh newMesh) | 274 | public void Append(IMesh newMesh) |
217 | { | 275 | { |
218 | if (pinnedIndex.IsAllocated || pinnedVirtexes.IsAllocated) | 276 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) |
219 | throw new NotSupportedException("Attempt to Append to a pinned Mesh"); | 277 | throw new NotSupportedException("Attempt to Append to a pinned Mesh"); |
220 | 278 | ||
221 | if (!(newMesh is Mesh)) | 279 | if (!(newMesh is Mesh)) |
222 | return; | 280 | return; |
223 | 281 | ||
224 | foreach (Triangle t in ((Mesh)newMesh).triangles) | 282 | foreach (Triangle t in ((Mesh)newMesh).m_triangles) |
225 | Add(t); | 283 | Add(t); |
226 | } | 284 | } |
227 | 285 | ||
228 | // Do a linear transformation of mesh. | 286 | // Do a linear transformation of mesh. |
229 | public void TransformLinear(float[,] matrix, float[] offset) | 287 | public void TransformLinear(float[,] matrix, float[] offset) |
230 | { | 288 | { |
231 | if (pinnedIndex.IsAllocated || pinnedVirtexes.IsAllocated) | 289 | if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) |
232 | throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); | 290 | throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); |
233 | 291 | ||
234 | foreach (Vertex v in vertices.Keys) | 292 | foreach (Vertex v in m_vertices.Keys) |
235 | { | 293 | { |
236 | if (v == null) | 294 | if (v == null) |
237 | continue; | 295 | continue; |
@@ -252,7 +310,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
252 | String fileName = name + "_" + title + ".raw"; | 310 | String fileName = name + "_" + title + ".raw"; |
253 | String completePath = Path.Combine(path, fileName); | 311 | String completePath = Path.Combine(path, fileName); |
254 | StreamWriter sw = new StreamWriter(completePath); | 312 | StreamWriter sw = new StreamWriter(completePath); |
255 | foreach (Triangle t in triangles) | 313 | foreach (Triangle t in m_triangles) |
256 | { | 314 | { |
257 | String s = t.ToStringRaw(); | 315 | String s = t.ToStringRaw(); |
258 | sw.WriteLine(s); | 316 | sw.WriteLine(s); |
@@ -262,7 +320,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
262 | 320 | ||
263 | public void TrimExcess() | 321 | public void TrimExcess() |
264 | { | 322 | { |
265 | triangles.TrimExcess(); | 323 | m_triangles.TrimExcess(); |
266 | } | 324 | } |
267 | } | 325 | } |
268 | } | 326 | } |
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 | |||
813 | } | 813 | } |
814 | } | 814 | } |
815 | 815 | ||
816 | float[] vertexList = mesh.getVertexListAsFloatLocked(); // Note, that vertextList is pinned in memory | 816 | IntPtr vertices, indices; |
817 | int[] indexList = mesh.getIndexListAsIntLocked(); // Also pinned, needs release after usage | 817 | int vertexCount, indexCount; |
818 | int vertexStride, triStride; | ||
819 | mesh.getVertexListAsPtrToFloatArray( out vertices, out vertexStride, out vertexCount ); // Note, that vertices are fixed in unmanaged heap | ||
820 | mesh.getIndexListAsPtrToIntArray( out indices, out triStride, out indexCount ); // Also fixed, needs release after usage | ||
818 | 821 | ||
819 | mesh.releaseSourceMeshData(); // free up the original mesh data to save memory | 822 | mesh.releaseSourceMeshData(); // free up the original mesh data to save memory |
820 | 823 | ||
821 | int VertexCount = vertexList.GetLength(0)/3; | ||
822 | int IndexCount = indexList.GetLength(0); | ||
823 | |||
824 | _triMeshData = d.GeomTriMeshDataCreate(); | 824 | _triMeshData = d.GeomTriMeshDataCreate(); |
825 | 825 | ||
826 | d.GeomTriMeshDataBuildSimple(_triMeshData, vertexList, 3*sizeof (float), VertexCount, indexList, IndexCount, | 826 | d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride); |
827 | 3*sizeof (int)); | ||
828 | d.GeomTriMeshDataPreprocess(_triMeshData); | 827 | d.GeomTriMeshDataPreprocess(_triMeshData); |
829 | 828 | ||
830 | _parent_scene.waitForSpaceUnlock(m_targetSpace); | 829 | _parent_scene.waitForSpaceUnlock(m_targetSpace); |