diff options
author | Dan Lake | 2009-09-24 10:00:31 -0700 |
---|---|---|
committer | dahlia | 2009-09-24 18:20:59 -0700 |
commit | 1b2828f5d859d2941167b0457158142e683efe39 (patch) | |
tree | c1cdac03732aed67c8d99ce6692f99c806c8d1c4 | |
parent | modify BulletDotNETPrim.cs in preparation for Mantis #4181 (diff) | |
download | opensim-SC-1b2828f5d859d2941167b0457158142e683efe39.zip opensim-SC-1b2828f5d859d2941167b0457158142e683efe39.tar.gz opensim-SC-1b2828f5d859d2941167b0457158142e683efe39.tar.bz2 opensim-SC-1b2828f5d859d2941167b0457158142e683efe39.tar.xz |
Meshmerizer stores dictionary of unique Meshes keyed on construction parameters. CreateMesh() returns a Mesh from the dictionary or creates a new Mesh if it has not been created before. Meshes are never purged from the dictionary. The raw Mesh data is discarded once the memory is pinned for ODE use. All copies of the same prim/mesh use the same pinned memory. ONLY IMPLEMENTED AND TESTED WITH MESHMERIZER AND ODE
Signed-off-by: dahlia <dahliaTrimble@gmailDotCom>
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Mesh.cs | 87 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 69 | ||||
-rw-r--r-- | OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 17 |
3 files changed, 95 insertions, 78 deletions
diff --git a/OpenSim/Region/Physics/Meshing/Mesh.cs b/OpenSim/Region/Physics/Meshing/Mesh.cs index ceafaad..7567556 100644 --- a/OpenSim/Region/Physics/Meshing/Mesh.cs +++ b/OpenSim/Region/Physics/Meshing/Mesh.cs | |||
@@ -40,7 +40,6 @@ namespace OpenSim.Region.Physics.Meshing | |||
40 | private List<Triangle> triangles; | 40 | private List<Triangle> triangles; |
41 | GCHandle pinnedVirtexes; | 41 | GCHandle pinnedVirtexes; |
42 | GCHandle pinnedIndex; | 42 | GCHandle pinnedIndex; |
43 | public PrimMesh primMesh = null; | ||
44 | public float[] normals; | 43 | public float[] normals; |
45 | 44 | ||
46 | public Mesh() | 45 | public Mesh() |
@@ -63,6 +62,8 @@ namespace OpenSim.Region.Physics.Meshing | |||
63 | 62 | ||
64 | public void Add(Triangle triangle) | 63 | public void Add(Triangle triangle) |
65 | { | 64 | { |
65 | if (pinnedIndex.IsAllocated || pinnedVirtexes.IsAllocated) | ||
66 | throw new NotSupportedException("Attempt to Add to a pinned Mesh"); | ||
66 | // If a vertex of the triangle is not yet in the vertices list, | 67 | // If a vertex of the triangle is not yet in the vertices list, |
67 | // add it and set its index to the current index count | 68 | // add it and set its index to the current index count |
68 | if (!vertices.ContainsKey(triangle.v1)) | 69 | if (!vertices.ContainsKey(triangle.v1)) |
@@ -148,40 +149,22 @@ namespace OpenSim.Region.Physics.Meshing | |||
148 | 149 | ||
149 | public float[] getVertexListAsFloatLocked() | 150 | public float[] getVertexListAsFloatLocked() |
150 | { | 151 | { |
152 | if( pinnedVirtexes.IsAllocated ) | ||
153 | return (float[])(pinnedVirtexes.Target); | ||
151 | float[] result; | 154 | float[] result; |
152 | 155 | ||
153 | if (primMesh == null) | 156 | //m_log.WarnFormat("vertices.Count = {0}", vertices.Count); |
157 | result = new float[vertices.Count * 3]; | ||
158 | foreach (KeyValuePair<Vertex, int> kvp in vertices) | ||
154 | { | 159 | { |
155 | //m_log.WarnFormat("vertices.Count = {0}", vertices.Count); | 160 | Vertex v = kvp.Key; |
156 | result = new float[vertices.Count * 3]; | 161 | int i = kvp.Value; |
157 | foreach (KeyValuePair<Vertex, int> kvp in vertices) | 162 | //m_log.WarnFormat("kvp.Value = {0}", i); |
158 | { | 163 | result[3 * i + 0] = v.X; |
159 | Vertex v = kvp.Key; | 164 | result[3 * i + 1] = v.Y; |
160 | int i = kvp.Value; | 165 | result[3 * i + 2] = v.Z; |
161 | //m_log.WarnFormat("kvp.Value = {0}", i); | ||
162 | result[3 * i + 0] = v.X; | ||
163 | result[3 * i + 1] = v.Y; | ||
164 | result[3 * i + 2] = v.Z; | ||
165 | } | ||
166 | pinnedVirtexes = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
167 | } | ||
168 | else | ||
169 | { | ||
170 | int count = primMesh.coords.Count; | ||
171 | result = new float[count * 3]; | ||
172 | for (int i = 0; i < count; i++) | ||
173 | { | ||
174 | Coord c = primMesh.coords[i]; | ||
175 | { | ||
176 | int resultIndex = 3 * i; | ||
177 | result[resultIndex] = c.X; | ||
178 | result[resultIndex + 1] = c.Y; | ||
179 | result[resultIndex + 2] = c.Z; | ||
180 | } | ||
181 | |||
182 | } | ||
183 | pinnedVirtexes = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
184 | } | 166 | } |
167 | pinnedVirtexes = GCHandle.Alloc(result, GCHandleType.Pinned); | ||
185 | return result; | 168 | return result; |
186 | } | 169 | } |
187 | 170 | ||
@@ -189,33 +172,13 @@ namespace OpenSim.Region.Physics.Meshing | |||
189 | { | 172 | { |
190 | int[] result; | 173 | int[] result; |
191 | 174 | ||
192 | if (primMesh == null) | 175 | result = new int[triangles.Count * 3]; |
193 | { | 176 | for (int i = 0; i < triangles.Count; i++) |
194 | result = new int[triangles.Count * 3]; | ||
195 | for (int i = 0; i < triangles.Count; i++) | ||
196 | { | ||
197 | Triangle t = triangles[i]; | ||
198 | result[3 * i + 0] = vertices[t.v1]; | ||
199 | result[3 * i + 1] = vertices[t.v2]; | ||
200 | result[3 * i + 2] = vertices[t.v3]; | ||
201 | } | ||
202 | } | ||
203 | else | ||
204 | { | 177 | { |
205 | int numFaces = primMesh.faces.Count; | 178 | Triangle t = triangles[i]; |
206 | result = new int[numFaces * 3]; | 179 | result[3 * i + 0] = vertices[t.v1]; |
207 | for (int i = 0; i < numFaces; i++) | 180 | result[3 * i + 1] = vertices[t.v2]; |
208 | { | 181 | result[3 * i + 2] = vertices[t.v3]; |
209 | Face f = primMesh.faces[i]; | ||
210 | // Coord c1 = primMesh.coords[f.v1]; | ||
211 | // Coord c2 = primMesh.coords[f.v2]; | ||
212 | // Coord c3 = primMesh.coords[f.v3]; | ||
213 | |||
214 | int resultIndex = i * 3; | ||
215 | result[resultIndex] = f.v1; | ||
216 | result[resultIndex + 1] = f.v2; | ||
217 | result[resultIndex + 2] = f.v3; | ||
218 | } | ||
219 | } | 182 | } |
220 | return result; | 183 | return result; |
221 | } | 184 | } |
@@ -226,6 +189,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
226 | /// <returns></returns> | 189 | /// <returns></returns> |
227 | public int[] getIndexListAsIntLocked() | 190 | public int[] getIndexListAsIntLocked() |
228 | { | 191 | { |
192 | if (pinnedIndex.IsAllocated) | ||
193 | return (int[])(pinnedIndex.Target); | ||
194 | |||
229 | int[] result = getIndexListAsInt(); | 195 | int[] result = getIndexListAsInt(); |
230 | pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); | 196 | pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); |
231 | 197 | ||
@@ -245,11 +211,13 @@ namespace OpenSim.Region.Physics.Meshing | |||
245 | { | 211 | { |
246 | triangles = null; | 212 | triangles = null; |
247 | vertices = null; | 213 | vertices = null; |
248 | primMesh = null; | ||
249 | } | 214 | } |
250 | 215 | ||
251 | public void Append(IMesh newMesh) | 216 | public void Append(IMesh newMesh) |
252 | { | 217 | { |
218 | if (pinnedIndex.IsAllocated || pinnedVirtexes.IsAllocated) | ||
219 | throw new NotSupportedException("Attempt to Append to a pinned Mesh"); | ||
220 | |||
253 | if (!(newMesh is Mesh)) | 221 | if (!(newMesh is Mesh)) |
254 | return; | 222 | return; |
255 | 223 | ||
@@ -260,6 +228,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
260 | // Do a linear transformation of mesh. | 228 | // Do a linear transformation of mesh. |
261 | public void TransformLinear(float[,] matrix, float[] offset) | 229 | public void TransformLinear(float[,] matrix, float[] offset) |
262 | { | 230 | { |
231 | if (pinnedIndex.IsAllocated || pinnedVirtexes.IsAllocated) | ||
232 | throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); | ||
233 | |||
263 | foreach (Vertex v in vertices.Keys) | 234 | foreach (Vertex v in vertices.Keys) |
264 | { | 235 | { |
265 | if (v == null) | 236 | if (v == null) |
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index f469ad6..0873035 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -76,6 +76,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
76 | 76 | ||
77 | private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh | 77 | private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh |
78 | 78 | ||
79 | private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); | ||
79 | 80 | ||
80 | /// <summary> | 81 | /// <summary> |
81 | /// creates a simple box mesh of the specified size. This mesh is of very low vertex count and may | 82 | /// creates a simple box mesh of the specified size. This mesh is of very low vertex count and may |
@@ -170,9 +171,62 @@ namespace OpenSim.Region.Physics.Meshing | |||
170 | 171 | ||
171 | } | 172 | } |
172 | 173 | ||
173 | public Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod) | 174 | private ulong GetMeshKey( PrimitiveBaseShape pbs, PhysicsVector size, float lod ) |
175 | { | ||
176 | ulong hash = 5381; | ||
177 | |||
178 | hash = djb2(hash, pbs.PathCurve); | ||
179 | hash = djb2(hash, (byte)((byte)pbs.HollowShape | (byte)pbs.ProfileShape)); | ||
180 | hash = djb2(hash, pbs.PathBegin); | ||
181 | hash = djb2(hash, pbs.PathEnd); | ||
182 | hash = djb2(hash, pbs.PathScaleX); | ||
183 | hash = djb2(hash, pbs.PathScaleY); | ||
184 | hash = djb2(hash, pbs.PathShearX); | ||
185 | hash = djb2(hash, pbs.PathShearY); | ||
186 | hash = djb2(hash, (byte)pbs.PathTwist); | ||
187 | hash = djb2(hash, (byte)pbs.PathTwistBegin); | ||
188 | hash = djb2(hash, (byte)pbs.PathRadiusOffset); | ||
189 | hash = djb2(hash, (byte)pbs.PathTaperX); | ||
190 | hash = djb2(hash, (byte)pbs.PathTaperY); | ||
191 | hash = djb2(hash, pbs.PathRevolutions); | ||
192 | hash = djb2(hash, (byte)pbs.PathSkew); | ||
193 | hash = djb2(hash, pbs.ProfileBegin); | ||
194 | hash = djb2(hash, pbs.ProfileEnd); | ||
195 | hash = djb2(hash, pbs.ProfileHollow); | ||
196 | |||
197 | // TODO: Separate scale out from the primitive shape data (after | ||
198 | // scaling is supported at the physics engine level) | ||
199 | byte[] scaleBytes = size.GetBytes(); | ||
200 | for (int i = 0; i < scaleBytes.Length; i++) | ||
201 | hash = djb2(hash, scaleBytes[i]); | ||
202 | |||
203 | // Include LOD in hash, accounting for endianness | ||
204 | byte[] lodBytes = new byte[4]; | ||
205 | Buffer.BlockCopy(BitConverter.GetBytes(lod), 0, lodBytes, 0, 4); | ||
206 | if (!BitConverter.IsLittleEndian) | ||
207 | { | ||
208 | Array.Reverse(lodBytes, 0, 4); | ||
209 | } | ||
210 | for (int i = 0; i < lodBytes.Length; i++) | ||
211 | hash = djb2(hash, lodBytes[i]); | ||
212 | |||
213 | return hash; | ||
214 | } | ||
215 | |||
216 | private ulong djb2(ulong hash, byte c) | ||
217 | { | ||
218 | return ((hash << 5) + hash) + (ulong)c; | ||
219 | } | ||
220 | |||
221 | private ulong djb2(ulong hash, ushort c) | ||
222 | { | ||
223 | hash = ((hash << 5) + hash) + (ulong)((byte)c); | ||
224 | return ((hash << 5) + hash) + (ulong)(c >> 8); | ||
225 | } | ||
226 | |||
227 | |||
228 | private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod) | ||
174 | { | 229 | { |
175 | Mesh mesh = new Mesh(); | ||
176 | PrimMesh primMesh; | 230 | PrimMesh primMesh; |
177 | PrimMesher.SculptMesh sculptMesh; | 231 | PrimMesher.SculptMesh sculptMesh; |
178 | 232 | ||
@@ -385,8 +439,6 @@ namespace OpenSim.Region.Physics.Meshing | |||
385 | 439 | ||
386 | coords = primMesh.coords; | 440 | coords = primMesh.coords; |
387 | faces = primMesh.faces; | 441 | faces = primMesh.faces; |
388 | |||
389 | |||
390 | } | 442 | } |
391 | 443 | ||
392 | 444 | ||
@@ -401,13 +453,13 @@ namespace OpenSim.Region.Physics.Meshing | |||
401 | vertices.Add(new Vertex(c.X, c.Y, c.Z)); | 453 | vertices.Add(new Vertex(c.X, c.Y, c.Z)); |
402 | } | 454 | } |
403 | 455 | ||
456 | Mesh mesh = new Mesh(); | ||
404 | // Add the corresponding triangles to the mesh | 457 | // Add the corresponding triangles to the mesh |
405 | for (int i = 0; i < numFaces; i++) | 458 | for (int i = 0; i < numFaces; i++) |
406 | { | 459 | { |
407 | Face f = faces[i]; | 460 | Face f = faces[i]; |
408 | mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); | 461 | mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); |
409 | } | 462 | } |
410 | |||
411 | return mesh; | 463 | return mesh; |
412 | } | 464 | } |
413 | 465 | ||
@@ -418,7 +470,12 @@ namespace OpenSim.Region.Physics.Meshing | |||
418 | 470 | ||
419 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod, bool isPhysical) | 471 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod, bool isPhysical) |
420 | { | 472 | { |
473 | // If this mesh has been created already, return it instead of creating another copy | ||
474 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory | ||
475 | ulong key = GetMeshKey(primShape, size, lod); | ||
421 | Mesh mesh = null; | 476 | Mesh mesh = null; |
477 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | ||
478 | return mesh; | ||
422 | 479 | ||
423 | if (size.X < 0.01f) size.X = 0.01f; | 480 | if (size.X < 0.01f) size.X = 0.01f; |
424 | if (size.Y < 0.01f) size.Y = 0.01f; | 481 | if (size.Y < 0.01f) size.Y = 0.01f; |
@@ -441,7 +498,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
441 | // trim the vertex and triangle lists to free up memory | 498 | // trim the vertex and triangle lists to free up memory |
442 | mesh.TrimExcess(); | 499 | mesh.TrimExcess(); |
443 | } | 500 | } |
444 | 501 | m_uniqueMeshes.Add(key, mesh); | |
445 | return mesh; | 502 | return mesh; |
446 | } | 503 | } |
447 | } | 504 | } |
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 673ae39..032b5df 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | |||
@@ -82,7 +82,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
82 | 82 | ||
83 | // private float m_tensor = 5f; | 83 | // private float m_tensor = 5f; |
84 | private int body_autodisable_frames = 20; | 84 | private int body_autodisable_frames = 20; |
85 | private IMesh primMesh = null; | ||
86 | 85 | ||
87 | 86 | ||
88 | private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom | 87 | private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom |
@@ -814,14 +813,10 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
814 | } | 813 | } |
815 | } | 814 | } |
816 | 815 | ||
817 | IMesh oldMesh = primMesh; | 816 | float[] vertexList = mesh.getVertexListAsFloatLocked(); // Note, that vertextList is pinned in memory |
817 | int[] indexList = mesh.getIndexListAsIntLocked(); // Also pinned, needs release after usage | ||
818 | 818 | ||
819 | primMesh = mesh; | 819 | mesh.releaseSourceMeshData(); // free up the original mesh data to save memory |
820 | |||
821 | float[] vertexList = primMesh.getVertexListAsFloatLocked(); // Note, that vertextList is pinned in memory | ||
822 | int[] indexList = primMesh.getIndexListAsIntLocked(); // Also pinned, needs release after usage | ||
823 | |||
824 | primMesh.releaseSourceMeshData(); // free up the original mesh data to save memory | ||
825 | 820 | ||
826 | int VertexCount = vertexList.GetLength(0)/3; | 821 | int VertexCount = vertexList.GetLength(0)/3; |
827 | int IndexCount = indexList.GetLength(0); | 822 | int IndexCount = indexList.GetLength(0); |
@@ -847,12 +842,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
847 | return; | 842 | return; |
848 | } | 843 | } |
849 | 844 | ||
850 | if (oldMesh != null) | ||
851 | { | ||
852 | oldMesh.releasePinned(); | ||
853 | oldMesh = null; | ||
854 | } | ||
855 | |||
856 | // if (IsPhysical && Body == (IntPtr) 0) | 845 | // if (IsPhysical && Body == (IntPtr) 0) |
857 | // { | 846 | // { |
858 | // Recreate the body | 847 | // Recreate the body |