From 27d6d9f7201304311f9955c14c75e9c42a24cfec Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Apr 2015 15:20:16 -0700 Subject: [PATCH] add Bullet profiling hooks for physics simulation --- libraries/physics/src/CharacterController.cpp | 9 ++ libraries/physics/src/PhysicsEngine.cpp | 118 ++++++++++-------- libraries/physics/src/PhysicsEngine.h | 4 + .../physics/src/ThreadSafeDynamicsWorld.cpp | 3 + 4 files changed, 81 insertions(+), 53 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index cdff02820d..1d7a84c177 100755 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -257,6 +257,7 @@ btPairCachingGhostObject* CharacterController::getGhostObject() { } bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorld) { + BT_PROFILE("recoverFromPenetration"); // Here we must refresh the overlapping paircache as the penetrating movement itself or the // previous recovery iteration might have used setWorldTransform and pushed us into an object // that is not in the previous cache contents from the last timestep, as will happen if we @@ -355,6 +356,7 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl void CharacterController::scanDown(btCollisionWorld* world) { + BT_PROFILE("scanDown"); // we test with downward raycast and if we don't find floor close enough then turn on "hover" btKinematicClosestNotMeRayResultCallback callback(_ghostObject); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; @@ -374,6 +376,7 @@ void CharacterController::scanDown(btCollisionWorld* world) { } void CharacterController::stepUp(btCollisionWorld* world) { + BT_PROFILE("stepUp"); // phase 1: up // compute start and end @@ -440,6 +443,7 @@ void CharacterController::updateTargetPositionBasedOnCollision(const btVector3& } void CharacterController::stepForward(btCollisionWorld* collisionWorld, const btVector3& movement) { + BT_PROFILE("stepForward"); // phase 2: forward _targetPosition = _currentPosition + movement; @@ -496,6 +500,7 @@ void CharacterController::stepForward(btCollisionWorld* collisionWorld, const bt } void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt) { + BT_PROFILE("stepDown"); // phase 3: down // // The "stepDown" phase first makes a normal sweep down that cancels the lift from the "stepUp" phase. @@ -607,6 +612,7 @@ void CharacterController::warp(const btVector3& origin) { void CharacterController::preStep(btCollisionWorld* collisionWorld) { + BT_PROFILE("preStep"); if (!_enabled) { return; } @@ -627,6 +633,7 @@ void CharacterController::preStep(btCollisionWorld* collisionWorld) { } void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar dt) { + BT_PROFILE("playerStep"); if (!_enabled) { return; // no motion } @@ -875,6 +882,7 @@ void CharacterController::updateShapeIfNecessary() { } void CharacterController::preSimulation(btScalar timeStep) { + BT_PROFILE("preSimulation"); if (_enabled && _dynamicsWorld) { glm::quat rotation = _avatarData->getOrientation(); _currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS); @@ -897,6 +905,7 @@ void CharacterController::preSimulation(btScalar timeStep) { } void CharacterController::postSimulation() { + BT_PROFILE("postSimulation"); if (_enabled && _ghostObject) { const btTransform& avatarTransform = _ghostObject->getWorldTransform(); glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 467b51560f..67e4e0616f 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -155,6 +155,7 @@ void PhysicsEngine::clearEntitiesInternal() { // end EntitySimulation overrides void PhysicsEngine::relayIncomingChangesToSimulation() { + BT_PROFILE("incomingChanges"); // process incoming changes QSet::iterator stateItr = _incomingChanges.begin(); while (stateItr != _incomingChanges.end()) { @@ -287,66 +288,76 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) { } void PhysicsEngine::stepSimulation() { - lock(); - // NOTE: the grand order of operations is: - // (1) pull incoming changes - // (2) step simulation - // (3) synchronize outgoing motion states - // (4) send outgoing packets - - // This is step (1) pull incoming changes - relayIncomingChangesToSimulation(); - - const int MAX_NUM_SUBSTEPS = 4; - const float MAX_TIMESTEP = (float)MAX_NUM_SUBSTEPS * PHYSICS_ENGINE_FIXED_SUBSTEP; - float dt = 1.0e-6f * (float)(_clock.getTimeMicroseconds()); - _clock.reset(); - float timeStep = btMin(dt, MAX_TIMESTEP); - - // TODO: move character->preSimulation() into relayIncomingChanges - if (_characterController) { - if (_characterController->needsRemoval()) { - _characterController->setDynamicsWorld(NULL); - } - _characterController->updateShapeIfNecessary(); - if (_characterController->needsAddition()) { - _characterController->setDynamicsWorld(_dynamicsWorld); - } - _characterController->preSimulation(timeStep); - } - - // This is step (2) step simulation - int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); - _numSubsteps += (uint32_t)numSubsteps; - stepNonPhysicalKinematics(usecTimestampNow()); - unlock(); - - // TODO: make all of this harvest stuff into one function: relayOutgoingChanges() - if (numSubsteps > 0) { - // This is step (3) which is done outside of stepSimulation() so we can lock _entityTree. - // - // Unfortunately we have to unlock the simulation (above) before we try to lock the _entityTree - // to avoid deadlock -- the _entityTree may try to lock its EntitySimulation (from which this - // PhysicsEngine derives) when updating/adding/deleting entities so we need to wait for our own - // lock on the tree before we re-lock ourselves. - // - // TODO: untangle these lock sequences. - _entityTree->lockForWrite(); + { lock(); - _dynamicsWorld->synchronizeMotionStates(); + CProfileManager::Reset(); + BT_PROFILE("stepSimulation"); + // NOTE: the grand order of operations is: + // (1) pull incoming changes + // (2) step simulation + // (3) synchronize outgoing motion states + // (4) send outgoing packets - if (_characterController) { - _characterController->postSimulation(); - } - - unlock(); - _entityTree->unlock(); + // This is step (1) pull incoming changes + relayIncomingChangesToSimulation(); - computeCollisionEvents(); + const int MAX_NUM_SUBSTEPS = 4; + const float MAX_TIMESTEP = (float)MAX_NUM_SUBSTEPS * PHYSICS_ENGINE_FIXED_SUBSTEP; + float dt = 1.0e-6f * (float)(_clock.getTimeMicroseconds()); + _clock.reset(); + float timeStep = btMin(dt, MAX_TIMESTEP); + + // TODO: move character->preSimulation() into relayIncomingChanges + if (_characterController) { + if (_characterController->needsRemoval()) { + _characterController->setDynamicsWorld(NULL); + } + _characterController->updateShapeIfNecessary(); + if (_characterController->needsAddition()) { + _characterController->setDynamicsWorld(_dynamicsWorld); + } + _characterController->preSimulation(timeStep); + } + + // This is step (2) step simulation + int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); + _numSubsteps += (uint32_t)numSubsteps; + stepNonPhysicalKinematics(usecTimestampNow()); + unlock(); + + // TODO: make all of this harvest stuff into one function: relayOutgoingChanges() + if (numSubsteps > 0) { + BT_PROFILE("postSimulation"); + // This is step (3) which is done outside of stepSimulation() so we can lock _entityTree. + // + // Unfortunately we have to unlock the simulation (above) before we try to lock the _entityTree + // to avoid deadlock -- the _entityTree may try to lock its EntitySimulation (from which this + // PhysicsEngine derives) when updating/adding/deleting entities so we need to wait for our own + // lock on the tree before we re-lock ourselves. + // + // TODO: untangle these lock sequences. + _entityTree->lockForWrite(); + lock(); + _dynamicsWorld->synchronizeMotionStates(); + + if (_characterController) { + _characterController->postSimulation(); + } + + unlock(); + _entityTree->unlock(); + + computeCollisionEvents(); + } + } + if (_dumpNextStats) { + _dumpNextStats = false; + CProfileManager::dumpAll(); } } void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) { + BT_PROFILE("nonPhysicalKinematics"); QSet::iterator stateItr = _nonPhysicalKinematicObjects.begin(); while (stateItr != _nonPhysicalKinematicObjects.end()) { ObjectMotionState* motionState = *stateItr; @@ -358,6 +369,7 @@ void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) { // TODO?: need to occasionally scan for stopped non-physical kinematics objects void PhysicsEngine::computeCollisionEvents() { + BT_PROFILE("computeCollisionEvents"); // update all contacts every frame int numManifolds = _collisionDispatcher->getNumManifolds(); for (int i = 0; i < numManifolds; ++i) { diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 0661b47d3a..d7d3278286 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -86,6 +86,8 @@ public: void setCharacterController(CharacterController* character); + void dumpNextStats() { _dumpNextStats = true; } + private: /// \param motionState pointer to Object's MotionState void removeObjectFromBullet(ObjectMotionState* motionState); @@ -121,6 +123,8 @@ private: /// character collisions CharacterController* _characterController = NULL; + + bool _dumpNextStats = false; }; #endif // hifi_PhysicsEngine_h diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index c7ee9ce2a0..b47269183d 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -15,6 +15,8 @@ * Copied and modified from btDiscreteDynamicsWorld.cpp by AndrewMeadows on 2014.11.12. * */ +#include + #include "ThreadSafeDynamicsWorld.h" ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld( @@ -26,6 +28,7 @@ ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld( } int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep) { + BT_PROFILE("stepSimulation"); int subSteps = 0; if (maxSubSteps) { //fixed timestep with interpolation