diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSScene.cs')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 129 |
1 files changed, 68 insertions, 61 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 4133107..7017194 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | using System; | 27 | using System; |
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Reflection; | ||
29 | using System.Runtime.InteropServices; | 30 | using System.Runtime.InteropServices; |
30 | using System.Text; | 31 | using System.Text; |
31 | using System.Threading; | 32 | using System.Threading; |
@@ -42,14 +43,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
42 | { | 43 | { |
43 | public sealed class BSScene : PhysicsScene, IPhysicsParameters | 44 | public sealed class BSScene : PhysicsScene, IPhysicsParameters |
44 | { | 45 | { |
45 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | 46 | internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); |
46 | private static readonly string LogHeader = "[BULLETS SCENE]"; | 47 | internal static readonly string LogHeader = "[BULLETS SCENE]"; |
47 | 48 | ||
48 | // The name of the region we're working for. | 49 | // The name of the region we're working for. |
49 | public string RegionName { get; private set; } | 50 | public string RegionName { get; private set; } |
50 | 51 | ||
51 | public string BulletSimVersion = "?"; | 52 | public string BulletSimVersion = "?"; |
52 | 53 | ||
54 | // The handle to the underlying managed or unmanaged version of Bullet being used. | ||
55 | public string BulletEngineName { get; private set; } | ||
56 | public BSAPITemplate PE; | ||
57 | |||
53 | public Dictionary<uint, BSPhysObject> PhysObjects; | 58 | public Dictionary<uint, BSPhysObject> PhysObjects; |
54 | public BSShapeCollection Shapes; | 59 | public BSShapeCollection Shapes; |
55 | 60 | ||
@@ -99,11 +104,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
99 | // Pinned memory used to pass step information between managed and unmanaged | 104 | // Pinned memory used to pass step information between managed and unmanaged |
100 | internal int m_maxCollisionsPerFrame; | 105 | internal int m_maxCollisionsPerFrame; |
101 | internal CollisionDesc[] m_collisionArray; | 106 | internal CollisionDesc[] m_collisionArray; |
102 | internal GCHandle m_collisionArrayPinnedHandle; | ||
103 | 107 | ||
104 | internal int m_maxUpdatesPerFrame; | 108 | internal int m_maxUpdatesPerFrame; |
105 | internal EntityProperties[] m_updateArray; | 109 | internal EntityProperties[] m_updateArray; |
106 | internal GCHandle m_updateArrayPinnedHandle; | ||
107 | 110 | ||
108 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero | 111 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero |
109 | public const uint GROUNDPLANE_ID = 1; | 112 | public const uint GROUNDPLANE_ID = 1; |
@@ -149,12 +152,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
149 | // A pointer to an instance if this structure is passed to the C++ code | 152 | // A pointer to an instance if this structure is passed to the C++ code |
150 | // Used to pass basic configuration values to the unmanaged code. | 153 | // Used to pass basic configuration values to the unmanaged code. |
151 | internal ConfigurationParameters[] UnmanagedParams; | 154 | internal ConfigurationParameters[] UnmanagedParams; |
152 | GCHandle m_paramsHandle; | ||
153 | |||
154 | // Handle to the callback used by the unmanaged code to call into the managed code. | ||
155 | // Used for debug logging. | ||
156 | // Need to store the handle in a persistant variable so it won't be freed. | ||
157 | private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; | ||
158 | 155 | ||
159 | // Sometimes you just have to log everything. | 156 | // Sometimes you just have to log everything. |
160 | public Logging.LogWriter PhysicsLogging; | 157 | public Logging.LogWriter PhysicsLogging; |
@@ -164,6 +161,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
164 | private int m_physicsLoggingFileMinutes; | 161 | private int m_physicsLoggingFileMinutes; |
165 | private bool m_physicsLoggingDoFlush; | 162 | private bool m_physicsLoggingDoFlush; |
166 | private bool m_physicsPhysicalDumpEnabled; | 163 | private bool m_physicsPhysicalDumpEnabled; |
164 | public float PhysicsMetricDumpFrames { get; set; } | ||
167 | // 'true' of the vehicle code is to log lots of details | 165 | // 'true' of the vehicle code is to log lots of details |
168 | public bool VehicleLoggingEnabled { get; private set; } | 166 | public bool VehicleLoggingEnabled { get; private set; } |
169 | public bool VehiclePhysicalLoggingEnabled { get; private set; } | 167 | public bool VehiclePhysicalLoggingEnabled { get; private set; } |
@@ -187,16 +185,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
187 | 185 | ||
188 | // Allocate pinned memory to pass parameters. | 186 | // Allocate pinned memory to pass parameters. |
189 | UnmanagedParams = new ConfigurationParameters[1]; | 187 | UnmanagedParams = new ConfigurationParameters[1]; |
190 | m_paramsHandle = GCHandle.Alloc(UnmanagedParams, GCHandleType.Pinned); | ||
191 | 188 | ||
192 | // Set default values for physics parameters plus any overrides from the ini file | 189 | // Set default values for physics parameters plus any overrides from the ini file |
193 | GetInitialParameterValues(config); | 190 | GetInitialParameterValues(config); |
194 | 191 | ||
195 | // allocate more pinned memory close to the above in an attempt to get the memory all together | 192 | // Get the connection to the physics engine (could be native or one of many DLLs) |
196 | m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; | 193 | PE = SelectUnderlyingBulletEngine(BulletEngineName); |
197 | m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned); | ||
198 | m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; | ||
199 | m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); | ||
200 | 194 | ||
201 | // Enable very detailed logging. | 195 | // Enable very detailed logging. |
202 | // By creating an empty logger when not logging, the log message invocation code | 196 | // By creating an empty logger when not logging, the log message invocation code |
@@ -211,22 +205,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
211 | PhysicsLogging = new Logging.LogWriter(); | 205 | PhysicsLogging = new Logging.LogWriter(); |
212 | } | 206 | } |
213 | 207 | ||
214 | // If Debug logging level, enable logging from the unmanaged code | 208 | // Allocate memory for returning of the updates and collisions from the physics engine |
215 | m_DebugLogCallbackHandle = null; | 209 | m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; |
216 | if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) | 210 | m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; |
217 | { | ||
218 | m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); | ||
219 | if (PhysicsLogging.Enabled) | ||
220 | // The handle is saved in a variable to make sure it doesn't get freed after this call | ||
221 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); | ||
222 | else | ||
223 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); | ||
224 | } | ||
225 | |||
226 | // Get the version of the DLL | ||
227 | // TODO: this doesn't work yet. Something wrong with marshaling the returned string. | ||
228 | // BulletSimVersion = BulletSimAPI.GetVersion(); | ||
229 | // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); | ||
230 | 211 | ||
231 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're | 212 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're |
232 | // a child in a mega-region. | 213 | // a child in a mega-region. |
@@ -234,11 +215,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
234 | // area. It tracks active objects no matter where they are. | 215 | // area. It tracks active objects no matter where they are. |
235 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | 216 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); |
236 | 217 | ||
237 | // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); | 218 | World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray); |
238 | World = new BulletWorld(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(), | ||
239 | m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), | ||
240 | m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(), | ||
241 | m_DebugLogCallbackHandle)); | ||
242 | 219 | ||
243 | Constraints = new BSConstraintCollection(World); | 220 | Constraints = new BSConstraintCollection(World); |
244 | 221 | ||
@@ -268,6 +245,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
268 | { | 245 | { |
269 | BSParam.SetParameterConfigurationValues(this, pConfig); | 246 | BSParam.SetParameterConfigurationValues(this, pConfig); |
270 | 247 | ||
248 | // There are two Bullet implementations to choose from | ||
249 | BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged"); | ||
250 | |||
271 | // Very detailed logging for physics debugging | 251 | // Very detailed logging for physics debugging |
272 | // TODO: the boolean values can be moved to the normal parameter processing. | 252 | // TODO: the boolean values can be moved to the normal parameter processing. |
273 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); | 253 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); |
@@ -309,16 +289,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
309 | return ret; | 289 | return ret; |
310 | } | 290 | } |
311 | 291 | ||
312 | // Called directly from unmanaged code so don't do much | 292 | // Select the connection to the actual Bullet implementation. |
313 | private void BulletLogger(string msg) | 293 | // The main engine selection is the engineName up to the first hypen. |
294 | // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name | ||
295 | // is passed to the engine to do its special selection, etc. | ||
296 | private BSAPITemplate SelectUnderlyingBulletEngine(string engineName) | ||
314 | { | 297 | { |
315 | m_log.Debug("[BULLETS UNMANAGED]:" + msg); | 298 | // For the moment, do a simple switch statement. |
316 | } | 299 | // Someday do fancyness with looking up the interfaces in the assembly. |
300 | BSAPITemplate ret = null; | ||
317 | 301 | ||
318 | // Called directly from unmanaged code so don't do much | 302 | string selectionName = engineName.ToLower(); |
319 | private void BulletLoggerPhysLog(string msg) | 303 | int hyphenIndex = engineName.IndexOf("-"); |
320 | { | 304 | if (hyphenIndex > 0) |
321 | DetailLog("[BULLETS UNMANAGED]:" + msg); | 305 | selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1); |
306 | |||
307 | switch (selectionName) | ||
308 | { | ||
309 | case "bulletunmanaged": | ||
310 | ret = new BSAPIUnman(engineName, this); | ||
311 | break; | ||
312 | case "bulletxna": | ||
313 | ret = new BSAPIXNA(engineName, this); | ||
314 | break; | ||
315 | } | ||
316 | |||
317 | if (ret == null) | ||
318 | { | ||
319 | m_log.ErrorFormat("{0) COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader); | ||
320 | } | ||
321 | else | ||
322 | { | ||
323 | m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); | ||
324 | } | ||
325 | |||
326 | return ret; | ||
322 | } | 327 | } |
323 | 328 | ||
324 | public override void Dispose() | 329 | public override void Dispose() |
@@ -355,7 +360,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
355 | } | 360 | } |
356 | 361 | ||
357 | // Anything left in the unmanaged code should be cleaned out | 362 | // Anything left in the unmanaged code should be cleaned out |
358 | BulletSimAPI.Shutdown2(World.ptr); | 363 | PE.Shutdown(World); |
359 | 364 | ||
360 | // Not logging any more | 365 | // Not logging any more |
361 | PhysicsLogging.Close(); | 366 | PhysicsLogging.Close(); |
@@ -468,9 +473,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
468 | LastTimeStep = timeStep; | 473 | LastTimeStep = timeStep; |
469 | 474 | ||
470 | int updatedEntityCount = 0; | 475 | int updatedEntityCount = 0; |
471 | IntPtr updatedEntitiesPtr; | ||
472 | int collidersCount = 0; | 476 | int collidersCount = 0; |
473 | IntPtr collidersPtr; | ||
474 | 477 | ||
475 | int beforeTime = 0; | 478 | int beforeTime = 0; |
476 | int simTime = 0; | 479 | int simTime = 0; |
@@ -486,6 +489,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
486 | TriggerPreStepEvent(timeStep); | 489 | TriggerPreStepEvent(timeStep); |
487 | 490 | ||
488 | // the prestep actions might have added taints | 491 | // the prestep actions might have added taints |
492 | numTaints += _taintOperations.Count; | ||
489 | ProcessTaints(); | 493 | ProcessTaints(); |
490 | 494 | ||
491 | InTaintTime = false; // Only used for debugging so locking is not necessary. | 495 | InTaintTime = false; // Only used for debugging so locking is not necessary. |
@@ -493,23 +497,25 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
493 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 497 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. |
494 | // Only enable this in a limited test world with few objects. | 498 | // Only enable this in a limited test world with few objects. |
495 | if (m_physicsPhysicalDumpEnabled) | 499 | if (m_physicsPhysicalDumpEnabled) |
496 | BulletSimAPI.DumpAllInfo2(World.ptr); | 500 | PE.DumpAllInfo(World); |
497 | 501 | ||
498 | // step the physical world one interval | 502 | // step the physical world one interval |
499 | m_simulationStep++; | 503 | m_simulationStep++; |
500 | int numSubSteps = 0; | 504 | int numSubSteps = 0; |
501 | |||
502 | try | 505 | try |
503 | { | 506 | { |
504 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | 507 | if (PhysicsLogging.Enabled) |
508 | beforeTime = Util.EnvironmentTickCount(); | ||
505 | 509 | ||
506 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, | 510 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); |
507 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); | ||
508 | 511 | ||
509 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); | 512 | if (PhysicsLogging.Enabled) |
510 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", | 513 | { |
511 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | 514 | simTime = Util.EnvironmentTickCountSubtract(beforeTime); |
512 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | 515 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", |
516 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | ||
517 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||
518 | } | ||
513 | } | 519 | } |
514 | catch (Exception e) | 520 | catch (Exception e) |
515 | { | 521 | { |
@@ -521,7 +527,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
521 | collidersCount = 0; | 527 | collidersCount = 0; |
522 | } | 528 | } |
523 | 529 | ||
524 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in. | 530 | if ((m_simulationStep % PhysicsMetricDumpFrames) == 0) |
531 | PE.DumpPhysicsStatistics(World); | ||
525 | 532 | ||
526 | // Get a value for 'now' so all the collision and update routines don't have to get their own. | 533 | // Get a value for 'now' so all the collision and update routines don't have to get their own. |
527 | SimulationNowTime = Util.EnvironmentTickCount(); | 534 | SimulationNowTime = Util.EnvironmentTickCount(); |
@@ -564,7 +571,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
564 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | 571 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. |
565 | // Not done above because it is inside an iteration of ObjectWithCollisions. | 572 | // Not done above because it is inside an iteration of ObjectWithCollisions. |
566 | // This complex collision processing is required to create an empty collision | 573 | // This complex collision processing is required to create an empty collision |
567 | // event call after all collisions have happened on an object. This enables | 574 | // event call after all real collisions have happened on an object. This enables |
568 | // the simulator to generate the 'collision end' event. | 575 | // the simulator to generate the 'collision end' event. |
569 | if (ObjectsWithNoMoreCollisions.Count > 0) | 576 | if (ObjectsWithNoMoreCollisions.Count > 0) |
570 | { | 577 | { |
@@ -593,11 +600,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
593 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 600 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. |
594 | // Only enable this in a limited test world with few objects. | 601 | // Only enable this in a limited test world with few objects. |
595 | if (m_physicsPhysicalDumpEnabled) | 602 | if (m_physicsPhysicalDumpEnabled) |
596 | BulletSimAPI.DumpAllInfo2(World.ptr); | 603 | PE.DumpAllInfo(World); |
597 | 604 | ||
598 | // The physics engine returns the number of milliseconds it simulated this call. | 605 | // The physics engine returns the number of milliseconds it simulated this call. |
599 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 606 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. |
600 | // Multiply by 55 to give a nominal frame rate of 55. | 607 | // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). |
601 | return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; | 608 | return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; |
602 | } | 609 | } |
603 | 610 | ||