From 6a9630d2bdc27ed702936f4c44e6978f728a9ef0 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 28 Mar 2013 10:56:21 -0700 Subject: BulletSim: fix race condition when creating very large mega-regions. The symptom was exceptions while creating physical terrain. Reduce default terrain mesh magnification to 2 from 3 because the higher resolution uses a lot of memory and doesn't solve the terrain smoothness for vehicles. Added comments here and there and improved some debugging log messages. --- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 4 +-- .../Region/Physics/BulletSPlugin/BSMaterials.cs | 3 ++ OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 2 +- .../Physics/BulletSPlugin/BSTerrainManager.cs | 38 ++++++++++++++-------- .../Region/Physics/BulletSPlugin/BSTerrainMesh.cs | 10 +++--- 5 files changed, 35 insertions(+), 22 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index e208d3a..90c2d9c 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -479,7 +479,7 @@ public sealed class BSCharacter : BSPhysObject // The character is out of the known/simulated area. // Force the avatar position to be within known. ScenePresence will use the position // plus the velocity to decide if the avatar is moving out of the region. - RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); + RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); return true; } @@ -898,7 +898,7 @@ public sealed class BSCharacter : BSPhysObject // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. if (PositionSanityCheck(true)) { - DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position); + DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position); entprop.Position = _position; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs index 92d62ff..ee77d6e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs @@ -180,11 +180,14 @@ public static class BSMaterials // Use reflection to set the value in the attribute structure. private static void SetAttributeValue(int matType, string attribName, float val) { + // Get the current attribute values for this material MaterialAttributes thisAttrib = Attributes[matType]; + // Find the field for the passed attribute name (eg, find field named 'friction') FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); if (fieldInfo != null) { fieldInfo.SetValue(thisAttrib, val); + // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference. Attributes[matType] = thisAttrib; } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index f3454c8..385ed9e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -482,7 +482,7 @@ public static class BSParam (s) => { return TerrainImplementation; }, (s,v) => { TerrainImplementation = v; } ), new ParameterDefn("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , - 3, + 2, (s) => { return TerrainMeshMagnification; }, (s,v) => { TerrainMeshMagnification = v; } ), new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index d4aecbc..b2fb835 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs @@ -132,6 +132,7 @@ public sealed class BSTerrainManager : IDisposable // safe to call Bullet in real time. We hope no one is moving prims around yet. public void CreateInitialGroundPlaneAndTerrain() { + DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); // The ground plane is here to catch things that are trying to drop to negative infinity BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, @@ -145,14 +146,18 @@ public sealed class BSTerrainManager : IDisposable m_groundPlane.collisionType = CollisionType.Groundplane; m_groundPlane.ApplyCollisionMask(PhysicsScene); - // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); - m_terrains.Add(Vector3.Zero, initialTerrain); + lock (m_terrains) + { + // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. + m_terrains.Add(Vector3.Zero, initialTerrain); + } } // Release all the terrain structures we might have allocated public void ReleaseGroundPlaneAndTerrain() { + DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); if (m_groundPlane.HasPhysicalBody) { if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) @@ -193,11 +198,16 @@ public sealed class BSTerrainManager : IDisposable // the terrain is added to our parent if (MegaRegionParentPhysicsScene is BSScene) { - DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", - BSScene.DetailLogZero, m_worldOffset, m_worldMax); - ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( - BSScene.CHILDTERRAIN_ID, localHeightMap, - m_worldOffset, m_worldOffset + DefaultRegionSize, true); + DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax); + // This looks really odd but this region is passing its terrain to its mega-region root region + // and the creation of the terrain must happen on the root region's taint thread and not + // my taint thread. + ((BSScene)MegaRegionParentPhysicsScene).PostTaintObject("TerrainManager.SetTerrain.Mega-" + m_worldOffset.ToString(), 0, delegate() + { + ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( + BSScene.CHILDTERRAIN_ID, localHeightMap, + m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */); + }); } } else @@ -206,16 +216,16 @@ public sealed class BSTerrainManager : IDisposable DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, - m_worldOffset, m_worldOffset + DefaultRegionSize, true); + m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */); } }); } - // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain + // If called for terrain has has not been previously allocated, a new terrain will be built // based on the passed information. The 'id' should be either the terrain id or // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. // The latter feature is for creating child terrains for mega-regions. - // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new + // If there is an existing terrain body, a new // terrain shape is created and added to the body. // This call is most often used to update the heightMap and parameters of the terrain. // (The above does suggest that some simplification/refactoring is in order.) @@ -223,8 +233,8 @@ public sealed class BSTerrainManager : IDisposable private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) { - DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}", - BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); + DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3},inTaintTime={4}", + BSScene.DetailLogZero, id, minCoords, maxCoords, inTaintTime); // Find high and low points of passed heightmap. // The min and max passed in is usually the area objects can be in (maximum @@ -253,7 +263,7 @@ public sealed class BSTerrainManager : IDisposable if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) { // There is already a terrain in this spot. Free the old and build the new. - DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", + DetailLog("{0},BSTErrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); // Remove old terrain from the collection @@ -292,7 +302,7 @@ public sealed class BSTerrainManager : IDisposable if (newTerrainID >= BSScene.CHILDTERRAIN_ID) newTerrainID = ++m_terrainCount; - DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", + DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); m_terrains.Add(terrainRegionBase, newTerrainPhys); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index a9cd8a1..2ce1513 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs @@ -98,20 +98,20 @@ public sealed class BSTerrainMesh : BSTerrainPhys if (!meshCreationSuccess) { // DISASTER!! - PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); + PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); // Something is very messed up and a crash is in our future. return; } - PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", - ID, indicesCount, indices.Length, verticesCount, vertices.Length); + PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", + BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length); m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices); if (!m_terrainShape.HasPhysicalShape) { // DISASTER!! - PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); + PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); // Something is very messed up and a crash is in our future. return; @@ -151,7 +151,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys if (BSParam.UseSingleSidedMeshes) { - PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial", id); + PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); } -- cgit v1.1