From 3f52d237edbf2cc7d810782f8b4c623d6d5e200f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 31 Mar 2016 10:27:17 -0700 Subject: [PATCH 01/55] adding Bullet profiler instances for better stats --- libraries/physics/src/EntityMotionState.cpp | 2 ++ libraries/physics/src/PhysicsEngine.cpp | 1 + .../physics/src/ThreadSafeDynamicsWorld.cpp | 26 ++++++++++++++++++- .../physics/src/ThreadSafeDynamicsWorld.h | 1 + 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index e3952ba1d6..7b83c2e2ce 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -175,11 +175,13 @@ bool EntityMotionState::isMoving() const { // (2) at the beginning of each simulation step for KINEMATIC RigidBody's -- // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { + BT_PROFILE("getWorldTransform"); if (!_entity) { return; } assert(entityTreeIsLocked()); if (_motionType == MOTION_TYPE_KINEMATIC) { + BT_PROFILE("kinematicIntegration"); // This is physical kinematic motion which steps strictly by the subframe count // of the physics simulation. uint32_t thisStep = ObjectMotionState::getWorldSimulationStep(); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 0040c19c3d..74f6f90900 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -240,6 +240,7 @@ void PhysicsEngine::stepSimulation() { float timeStep = btMin(dt, MAX_TIMESTEP); if (_myAvatarController) { + BT_PROFILE("avatarController"); // TODO: move this stuff outside and in front of stepSimulation, because // the updateShapeIfNecessary() call needs info from MyAvatar and should // be done on the main thread during the pre-simulation stuff diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index b6f3487f1a..5fe99f137c 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -67,7 +67,10 @@ int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep saveKinematicState(fixedTimeStep*clampedSimulationSteps); - applyGravity(); + { + BT_PROFILE("applyGravity"); + applyGravity(); + } for (int i=0;igetActivationState() != ISLAND_SLEEPING) + { + if (body->isKinematicObject()) + { + //to calculate velocities next frame + body->saveKinematicState(timeStep); + } + } + } +} + + diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h index e9708149da..68062d8d29 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.h +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h @@ -41,6 +41,7 @@ public: btScalar fixedTimeStep = btScalar(1.)/btScalar(60.), SubStepCallback onSubStep = []() { }); virtual void synchronizeMotionStates() override; + virtual void saveKinematicState(btScalar timeStep) override; // btDiscreteDynamicsWorld::m_localTime is the portion of real-time that has not yet been simulated // but is used for MotionState::setWorldTransform() extrapolation (a feature that Bullet uses to provide From 442b52313fbee5398df9311b35c234f06ba5ec2b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Apr 2016 12:02:01 -0700 Subject: [PATCH 02/55] faster kinematic motion calculations --- libraries/entities/src/EntityItem.cpp | 139 +++++++-------------- libraries/shared/src/SpatiallyNestable.cpp | 50 ++++++-- libraries/shared/src/SpatiallyNestable.h | 7 ++ 3 files changed, 93 insertions(+), 103 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 431d638063..69614d0d12 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -876,123 +876,76 @@ void EntityItem::simulate(const quint64& now) { } void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { -#ifdef WANT_DEBUG - qCDebug(entities) << "EntityItem::simulateKinematicMotion timeElapsed" << timeElapsed; -#endif - - const float MIN_TIME_SKIP = 0.0f; - const float MAX_TIME_SKIP = 1.0f; // in seconds - - timeElapsed = glm::clamp(timeElapsed, MIN_TIME_SKIP, MAX_TIME_SKIP); - - if (hasActions()) { + if (hasActions() || timeElapsed < 0.0f) { return; } - if (hasLocalAngularVelocity()) { - glm::vec3 localAngularVelocity = getLocalAngularVelocity(); + const float MAX_TIME_ELAPSED = 1.0f; // seconds + timeElapsed = glm::min(timeElapsed, MAX_TIME_ELAPSED); + Transform transform; + glm::vec3 linearVelocity; + glm::vec3 angularVelocity; + getLocalEverything(transform, linearVelocity, angularVelocity); + + bool isMoving = false; + if (glm::length2(angularVelocity) > 0.0f) { // angular damping if (_angularDamping > 0.0f) { - localAngularVelocity *= powf(1.0f - _angularDamping, timeElapsed); - #ifdef WANT_DEBUG - qCDebug(entities) << " angularDamping :" << _angularDamping; - qCDebug(entities) << " newAngularVelocity:" << localAngularVelocity; - #endif + angularVelocity *= powf(1.0f - _angularDamping, timeElapsed); } - float angularSpeed = glm::length(localAngularVelocity); - - const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec - if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) { - if (setFlags && angularSpeed > 0.0f) { - _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; - } - localAngularVelocity = ENTITY_ITEM_ZERO_VEC3; + const float EPSILON_ANGULAR_VELOCITY_LENGTH_SQUARED = 0.0017453f * 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec + if (glm::length2(angularVelocity) < EPSILON_ANGULAR_VELOCITY_LENGTH_SQUARED) { + angularVelocity = ENTITY_ITEM_ZERO_VEC3; } else { // for improved agreement with the way Bullet integrates rotations we use an approximation // and break the integration into bullet-sized substeps - glm::quat rotation = getRotation(); + glm::quat rotation = transform.getRotation(); float dt = timeElapsed; - while (dt > PHYSICS_ENGINE_FIXED_SUBSTEP) { - glm::quat dQ = computeBulletRotationStep(localAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP); + while (dt > 0.0f) { + glm::quat dQ = computeBulletRotationStep(angularVelocity, glm::min(dt, PHYSICS_ENGINE_FIXED_SUBSTEP)); rotation = glm::normalize(dQ * rotation); dt -= PHYSICS_ENGINE_FIXED_SUBSTEP; } - // NOTE: this final partial substep can drift away from a real Bullet simulation however - // it only becomes significant for rapidly rotating objects - // (e.g. around PI/4 radians per substep, or 7.5 rotations/sec at 60 substeps/sec). - glm::quat dQ = computeBulletRotationStep(localAngularVelocity, dt); - rotation = glm::normalize(dQ * rotation); - - setRotation(rotation); + transform.setRotation(rotation); + isMoving = true; } - - setLocalAngularVelocity(localAngularVelocity); } - - if (hasLocalVelocity()) { - - // acceleration is in the global frame, so transform it into the local frame. - // TODO: Move this into SpatiallyNestable. - bool success; - Transform transform = getParentTransform(success); - glm::vec3 localAcceleration(glm::vec3::_null); - if (success) { - localAcceleration = glm::inverse(transform.getRotation()) * getAcceleration(); - } else { - localAcceleration = getAcceleration(); - } - + if (glm::length2(linearVelocity) > 0.0f) { // linear damping - glm::vec3 localVelocity = getLocalVelocity(); if (_damping > 0.0f) { - localVelocity *= powf(1.0f - _damping, timeElapsed); - #ifdef WANT_DEBUG - qCDebug(entities) << " damping:" << _damping; - qCDebug(entities) << " velocity AFTER dampingResistance:" << localVelocity; - qCDebug(entities) << " glm::length(velocity):" << glm::length(localVelocity); - #endif + linearVelocity *= powf(1.0f - _damping, timeElapsed); } - // integrate position forward - glm::vec3 localPosition = getLocalPosition(); - glm::vec3 newLocalPosition = localPosition + (localVelocity * timeElapsed) + 0.5f * localAcceleration * timeElapsed * timeElapsed; - - #ifdef WANT_DEBUG - qCDebug(entities) << " EntityItem::simulate()...."; - qCDebug(entities) << " timeElapsed:" << timeElapsed; - qCDebug(entities) << " old AACube:" << getMaximumAACube(); - qCDebug(entities) << " old position:" << localPosition; - qCDebug(entities) << " old velocity:" << localVelocity; - qCDebug(entities) << " old getAABox:" << getAABox(); - qCDebug(entities) << " newPosition:" << newPosition; - qCDebug(entities) << " glm::distance(newPosition, position):" << glm::distance(newLocalPosition, localPosition); - #endif - - localPosition = newLocalPosition; - - // apply effective acceleration, which will be the same as gravity if the Entity isn't at rest. - localVelocity += localAcceleration * timeElapsed; - - float speed = glm::length(localVelocity); - const float EPSILON_LINEAR_VELOCITY_LENGTH = 0.001f; // 1mm/sec - if (speed < EPSILON_LINEAR_VELOCITY_LENGTH) { - setVelocity(ENTITY_ITEM_ZERO_VEC3); - if (setFlags && speed > 0.0f) { - _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; + glm::vec3 linearAcceleration = _acceleration; + if (glm::length2(_acceleration) > 0.0f) { + // acceleration is in world-frame but we need it in local-frame + bool success; + Transform parentTransform = getParentTransform(success); + if (success) { + linearAcceleration = glm::inverse(parentTransform.getRotation()) * linearAcceleration; } - } else { - setLocalPosition(localPosition); - setLocalVelocity(localVelocity); } - #ifdef WANT_DEBUG - qCDebug(entities) << " new position:" << position; - qCDebug(entities) << " new velocity:" << velocity; - qCDebug(entities) << " new AACube:" << getMaximumAACube(); - qCDebug(entities) << " old getAABox:" << getAABox(); - #endif + // integrate linearVelocity + linearVelocity += linearAcceleration * timeElapsed; + + const float EPSILON_LINEAR_VELOCITY_LENGTH_SQUARED = 1.0e-6f; // 1mm/sec ^2 + if (glm::length2(linearVelocity) < EPSILON_LINEAR_VELOCITY_LENGTH_SQUARED) { + setVelocity(ENTITY_ITEM_ZERO_VEC3); + } else { + // integrate position forward + // NOTE: we're using the NEW linear velocity, which is why we negate the acceleration term + glm::vec3 position = transform.getTranslation() + (linearVelocity * timeElapsed) - 0.5f * linearAcceleration * timeElapsed * timeElapsed; + transform.setTranslation(position); + isMoving = true; + } + } + setLocalEverything(transform, linearVelocity, angularVelocity); + if (!isMoving) { + // flag this entity to be removed from kinematic motion + _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } } diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 13bf5d9054..550864265f 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -90,11 +90,9 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) cons return parent; } - SpatiallyNestablePointer thisPointer = getThisPointer(); - if (parent) { // we have a parent pointer but our _parentID doesn't indicate this parent. - parent->forgetChild(thisPointer); + parent->forgetChild(getThisPointer()); _parentKnowsMe = false; _parent.reset(); } @@ -112,16 +110,11 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) cons parent = _parent.lock(); if (parent) { - parent->beParentOfChild(thisPointer); + parent->beParentOfChild(getThisPointer()); _parentKnowsMe = true; } - if (parent || parentID.isNull()) { - success = true; - } else { - success = false; - } - + success = (parent || parentID.isNull()); return parent; } @@ -849,3 +842,40 @@ AACube SpatiallyNestable::getQueryAACube() const { } return result; } + +void SpatiallyNestable::getLocalEverything( + Transform& transform, + glm::vec3& velocity, + glm::vec3& angularVelocity) const { + // transform + _transformLock.withReadLock([&] { + transform = _transform; + }); + // linear velocity + _velocityLock.withReadLock([&] { + velocity = _velocity; + }); + // angular velocity + _angularVelocityLock.withReadLock([&] { + angularVelocity = _angularVelocity; + }); +} + +void SpatiallyNestable::setLocalEverything( + const Transform& localTransform, + const glm::vec3& localVelocity, + const glm::vec3& localAngularVelocity) { + // transform + _transformLock.withWriteLock([&] { + _transform = localTransform; + }); + // linear velocity + _velocityLock.withWriteLock([&] { + _velocity = localVelocity; + }); + // angular velocity + _angularVelocityLock.withWriteLock([&] { + _angularVelocity = localAngularVelocity; + }); + locationChanged(); +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 379f2facd7..6546d46e51 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -149,6 +149,13 @@ protected: quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer(bool& success) const; + void getLocalEverything(Transform& localTransform, glm::vec3& localVelocity, glm::vec3& localAngularVelocity) const; + + void setLocalEverything( + const Transform& localTransform, + const glm::vec3& localVelocity, + const glm::vec3& localAngularVelocity); + mutable SpatiallyNestableWeakPointer _parent; virtual void beParentOfChild(SpatiallyNestablePointer newChild) const; From e1602b57faad3e92c2c3862bda45016587882719 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Apr 2016 12:03:21 -0700 Subject: [PATCH 03/55] faster isNaN checks --- libraries/shared/src/GLMHelpers.cpp | 8 -------- libraries/shared/src/GLMHelpers.h | 4 ++-- libraries/shared/src/SharedUtil.cpp | 17 +---------------- libraries/shared/src/SharedUtil.h | 6 +++--- libraries/shared/src/Transform.cpp | 4 ---- libraries/shared/src/Transform.h | 2 +- 6 files changed, 7 insertions(+), 34 deletions(-) diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index d21d88d212..53abb3827d 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -463,14 +463,6 @@ glm::vec2 getFacingDir2D(const glm::mat4& m) { } } -bool isNaN(glm::vec3 value) { - return isNaN(value.x) || isNaN(value.y) || isNaN(value.z); -} - -bool isNaN(glm::quat value) { - return isNaN(value.w) || isNaN(value.x) || isNaN(value.y) || isNaN(value.z); -} - glm::mat4 orthoInverse(const glm::mat4& m) { glm::mat4 r = m; r[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 469ca1fc81..8b1446d4e5 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -229,8 +229,8 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda glm::vec2 getFacingDir2D(const glm::quat& rot); glm::vec2 getFacingDir2D(const glm::mat4& m); -bool isNaN(glm::vec3 value); -bool isNaN(glm::quat value); +inline bool isNaN(const glm::vec3& value) { return isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } +inline bool isNaN(const glm::quat& value) { return isNaN(value.w) || isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } glm::mat4 orthoInverse(const glm::mat4& m); diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 30d4726bcc..d48bddbd88 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -247,12 +247,6 @@ int getNthBit(unsigned char byte, int ordinal) { return ERROR_RESULT; } -bool isBetween(int64_t value, int64_t max, int64_t min) { - return ((value <= max) && (value >= min)); -} - - - void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { //assert(value <= 3 && value >= 0); byte |= ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 @@ -260,12 +254,7 @@ void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { bool isInEnvironment(const char* environment) { char* environmentString = getenv("HIFI_ENVIRONMENT"); - - if (environmentString && strcmp(environmentString, environment) == 0) { - return true; - } else { - return false; - } + return (environmentString && strcmp(environmentString, environment) == 0); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -632,10 +621,6 @@ void debug::checkDeadBeef(void* memoryVoid, int size) { assert(memcmp((unsigned char*)memoryVoid, DEADBEEF, std::min(size, DEADBEEF_SIZE)) != 0); } -bool isNaN(float value) { - return value != value; -} - QString formatUsecTime(float usecs, int prec) { static const quint64 SECONDS_PER_MINUTE = 60; static const quint64 USECS_PER_MINUTE = USECS_PER_SECOND * SECONDS_PER_MINUTE; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 8fb65a5247..e9201b4a92 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -180,11 +180,11 @@ private: static int DEADBEEF_SIZE; }; -bool isBetween(int64_t value, int64_t max, int64_t min); - +/// \return true when value is between max and min +inline bool isBetween(int64_t value, int64_t max, int64_t min) { return ((value <= max) && (value >= min)); } /// \return bool is the float NaN -bool isNaN(float value); +inline bool isNaN(float value) { return value != value; } QString formatUsecTime(float usecs, int prec = 3); QString formatSecondsElapsed(float seconds); diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index a3a3c05731..c51b3dae4b 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -150,7 +150,3 @@ QJsonObject Transform::toJson(const Transform& transform) { } return result; } - -bool Transform::containsNaN() const { - return isNaN(_rotation) || isNaN(_scale) || isNaN(_translation); -} diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 1024173cbd..1e1d10c54b 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -145,7 +145,7 @@ public: Vec4 transform(const Vec4& pos) const; Vec3 transform(const Vec3& pos) const; - bool containsNaN() const; + bool containsNaN() const { return isNaN(_rotation) || isNaN(glm::dot(_scale, _translation)); } protected: From 25fbf926df007496267efcc3c1b97331a430834a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Apr 2016 12:04:27 -0700 Subject: [PATCH 04/55] CollisionWorld only updates _active_ Aabbs we manually set/clear active state of static objects that need their Aabbs updated also fixing a bug when starting kinematic motion --- libraries/physics/src/EntityMotionState.cpp | 17 ++++++--------- libraries/physics/src/EntityMotionState.h | 6 +----- libraries/physics/src/ObjectMotionState.cpp | 18 ++++++++++++---- libraries/physics/src/ObjectMotionState.h | 10 +++++---- libraries/physics/src/PhysicsEngine.cpp | 24 ++++++++++++++++----- libraries/physics/src/PhysicsEngine.h | 6 +++--- 6 files changed, 50 insertions(+), 31 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 7b83c2e2ce..5f168d2e33 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -94,7 +94,7 @@ void EntityMotionState::updateServerPhysicsVariables() { } // virtual -bool EntityMotionState::handleEasyChanges(uint32_t& flags) { +void EntityMotionState::handleEasyChanges(uint32_t& flags) { assert(entityTreeIsLocked()); updateServerPhysicsVariables(); ObjectMotionState::handleEasyChanges(flags); @@ -137,8 +137,6 @@ bool EntityMotionState::handleEasyChanges(uint32_t& flags) { if ((flags & Simulation::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) { _body->activate(); } - - return true; } @@ -422,19 +420,18 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { // acceleration measured during the most recent simulation step was close to gravity. - if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { - // only increment this if we haven't reached the threshold yet. this is to avoid - // overflowing the counter. - incrementAccelerationNearlyGravityCount(); + if (_accelerationNearlyGravityCount < STEPS_TO_DECIDE_BALLISTIC) { + // only increment this if we haven't reached the threshold yet, to avoid overflowing the counter + ++_accelerationNearlyGravityCount; } } else { - // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter - resetAccelerationNearlyGravityCount(); + // acceleration wasn't similar to this entity's gravity, reset the counter + _accelerationNearlyGravityCount = 0; } // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let // the entity server's estimates include gravity. - if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { + if (_accelerationNearlyGravityCount >= STEPS_TO_DECIDE_BALLISTIC) { _entity->setAcceleration(_entity->getGravity()); } else { _entity->setAcceleration(glm::vec3(0.0f)); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index ac16ec6d5d..eb42d03b52 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -29,7 +29,7 @@ public: virtual ~EntityMotionState(); void updateServerPhysicsVariables(); - virtual bool handleEasyChanges(uint32_t& flags) override; + virtual void handleEasyChanges(uint32_t& flags) override; virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) override; /// \return PhysicsMotionType based on params set in EntityItem @@ -51,10 +51,6 @@ public: virtual uint32_t getIncomingDirtyFlags() override; virtual void clearIncomingDirtyFlags() override; - void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; } - void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } - uint8_t getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } - virtual float getObjectRestitution() const override { return _entity->getRestitution(); } virtual float getObjectFriction() const override { return _entity->getFriction(); } virtual float getObjectLinearDamping() const override { return _entity->getDamping(); } diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 482c3146f8..6b2022e204 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -39,7 +39,7 @@ const glm::vec3& ObjectMotionState::getWorldOffset() { } // static -uint32_t worldSimulationStep = 0; +uint32_t worldSimulationStep = 1; void ObjectMotionState::setWorldSimulationStep(uint32_t step) { assert(step > worldSimulationStep); worldSimulationStep = step; @@ -164,7 +164,7 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { } } -bool ObjectMotionState::handleEasyChanges(uint32_t& flags) { +void ObjectMotionState::handleEasyChanges(uint32_t& flags) { if (flags & Simulation::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); btVector3 newPosition = glmToBullet(getObjectPosition()); @@ -183,6 +183,10 @@ bool ObjectMotionState::handleEasyChanges(uint32_t& flags) { worldTrans.setRotation(newRotation); } _body->setWorldTransform(worldTrans); + if (!(flags & HARD_DIRTY_PHYSICS_FLAGS) && _body->isStaticObject()) { + // force activate static body so its Aabb is updated later + _body->activate(true); + } } else if (flags & Simulation::DIRTY_ROTATION) { btTransform worldTrans = _body->getWorldTransform(); btQuaternion newRotation = glmToBullet(getObjectRotation()); @@ -192,6 +196,10 @@ bool ObjectMotionState::handleEasyChanges(uint32_t& flags) { } worldTrans.setRotation(newRotation); _body->setWorldTransform(worldTrans); + if (!(flags & HARD_DIRTY_PHYSICS_FLAGS) && _body->isStaticObject()) { + // force activate static body so its Aabb is updated later + _body->activate(true); + } } if (flags & Simulation::DIRTY_LINEAR_VELOCITY) { @@ -232,8 +240,6 @@ bool ObjectMotionState::handleEasyChanges(uint32_t& flags) { if (flags & Simulation::DIRTY_MASS) { updateBodyMassProperties(); } - - return true; } bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) { @@ -292,6 +298,10 @@ void ObjectMotionState::updateBodyVelocities() { _body->setActivationState(ACTIVE_TAG); } +void ObjectMotionState::updateLastKinematicStep() { + _lastKinematicStep = ObjectMotionState::getWorldSimulationStep() - 1; +} + void ObjectMotionState::updateBodyMassProperties() { float mass = getMass(); btVector3 inertia(0.0f, 0.0f, 0.0f); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index bb78eb12d6..44cb88721c 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -50,11 +50,12 @@ const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_MOTION_TY Simulation::DIRTY_COLLISION_GROUP); const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES | Simulation::DIRTY_MASS | Simulation::DIRTY_MATERIAL | - Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY); + Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY | + Simulation::DIRTY_PHYSICS_ACTIVATION); + // These are the set of incoming flags that the PhysicsEngine needs to hear about: -const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS | - Simulation::DIRTY_PHYSICS_ACTIVATION); +const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS); // These are the outgoing flags that the PhysicsEngine can affect: const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES; @@ -80,11 +81,12 @@ public: ObjectMotionState(btCollisionShape* shape); ~ObjectMotionState(); - virtual bool handleEasyChanges(uint32_t& flags); + virtual void handleEasyChanges(uint32_t& flags); virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine); void updateBodyMaterialProperties(); void updateBodyVelocities(); + void updateLastKinematicStep(); virtual void updateBodyMassProperties(); MotionStateType getType() const { return _type; } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 74f6f90900..55861e9b3a 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -50,6 +50,7 @@ void PhysicsEngine::init() { // default gravity of the world is zero, so each object must specify its own gravity // TODO: set up gravity zones _dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f)); + _dynamicsWorld->setForceUpdateAllAabbs(false); } } @@ -80,6 +81,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); body->updateInertiaTensor(); motionState->updateBodyVelocities(); + motionState->updateLastKinematicStep(); const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); @@ -189,12 +191,18 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob stillNeedChange.push_back(object); } } else if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - if (object->handleEasyChanges(flags)) { - object->clearIncomingDirtyFlags(); - } else { - stillNeedChange.push_back(object); - } + object->handleEasyChanges(flags); + object->clearIncomingDirtyFlags(); } + if (object->getMotionType() == MOTION_TYPE_STATIC && object->isActive()) { + _activeStaticBodies.push_back(object->getRigidBody()); + } + } + // active static bodies have changed (in an Easy way) and need their Aabbs updated + // but we've configured Bullet to NOT update them automatically (for improved performance) + // so we must do it outselves + for (int i = 0; i < _activeStaticBodies.size(); ++i) { + _dynamicsWorld->updateSingleAabb(_activeStaticBodies[i]); } return stillNeedChange; } @@ -389,6 +397,12 @@ const CollisionEvents& PhysicsEngine::getCollisionEvents() { const VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() { BT_PROFILE("copyOutgoingChanges"); + // Bullet will not deactivate static objects (it doesn't expect them to be active) + // so we must deactivate them ourselves + for (int i = 0; i < _activeStaticBodies.size(); ++i) { + _activeStaticBodies[i]->forceActivationState(ISLAND_SLEEPING); + } + _activeStaticBodies.clear(); _dynamicsWorld->synchronizeMotionStates(); _hasOutgoingChanges = false; return _dynamicsWorld->getChangedMotionStates(); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index f644d6f5b2..18e4016fec 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -13,9 +13,9 @@ #define hifi_PhysicsEngine_h #include +#include #include -#include #include #include @@ -41,7 +41,7 @@ public: }; typedef std::map ContactMap; -typedef QVector CollisionEvents; +typedef std::vector CollisionEvents; class PhysicsEngine { public: @@ -110,6 +110,7 @@ private: ContactMap _contactMap; CollisionEvents _collisionEvents; QHash _objectActions; + std::vector _activeStaticBodies; glm::vec3 _originOffset; QUuid _sessionID; @@ -121,7 +122,6 @@ private: bool _dumpNextStats = false; bool _hasOutgoingChanges = false; - }; typedef std::shared_ptr PhysicsEnginePointer; From de5fe705a33e171016b9855c9383c147620ba312 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Apr 2016 12:06:47 -0700 Subject: [PATCH 05/55] optimize Bullet broadphase using collision groups --- libraries/shared/src/PhysicsCollisionGroups.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index 6d320e69cb..794f338dc5 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -51,10 +51,10 @@ const int16_t BULLET_COLLISION_GROUP_COLLISIONLESS = 1 << 14; const int16_t BULLET_COLLISION_MASK_DEFAULT = ~ BULLET_COLLISION_GROUP_COLLISIONLESS; // STATIC does not collide with itself (as optimization of physics simulation) -const int16_t BULLET_COLLISION_MASK_STATIC = ~ (BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_STATIC); +const int16_t BULLET_COLLISION_MASK_STATIC = ~ (BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_KINEMATIC | BULLET_COLLISION_GROUP_STATIC); const int16_t BULLET_COLLISION_MASK_DYNAMIC = BULLET_COLLISION_MASK_DEFAULT; -const int16_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_DEFAULT; +const int16_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_STATIC; // MY_AVATAR does not collide with itself const int16_t BULLET_COLLISION_MASK_MY_AVATAR = ~(BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_MY_AVATAR); From 20914df3303e79cd61c79a1c91222171e4c15956 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Apr 2016 13:31:14 -0700 Subject: [PATCH 06/55] fix warning about signed/unsigned comparison --- libraries/physics/src/PhysicsEngine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 55861e9b3a..973be0b4e8 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -201,7 +201,7 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob // active static bodies have changed (in an Easy way) and need their Aabbs updated // but we've configured Bullet to NOT update them automatically (for improved performance) // so we must do it outselves - for (int i = 0; i < _activeStaticBodies.size(); ++i) { + for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { _dynamicsWorld->updateSingleAabb(_activeStaticBodies[i]); } return stillNeedChange; @@ -399,7 +399,7 @@ const VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() { BT_PROFILE("copyOutgoingChanges"); // Bullet will not deactivate static objects (it doesn't expect them to be active) // so we must deactivate them ourselves - for (int i = 0; i < _activeStaticBodies.size(); ++i) { + for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { _activeStaticBodies[i]->forceActivationState(ISLAND_SLEEPING); } _activeStaticBodies.clear(); From d72c6954174ac2469d4b4324bc9739b4854b84fd Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 16:21:32 -0700 Subject: [PATCH 07/55] Sanitize ResourceCache to expose to JS/QML fix sanitize --- interface/src/Application.cpp | 5 ++--- libraries/networking/src/ResourceCache.h | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bd1a44fc76..f11fd22e2f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -588,9 +588,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // Model background downloads need to happen on the Datagram Processor Thread. The idle loop will // emit checkBackgroundDownloads to cause the ModelCache to check it's queue for requested background // downloads. - QSharedPointer modelCacheP = DependencyManager::get(); - ResourceCache* modelCache = modelCacheP.data(); - connect(this, &Application::checkBackgroundDownloads, modelCache, &ResourceCache::checkAsynchronousGets); + auto modelCache = DependencyManager::get(); + connect(this, &Application::checkBackgroundDownloads, modelCache.data(), &ModelCache::checkAsynchronousGets); // put the audio processing on a separate thread QThread* audioThread = new QThread(); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index f674c96a1e..10f0289052 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -109,7 +109,7 @@ protected: /// \param fallback a fallback URL to load if the desired one is unavailable /// \param delayLoad if true, don't load the resource immediately; wait until load is first requested /// \param extra extra data to pass to the creator, if appropriate - Q_INVOKABLE QSharedPointer getResource(const QUrl& url, const QUrl& fallback = QUrl(), + QSharedPointer getResource(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false, void* extra = NULL); /// Creates a new resource. @@ -123,7 +123,7 @@ protected: /// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading /// \return true if the resource began loading, otherwise false if the resource is in the pending queue - Q_INVOKABLE static bool attemptRequest(Resource* resource); + static bool attemptRequest(Resource* resource); static void requestCompleted(Resource* resource); static bool attemptHighestPriorityRequest(); From 3b45a57e1d785d63830e2d31eb989271d0a86b21 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 17:02:44 -0700 Subject: [PATCH 08/55] Remove resource completely when uncached --- libraries/networking/src/ResourceCache.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index b5f5ca7c25..54b70c7da3 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -142,8 +142,9 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { // unload the oldest resource QMap >::iterator it = _unusedResources.begin(); - _unusedResourcesSize -= it.value()->getBytes(); + _resources.remove(it.value()->getURL()); it.value()->setCache(nullptr); + _unusedResourcesSize -= it.value()->getBytes(); _unusedResources.erase(it); } } From 0830c55bcfacef6c6f2fa49ad636acae83b4ed8d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Apr 2016 17:48:56 -0700 Subject: [PATCH 09/55] getLocalEverything->getLocalTransformAndVelocities --- libraries/entities/src/EntityItem.cpp | 4 ++-- libraries/shared/src/SpatiallyNestable.cpp | 4 ++-- libraries/shared/src/SpatiallyNestable.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 69614d0d12..5c825495b9 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -886,7 +886,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { Transform transform; glm::vec3 linearVelocity; glm::vec3 angularVelocity; - getLocalEverything(transform, linearVelocity, angularVelocity); + getLocalTransformAndVelocities(transform, linearVelocity, angularVelocity); bool isMoving = false; if (glm::length2(angularVelocity) > 0.0f) { @@ -942,7 +942,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { isMoving = true; } } - setLocalEverything(transform, linearVelocity, angularVelocity); + setLocalTransformAndVelocities(transform, linearVelocity, angularVelocity); if (!isMoving) { // flag this entity to be removed from kinematic motion _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 550864265f..3cbd3c5ac9 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -843,7 +843,7 @@ AACube SpatiallyNestable::getQueryAACube() const { return result; } -void SpatiallyNestable::getLocalEverything( +void SpatiallyNestable::getLocalTransformAndVelocities( Transform& transform, glm::vec3& velocity, glm::vec3& angularVelocity) const { @@ -861,7 +861,7 @@ void SpatiallyNestable::getLocalEverything( }); } -void SpatiallyNestable::setLocalEverything( +void SpatiallyNestable::setLocalTransformAndVelocities( const Transform& localTransform, const glm::vec3& localVelocity, const glm::vec3& localAngularVelocity) { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 6546d46e51..ef70d0231b 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -149,9 +149,9 @@ protected: quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer(bool& success) const; - void getLocalEverything(Transform& localTransform, glm::vec3& localVelocity, glm::vec3& localAngularVelocity) const; + void getLocalTransformAndVelocities(Transform& localTransform, glm::vec3& localVelocity, glm::vec3& localAngularVelocity) const; - void setLocalEverything( + void setLocalTransformAndVelocities( const Transform& localTransform, const glm::vec3& localVelocity, const glm::vec3& localAngularVelocity); From b70a4d043bdfa9f6906e76e732198a796eb5c062 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 17:33:12 -0700 Subject: [PATCH 10/55] Expose resource cache count props --- libraries/networking/src/ResourceCache.cpp | 23 +++++++++++++++--- libraries/networking/src/ResourceCache.h | 27 ++++++++++++++++++---- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 54b70c7da3..c10b96ca19 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -114,6 +114,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) { _unusedResourcesMaxSize = clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE); reserveUnusedResource(0); + emit dirty(); } void ResourceCache::addUnusedResource(const QSharedPointer& resource) { @@ -127,6 +128,7 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) resource->setLRUKey(++_lastLRUKey); _unusedResources.insert(resource->getLRUKey(), resource); _unusedResourcesSize += resource->getBytes(); + emit dirty(); } void ResourceCache::removeUnusedResource(const QSharedPointer& resource) { @@ -134,6 +136,7 @@ void ResourceCache::removeUnusedResource(const QSharedPointer& resourc _unusedResources.remove(resource->getLRUKey()); _unusedResourcesSize -= resource->getBytes(); } + emit dirty(); } void ResourceCache::reserveUnusedResource(qint64 resourceSize) { @@ -142,9 +145,13 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { // unload the oldest resource QMap >::iterator it = _unusedResources.begin(); - _resources.remove(it.value()->getURL()); it.value()->setCache(nullptr); - _unusedResourcesSize -= it.value()->getBytes(); + auto size = it.value()->getBytes(); + + _totalResourcesSize -= size; + _resources.remove(it.value()->getURL()); + + _unusedResourcesSize -= size; _unusedResources.erase(it); } } @@ -160,6 +167,11 @@ void ResourceCache::clearUnusedResource() { } } +void ResourceCache::updateTotalSize(const qint64& oldSize, const qint64& newSize) { + _totalResourcesSize += (newSize - oldSize); + emit dirty(); +} + void ResourceCacheSharedItems::appendActiveRequest(Resource* resource) { Lock lock(_mutex); _loadingRequests.append(resource); @@ -378,6 +390,11 @@ void Resource::finishedLoading(bool success) { emit finished(success); } +void Resource::setBytes(const qint64& bytes) { + QMetaObject::invokeMethod(_cache.data(), "updateTotalSize", Q_ARG(qint64, _bytes), Q_ARG(qint64, bytes)); + _bytes = bytes; +} + void Resource::reinsert() { _cache->_resources.insert(_url, _self); } @@ -413,7 +430,7 @@ void Resource::handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTota void Resource::handleReplyFinished() { Q_ASSERT_X(_request, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished"); - _bytes = _bytesTotal; + setBytes(_bytesTotal); if (!_request || _request != sender()) { // This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted. diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 10f0289052..f113254995 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -79,8 +79,18 @@ private: /// Base class for resource caches. class ResourceCache : public QObject { Q_OBJECT + Q_PROPERTY(int numTotal READ getNumTotalResources NOTIFY dirty) + Q_PROPERTY(int numCached READ getNumCachedResources NOTIFY dirty) + Q_PROPERTY(qint64 sizeTotal READ getSizeTotalResources NOTIFY dirty) + Q_PROPERTY(qint64 sizeCached READ getSizeCachedResources NOTIFY dirty) public: + int getNumTotalResources() const { return _resources.size(); } + qint64 getSizeTotalResources() const { return _totalResourcesSize; } + + int getNumCachedResources() const { return _unusedResources.size(); } + qint64 getSizeCachedResources() const { return _unusedResourcesSize; } + static void setRequestLimit(int limit); static int getRequestLimit() { return _requestLimit; } @@ -101,9 +111,15 @@ public: void refreshAll(); void refresh(const QUrl& url); +signals: + void dirty(); + public slots: void checkAsynchronousGets(); +protected slots: + void updateTotalSize(const qint64& oldSize, const qint64& newSize); + protected: /// Loads a resource from the specified URL. /// \param fallback a fallback URL to load if the desired one is unavailable @@ -118,8 +134,6 @@ protected: void addUnusedResource(const QSharedPointer& resource); void removeUnusedResource(const QSharedPointer& resource); - void reserveUnusedResource(qint64 resourceSize); - void clearUnusedResource(); /// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading /// \return true if the resource began loading, otherwise false if the resource is in the pending queue @@ -130,6 +144,9 @@ protected: private: friend class Resource; + void reserveUnusedResource(qint64 resourceSize); + void clearUnusedResource(); + QHash> _resources; int _lastLRUKey = 0; @@ -140,8 +157,10 @@ private: QReadWriteLock _resourcesToBeGottenLock; QQueue _resourcesToBeGotten; + qint64 _totalResourcesSize { 0 }; + qint64 _unusedResourcesSize { 0 }; + qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; - qint64 _unusedResourcesSize = 0; QMap> _unusedResources; }; @@ -226,7 +245,7 @@ protected: virtual void downloadFinished(const QByteArray& data) { finishedLoading(true); } /// Called when the download is finished and processed, sets the number of actual bytes. - void setBytes(qint64 bytes) { _bytes = bytes; } + void setBytes(const qint64& bytes); /// Called when the download is finished and processed. /// This should be called by subclasses that override downloadFinished to mark the end of processing. From 5b9198ed3d5df8b6cb69b95b8a6afb6b6dc433e9 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 17:41:57 -0700 Subject: [PATCH 11/55] Expose tex/model cache to js/qml --- interface/src/Application.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f11fd22e2f..802c2569c4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1351,7 +1351,6 @@ void Application::initializeUi() { // though I can't find it. Hence, "ApplicationInterface" rootContext->setContextProperty("SnapshotUploader", new SnapshotUploader()); rootContext->setContextProperty("ApplicationInterface", this); - rootContext->setContextProperty("AnimationCache", DependencyManager::get().data()); rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance()); rootContext->setContextProperty("Controller", DependencyManager::get().data()); rootContext->setContextProperty("Entities", DependencyManager::get().data()); @@ -1381,8 +1380,13 @@ void Application::initializeUi() { rootContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); rootContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get().data()); rootContext->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance()); + + // Caches rootContext->setContextProperty("AnimationCache", DependencyManager::get().data()); + rootContext->setContextProperty("TextureCache", DependencyManager::get().data()); + rootContext->setContextProperty("ModelCache", DependencyManager::get().data()); rootContext->setContextProperty("SoundCache", DependencyManager::get().data()); + rootContext->setContextProperty("Account", AccountScriptingInterface::getInstance()); rootContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface); rootContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance()); @@ -4334,8 +4338,13 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Stats", Stats::getInstance()); scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance()); + + // Caches scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("TextureCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("ModelCache", DependencyManager::get().data()); scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("DialogsManager", _dialogsManagerScriptingInterface); From 36e04f4434ec71894cf211d3ded0a039aabb231c Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 18:22:51 -0700 Subject: [PATCH 12/55] Mv PlotPerf to shared dir --- examples/utilities/{render => lib}/plotperf/PlotPerf.qml | 0 examples/utilities/{render => lib}/plotperf/qmldir | 0 examples/utilities/render/stats.qml | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename examples/utilities/{render => lib}/plotperf/PlotPerf.qml (100%) rename examples/utilities/{render => lib}/plotperf/qmldir (100%) diff --git a/examples/utilities/render/plotperf/PlotPerf.qml b/examples/utilities/lib/plotperf/PlotPerf.qml similarity index 100% rename from examples/utilities/render/plotperf/PlotPerf.qml rename to examples/utilities/lib/plotperf/PlotPerf.qml diff --git a/examples/utilities/render/plotperf/qmldir b/examples/utilities/lib/plotperf/qmldir similarity index 100% rename from examples/utilities/render/plotperf/qmldir rename to examples/utilities/lib/plotperf/qmldir diff --git a/examples/utilities/render/stats.qml b/examples/utilities/render/stats.qml index 0e51cb8834..0902695f93 100644 --- a/examples/utilities/render/stats.qml +++ b/examples/utilities/render/stats.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 import QtQuick.Controls 1.4 -import "plotperf" +import "../lib/plotperf" Item { id: statsUI From 41cdb29bd23ab44ee6d2864566ce6a82bc1c4b94 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 19:51:05 -0700 Subject: [PATCH 13/55] Use a timer in plotperf --- examples/utilities/lib/plotperf/PlotPerf.qml | 63 +++++++++----------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/examples/utilities/lib/plotperf/PlotPerf.qml b/examples/utilities/lib/plotperf/PlotPerf.qml index 179707c0f1..6871ffe6a6 100644 --- a/examples/utilities/lib/plotperf/PlotPerf.qml +++ b/examples/utilities/lib/plotperf/PlotPerf.qml @@ -19,12 +19,8 @@ Item { // The title of the graph property string title - // THe object used as the default source object for the prop plots + // The object used as the default source object for the prop plots property var object - - // THis is my hack to get a property and assign it to a trigger var in order to get - // a signal called whenever the value changed - property var trigger // Plots is an array of plot descriptor // a default plot descriptor expects the following object: @@ -55,45 +51,38 @@ Item { property var tick : 0 function createValues() { - print("trigger is: " + JSON.stringify(trigger)) - if (Array.isArray(plots)) { - for (var i =0; i < plots.length; i++) { - var plot = plots[i]; - print(" a pnew Plot:" + JSON.stringify(plot)); - _values.push( { - object: (plot["object"] !== undefined ? plot["object"] : root.object), - value: plot["prop"], - valueMax: 1, - numSamplesConstantMax: 0, - valueHistory: new Array(), - label: (plot["label"] !== undefined ? plot["label"] : ""), - color: (plot["color"] !== undefined ? plot["color"] : "white"), - scale: (plot["scale"] !== undefined ? plot["scale"] : 1), - unit: (plot["unit"] !== undefined ? plot["unit"] : valueUnit) - }) - } + for (var i =0; i < plots.length; i++) { + var plot = plots[i]; + _values.push( { + object: (plot["object"] !== undefined ? plot["object"] : root.object), + value: plot["prop"], + valueMax: 1, + numSamplesConstantMax: 0, + valueHistory: new Array(), + label: (plot["label"] !== undefined ? plot["label"] : ""), + color: (plot["color"] !== undefined ? plot["color"] : "white"), + scale: (plot["scale"] !== undefined ? plot["scale"] : 1), + unit: (plot["unit"] !== undefined ? plot["unit"] : valueUnit) + }) } - print("in creator" + JSON.stringify(_values)); - + pullFreshValues(); } Component.onCompleted: { createValues(); - print(JSON.stringify(_values)); - } function pullFreshValues() { - //print("pullFreshValues"); + // Wait until values are created to begin pulling + if (!_values) { return; } + var VALUE_HISTORY_SIZE = 100; - var UPDATE_CANVAS_RATE = 20; tick++; - var currentValueMax = 0 for (var i = 0; i < _values.length; i++) { - var currentVal = _values[i].object[_values[i].value] * _values[i].scale; + var currentVal = (+_values[i].object[_values[i].value]) * _values[i].scale; _values[i].valueHistory.push(currentVal) _values[i].numSamplesConstantMax++; @@ -125,11 +114,13 @@ Item { valueMax = currentValueMax; } - if (tick % UPDATE_CANVAS_RATE == 0) { - mycanvas.requestPaint() - } + mycanvas.requestPaint() + } + + Timer { + interval: 100; running: true; repeat: true + onTriggered: pullFreshValues() } - onTriggerChanged: pullFreshValues() Canvas { id: mycanvas @@ -165,9 +156,9 @@ Item { ctx.fillStyle = val.color; var bestValue = val.valueHistory[val.valueHistory.length -1]; ctx.textAlign = "right"; - ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1.5); + ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1); ctx.textAlign = "left"; - ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1.5); + ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1); } function displayTitle(ctx, text, maxVal) { From b0185dc355590eb578004b4f6c7e47eedf07dfad Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 19:52:08 -0700 Subject: [PATCH 14/55] Add cacheStats.js --- examples/utilities/cache/cacheStats.js | 21 +++++++ examples/utilities/cache/stats.qml | 77 ++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 examples/utilities/cache/cacheStats.js create mode 100644 examples/utilities/cache/stats.qml diff --git a/examples/utilities/cache/cacheStats.js b/examples/utilities/cache/cacheStats.js new file mode 100644 index 0000000000..e58a5d0e21 --- /dev/null +++ b/examples/utilities/cache/cacheStats.js @@ -0,0 +1,21 @@ +// +// cacheStats.js +// examples/utilities/cache +// +// Zach Pomerantz, created on 4/1/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// Set up the qml ui +var qml = Script.resolvePath('stats.qml'); +var window = new OverlayWindow({ + title: 'Cache Stats', + source: qml, + width: 300, + height: 200 +}); +window.setPosition(500, 50); +window.closed.connect(function() { Script.stop(); }); diff --git a/examples/utilities/cache/stats.qml b/examples/utilities/cache/stats.qml new file mode 100644 index 0000000000..d7888eb1aa --- /dev/null +++ b/examples/utilities/cache/stats.qml @@ -0,0 +1,77 @@ +// +// stats.qml +// examples/utilities/cache +// +// Created by Zach Pomerantz on 4/1/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import "../lib/plotperf" + +Item { + id: root + anchors.fill: parent + + property var caches: [["Animation", AnimationCache], ["Model", ModelCache], ["Texture", TextureCache], ["Sound", SoundCache]] + + Grid { + id: grid + rows: root.caches.length; columns: 1; spacing: 8 + anchors.fill: parent + + Repeater { + id: repeater + + model: root.caches + + Row { + PlotPerf { + title: modelData[0] + " Count" + anchors.left: parent + height: (grid.height - (grid.spacing * (root.caches.length + 1))) / root.caches.length + width: grid.width / 2 - grid.spacing * 1.5 + object: modelData[1] + valueNumDigits: "1" + plots: [ + { + prop: "numTotal", + label: "total", + color: "#00B4EF" + }, + { + prop: "numCached", + label: "cached", + color: "#1AC567" + } + ] + } + PlotPerf { + title: modelData[0] + " Size" + anchors.right: parent + height: (grid.height - (grid.spacing * (root.caches.length + 1))) / root.caches.length + width: grid.width / 2 - grid.spacing * 1.5 + object: modelData[1] + valueScale: 1048576 + valueUnit: "Mb" + valueNumDigits: "1" + plots: [ + { + prop: "sizeTotal", + label: "total", + color: "#00B4EF" + }, + { + prop: "sizeCached", + label: "cached", + color: "#1AC567" + } + ] + } + } + } + } +} From d78338330c70a8328f2c4a9ee604b5ffb78a3beb Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 19:53:41 -0700 Subject: [PATCH 15/55] Rm unused trigger from renderStats --- examples/utilities/render/stats.qml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/examples/utilities/render/stats.qml b/examples/utilities/render/stats.qml index 0902695f93..4988c23e3b 100644 --- a/examples/utilities/render/stats.qml +++ b/examples/utilities/render/stats.qml @@ -32,7 +32,6 @@ Item { title: "Num Buffers" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["bufferCPUCount"] plots: [ { prop: "bufferCPUCount", @@ -50,7 +49,6 @@ Item { title: "gpu::Buffer Memory" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["bufferCPUMemoryUsage"] valueScale: 1048576 valueUnit: "Mb" valueNumDigits: "1" @@ -71,7 +69,6 @@ Item { title: "Num Textures" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["textureCPUCount"] plots: [ { prop: "textureCPUCount", @@ -94,7 +91,6 @@ Item { title: "gpu::Texture Memory" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["textureCPUMemoryUsage"] valueScale: 1048576 valueUnit: "Mb" valueNumDigits: "1" @@ -116,7 +112,6 @@ Item { title: "Triangles" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["frameTriangleCount"] valueScale: 1000 valueUnit: "K" plots: [ @@ -138,7 +133,6 @@ Item { title: "Drawcalls" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["frameDrawcallCount"] plots: [ { prop: "frameAPIDrawcallCount", @@ -168,7 +162,6 @@ Item { title: "Items" height: parent.evalEvenHeight() object: parent.drawOpaqueConfig - trigger: Render.getConfig("DrawOpaqueDeferred")["numDrawn"] plots: [ { object: Render.getConfig("DrawOpaqueDeferred"), From 3c86191a59f7f68cdcb0526b071480151e598cb5 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Sat, 2 Apr 2016 17:17:06 -0700 Subject: [PATCH 16/55] Add resources prop to caches --- libraries/networking/src/ResourceCache.cpp | 10 ++++++++++ libraries/networking/src/ResourceCache.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index c10b96ca19..1f687593bb 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -56,6 +56,16 @@ void ResourceCache::refresh(const QUrl& url) { } } +const QVariantList ResourceCache::getResourceList() const { + QVariantList list; + auto resources = _resources.uniqueKeys(); + list.reserve(resources.size()); + for (auto& resource : resources) { + list << resource; + } + return list; +} + void ResourceCache::setRequestLimit(int limit) { _requestLimit = limit; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index f113254995..3f930a1f11 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -83,6 +83,7 @@ class ResourceCache : public QObject { Q_PROPERTY(int numCached READ getNumCachedResources NOTIFY dirty) Q_PROPERTY(qint64 sizeTotal READ getSizeTotalResources NOTIFY dirty) Q_PROPERTY(qint64 sizeCached READ getSizeCachedResources NOTIFY dirty) + Q_PROPERTY(QVariantList resources READ getResourceList NOTIFY dirty) public: int getNumTotalResources() const { return _resources.size(); } @@ -91,6 +92,8 @@ public: int getNumCachedResources() const { return _unusedResources.size(); } qint64 getSizeCachedResources() const { return _unusedResourcesSize; } + const QVariantList getResourceList() const; + static void setRequestLimit(int limit); static int getRequestLimit() { return _requestLimit; } From 79e528633584f111a2c9a9fcdec07e8b798838d0 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Sun, 3 Apr 2016 11:53:59 -0700 Subject: [PATCH 17/55] Fix ImageReader threading issues --- .../src/model-networking/TextureCache.cpp | 58 ++++++++++++------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 3ba36dc2da..ff189b46f7 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -196,7 +196,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& texture { _textureLoader = textureLoader; } - + NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { switch (_type) { case CUBE_TEXTURE: { @@ -240,14 +240,14 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { class ImageReader : public QRunnable { public: - ImageReader(const QWeakPointer& texture, const QByteArray& data, const QUrl& url = QUrl()); + ImageReader(const QWeakPointer& resource, const QByteArray& data, const QUrl& url = QUrl()); virtual void run(); private: static void listSupportedImageFormats(); - QWeakPointer _texture; + QWeakPointer _resource; QUrl _url; QByteArray _content; }; @@ -261,9 +261,9 @@ void NetworkTexture::loadContent(const QByteArray& content) { QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url)); } -ImageReader::ImageReader(const QWeakPointer& texture, const QByteArray& data, +ImageReader::ImageReader(const QWeakPointer& resource, const QByteArray& data, const QUrl& url) : - _texture(texture), + _resource(resource), _url(url), _content(data) { @@ -284,25 +284,25 @@ void ImageReader::run() { } QThread::currentThread()->setPriority(QThread::LowPriority); - auto texture = _texture.toStrongRef(); - if (!texture) { - qCWarning(modelnetworking) << "Could not get strong ref"; + if (!_resource.data()) { + qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; + QThread::currentThread()->setPriority(originalPriority); return; } listSupportedImageFormats(); - // try to help the QImage loader by extracting the image file format from the url filename ext - // Some tga are not created properly for example without it + // Help the QImage loader by extracting the image file format from the url filename ext. + // Some tga are not created properly without it. auto filename = _url.fileName().toStdString(); auto filenameExtension = filename.substr(filename.find_last_of('.') + 1); QImage image = QImage::fromData(_content, filenameExtension.c_str()); // Note that QImage.format is the pixel format which is different from the "format" of the image file... - auto imageFormat = image.format(); + auto imageFormat = image.format(); int originalWidth = image.width(); int originalHeight = image.height(); - + if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) { if (filenameExtension.empty()) { qCDebug(modelnetworking) << "QImage failed to create from content, no file extension:" << _url; @@ -312,15 +312,31 @@ void ImageReader::run() { return; } - gpu::Texture* theTexture = nullptr; - auto ntex = texture.dynamicCast(); - if (ntex) { - theTexture = ntex->getTextureLoader()(image, _url.toString().toStdString()); + gpu::Texture* texture = nullptr; + { + // Double-check the resource still exists between long operations. + auto resource = _resource.toStrongRef(); + if (!resource) { + qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; + QThread::currentThread()->setPriority(originalPriority); + return; + } + + auto url = _url.toString().toStdString(); + texture = resource.dynamicCast()->getTextureLoader()(image, url); + } + + // Ensure the resource has not been deleted, and won't be while invokeMethod is in flight. + auto resource = _resource.toStrongRef(); + if (!resource) { + qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; + delete texture; + } else { + QMetaObject::invokeMethod(resource.data(), "setImage", Qt::BlockingQueuedConnection, + Q_ARG(void*, texture), + Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); } - QMetaObject::invokeMethod(texture.data(), "setImage", - Q_ARG(void*, theTexture), - Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); QThread::currentThread()->setPriority(originalPriority); } @@ -328,9 +344,9 @@ void NetworkTexture::setImage(void* voidTexture, int originalWidth, int originalHeight) { _originalWidth = originalWidth; _originalHeight = originalHeight; - + gpu::Texture* texture = static_cast(voidTexture); - + // Passing ownership _textureSource->resetTexture(texture); auto gpuTexture = _textureSource->getGPUTexture(); From 7ea81f39379105104e8e3505b31025599c42dbe6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 3 Apr 2016 19:15:01 -0700 Subject: [PATCH 18/55] add and fix comments --- libraries/physics/src/ObjectMotionState.cpp | 5 ++++- libraries/physics/src/PhysicsEngine.cpp | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 6b2022e204..e902758461 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -38,8 +38,11 @@ const glm::vec3& ObjectMotionState::getWorldOffset() { return _worldOffset; } +// We init worldSimulationStep to 1 instead of 0 because we initialize _lastKineticStep to (worldSimulationStep - 1) +// so that the object starts moving on the first frame that it was set kinematic. +static uint32_t worldSimulationStep { 1 }; + // static -uint32_t worldSimulationStep = 1; void ObjectMotionState::setWorldSimulationStep(uint32_t step) { assert(step > worldSimulationStep); worldSimulationStep = step; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 973be0b4e8..be80149c96 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -50,6 +50,12 @@ void PhysicsEngine::init() { // default gravity of the world is zero, so each object must specify its own gravity // TODO: set up gravity zones _dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f)); + + // By default Bullet will update the Aabb's of all objects every frame, even statics. + // This can waste CPU cycles so we configure Bullet to only update ACTIVE objects here. + // However, this means when a static object is moved we must manually update its Aabb + // in order for its broadphase collision queries to work correctly. Look at how we use + // _activeStaticBodies to track and update the Aabb's of moved static objects. _dynamicsWorld->setForceUpdateAllAabbs(false); } } @@ -200,7 +206,7 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob } // active static bodies have changed (in an Easy way) and need their Aabbs updated // but we've configured Bullet to NOT update them automatically (for improved performance) - // so we must do it outselves + // so we must do it ourselves for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { _dynamicsWorld->updateSingleAabb(_activeStaticBodies[i]); } From 74058ac049336dbdf7a332b6458be7ee68b7e8f5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 3 Apr 2016 19:15:16 -0700 Subject: [PATCH 19/55] more correct moving test for ballistic kinematics --- libraries/entities/src/EntityItem.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5c825495b9..5b9791ca7b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -919,7 +919,8 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { } glm::vec3 linearAcceleration = _acceleration; - if (glm::length2(_acceleration) > 0.0f) { + bool nonZeroAcceleration = (glm::length2(_acceleration) > 0.0f); + if (nonZeroAcceleration) { // acceleration is in world-frame but we need it in local-frame bool success; Transform parentTransform = getParentTransform(success); @@ -928,17 +929,20 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { } } + // integrate position forward + glm::vec3 position = transform.getTranslation() + (linearVelocity * timeElapsed) + 0.5f * linearAcceleration * timeElapsed * timeElapsed; + transform.setTranslation(position); + // integrate linearVelocity linearVelocity += linearAcceleration * timeElapsed; const float EPSILON_LINEAR_VELOCITY_LENGTH_SQUARED = 1.0e-6f; // 1mm/sec ^2 if (glm::length2(linearVelocity) < EPSILON_LINEAR_VELOCITY_LENGTH_SQUARED) { setVelocity(ENTITY_ITEM_ZERO_VEC3); + if (nonZeroAcceleration) { + isMoving = true; + } } else { - // integrate position forward - // NOTE: we're using the NEW linear velocity, which is why we negate the acceleration term - glm::vec3 position = transform.getTranslation() + (linearVelocity * timeElapsed) - 0.5f * linearAcceleration * timeElapsed * timeElapsed; - transform.setTranslation(position); isMoving = true; } } From 4f373937f9dc94d54cf4da57fa612de801f9539d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 2 Apr 2016 20:37:11 -0700 Subject: [PATCH 20/55] Additional performance markers --- libraries/fbx/src/FBXReader_Node.cpp | 22 +++++++++++-------- libraries/fbx/src/OBJReader.cpp | 17 ++++++++------ .../src/model-networking/TextureCache.cpp | 4 ++++ libraries/shared/src/shared/NsightHelpers.h | 2 +- 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/libraries/fbx/src/FBXReader_Node.cpp b/libraries/fbx/src/FBXReader_Node.cpp index a6fba5a4d5..68e9d6abac 100644 --- a/libraries/fbx/src/FBXReader_Node.cpp +++ b/libraries/fbx/src/FBXReader_Node.cpp @@ -9,17 +9,20 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "FBXReader.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + template int streamSize() { return sizeof(T); } @@ -299,6 +302,7 @@ FBXNode parseTextFBXNode(Tokenizer& tokenizer) { } FBXNode FBXReader::parseFBX(QIODevice* device) { + PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, device); // verify the prolog const QByteArray BINARY_PROLOG = "Kaydara FBX Binary "; if (device->peek(BINARY_PROLOG.size()) != BINARY_PROLOG) { diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index c28d680fb0..84c6c7aaa4 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -12,17 +12,20 @@ // http://www.scratchapixel.com/old/lessons/3d-advanced-lessons/obj-file-format/obj-file-format/ // http://paulbourke.net/dataformats/obj/ +#include "OBJReader.h" -#include -#include -#include -#include -#include #include // .obj files are not locale-specific. The C/ASCII charset applies. +#include +#include +#include +#include +#include + +#include #include + #include "FBXReader.h" -#include "OBJReader.h" #include "ModelFormatLogging.h" QHash COMMENT_SCALE_HINTS = {{"This file uses centimeters as units", 1.0f / 100.0f}, @@ -404,7 +407,7 @@ done: FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, const QUrl& url) { - + PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, nullptr); QBuffer buffer { &model }; buffer.open(QIODevice::ReadOnly); diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 3ba36dc2da..6870fa9b72 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -21,6 +21,8 @@ #include #include #include + +#include #include #include @@ -278,6 +280,7 @@ void ImageReader::listSupportedImageFormats() { } void ImageReader::run() { + PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, nullptr); auto originalPriority = QThread::currentThread()->priority(); if (originalPriority == QThread::InheritPriority) { originalPriority = QThread::NormalPriority; @@ -315,6 +318,7 @@ void ImageReader::run() { gpu::Texture* theTexture = nullptr; auto ntex = texture.dynamicCast(); if (ntex) { + PROFILE_RANGE_EX(__FUNCTION__"::textureLoader", 0xffffff00, nullptr); theTexture = ntex->getTextureLoader()(image, _url.toString().toStdString()); } diff --git a/libraries/shared/src/shared/NsightHelpers.h b/libraries/shared/src/shared/NsightHelpers.h index 9853171b34..c637c78162 100644 --- a/libraries/shared/src/shared/NsightHelpers.h +++ b/libraries/shared/src/shared/NsightHelpers.h @@ -20,7 +20,7 @@ public: }; #define PROFILE_RANGE(name) ProfileRange profileRangeThis(name); -#define PROFILE_RANGE_EX(name, argbColor, payload) ProfileRange profileRangeThis(name, argbColor, payload); +#define PROFILE_RANGE_EX(name, argbColor, payload) ProfileRange profileRangeThis(name, argbColor, (uint64_t)payload); #else #define PROFILE_RANGE(name) #define PROFILE_RANGE_EX(name, argbColor, payload) From 667c27866ed152019f2a5e0762aacc592d4fa747 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 3 Apr 2016 20:15:42 -0700 Subject: [PATCH 21/55] Pushing texel format translation into header --- libraries/gpu/src/gpu/GLBackendTexture.cpp | 364 +------------------- libraries/gpu/src/gpu/GLTexelFormat.h | 372 +++++++++++++++++++++ 2 files changed, 373 insertions(+), 363 deletions(-) create mode 100644 libraries/gpu/src/gpu/GLTexelFormat.h diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 3fc7906285..242b9100e1 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -10,6 +10,7 @@ // #include "GPULogging.h" #include "GLBackendShared.h" +#include "GLTexelFormat.h" using namespace gpu; @@ -36,369 +37,6 @@ void GLBackend::GLTexture::setSize(GLuint size) { _size = size; } -class GLTexelFormat { -public: - GLenum internalFormat; - GLenum format; - GLenum type; - - static GLTexelFormat evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat) { - if (dstFormat != srcFormat) { - GLTexelFormat texel = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}; - - switch(dstFormat.getDimension()) { - case gpu::SCALAR: { - texel.format = GL_RED; - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - texel.internalFormat = GL_RED; - break; - case gpu::DEPTH: - texel.internalFormat = GL_DEPTH_COMPONENT; - break; - case gpu::DEPTH_STENCIL: - texel.type = GL_UNSIGNED_INT_24_8; - texel.format = GL_DEPTH_STENCIL; - texel.internalFormat = GL_DEPTH24_STENCIL8; - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - break; - } - - case gpu::VEC2: { - texel.format = GL_RG; - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - texel.internalFormat = GL_RG; - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - - break; - } - - case gpu::VEC3: { - texel.format = GL_RGB; - - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - texel.internalFormat = GL_RGB; - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - - break; - } - - case gpu::VEC4: { - texel.format = GL_RGBA; - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(srcFormat.getSemantic()) { - case gpu::BGRA: - case gpu::SBGRA: - texel.format = GL_BGRA; - break; - case gpu::RGB: - case gpu::RGBA: - case gpu::SRGB: - case gpu::SRGBA: - default: - break; - }; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - texel.internalFormat = GL_RGB; - break; - case gpu::RGBA: - texel.internalFormat = GL_RGBA; - break; - case gpu::SRGB: - texel.internalFormat = GL_SRGB; - break; - case gpu::SRGBA: - texel.internalFormat = GL_SRGB_ALPHA; - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - break; - } - - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - return texel; - } else { - GLTexelFormat texel = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}; - - switch(dstFormat.getDimension()) { - case gpu::SCALAR: { - texel.format = GL_RED; - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - case gpu::SRGB: - case gpu::SRGBA: - texel.internalFormat = GL_RED; - switch (dstFormat.getType()) { - case gpu::UINT32: { - texel.internalFormat = GL_R32UI; - break; - } - case gpu::INT32: { - texel.internalFormat = GL_R32I; - break; - } - case gpu::NUINT32: { - texel.internalFormat = GL_RED; - break; - } - case gpu::NINT32: { - texel.internalFormat = GL_RED_SNORM; - break; - } - case gpu::FLOAT: { - texel.internalFormat = GL_R32F; - break; - } - case gpu::UINT16: { - texel.internalFormat = GL_R16UI; - break; - } - case gpu::INT16: { - texel.internalFormat = GL_R16I; - break; - } - case gpu::NUINT16: { - texel.internalFormat = GL_R16; - break; - } - case gpu::NINT16: { - texel.internalFormat = GL_R16_SNORM; - break; - } - case gpu::HALF: { - texel.internalFormat = GL_R16F; - break; - } - case gpu::UINT8: { - texel.internalFormat = GL_R8UI; - break; - } - case gpu::INT8: { - texel.internalFormat = GL_R8I; - break; - } - case gpu::NUINT8: { - if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) { - texel.internalFormat = GL_SLUMINANCE; - } else { - texel.internalFormat = GL_R8; - } - break; - } - case gpu::NINT8: { - texel.internalFormat = GL_R8_SNORM; - break; - } - case gpu::NUM_TYPES: { // quiet compiler - Q_UNREACHABLE(); - } - - } - break; - - case gpu::R11G11B10: - texel.format = GL_RGB; - // the type should be float - texel.internalFormat = GL_R11F_G11F_B10F; - break; - - case gpu::DEPTH: - texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it - texel.internalFormat = GL_DEPTH_COMPONENT; - switch (dstFormat.getType()) { - case gpu::UINT32: - case gpu::INT32: - case gpu::NUINT32: - case gpu::NINT32: { - texel.internalFormat = GL_DEPTH_COMPONENT32; - break; - } - case gpu::FLOAT: { - texel.internalFormat = GL_DEPTH_COMPONENT32F; - break; - } - case gpu::UINT16: - case gpu::INT16: - case gpu::NUINT16: - case gpu::NINT16: - case gpu::HALF: { - texel.internalFormat = GL_DEPTH_COMPONENT16; - break; - } - case gpu::UINT8: - case gpu::INT8: - case gpu::NUINT8: - case gpu::NINT8: { - texel.internalFormat = GL_DEPTH_COMPONENT24; - break; - } - case gpu::NUM_TYPES: { // quiet compiler - Q_UNREACHABLE(); - } - } - break; - case gpu::DEPTH_STENCIL: - texel.type = GL_UNSIGNED_INT_24_8; - texel.format = GL_DEPTH_STENCIL; - texel.internalFormat = GL_DEPTH24_STENCIL8; - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - - break; - } - - case gpu::VEC2: { - texel.format = GL_RG; - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - texel.internalFormat = GL_RG; - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - - break; - } - - case gpu::VEC3: { - texel.format = GL_RGB; - - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - texel.internalFormat = GL_RGB; - break; - case gpu::SRGB: - case gpu::SRGBA: - texel.internalFormat = GL_SRGB; // standard 2.2 gamma correction color - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - break; - } - - case gpu::VEC4: { - texel.format = GL_RGBA; - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - texel.internalFormat = GL_RGB; - break; - case gpu::RGBA: - texel.internalFormat = GL_RGBA; - switch (dstFormat.getType()) { - case gpu::UINT32: - texel.format = GL_RGBA_INTEGER; - texel.internalFormat = GL_RGBA32UI; - break; - case gpu::INT32: - texel.format = GL_RGBA_INTEGER; - texel.internalFormat = GL_RGBA32I; - break; - case gpu::FLOAT: - texel.internalFormat = GL_RGBA32F; - break; - case gpu::UINT16: - texel.format = GL_RGBA_INTEGER; - texel.internalFormat = GL_RGBA16UI; - break; - case gpu::INT16: - texel.format = GL_RGBA_INTEGER; - texel.internalFormat = GL_RGBA16I; - break; - case gpu::NUINT16: - texel.format = GL_RGBA; - texel.internalFormat = GL_RGBA16; - break; - case gpu::NINT16: - texel.format = GL_RGBA; - texel.internalFormat = GL_RGBA16_SNORM; - break; - case gpu::HALF: - texel.format = GL_RGBA; - texel.internalFormat = GL_RGBA16F; - break; - case gpu::UINT8: - texel.format = GL_RGBA_INTEGER; - texel.internalFormat = GL_RGBA8UI; - break; - case gpu::INT8: - texel.format = GL_RGBA_INTEGER; - texel.internalFormat = GL_RGBA8I; - break; - case gpu::NUINT8: - texel.format = GL_RGBA; - texel.internalFormat = GL_RGBA8; - break; - case gpu::NINT8: - texel.format = GL_RGBA; - texel.internalFormat = GL_RGBA8_SNORM; - break; - case gpu::NUINT32: - case gpu::NINT32: - case gpu::NUM_TYPES: // quiet compiler - Q_UNREACHABLE(); - } - break; - case gpu::SRGB: - texel.internalFormat = GL_SRGB; - break; - case gpu::SRGBA: - texel.internalFormat = GL_SRGB_ALPHA; // standard 2.2 gamma correction color - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - break; - } - - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - return texel; - } - } -}; - - GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { GLTexture* object = Backend::getGPUObject(texture); diff --git a/libraries/gpu/src/gpu/GLTexelFormat.h b/libraries/gpu/src/gpu/GLTexelFormat.h new file mode 100644 index 0000000000..274b5eeba3 --- /dev/null +++ b/libraries/gpu/src/gpu/GLTexelFormat.h @@ -0,0 +1,372 @@ +// +// Created by Bradley Austin Davis on 2016/04/03 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLBackendShared.h" + +class GLTexelFormat { +public: + GLenum internalFormat; + GLenum format; + GLenum type; + + static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat, const gpu::Element& srcFormat) { + using namespace gpu; + if (dstFormat != srcFormat) { + GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }; + + switch (dstFormat.getDimension()) { + case gpu::SCALAR: { + texel.format = GL_RED; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_R8; + break; + case gpu::DEPTH: + texel.internalFormat = GL_DEPTH_COMPONENT32; + break; + case gpu::DEPTH_STENCIL: + texel.type = GL_UNSIGNED_INT_24_8; + texel.format = GL_DEPTH_STENCIL; + texel.internalFormat = GL_DEPTH24_STENCIL8; + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + break; + } + + case gpu::VEC2: { + texel.format = GL_RG; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RG8; + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC3: { + texel.format = GL_RGB; + + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RGB8; + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC4: { + texel.format = GL_RGBA; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (srcFormat.getSemantic()) { + case gpu::BGRA: + case gpu::SBGRA: + texel.format = GL_BGRA; + break; + case gpu::RGB: + case gpu::RGBA: + case gpu::SRGB: + case gpu::SRGBA: + default: + break; + }; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + texel.internalFormat = GL_RGB8; + break; + case gpu::RGBA: + texel.internalFormat = GL_RGBA8; + break; + case gpu::SRGB: + texel.internalFormat = GL_SRGB8; + break; + case gpu::SRGBA: + texel.internalFormat = GL_SRGB8_ALPHA8; + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + break; + } + + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + return texel; + } else { + GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }; + + switch (dstFormat.getDimension()) { + case gpu::SCALAR: { + texel.format = GL_RED; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + case gpu::SRGB: + case gpu::SRGBA: + texel.internalFormat = GL_R8; + switch (dstFormat.getType()) { + case gpu::UINT32: { + texel.internalFormat = GL_R32UI; + break; + } + case gpu::INT32: { + texel.internalFormat = GL_R32I; + break; + } + case gpu::NUINT32: { + texel.internalFormat = GL_R8; + break; + } + case gpu::NINT32: { + texel.internalFormat = GL_R8_SNORM; + break; + } + case gpu::FLOAT: { + texel.internalFormat = GL_R32F; + break; + } + case gpu::UINT16: { + texel.internalFormat = GL_R16UI; + break; + } + case gpu::INT16: { + texel.internalFormat = GL_R16I; + break; + } + case gpu::NUINT16: { + texel.internalFormat = GL_R16; + break; + } + case gpu::NINT16: { + texel.internalFormat = GL_R16_SNORM; + break; + } + case gpu::HALF: { + texel.internalFormat = GL_R16F; + break; + } + case gpu::UINT8: { + texel.internalFormat = GL_R8UI; + break; + } + case gpu::INT8: { + texel.internalFormat = GL_R8I; + break; + } + case gpu::NUINT8: { + if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) { + texel.internalFormat = GL_SLUMINANCE8; + } else { + texel.internalFormat = GL_R8; + } + break; + } + case gpu::NINT8: { + texel.internalFormat = GL_R8_SNORM; + break; + } + case gpu::NUM_TYPES: { // quiet compiler + Q_UNREACHABLE(); + } + + } + break; + + case gpu::R11G11B10: + texel.format = GL_RGB; + // the type should be float + texel.internalFormat = GL_R11F_G11F_B10F; + break; + + case gpu::DEPTH: + texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it + texel.internalFormat = GL_DEPTH_COMPONENT32; + switch (dstFormat.getType()) { + case gpu::UINT32: + case gpu::INT32: + case gpu::NUINT32: + case gpu::NINT32: { + texel.internalFormat = GL_DEPTH_COMPONENT32; + break; + } + case gpu::FLOAT: { + texel.internalFormat = GL_DEPTH_COMPONENT32F; + break; + } + case gpu::UINT16: + case gpu::INT16: + case gpu::NUINT16: + case gpu::NINT16: + case gpu::HALF: { + texel.internalFormat = GL_DEPTH_COMPONENT16; + break; + } + case gpu::UINT8: + case gpu::INT8: + case gpu::NUINT8: + case gpu::NINT8: { + texel.internalFormat = GL_DEPTH_COMPONENT24; + break; + } + case gpu::NUM_TYPES: { // quiet compiler + Q_UNREACHABLE(); + } + } + break; + case gpu::DEPTH_STENCIL: + texel.type = GL_UNSIGNED_INT_24_8; + texel.format = GL_DEPTH_STENCIL; + texel.internalFormat = GL_DEPTH24_STENCIL8; + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC2: { + texel.format = GL_RG; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RG8; + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC3: { + texel.format = GL_RGB; + + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RGB8; + break; + case gpu::SRGB: + case gpu::SRGBA: + texel.internalFormat = GL_SRGB8; // standard 2.2 gamma correction color + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + break; + } + + case gpu::VEC4: { + texel.format = GL_RGBA; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + texel.internalFormat = GL_RGB8; + break; + case gpu::RGBA: + texel.internalFormat = GL_RGBA8; + switch (dstFormat.getType()) { + case gpu::UINT32: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA32UI; + break; + case gpu::INT32: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA32I; + break; + case gpu::FLOAT: + texel.internalFormat = GL_RGBA32F; + break; + case gpu::UINT16: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA16UI; + break; + case gpu::INT16: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA16I; + break; + case gpu::NUINT16: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA16; + break; + case gpu::NINT16: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA16_SNORM; + break; + case gpu::HALF: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA16F; + break; + case gpu::UINT8: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA8UI; + break; + case gpu::INT8: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA8I; + break; + case gpu::NUINT8: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA8; + break; + case gpu::NINT8: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA8_SNORM; + break; + case gpu::NUINT32: + case gpu::NINT32: + case gpu::NUM_TYPES: // quiet compiler + Q_UNREACHABLE(); + } + break; + case gpu::SRGB: + texel.internalFormat = GL_SRGB8; + break; + case gpu::SRGBA: + texel.internalFormat = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + break; + } + + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + return texel; + } + } +}; From b2058376ba38c4df8418197a5013386a6555dad2 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Mon, 4 Apr 2016 17:03:05 +0200 Subject: [PATCH 22/55] used "ReSharper C++" to fix some style and spelling in Application.(h|cpp) --- interface/src/Application.cpp | 182 +++++++++++++++------------------- interface/src/Application.h | 85 ++++++++-------- 2 files changed, 123 insertions(+), 144 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 61d0f4f995..0130df4a73 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -18,23 +18,12 @@ #include #include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include -#include -#include #include -#include -#include #include #include @@ -44,28 +33,18 @@ #include #include -#include #include -#include -#include -#include #include #include -#include - -#include #include -#include - #include #include #include #include #include -#include #include #include #include @@ -110,12 +89,9 @@ #include #include #include -#include #include #include #include -#include -#include #include #include #include @@ -137,7 +113,6 @@ #include "InterfaceActionFactory.h" #include "InterfaceLogging.h" #include "LODManager.h" -#include "Menu.h" #include "ModelPackager.h" #include "PluginContainerProxy.h" #include "scripting/AccountScriptingInterface.h" @@ -171,7 +146,7 @@ -// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU +// ON Windows PC, Nvidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. #if defined(Q_OS_WIN) extern "C" { @@ -254,14 +229,14 @@ public: }); } - void updateHeartbeat() { + static void updateHeartbeat() { auto now = usecTimestampNow(); auto elapsed = now - _heartbeat; _movingAverage.addSample(elapsed); _heartbeat = now; } - void deadlockDetectionCrash() { + static void deadlockDetectionCrash() { uint32_t* crashTrigger = nullptr; *crashTrigger = 0xDEAD10CC; } @@ -390,11 +365,11 @@ public: LambdaEvent(std::function && fun) : QEvent(static_cast(Lambda)), _fun(fun) { } - void call() { _fun(); } + void call() const { _fun(); } }; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); + QString logMessage = LogHandler::getInstance().printMessage(static_cast(type), context, message); if (!logMessage.isEmpty()) { #ifdef Q_OS_WIN @@ -528,7 +503,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _maxOctreePPS(maxOctreePacketsPerSecond.get()), _lastFaceTrackerUpdate(0) { - // FIXME this may be excessivly conservative. On the other hand + // FIXME this may be excessively conservative. On the other hand // maybe I'm used to having an 8-core machine // Perhaps find the ideal thread count and subtract 2 or 3 // (main thread, present thread, random OS load) @@ -940,13 +915,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _applicationStateDevice = std::make_shared(); _applicationStateDevice->addInputVariant(QString("InHMD"), controller::StateController::ReadLambda([]() -> float { - return (float)qApp->isHMDMode(); + return static_cast(qApp->isHMDMode()); })); _applicationStateDevice->addInputVariant(QString("SnapTurn"), controller::StateController::ReadLambda([]() -> float { - return (float)qApp->getMyAvatar()->getSnapTurn(); + return static_cast(qApp->getMyAvatar()->getSnapTurn()); })); _applicationStateDevice->addInputVariant(QString("Grounded"), controller::StateController::ReadLambda([]() -> float { - return (float)qApp->getMyAvatar()->getCharacterController()->onGround(); + return static_cast(qApp->getMyAvatar()->getCharacterController()->onGround()); })); _applicationStateDevice->addInputVariant(QString("NavigationFocused"), controller::StateController::ReadLambda([]() -> float { auto offscreenUi = DependencyManager::get(); @@ -1014,12 +989,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), &DialogsManager::showUpdateDialog); applicationUpdater->checkForUpdate(); - // Now that menu is initalized we can sync myAvatar with it's state. + // Now that menu is initialized we can sync myAvatar with it's state. getMyAvatar()->updateMotionBehaviorFromMenu(); // FIXME spacemouse code still needs cleanup #if 0 - // the 3Dconnexion device wants to be initiliazed after a window is displayed. + // the 3Dconnexion device wants to be initialized after a window is displayed. SpacemouseManager::getInstance().init(); #endif @@ -1124,7 +1099,7 @@ void Application::showCursor(const QCursor& cursor) { _cursorNeedsChanging = true; } -void Application::updateHeartbeat() { +void Application::updateHeartbeat() const { static_cast(_deadlockWatchdogThread)->updateHeartbeat(); } @@ -1218,12 +1193,12 @@ void Application::cleanupBeforeQuit() { Application::~Application() { EntityTreePointer tree = getEntities()->getTree(); - tree->setSimulation(NULL); + tree->setSimulation(nullptr); _octreeProcessor.terminate(); _entityEditSender.terminate(); - _physicsEngine->setCharacterController(NULL); + _physicsEngine->setCharacterController(nullptr); ModelEntityItem::cleanupLoadedAnimations(); @@ -1264,7 +1239,7 @@ Application::~Application() { _window->deleteLater(); - qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages + qInstallMessageHandler(nullptr); // NOTE: Do this as late as possible so we continue to get our log messages } void Application::initializeGL() { @@ -1467,7 +1442,7 @@ void Application::paintGL() { uint64_t diff = now - lastPaintBegin; float instantaneousFps = 0.0f; if (diff != 0) { - instantaneousFps = (float)USECS_PER_SECOND / (float)diff; + instantaneousFps = static_cast(USECS_PER_SECOND) / static_cast(diff); _framesPerSecond.updateAverage(_lastInstantaneousFps); } @@ -1479,7 +1454,7 @@ void Application::paintGL() { _lastFramesPerSecondUpdate = now; } - PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, (uint64_t)_frameCount); + PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, static_cast(_frameCount)); PerformanceTimer perfTimer("paintGL"); if (nullptr == _displayPlugin) { @@ -1744,7 +1719,7 @@ void Application::runTests() { runUnitTests(); } -void Application::audioMuteToggled() { +void Application::audioMuteToggled() const { QAction* muteAction = Menu::getInstance()->getActionForOption(MenuOption::MuteAudio); Q_CHECK_PTR(muteAction); muteAction->setChecked(DependencyManager::get()->isMuted()); @@ -1825,12 +1800,12 @@ bool Application::event(QEvent* event) { return false; } - if ((int)event->type() == (int)Lambda) { - ((LambdaEvent*)event)->call(); + if (static_cast(event->type()) == static_cast(Lambda)) { + static_cast(event)->call(); return true; } - if ((int)event->type() == (int)Paint) { + if (static_cast(event->type()) == static_cast(Paint)) { paintGL(); return true; } @@ -1860,25 +1835,25 @@ bool Application::event(QEvent* event) { switch (event->type()) { case QEvent::MouseMove: - mouseMoveEvent((QMouseEvent*)event); + mouseMoveEvent(static_cast(event)); return true; case QEvent::MouseButtonPress: - mousePressEvent((QMouseEvent*)event); + mousePressEvent(static_cast(event)); return true; case QEvent::MouseButtonDblClick: - mouseDoublePressEvent((QMouseEvent*)event); + mouseDoublePressEvent(static_cast(event)); return true; case QEvent::MouseButtonRelease: - mouseReleaseEvent((QMouseEvent*)event); + mouseReleaseEvent(static_cast(event)); return true; case QEvent::KeyPress: - keyPressEvent((QKeyEvent*)event); + keyPressEvent(static_cast(event)); return true; case QEvent::KeyRelease: - keyReleaseEvent((QKeyEvent*)event); + keyReleaseEvent(static_cast(event)); return true; case QEvent::FocusOut: - focusOutEvent((QFocusEvent*)event); + focusOutEvent(static_cast(event)); return true; case QEvent::TouchBegin: touchBeginEvent(static_cast(event)); @@ -2306,13 +2281,13 @@ void Application::focusOutEvent(QFocusEvent* event) { // synthesize events for keys currently pressed, since we may not get their release events foreach (int key, _keysPressed) { - QKeyEvent event(QEvent::KeyRelease, key, Qt::NoModifier); - keyReleaseEvent(&event); + QKeyEvent keyEvent(QEvent::KeyRelease, key, Qt::NoModifier); + keyReleaseEvent(&keyEvent); } _keysPressed.clear(); } -void Application::maybeToggleMenuVisible(QMouseEvent* event) { +void Application::maybeToggleMenuVisible(QMouseEvent* event) const { #ifndef Q_OS_MAC // If in full screen, and our main windows menu bar is hidden, and we're close to the top of the QMainWindow // then show the menubar. @@ -2428,7 +2403,7 @@ void Application::mousePressEvent(QMouseEvent* event) { } } -void Application::mouseDoublePressEvent(QMouseEvent* event) { +void Application::mouseDoublePressEvent(QMouseEvent* event) const { // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { return; @@ -2528,7 +2503,7 @@ void Application::touchEndEvent(QTouchEvent* event) { // put any application specific touch behavior below here.. } -void Application::wheelEvent(QWheelEvent* event) { +void Application::wheelEvent(QWheelEvent* event) const { _altPressed = false; _controllerScriptingInterface->emitWheelEvent(event); // send events to any registered scripts @@ -2599,7 +2574,7 @@ void Application::idle(uint64_t now) { bool isThrottled = displayPlugin->isThrottled(); // Only run simulation code if more than the targetFramePeriod have passed since last time we ran // This attempts to lock the simulation at 60 updates per second, regardless of framerate - float timeSinceLastUpdateUs = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_USEC; + float timeSinceLastUpdateUs = static_cast(_lastTimeUpdated.nsecsElapsed()) / NSECS_PER_USEC; float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND; if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) { @@ -2639,7 +2614,7 @@ void Application::idle(uint64_t now) { static uint64_t lastIdleStart{ now }; uint64_t idleStartToStartDuration = now - lastIdleStart; if (idleStartToStartDuration != 0) { - _simsPerSecond.updateAverage((float)USECS_PER_SECOND / (float)idleStartToStartDuration); + _simsPerSecond.updateAverage(static_cast(USECS_PER_SECOND) / static_cast(idleStartToStartDuration)); } lastIdleStart = now; } @@ -2707,9 +2682,11 @@ float Application::getAverageSimsPerSecond() { } return _simsPerSecondReport; } + void Application::setAvatarSimrateSample(float sample) { _avatarSimsPerSecond.updateAverage(sample); } + float Application::getAvatarSimrate() { uint64_t now = usecTimestampNow(); @@ -2724,7 +2701,7 @@ void Application::setLowVelocityFilter(bool lowVelocityFilter) { controller::InputDevice::setLowVelocityFilter(lowVelocityFilter); } -ivec2 Application::getMouse() { +ivec2 Application::getMouse() const { auto reticlePosition = getApplicationCompositor().getReticlePosition(); // in the HMD, the reticlePosition is the mouse position @@ -2741,11 +2718,11 @@ FaceTracker* Application::getActiveFaceTracker() { auto dde = DependencyManager::get(); return (dde->isActive() ? static_cast(dde.data()) : - (faceshift->isActive() ? static_cast(faceshift.data()) : NULL)); + (faceshift->isActive() ? static_cast(faceshift.data()) : nullptr)); } FaceTracker* Application::getSelectedFaceTracker() { - FaceTracker* faceTracker = NULL; + FaceTracker* faceTracker = nullptr; #ifdef HAVE_FACESHIFT if (Menu::getInstance()->isOptionChecked(MenuOption::Faceshift)) { faceTracker = DependencyManager::get().data(); @@ -2759,7 +2736,7 @@ FaceTracker* Application::getSelectedFaceTracker() { return faceTracker; } -void Application::setActiveFaceTracker() { +void Application::setActiveFaceTracker() const { #if defined(HAVE_FACESHIFT) || defined(HAVE_DDE) bool isMuted = Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking); #endif @@ -2896,7 +2873,7 @@ void Application::loadSettings() { _settingsLoaded = true; } -void Application::saveSettings() { +void Application::saveSettings() const { sessionRunTime.set(_sessionRunTimer.elapsed() / MSECS_PER_SEC); DependencyManager::get()->saveSettings(); DependencyManager::get()->saveSettings(); @@ -2986,7 +2963,7 @@ void Application::init() { connect(getMyAvatar(), &MyAvatar::newCollisionSoundURL, DependencyManager::get().data(), &SoundCache::getSound); } -void Application::updateLOD() { +void Application::updateLOD() const { PerformanceTimer perfTimer("LOD"); // adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode if (!isThrottleRendering()) { @@ -3188,13 +3165,13 @@ void Application::reloadResourceCaches() { getMyAvatar()->resetFullAvatarURL(); } -void Application::rotationModeChanged() { +void Application::rotationModeChanged() const { if (!Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { getMyAvatar()->setHeadPitch(0); } } -void Application::updateDialogs(float deltaTime) { +void Application::updateDialogs(float deltaTime) const { PerformanceTimer perfTimer("updateDialogs"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateDialogs()"); @@ -3220,7 +3197,7 @@ void Application::updateDialogs(float deltaTime) { void Application::update(float deltaTime) { - PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, (uint64_t)_frameCount + 1); + PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, static_cast(_frameCount) + 1); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::update()"); @@ -3230,7 +3207,7 @@ void Application::update(float deltaTime) { if (!_physicsEnabled && _processOctreeStatsCounter > 0) { // process octree stats packets are sent in between full sends of a scene. - // We keep physics disabled until we've recieved a full scene and everything near the avatar in that + // We keep physics disabled until we've received a full scene and everything near the avatar in that // scene is ready to compute its collision shape. if (nearbyEntitiesAreReadyForPhysics()) { @@ -3380,14 +3357,14 @@ void Application::update(float deltaTime) { }); } { - PROFILE_RANGE_EX("StepSimulation", 0xffff8000, (uint64_t)getActiveDisplayPlugin()->presentCount()); + PROFILE_RANGE_EX("StepSimulation", 0xffff8000, static_cast(getActiveDisplayPlugin()->presentCount())); PerformanceTimer perfTimer("stepSimulation"); getEntities()->getTree()->withWriteLock([&] { _physicsEngine->stepSimulation(); }); } { - PROFILE_RANGE_EX("HarvestChanges", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount()); + PROFILE_RANGE_EX("HarvestChanges", 0xffffff00, static_cast(getActiveDisplayPlugin()->presentCount())); PerformanceTimer perfTimer("harvestChanges"); if (_physicsEngine->hasOutgoingChanges()) { getEntities()->getTree()->withWriteLock([&] { @@ -3425,20 +3402,20 @@ void Application::update(float deltaTime) { qApp->setAvatarSimrateSample(1.0f / deltaTime); { - PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount()); + PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, static_cast(getActiveDisplayPlugin()->presentCount())); avatarManager->updateOtherAvatars(deltaTime); } qApp->updateMyAvatarLookAtPosition(); { - PROFILE_RANGE_EX("MyAvatar", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount()); + PROFILE_RANGE_EX("MyAvatar", 0xffff00ff, static_cast(getActiveDisplayPlugin()->presentCount())); avatarManager->updateMyAvatar(deltaTime); } } { - PROFILE_RANGE_EX("Overlays", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount()); + PROFILE_RANGE_EX("Overlays", 0xffff0000, static_cast(getActiveDisplayPlugin()->presentCount())); PerformanceTimer perfTimer("overlays"); _overlays.update(deltaTime); } @@ -3458,7 +3435,7 @@ void Application::update(float deltaTime) { // Update my voxel servers with my current voxel query... { - PROFILE_RANGE_EX("QueryOctree", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount()); + PROFILE_RANGE_EX("QueryOctree", 0xffff0000, static_cast(getActiveDisplayPlugin()->presentCount())); PerformanceTimer perfTimer("queryOctree"); quint64 sinceLastQuery = now - _lastQueriedTime; const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; @@ -3497,7 +3474,7 @@ void Application::update(float deltaTime) { } { - PROFILE_RANGE_EX("PreRenderLambdas", 0xffff0000, (uint64_t)0); + PROFILE_RANGE_EX("PreRenderLambdas", 0xffff0000, static_cast(0)); std::unique_lock guard(_preRenderLambdasLock); for (auto& iter : _preRenderLambdas) { @@ -3535,7 +3512,7 @@ int Application::sendNackPackets() { QSet missingSequenceNumbers; _octreeServerSceneStats.withReadLock([&] { - // retreive octree scene stats of this node + // retrieve octree scene stats of this node if (_octreeServerSceneStats.find(nodeUUID) == _octreeServerSceneStats.end()) { return; } @@ -3551,7 +3528,7 @@ int Application::sendNackPackets() { } if (nackPacketList->getNumPackets()) { - packetsSent += (int)nackPacketList->getNumPackets(); + packetsSent += static_cast(nackPacketList->getNumPackets()); // send the packet list nodeList->sendPacketList(std::move(nackPacketList), *node); @@ -3735,7 +3712,7 @@ bool Application::isHMDMode() const { } float Application::getTargetFrameRate() { return getActiveDisplayPlugin()->getTargetFrameRate(); } -QRect Application::getDesirableApplicationGeometry() { +QRect Application::getDesirableApplicationGeometry() const { QRect applicationGeometry = getWindow()->geometry(); // If our parent window is on the HMD, then don't use its geometry, instead use @@ -3748,7 +3725,7 @@ QRect Application::getDesirableApplicationGeometry() { // if our app's screen is the hmd screen, we don't want to place the // running scripts widget on it. So we need to pick a better screen. - // we will use the screen for the HMDTools since it's a guarenteed + // we will use the screen for the HMDTools since it's a guaranteed // better screen. if (appScreen == hmdScreen) { QScreen* betterScreen = hmdTools->windowHandle()->screen(); @@ -3777,7 +3754,7 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { viewFrustum.calculate(); } -glm::vec3 Application::getSunDirection() { +glm::vec3 Application::getSunDirection() const { // Sun direction is in fact just the location of the sun relative to the origin auto skyStage = DependencyManager::get()->getSkyStage(); return skyStage->getSunLight()->getDirection(); @@ -3979,7 +3956,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE; if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) { - renderDebugFlags = (RenderArgs::DebugFlags) (renderDebugFlags | (int)RenderArgs::RENDER_DEBUG_HULLS); + renderDebugFlags = static_cast(renderDebugFlags | + static_cast(RenderArgs::RENDER_DEBUG_HULLS)); } renderArgs->_debugFlags = renderDebugFlags; //ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, pendingChanges); @@ -4033,7 +4011,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi auto originalViewport = renderArgs->_viewport; // Grab current viewport to reset it at the end - float aspect = (float)region.width() / region.height(); + float aspect = static_cast(region.width()) / region.height(); float fov = MIRROR_FIELD_OF_VIEW; auto myAvatar = getMyAvatar(); @@ -4044,7 +4022,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_BODY_DISTANCE * myAvatar->getScale()); } else { // HEAD zoom level - // FIXME note that the positioing of the camera relative to the avatar can suffer limited + // FIXME note that the positioning of the camera relative to the avatar can suffer limited // precision as the user's position moves further away from the origin. Thus at // /1e7,1e7,1e7 (well outside the buildable volume) the mirror camera veers and sways // wildly as you rotate your avatar because the floating point values are becoming @@ -4069,7 +4047,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi // set the bounds of rear mirror view // the region is in device independent coordinates; must convert to device - float ratio = (float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale(); + float ratio = static_cast(QApplication::desktop()->windowHandle()->devicePixelRatio()) * getRenderResolutionScale(); int width = region.width() * ratio; int height = region.height() * ratio; gpu::Vec4i viewport = gpu::Vec4i(0, 0, width, height); @@ -4090,7 +4068,7 @@ void Application::resetSensors(bool andReload) { QMetaObject::invokeMethod(DependencyManager::get().data(), "reset", Qt::QueuedConnection); } -void Application::updateWindowTitle(){ +void Application::updateWindowTitle() const { QString buildVersion = " (build " + applicationVersion() + ")"; auto nodeList = DependencyManager::get(); @@ -4148,14 +4126,14 @@ void Application::resettingDomain() { _notifiedPacketVersionMismatchThisDomain = false; } -void Application::nodeAdded(SharedNodePointer node) { +void Application::nodeAdded(SharedNodePointer node) const { if (node->getType() == NodeType::AvatarMixer) { // new avatar mixer, send off our identity packet right away getMyAvatar()->sendIdentityPacket(); } } -void Application::nodeActivated(SharedNodePointer node) { +void Application::nodeActivated(SharedNodePointer node) const { if (node->getType() == NodeType::AssetServer) { // asset server just connected - check if we have the asset browser showing @@ -4289,7 +4267,7 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer statsMessageLength = octreeStats.unpackFromPacket(message); // see if this is the first we've heard of this node... - NodeToJurisdictionMap* jurisdiction = NULL; + NodeToJurisdictionMap* jurisdiction = nullptr; QString serverType; if (sendingNode->getType() == NodeType::EntityServer) { jurisdiction = &_entityServerJurisdictions; @@ -4445,7 +4423,7 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) { return defaultUpload; } -void Application::setSessionUUID(const QUuid& sessionUUID) { +void Application::setSessionUUID(const QUuid& sessionUUID) const { // HACK: until we swap the library dependency order between physics and entities // we cache the sessionID in two distinct places for physics. Physics::setSessionUUID(sessionUUID); // TODO: remove this one @@ -4586,7 +4564,7 @@ bool Application::displayAvatarAttachmentConfirmationDialog(const QString& name) } } -void Application::toggleRunningScriptsWidget() { +void Application::toggleRunningScriptsWidget() const { static const QUrl url("hifi/dialogs/RunningScripts.qml"); DependencyManager::get()->show(url, "RunningScripts"); //if (_runningScriptsWidget->isVisible()) { @@ -4623,7 +4601,7 @@ void Application::packageModel() { ModelPackager::package(); } -void Application::openUrl(const QUrl& url) { +void Application::openUrl(const QUrl& url) const { if (!url.isEmpty()) { if (url.scheme() == HIFI_URL_SCHEME) { DependencyManager::get()->handleLookupString(url.toString()); @@ -4653,7 +4631,7 @@ void Application::setPreviousScriptLocation(const QString& location) { _previousScriptLocation.set(location); } -void Application::loadScriptURLDialog() { +void Application::loadScriptURLDialog() const { auto newScript = OffscreenUi::getText(nullptr, "Open and Run Script", "Script URL"); if (!newScript.isEmpty()) { DependencyManager::get()->loadScript(newScript); @@ -4718,7 +4696,7 @@ void Application::notifyPacketVersionMismatch() { } } -void Application::checkSkeleton() { +void Application::checkSkeleton() const { if (getMyAvatar()->getSkeletonModel()->isActive() && !getMyAvatar()->getSkeletonModel()->hasSkeleton()) { qCDebug(interfaceapp) << "MyAvatar model has no skeleton"; @@ -4799,7 +4777,7 @@ void Application::setMaxOctreePacketsPerSecond(int maxOctreePPS) { } } -int Application::getMaxOctreePacketsPerSecond() { +int Application::getMaxOctreePacketsPerSecond() const { return _maxOctreePPS; } @@ -4823,7 +4801,7 @@ DisplayPlugin* Application::getActiveDisplayPlugin() { } const DisplayPlugin* Application::getActiveDisplayPlugin() const { - return ((Application*)this)->getActiveDisplayPlugin(); + return const_cast(this)->getActiveDisplayPlugin(); } static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) { @@ -4903,7 +4881,7 @@ void Application::updateDisplayMode() { } } - // concactonate the groupings into a single list in the order: standard, advanced, developer + // concatenate the groupings into a single list in the order: standard, advanced, developer standard.insert(std::end(standard), std::begin(advanced), std::end(advanced)); standard.insert(std::end(standard), std::begin(developer), std::end(developer)); @@ -4915,7 +4893,7 @@ void Application::updateDisplayMode() { first = false; } - // after all plugins have been added to the menu, add a seperator to the menu + // after all plugins have been added to the menu, add a separator to the menu auto menu = Menu::getInstance(); auto parent = menu->getMenu(MenuOption::OutputMenu); parent->addSeparator(); @@ -4986,7 +4964,7 @@ void Application::updateDisplayMode() { emit activeDisplayPluginChanged(); - // reset the avatar, to set head and hand palms back to a resonable default pose. + // reset the avatar, to set head and hand palms back to a reasonable default pose. getMyAvatar()->reset(false); Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin"); @@ -5115,7 +5093,7 @@ void Application::setActiveDisplayPlugin(const QString& pluginName) { updateDisplayMode(); } -void Application::handleLocalServerConnection() { +void Application::handleLocalServerConnection() const { auto server = qobject_cast(sender()); qDebug() << "Got connection on local server from additional instance - waiting for parameters"; @@ -5128,7 +5106,7 @@ void Application::handleLocalServerConnection() { qApp->getWindow()->activateWindow(); } -void Application::readArgumentsFromLocalSocket() { +void Application::readArgumentsFromLocalSocket() const { auto socket = qobject_cast(sender()); auto message = socket->readAll(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 4f67fbb545..4f6064df20 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -135,14 +135,14 @@ public: const ViewFrustum* getDisplayViewFrustum() const; ViewFrustum* getShadowViewFrustum() override { return &_shadowViewFrustum; } const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; } - EntityTreeRenderer* getEntities() { return DependencyManager::get().data(); } + EntityTreeRenderer* getEntities() const { return DependencyManager::get().data(); } QUndoStack* getUndoStack() { return &_undoStack; } - MainWindow* getWindow() { return _window; } - EntityTreePointer getEntityClipboard() { return _entityClipboard; } + MainWindow* getWindow() const { return _window; } + EntityTreePointer getEntityClipboard() const { return _entityClipboard; } EntityTreeRenderer* getEntityClipboardRenderer() { return &_entityClipboardRenderer; } EntityEditPacketSender* getEntityEditPacketSender() { return &_entityEditSender; } - ivec2 getMouse(); + ivec2 getMouse() const; FaceTracker* getActiveFaceTracker(); FaceTracker* getSelectedFaceTracker(); @@ -155,7 +155,7 @@ public: bool isForeground() const { return _isForeground; } - uint32_t getFrameCount() { return _frameCount; } + uint32_t getFrameCount() const { return _frameCount; } float getFps() const { return _fps; } float getTargetFrameRate(); // frames/second float getLastInstanteousFps() const { return _lastInstantaneousFps; } @@ -179,7 +179,7 @@ public: DisplayPlugin* getActiveDisplayPlugin(); const DisplayPlugin* getActiveDisplayPlugin() const; - FileLogger* getLogger() { return _logger; } + FileLogger* getLogger() const { return _logger; } glm::vec2 getViewportDimensions() const; @@ -189,7 +189,7 @@ public: bool isAboutToQuit() const { return _aboutToQuit; } - // the isHMDmode is true whenever we use the interface from an HMD and not a standard flat display + // the isHMDMode is true whenever we use the interface from an HMD and not a standard flat display // rendering of several elements depend on that // TODO: carry that information on the Camera as a setting bool isHMDMode() const; @@ -197,14 +197,14 @@ public: glm::mat4 getEyeOffset(int eye) const; glm::mat4 getEyeProjection(int eye) const; - QRect getDesirableApplicationGeometry(); + QRect getDesirableApplicationGeometry() const; Bookmarks* getBookmarks() const { return _bookmarks; } virtual bool canAcceptURL(const QString& url) const override; virtual bool acceptURL(const QString& url, bool defaultUpload = false) override; void setMaxOctreePacketsPerSecond(int maxOctreePPS); - int getMaxOctreePacketsPerSecond(); + int getMaxOctreePacketsPerSecond() const; render::ScenePointer getMain3DScene() override { return _main3DScene; } render::ScenePointer getMain3DScene() const { return _main3DScene; } @@ -239,22 +239,22 @@ public slots: bool exportEntities(const QString& filename, float x, float y, float z, float scale); bool importEntities(const QString& url); - void setLowVelocityFilter(bool lowVelocityFilter); + static void setLowVelocityFilter(bool lowVelocityFilter); Q_INVOKABLE void loadDialog(); - Q_INVOKABLE void loadScriptURLDialog(); + Q_INVOKABLE void loadScriptURLDialog() const; void toggleLogDialog(); - void toggleRunningScriptsWidget(); + void toggleRunningScriptsWidget() const; void toggleAssetServerWidget(QString filePath = ""); - void handleLocalServerConnection(); - void readArgumentsFromLocalSocket(); + void handleLocalServerConnection() const; + void readArgumentsFromLocalSocket() const; - void packageModel(); + static void packageModel(); - void openUrl(const QUrl& url); + void openUrl(const QUrl& url) const; void resetSensors(bool andReload = false); - void setActiveFaceTracker(); + void setActiveFaceTracker() const; #ifdef HAVE_IVIEWHMD void setActiveEyeTracker(); @@ -264,7 +264,7 @@ public slots: #endif void aboutApp(); - void showHelp(); + static void showHelp(); void cycleCamera(); void cameraMenuChanged(); @@ -273,14 +273,14 @@ public slots: void reloadResourceCaches(); - void updateHeartbeat(); + void updateHeartbeat() const; - void crashApplication(); - void deadlockApplication(); + static void crashApplication(); + static void deadlockApplication(); - void rotationModeChanged(); + void rotationModeChanged() const; - void runTests(); + static void runTests(); private slots: void showDesktop(); @@ -290,7 +290,7 @@ private slots: void resettingDomain(); - void audioMuteToggled(); + void audioMuteToggled() const; void faceTrackerMuteToggled(); void activeChanged(Qt::ApplicationState state); @@ -298,7 +298,7 @@ private slots: void notifyPacketVersionMismatch(); void loadSettings(); - void saveSettings(); + void saveSettings() const; bool acceptSnapshot(const QString& urlString); bool askToSetAvatarUrl(const QString& url); @@ -308,18 +308,18 @@ private slots: void displayAvatarAttachmentWarning(const QString& message) const; bool displayAvatarAttachmentConfirmationDialog(const QString& name) const; - void setSessionUUID(const QUuid& sessionUUID); + void setSessionUUID(const QUuid& sessionUUID) const; void domainChanged(const QString& domainHostname); - void updateWindowTitle(); - void nodeAdded(SharedNodePointer node); - void nodeActivated(SharedNodePointer node); + void updateWindowTitle() const; + void nodeAdded(SharedNodePointer node) const; + void nodeActivated(SharedNodePointer node) const; void nodeKilled(SharedNodePointer node); - void packetSent(quint64 length); + static void packetSent(quint64 length); void updateDisplayMode(); void updateInputModes(); private: - void initDisplay(); + static void initDisplay(); void init(); void cleanupBeforeQuit(); @@ -327,14 +327,14 @@ private: void update(float deltaTime); // Various helper functions called during update() - void updateLOD(); + void updateLOD() const; void updateThreads(float deltaTime); - void updateDialogs(float deltaTime); + void updateDialogs(float deltaTime) const; void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions); - void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum); + static void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum); - glm::vec3 getSunDirection(); + glm::vec3 getSunDirection() const; void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region); @@ -344,7 +344,7 @@ private: MyAvatar* getMyAvatar() const; - void checkSkeleton(); + void checkSkeleton() const; void initializeAcceptedFiles(); @@ -366,18 +366,18 @@ private: void mouseMoveEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); - void mouseDoublePressEvent(QMouseEvent* event); + void mouseDoublePressEvent(QMouseEvent* event) const; void mouseReleaseEvent(QMouseEvent* event); void touchBeginEvent(QTouchEvent* event); void touchEndEvent(QTouchEvent* event); void touchUpdateEvent(QTouchEvent* event); - void wheelEvent(QWheelEvent* event); + void wheelEvent(QWheelEvent* event) const; void dropEvent(QDropEvent* event); - void dragEnterEvent(QDragEnterEvent* event); + static void dragEnterEvent(QDragEnterEvent* event); - void maybeToggleMenuVisible(QMouseEvent* event); + void maybeToggleMenuVisible(QMouseEvent* event) const; MainWindow* _window; QElapsedTimer& _sessionRunTimer; @@ -423,7 +423,7 @@ private: int _avatarSimsPerSecondReport {0}; quint64 _lastAvatarSimsPerSecondUpdate {0}; Camera _myCamera; // My view onto the world - Camera _mirrorCamera; // Cammera for mirror view + Camera _mirrorCamera; // Camera for mirror view QRect _mirrorViewRect; Setting::Handle _previousScriptLocation; @@ -475,7 +475,8 @@ private: quint64 _lastFaceTrackerUpdate; - render::ScenePointer _main3DScene{ new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) }; + render::ScenePointer _main3DScene{ new render::Scene(glm::vec3(-0.5f * static_cast(TREE_SCALE)), + static_cast(TREE_SCALE)) }; render::EnginePointer _renderEngine{ new render::Engine() }; gpu::ContextPointer _gpuContext; // initialized during window creation From 142f37da1c55c08fe7c6268aa0b261647f16ca22 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Mon, 4 Apr 2016 17:33:47 +0200 Subject: [PATCH 23/55] fix accidentally violated style rule 3.1.2.1 --- CONTRIBUTING.md | 2 +- interface/src/Application.cpp | 40 +++++++++++++++++------------------ interface/src/Application.h | 3 +-- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4f1153b4f4..86ea351609 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ Contributing git checkout -b new_branch_name ``` 4. Code - * Follow the [coding standard](http://docs.highfidelity.io/v1.0/docs/coding-standard) + * Follow the [coding standard](https://readme.highfidelity.com/v1.0/docs/coding-standard) 5. Commit * Use [well formed commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 6. Update your branch diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0130df4a73..17a918c0e8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -369,7 +369,7 @@ public: }; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - QString logMessage = LogHandler::getInstance().printMessage(static_cast(type), context, message); + QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); if (!logMessage.isEmpty()) { #ifdef Q_OS_WIN @@ -915,13 +915,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _applicationStateDevice = std::make_shared(); _applicationStateDevice->addInputVariant(QString("InHMD"), controller::StateController::ReadLambda([]() -> float { - return static_cast(qApp->isHMDMode()); + return (float)qApp->isHMDMode(); })); _applicationStateDevice->addInputVariant(QString("SnapTurn"), controller::StateController::ReadLambda([]() -> float { - return static_cast(qApp->getMyAvatar()->getSnapTurn()); + return (float)qApp->getMyAvatar()->getSnapTurn(); })); _applicationStateDevice->addInputVariant(QString("Grounded"), controller::StateController::ReadLambda([]() -> float { - return static_cast(qApp->getMyAvatar()->getCharacterController()->onGround()); + return (float)qApp->getMyAvatar()->getCharacterController()->onGround(); })); _applicationStateDevice->addInputVariant(QString("NavigationFocused"), controller::StateController::ReadLambda([]() -> float { auto offscreenUi = DependencyManager::get(); @@ -1442,7 +1442,7 @@ void Application::paintGL() { uint64_t diff = now - lastPaintBegin; float instantaneousFps = 0.0f; if (diff != 0) { - instantaneousFps = static_cast(USECS_PER_SECOND) / static_cast(diff); + instantaneousFps = (float)USECS_PER_SECOND / (float)diff; _framesPerSecond.updateAverage(_lastInstantaneousFps); } @@ -1454,7 +1454,7 @@ void Application::paintGL() { _lastFramesPerSecondUpdate = now; } - PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, static_cast(_frameCount)); + PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, (uint64_t)_frameCount); PerformanceTimer perfTimer("paintGL"); if (nullptr == _displayPlugin) { @@ -1800,12 +1800,12 @@ bool Application::event(QEvent* event) { return false; } - if (static_cast(event->type()) == static_cast(Lambda)) { + if ((int)event->type() == (int)Lambda) { static_cast(event)->call(); return true; } - if (static_cast(event->type()) == static_cast(Paint)) { + if ((int)event->type() == (int)Paint) { paintGL(); return true; } @@ -2574,7 +2574,7 @@ void Application::idle(uint64_t now) { bool isThrottled = displayPlugin->isThrottled(); // Only run simulation code if more than the targetFramePeriod have passed since last time we ran // This attempts to lock the simulation at 60 updates per second, regardless of framerate - float timeSinceLastUpdateUs = static_cast(_lastTimeUpdated.nsecsElapsed()) / NSECS_PER_USEC; + float timeSinceLastUpdateUs = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_USEC; float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND; if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) { @@ -3197,7 +3197,7 @@ void Application::updateDialogs(float deltaTime) const { void Application::update(float deltaTime) { - PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, static_cast(_frameCount) + 1); + PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, (uint64_t)_frameCount + 1); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::update()"); @@ -3357,14 +3357,14 @@ void Application::update(float deltaTime) { }); } { - PROFILE_RANGE_EX("StepSimulation", 0xffff8000, static_cast(getActiveDisplayPlugin()->presentCount())); + PROFILE_RANGE_EX("StepSimulation", 0xffff8000, (uint64_t)getActiveDisplayPlugin()->presentCount()); PerformanceTimer perfTimer("stepSimulation"); getEntities()->getTree()->withWriteLock([&] { _physicsEngine->stepSimulation(); }); } { - PROFILE_RANGE_EX("HarvestChanges", 0xffffff00, static_cast(getActiveDisplayPlugin()->presentCount())); + PROFILE_RANGE_EX("HarvestChanges", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount()); PerformanceTimer perfTimer("harvestChanges"); if (_physicsEngine->hasOutgoingChanges()) { getEntities()->getTree()->withWriteLock([&] { @@ -3402,20 +3402,20 @@ void Application::update(float deltaTime) { qApp->setAvatarSimrateSample(1.0f / deltaTime); { - PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, static_cast(getActiveDisplayPlugin()->presentCount())); + PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount()); avatarManager->updateOtherAvatars(deltaTime); } qApp->updateMyAvatarLookAtPosition(); { - PROFILE_RANGE_EX("MyAvatar", 0xffff00ff, static_cast(getActiveDisplayPlugin()->presentCount())); + PROFILE_RANGE_EX("MyAvatar", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount()); avatarManager->updateMyAvatar(deltaTime); } } { - PROFILE_RANGE_EX("Overlays", 0xffff0000, static_cast(getActiveDisplayPlugin()->presentCount())); + PROFILE_RANGE_EX("Overlays", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount()); PerformanceTimer perfTimer("overlays"); _overlays.update(deltaTime); } @@ -3435,7 +3435,7 @@ void Application::update(float deltaTime) { // Update my voxel servers with my current voxel query... { - PROFILE_RANGE_EX("QueryOctree", 0xffff0000, static_cast(getActiveDisplayPlugin()->presentCount())); + PROFILE_RANGE_EX("QueryOctree", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount()); PerformanceTimer perfTimer("queryOctree"); quint64 sinceLastQuery = now - _lastQueriedTime; const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; @@ -3474,7 +3474,7 @@ void Application::update(float deltaTime) { } { - PROFILE_RANGE_EX("PreRenderLambdas", 0xffff0000, static_cast(0)); + PROFILE_RANGE_EX("PreRenderLambdas", 0xffff0000, (uint64_t)0); std::unique_lock guard(_preRenderLambdasLock); for (auto& iter : _preRenderLambdas) { @@ -3528,7 +3528,7 @@ int Application::sendNackPackets() { } if (nackPacketList->getNumPackets()) { - packetsSent += static_cast(nackPacketList->getNumPackets()); + packetsSent += (int)nackPacketList->getNumPackets(); // send the packet list nodeList->sendPacketList(std::move(nackPacketList), *node); @@ -4011,7 +4011,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi auto originalViewport = renderArgs->_viewport; // Grab current viewport to reset it at the end - float aspect = static_cast(region.width()) / region.height(); + float aspect = (float)region.width() / region.height(); float fov = MIRROR_FIELD_OF_VIEW; auto myAvatar = getMyAvatar(); @@ -4047,7 +4047,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi // set the bounds of rear mirror view // the region is in device independent coordinates; must convert to device - float ratio = static_cast(QApplication::desktop()->windowHandle()->devicePixelRatio()) * getRenderResolutionScale(); + float ratio = (float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale(); int width = region.width() * ratio; int height = region.height() * ratio; gpu::Vec4i viewport = gpu::Vec4i(0, 0, width, height); diff --git a/interface/src/Application.h b/interface/src/Application.h index 4f6064df20..e3196febd5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -475,8 +475,7 @@ private: quint64 _lastFaceTrackerUpdate; - render::ScenePointer _main3DScene{ new render::Scene(glm::vec3(-0.5f * static_cast(TREE_SCALE)), - static_cast(TREE_SCALE)) }; + render::ScenePointer _main3DScene{ new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) }; render::EnginePointer _renderEngine{ new render::Engine() }; gpu::ContextPointer _gpuContext; // initialized during window creation From 2be4097bc528ddfde0287b3a9a21ef651ec72b54 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Mon, 4 Apr 2016 17:36:43 +0200 Subject: [PATCH 24/55] another 3.1.2.1 rollback --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 17a918c0e8..0172b3ce3a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2614,7 +2614,7 @@ void Application::idle(uint64_t now) { static uint64_t lastIdleStart{ now }; uint64_t idleStartToStartDuration = now - lastIdleStart; if (idleStartToStartDuration != 0) { - _simsPerSecond.updateAverage(static_cast(USECS_PER_SECOND) / static_cast(idleStartToStartDuration)); + _simsPerSecond.updateAverage((float)USECS_PER_SECOND / (float)idleStartToStartDuration); } lastIdleStart = now; } From 1da8fe5838df37c9ea2260d5823d19d98c738f45 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Apr 2016 09:46:10 -0700 Subject: [PATCH 25/55] only a single log line per client version mismatch --- ice-server/src/IceServer.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index a512d5a049..59c36eae30 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -62,7 +62,14 @@ bool IceServer::packetVersionMatch(const udt::Packet& packet) { if (headerVersion == versionForPacketType(headerType)) { return true; } else { - qDebug() << "Packet version mismatch for packet" << headerType << " from" << packet.getSenderSockAddr(); + static QSet mismatchedClients; + + // only output a version mismatch once per ice-server run + if (!mismatchedClients.contains(packet.getSenderSockAddr())) { + mismatchedClients.insert(packet.getSenderSockAddr()); + + qDebug() << "Packet version mismatch for packet" << headerType << " from" << packet.getSenderSockAddr(); + } return false; } From 145b734b98cb557b9e8a5e12868db572bf1bfbbc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Apr 2016 09:49:04 -0700 Subject: [PATCH 26/55] completely remove version mismatch debug --- ice-server/src/IceServer.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 59c36eae30..c1e92f276f 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -62,15 +62,6 @@ bool IceServer::packetVersionMatch(const udt::Packet& packet) { if (headerVersion == versionForPacketType(headerType)) { return true; } else { - static QSet mismatchedClients; - - // only output a version mismatch once per ice-server run - if (!mismatchedClients.contains(packet.getSenderSockAddr())) { - mismatchedClients.insert(packet.getSenderSockAddr()); - - qDebug() << "Packet version mismatch for packet" << headerType << " from" << packet.getSenderSockAddr(); - } - return false; } } From d98abbc7df5d05b72a29a5015c81445df4f89499 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 3 Apr 2016 01:04:05 -0700 Subject: [PATCH 27/55] First pass at threaded texture transfers --- interface/src/Application.cpp | 3 + libraries/gl/src/gl/GLHelpers.cpp | 4 +- libraries/gl/src/gl/OffscreenGLCanvas.cpp | 5 + libraries/gl/src/gl/OffscreenGLCanvas.h | 1 + libraries/gl/src/gl/OglplusHelpers.cpp | 40 +- libraries/gl/src/gl/OglplusHelpers.h | 3 +- libraries/gl/src/gl/QOpenGLContextWrapper.cpp | 3 + libraries/gl/src/gl/QOpenGLContextWrapper.h | 3 +- libraries/gpu/src/gpu/GLBackend.cpp | 1 + libraries/gpu/src/gpu/GLBackend.h | 65 ++- libraries/gpu/src/gpu/GLBackendOutput.cpp | 4 +- libraries/gpu/src/gpu/GLBackendPipeline.cpp | 2 +- libraries/gpu/src/gpu/GLBackendTexture.cpp | 441 +++++++++--------- .../gpu/src/gpu/GLBackendTextureTransfer.cpp | 109 +++++ .../gpu/src/gpu/GLBackendTextureTransfer.h | 61 +++ libraries/gpu/src/gpu/GLTexelFormat.h | 3 + libraries/shared/src/GenericThread.cpp | 19 +- libraries/shared/src/GenericThread.h | 7 +- 18 files changed, 540 insertions(+), 234 deletions(-) create mode 100644 libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp create mode 100644 libraries/gpu/src/gpu/GLBackendTextureTransfer.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0172b3ce3a..80173b7d9d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1255,6 +1255,9 @@ void Application::initializeGL() { // Where the gpuContext is initialized and where the TRUE Backend is created and assigned gpu::Context::init(); _gpuContext = std::make_shared(); + // The gpu context can make child contexts for transfers, so + // we need to restore primary rendering context + _offscreenContext->makeCurrent(); initDisplay(); qCDebug(interfaceapp, "Initialized Display."); diff --git a/libraries/gl/src/gl/GLHelpers.cpp b/libraries/gl/src/gl/GLHelpers.cpp index 6ad7f816b8..c9de3ccd90 100644 --- a/libraries/gl/src/gl/GLHelpers.cpp +++ b/libraries/gl/src/gl/GLHelpers.cpp @@ -12,7 +12,7 @@ const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() { // Qt Quick may need a depth and stencil buffer. Always make sure these are available. format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS); format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS); - format.setVersion(4, 1); + format.setVersion(4, 5); #ifdef DEBUG format.setOption(QSurfaceFormat::DebugContext); #endif @@ -27,7 +27,7 @@ const QGLFormat& getDefaultGLFormat() { static QGLFormat glFormat; static std::once_flag once; std::call_once(once, [] { - glFormat.setVersion(4, 1); + glFormat.setVersion(4, 5); glFormat.setProfile(QGLFormat::CoreProfile); // Requires >=Qt-4.8.0 glFormat.setSampleBuffers(false); glFormat.setDepth(false); diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp index 8e5579f90b..90ff369cd6 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -83,3 +83,8 @@ void OffscreenGLCanvas::doneCurrent() { QObject* OffscreenGLCanvas::getContextObject() { return _context; } + +void OffscreenGLCanvas::moveToThreadWithContext(QThread* thread) { + moveToThread(thread); + _context->moveToThread(thread); +} \ No newline at end of file diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.h b/libraries/gl/src/gl/OffscreenGLCanvas.h index 9858c7cefa..387804bf56 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.h +++ b/libraries/gl/src/gl/OffscreenGLCanvas.h @@ -26,6 +26,7 @@ public: bool create(QOpenGLContext* sharedContext = nullptr); bool makeCurrent(); void doneCurrent(); + void moveToThreadWithContext(QThread* thread); QOpenGLContext* getContext() { return _context; } diff --git a/libraries/gl/src/gl/OglplusHelpers.cpp b/libraries/gl/src/gl/OglplusHelpers.cpp index 1dd7068448..11c4f2fe3d 100644 --- a/libraries/gl/src/gl/OglplusHelpers.cpp +++ b/libraries/gl/src/gl/OglplusHelpers.cpp @@ -6,8 +6,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "OglplusHelpers.h" -#include + #include +#include +#include using namespace oglplus; using namespace oglplus::shapes; @@ -20,11 +22,13 @@ uniform mat4 mvp = mat4(1); in vec3 Position; in vec2 TexCoord; +out vec3 vPosition; out vec2 vTexCoord; void main() { gl_Position = mvp * vec4(Position, 1); - vTexCoord = TexCoord ; + vTexCoord = TexCoord; + vPosition = Position; } )VS"; @@ -35,7 +39,9 @@ static const char * SIMPLE_TEXTURED_FS = R"FS(#version 410 core uniform sampler2D sampler; uniform float alpha = 1.0; +in vec3 vPosition; in vec2 vTexCoord; + out vec4 FragColor; void main() { @@ -47,12 +53,38 @@ void main() { )FS"; +static const char * SIMPLE_TEXTURED_CUBEMAP_FS = R"FS(#version 410 core +#pragma line __LINE__ + +uniform samplerCube sampler; +uniform float alpha = 1.0; + +in vec3 vPosition; +in vec3 vTexCoord; + +out vec4 FragColor; + +void main() { + + FragColor = texture(sampler, vPosition); + FragColor.a *= alpha; +} + +)FS"; + + ProgramPtr loadDefaultShader() { ProgramPtr result; compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_FS); return result; } +ProgramPtr loadCubemapShader() { + ProgramPtr result; + compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_CUBEMAP_FS); + return result; +} + void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs) { using namespace oglplus; try { @@ -93,6 +125,10 @@ ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect) { ); } +ShapeWrapperPtr loadSkybox(ProgramPtr program) { + return ShapeWrapperPtr(new shapes::ShapeWrapper({ { "Position" } }, shapes::SkyBox(), *program)); +} + // Return a point's cartesian coordinates on a sphere from pitch and yaw static glm::vec3 getPoint(float yaw, float pitch) { return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)), diff --git a/libraries/gl/src/gl/OglplusHelpers.h b/libraries/gl/src/gl/OglplusHelpers.h index 4734b8b213..b599e8270d 100644 --- a/libraries/gl/src/gl/OglplusHelpers.h +++ b/libraries/gl/src/gl/OglplusHelpers.h @@ -37,7 +37,6 @@ #include #include #include -#include #ifdef _WIN32 #pragma warning(pop) @@ -55,7 +54,9 @@ using ProgramPtr = std::shared_ptr; using Mat4Uniform = oglplus::Uniform; ProgramPtr loadDefaultShader(); +ProgramPtr loadCubemapShader(); void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs); +ShapeWrapperPtr loadSkybox(ProgramPtr program); ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect = 1.0f); ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov = PI / 3.0f * 2.0f, float aspect = 16.0f / 9.0f, int slices = 32, int stacks = 32); diff --git a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp index 6397d30e13..185fdaf7f4 100644 --- a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp +++ b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp @@ -13,6 +13,9 @@ #include +QOpenGLContext* QOpenGLContextWrapper::currentContext() { + return QOpenGLContext::currentContext(); +} QOpenGLContextWrapper::QOpenGLContextWrapper() : _context(new QOpenGLContext) diff --git a/libraries/gl/src/gl/QOpenGLContextWrapper.h b/libraries/gl/src/gl/QOpenGLContextWrapper.h index b736253213..09f1d67280 100644 --- a/libraries/gl/src/gl/QOpenGLContextWrapper.h +++ b/libraries/gl/src/gl/QOpenGLContextWrapper.h @@ -19,7 +19,6 @@ class QSurfaceFormat; class QOpenGLContextWrapper { public: QOpenGLContextWrapper(); - void setFormat(const QSurfaceFormat& format); bool create(); void swapBuffers(QSurface* surface); @@ -27,6 +26,8 @@ public: void doneCurrent(); void setShareContext(QOpenGLContext* otherContext); + static QOpenGLContext* currentContext(); + QOpenGLContext* getContext() { return _context; } diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index b5b6437ed8..f51448f8fd 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -125,6 +125,7 @@ GLBackend::GLBackend() { glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uboAlignment); initInput(); initTransform(); + initTextureTransferHelper(); } GLBackend::~GLBackend() { diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index f5abacd279..4f22a68631 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -24,6 +24,8 @@ namespace gpu { +class GLTextureTransferHelper; + class GLBackend : public Backend { // Context Backend static interface required @@ -35,7 +37,6 @@ class GLBackend : public Backend { explicit GLBackend(bool syncCache); GLBackend(); public: - virtual ~GLBackend(); virtual void render(Batch& batch); @@ -75,25 +76,63 @@ public: class GLTexture : public GPUObject { public: - Stamp _storageStamp; - Stamp _contentStamp; - GLuint _texture; - GLenum _target; + const Stamp _storageStamp; + Stamp _contentStamp { 0 }; + const GLuint _texture; + const GLenum _target; - GLTexture(); + GLTexture(const gpu::Texture& gpuTexture); ~GLTexture(); - void setSize(GLuint size); GLuint size() const { return _size; } + enum SyncState { + // The texture is currently undergoing no processing, although it's content + // may be out of date, or it's storage may be invalid relative to the + // owning GPU texture + Idle, + // The texture has been queued for transfer to the GPU + Pending, + // The texture has been transferred to the GPU, but is awaiting + // any post transfer operations that may need to occur on the + // primary rendering thread + Transferred, + }; + + void setSyncState(SyncState syncState) { _syncState = syncState; } + SyncState getSyncState() const { return _syncState; } + + // Is the storage out of date relative to the gpu texture? + bool invalid() const; + + // Is the content out of date relative to the gpu texture? + bool outdated() const; + + // Is the texture in a state where it can be rendered with no work? + bool ready() const; + + // Move the image bits from the CPU to the GPU + void transfer() const; + + // Execute any post-move operations that must occur only on the main thread + void postTransfer(); + + static const size_t CUBE_NUM_FACES = 6; + static const GLenum CUBE_FACE_LAYOUT[6]; + private: - GLuint _size; + void transferMip(GLenum target, const Texture::PixelsPointer& mip) const; + + const GLuint _size; + // The owning texture + const Texture& _gpuTexture; + std::atomic _syncState { SyncState::Idle }; }; - static GLTexture* syncGPUObject(const Texture& texture); + static GLTexture* syncGPUObject(const TexturePointer& texture); static GLuint getTextureID(const TexturePointer& texture, bool sync = true); // very specific for now - static void syncSampler(const Sampler& sampler, Texture::Type type, GLTexture* object); + static void syncSampler(const Sampler& sampler, Texture::Type type, const GLTexture* object); class GLShader : public GPUObject { public: @@ -241,6 +280,11 @@ protected: void renderPassTransfer(Batch& batch); void renderPassDraw(Batch& batch); + void initTextureTransferHelper(); + static void transferGPUObject(const TexturePointer& texture); + + static std::shared_ptr _textureTransferHelper; + // Draw Stage void do_draw(Batch& batch, size_t paramOffset); void do_drawIndexed(Batch& batch, size_t paramOffset); @@ -484,6 +528,7 @@ protected: typedef void (GLBackend::*CommandCall)(Batch&, size_t); static CommandCall _commandCalls[Batch::NUM_COMMANDS]; + }; }; diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index 37a10e670b..4f714fb53d 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -83,7 +83,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe for (auto& b : framebuffer.getRenderBuffers()) { surface = b._texture; if (surface) { - gltexture = GLBackend::syncGPUObject(*surface); + gltexture = GLBackend::syncGPUObject(surface); } else { gltexture = nullptr; } @@ -123,7 +123,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe if (framebuffer.getDepthStamp() != object->_depthStamp) { auto surface = framebuffer.getDepthStencilBuffer(); if (framebuffer.hasDepthStencil() && surface) { - gltexture = GLBackend::syncGPUObject(*surface); + gltexture = GLBackend::syncGPUObject(surface); } if (gltexture) { diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 046f1ff0e5..10845d1129 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -255,7 +255,7 @@ void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) { _stats._RSNumTextureBounded++; // Always make sure the GLObject is in sync - GLTexture* object = GLBackend::syncGPUObject(*resourceTexture); + GLTexture* object = GLBackend::syncGPUObject(resourceTexture); if (object) { GLuint to = object->_texture; GLuint target = object->_target; diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 242b9100e1..92123a68be 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -9,19 +9,81 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "GPULogging.h" + +#include + #include "GLBackendShared.h" #include "GLTexelFormat.h" +#include "GLBackendTextureTransfer.h" using namespace gpu; -GLBackend::GLTexture::GLTexture() : - _storageStamp(0), - _contentStamp(0), - _texture(0), - _target(GL_TEXTURE_2D), - _size(0) +GLenum gpuToGLTextureType(const Texture& texture) { + // If we get here, we need to allocate and or update the content of the texture + // or it's already being transferred + switch (texture.getType()) { + case Texture::TEX_2D: + return GL_TEXTURE_2D; + break; + + case Texture::TEX_CUBE: + return GL_TEXTURE_CUBE_MAP; + break; + + default: + qFatal("Unsupported texture type"); + } + Q_UNREACHABLE(); + return GL_TEXTURE_2D; +} + +GLuint allocateSingleTexture() { + GLuint result; + glGenTextures(1, &result); + return result; +} + +const GLenum GLBackend::GLTexture::CUBE_FACE_LAYOUT[6] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z +}; + +// Create the texture and allocate storage +GLBackend::GLTexture::GLTexture(const Texture& texture) : + _storageStamp(texture.getStamp()), _texture(allocateSingleTexture()), + _target(gpuToGLTextureType(texture)), _size((GLuint)texture.getSize()), _gpuTexture(texture) { Backend::incrementTextureGPUCount(); + Backend::updateTextureGPUMemoryUsage(0, _size); + Backend::setGPUObject(texture, this); + + GLsizei width = texture.getWidth(); + GLsizei height = texture.getHeight(); + GLsizei levels = 1; + if (texture.maxMip() > 0) { + if (texture.isAutogenerateMips()) { + while ((width | height) >> levels) { + ++levels; + } + } + levels = std::max(1, std::min(texture.maxMip() + 1, levels)); + } + + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat()); + withPreservedTexture(_target, [&] { + glBindTexture(_target, _texture); + (void)CHECK_GL_ERROR(); + // GO through the process of allocating the correct storage + if (GLEW_VERSION_4_2) { + glTexStorage2D(_target, levels, texelFormat.internalFormat, width, height); + } else { + glTexImage2D(_target, 0, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, 0); + } + (void)CHECK_GL_ERROR(); + syncSampler(texture.getSampler(), texture.getType(), this); + (void)CHECK_GL_ERROR(); + }); } GLBackend::GLTexture::~GLTexture() { @@ -32,199 +94,164 @@ GLBackend::GLTexture::~GLTexture() { Backend::decrementTextureGPUCount(); } -void GLBackend::GLTexture::setSize(GLuint size) { - Backend::updateTextureGPUMemoryUsage(_size, size); - _size = size; +bool GLBackend::GLTexture::invalid() const { + return _storageStamp < _gpuTexture.getStamp(); } -GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { - GLTexture* object = Backend::getGPUObject(texture); +bool GLBackend::GLTexture::outdated() const { + return _contentStamp < _gpuTexture.getDataStamp(); +} - // If GPU object already created and in sync - bool needUpdate = false; - if (object && (object->_storageStamp == texture.getStamp())) { - // If gpu object info is in sync with sysmem version - if (object->_contentStamp >= texture.getDataStamp()) { - // Then all good, GPU object is ready to be used - return object; - } else { - // Need to update the content of the GPU object from the source sysmem of the texture - needUpdate = true; - } - } else if (!texture.isDefined()) { +bool GLBackend::GLTexture::ready() const { + // If we have an invalid texture, we're never ready + if (invalid()) { + return false; + } + + // If we're out of date, but the transfer is in progress, report ready + // as a special case + auto syncState = _syncState.load(); + + if (outdated()) { + return Pending == syncState; + } + + return Idle == syncState; +} + +//#define USE_PBO + +// Move content bits from the CPU to the GPU for a given mip / face +void GLBackend::GLTexture::transferMip(GLenum target, const Texture::PixelsPointer& mip) const { + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuTexture.getTexelFormat(), mip->getFormat()); +#ifdef USE_PBO + GLuint pixelBufferID; + glGenBuffers(1, &pixelBufferID); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBufferID); + //if (GLEW_VERSION_4_4) { + // glBufferStorage(GL_PIXEL_UNPACK_BUFFER, mip->getSize(), nullptr, GL_STREAM_DRAW); + //} else { + glBufferData(GL_PIXEL_UNPACK_BUFFER, mip->getSize(), nullptr, GL_STREAM_DRAW); + //} + void* mappedBuffer = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + memcpy(mappedBuffer, mip->readData(), mip->getSize()); + //// use while PBO is still bound, assumes GL_TEXTURE_2D and offset 0 + glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, 0); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + glDeleteBuffers(1, &pixelBufferID); +#else + //glTexImage2D(target, 0, internalFormat, texture.getWidth(), texture.getHeight(), 0, texelFormat.format, texelFormat.type, bytes); + glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, mip->readData()); + (void)CHECK_GL_ERROR(); +#endif +} + +// Move content bits from the CPU to the GPU +void GLBackend::GLTexture::transfer() const { + PROFILE_RANGE(__FUNCTION__); + qDebug() << "Transferring texture: " << _texture; + // Need to update the content of the GPU object from the source sysmem of the texture + if (_contentStamp >= _gpuTexture.getDataStamp()) { + return; + } + + glBindTexture(_target, _texture); + // GO through the process of allocating the correct storage and/or update the content + switch (_gpuTexture.getType()) { + case Texture::TEX_2D: + if (_gpuTexture.isStoredMipFaceAvailable(0)) { + transferMip(GL_TEXTURE_2D, _gpuTexture.accessStoredMipFace(0)); + } + break; + + case Texture::TEX_CUBE: + // transfer pixels from each faces + for (int f = 0; f < CUBE_NUM_FACES; f++) { + if (_gpuTexture.isStoredMipFaceAvailable(0, f)) { + transferMip(CUBE_FACE_LAYOUT[f], _gpuTexture.accessStoredMipFace(0, f)); + } + } + break; + + default: + qCWarning(gpulogging) << __FUNCTION__ << " case for Texture Type " << _gpuTexture.getType() << " not supported"; + break; + } + + if (_gpuTexture.isAutogenerateMips()) { + glGenerateMipmap(_target); + (void)CHECK_GL_ERROR(); + } +} + +// Do any post-transfer operations that might be required on the main context / rendering thread +void GLBackend::GLTexture::postTransfer() { + setSyncState(GLTexture::Idle); + switch (_gpuTexture.getType()) { + case Texture::TEX_2D: + // At this point the mip piels have been loaded, we can notify + _gpuTexture.notifyMipFaceGPULoaded(0, 0); + break; + + case Texture::TEX_CUBE: + for (uint8_t f = 0; f < CUBE_NUM_FACES; ++f) { + // At this point the mip piels have been loaded, we can notify + _gpuTexture.notifyMipFaceGPULoaded(0, f); + } + break; + + default: + qCWarning(gpulogging) << __FUNCTION__ << " case for Texture Type " << _gpuTexture.getType() << " not supported"; + break; + } +} + +GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePointer) { + const Texture& texture = *texturePointer; + if (!texture.isDefined()) { // NO texture definition yet so let's avoid thinking return nullptr; } + // If the object hasn't been created, or the object definition is out of date, drop and re-create + GLTexture* object = Backend::getGPUObject(texture); + if (object && object->ready()) { + return object; + } + + // Object isn't ready, check what we need to do... + + // Create the texture if need be (force re-creation if the storage stamp changes + // for easier use of immutable storage) + if (!object || object->invalid()) { + // This automatically destroys the old texture + object = new GLTexture(texture); + } + // need to have a gpu object? - if (!object) { - object = new GLTexture(); - glGenTextures(1, &object->_texture); - (void) CHECK_GL_ERROR(); - Backend::setGPUObject(texture, object); + if (texture.getNumSlices() != 1) { + return object; } - // GO through the process of allocating the correct storage and/or update the content - switch (texture.getType()) { - case Texture::TEX_2D: { - if (texture.getNumSlices() == 1) { - GLint boundTex = -1; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); - glBindTexture(GL_TEXTURE_2D, object->_texture); - - if (needUpdate) { - if (texture.isStoredMipFaceAvailable(0)) { - Texture::PixelsPointer mip = texture.accessStoredMipFace(0); - const GLvoid* bytes = mip->readData(); - Element srcFormat = mip->getFormat(); - - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - - glBindTexture(GL_TEXTURE_2D, object->_texture); - glTexSubImage2D(GL_TEXTURE_2D, 0, - texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0, - texelFormat.format, texelFormat.type, bytes); - - if (texture.isAutogenerateMips()) { - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - - object->_target = GL_TEXTURE_2D; - - syncSampler(texture.getSampler(), texture.getType(), object); - - - // At this point the mip piels have been loaded, we can notify - texture.notifyMipFaceGPULoaded(0, 0); - - object->_contentStamp = texture.getDataStamp(); - } - } else { - const GLvoid* bytes = 0; - Element srcFormat = texture.getTexelFormat(); - if (texture.isStoredMipFaceAvailable(0)) { - Texture::PixelsPointer mip = texture.accessStoredMipFace(0); - - bytes = mip->readData(); - srcFormat = mip->getFormat(); - - object->_contentStamp = texture.getDataStamp(); - } - - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - - glTexImage2D(GL_TEXTURE_2D, 0, - texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0, - texelFormat.format, texelFormat.type, bytes); - - if (bytes && texture.isAutogenerateMips()) { - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - object->_target = GL_TEXTURE_2D; - - syncSampler(texture.getSampler(), texture.getType(), object); - - // At this point the mip pixels have been loaded, we can notify - texture.notifyMipFaceGPULoaded(0, 0); - - object->_storageStamp = texture.getStamp(); - object->_contentStamp = texture.getDataStamp(); - object->setSize((GLuint)texture.getSize()); - } - - glBindTexture(GL_TEXTURE_2D, boundTex); - } - break; + // Object might be outdated, if so, start the transfer + // (outdated objects that are already in transfer will have reported 'true' for ready() + if (object->outdated()) { + _textureTransferHelper->transferTexture(texturePointer); } - case Texture::TEX_CUBE: { - if (texture.getNumSlices() == 1) { - GLint boundTex = -1; - glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex); - glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture); - const int NUM_FACES = 6; - const GLenum FACE_LAYOUT[] = { - GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; - if (needUpdate) { - glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture); - // transfer pixels from each faces - for (int f = 0; f < NUM_FACES; f++) { - if (texture.isStoredMipFaceAvailable(0, f)) { - Texture::PixelsPointer mipFace = texture.accessStoredMipFace(0, f); - Element srcFormat = mipFace->getFormat(); - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - - glTexSubImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, texture.getWidth(), texture.getWidth(), 0, - texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->readData())); - - // At this point the mip pixels have been loaded, we can notify - texture.notifyMipFaceGPULoaded(0, f); - } - } - - if (texture.isAutogenerateMips()) { - glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - - object->_target = GL_TEXTURE_CUBE_MAP; - - syncSampler(texture.getSampler(), texture.getType(), object); - - object->_contentStamp = texture.getDataStamp(); - - } else { - glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture); - - // transfer pixels from each faces - for (int f = 0; f < NUM_FACES; f++) { - if (texture.isStoredMipFaceAvailable(0, f)) { - Texture::PixelsPointer mipFace = texture.accessStoredMipFace(0, f); - Element srcFormat = mipFace->getFormat(); - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - - glTexImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, texture.getWidth(), texture.getWidth(), 0, - texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->readData())); - - // At this point the mip pixels have been loaded, we can notify - texture.notifyMipFaceGPULoaded(0, f); - } - } - - if (texture.isAutogenerateMips()) { - glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } else { - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - - object->_target = GL_TEXTURE_CUBE_MAP; - - syncSampler(texture.getSampler(), texture.getType(), object); - - object->_storageStamp = texture.getStamp(); - object->_contentStamp = texture.getDataStamp(); - object->setSize((GLuint)texture.getSize()); - } - - glBindTexture(GL_TEXTURE_CUBE_MAP, boundTex); - } - break; + if (GLTexture::Transferred == object->getSyncState()) { + object->postTransfer(); } - default: - qCDebug(gpulogging) << "GLBackend::syncGPUObject(const Texture&) case for Texture Type " << texture.getType() << " not supported"; - } - (void) CHECK_GL_ERROR(); return object; } +std::shared_ptr GLBackend::_textureTransferHelper; +void GLBackend::initTextureTransferHelper() { + _textureTransferHelper = std::make_shared(); +} GLuint GLBackend::getTextureID(const TexturePointer& texture, bool sync) { if (!texture) { @@ -232,7 +259,7 @@ GLuint GLBackend::getTextureID(const TexturePointer& texture, bool sync) { } GLTexture* object { nullptr }; if (sync) { - object = GLBackend::syncGPUObject(*texture); + object = GLBackend::syncGPUObject(texture); } else { object = Backend::getGPUObject(*texture); } @@ -243,38 +270,37 @@ GLuint GLBackend::getTextureID(const TexturePointer& texture, bool sync) { } } -void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTexture* object) { +void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, const GLTexture* object) { if (!object) return; - if (!object->_texture) return; class GLFilterMode { public: GLint minFilter; GLint magFilter; }; - static const GLFilterMode filterModes[] = { - {GL_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_POINT, - {GL_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR, - {GL_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT, - {GL_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR, - - {GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT, - {GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT, - {GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_MAG_POINT_MIP_LINEAR, - {GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT, - {GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_POINT_MAG_MIP_LINEAR, - {GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_MIP_POINT, - {GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, - {GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR_MIP_POINT, - {GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_MIP_LINEAR, - {GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} //FILTER_ANISOTROPIC, + static const GLFilterMode filterModes[] = { + { GL_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_POINT, + { GL_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR, + { GL_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT, + { GL_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR, + + { GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_MIP_POINT, + { GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_MIP_POINT, + { GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_MAG_POINT_MIP_LINEAR, + { GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT, + { GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_POINT_MAG_MIP_LINEAR, + { GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_MIP_POINT, + { GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, + { GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR_MIP_POINT, + { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_MIP_LINEAR, + { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR } //FILTER_ANISOTROPIC, }; auto fm = filterModes[sampler.getFilter()]; glTexParameteri(object->_target, GL_TEXTURE_MIN_FILTER, fm.minFilter); glTexParameteri(object->_target, GL_TEXTURE_MAG_FILTER, fm.magFilter); - static const GLenum comparisonFuncs[] = { + static const GLenum comparisonFuncs[] = { GL_NEVER, GL_LESS, GL_EQUAL, @@ -291,7 +317,7 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTextur glTexParameteri(object->_target, GL_TEXTURE_COMPARE_MODE, GL_NONE); } - static const GLenum wrapModes[] = { + static const GLenum wrapModes[] = { GL_REPEAT, // WRAP_REPEAT, GL_MIRRORED_REPEAT, // WRAP_MIRROR, GL_CLAMP_TO_EDGE, // WRAP_CLAMP, @@ -302,23 +328,20 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTextur glTexParameteri(object->_target, GL_TEXTURE_WRAP_T, wrapModes[sampler.getWrapModeV()]); glTexParameteri(object->_target, GL_TEXTURE_WRAP_R, wrapModes[sampler.getWrapModeW()]); - glTexParameterfv(object->_target, GL_TEXTURE_BORDER_COLOR, (const float*) &sampler.getBorderColor()); + glTexParameterfv(object->_target, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); glTexParameteri(object->_target, GL_TEXTURE_BASE_LEVEL, sampler.getMipOffset()); - glTexParameterf(object->_target, GL_TEXTURE_MIN_LOD, (float) sampler.getMinMip()); + glTexParameterf(object->_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); glTexParameterf(object->_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); glTexParameterf(object->_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); - } - - void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) { TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); if (!resourceTexture) { return; } - GLTexture* object = GLBackend::syncGPUObject(*resourceTexture); + GLTexture* object = GLBackend::syncGPUObject(resourceTexture); if (!object) { return; } @@ -333,7 +356,7 @@ void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) { if (freeSlot < 0) { // If had to use slot 0 then restore state - GLTexture* boundObject = GLBackend::syncGPUObject(*_resource._textures[0]); + GLTexture* boundObject = GLBackend::syncGPUObject(_resource._textures[0]); if (boundObject) { glBindTexture(boundObject->_target, boundObject->_texture); } diff --git a/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp new file mode 100644 index 0000000000..aa5839b5b2 --- /dev/null +++ b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp @@ -0,0 +1,109 @@ +// +// Created by Bradley Austin Davis on 2016/04/03 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLBackendTextureTransfer.h" + +#include "GLBackendShared.h" +#include "GLTexelFormat.h" + +#ifdef THREADED_TEXTURE_TRANSFER +#include +#include +#include +#endif + +using namespace gpu; + +static ProgramPtr _program; +static ProgramPtr _cubeProgram; +static ShapeWrapperPtr _plane; +static ShapeWrapperPtr _skybox; +static BasicFramebufferWrapperPtr _framebuffer; + +GLTextureTransferHelper::GLTextureTransferHelper() { +#ifdef THREADED_TEXTURE_TRANSFER + _canvas = std::make_shared(); + _canvas->create(QOpenGLContextWrapper::currentContext()); + if (!_canvas->makeCurrent()) { + qFatal("Unable to create texture transfer context"); + } + _canvas->doneCurrent(); + initialize(true, QThread::LowPriority); + _canvas->moveToThreadWithContext(_thread); +#endif +} + +void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texturePointer) { + GLBackend::GLTexture* object = Backend::getGPUObject(*texturePointer); +#ifdef THREADED_TEXTURE_TRANSFER + TextureTransferPackage package { texturePointer, glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0) }; + glFlush(); + object->setSyncState(GLBackend::GLTexture::Pending); + queueItem(package); +#else + object->transfer(); + object->postTransfer(); +#endif +} + +void GLTextureTransferHelper::setup() { +#ifdef THREADED_TEXTURE_TRANSFER + _canvas->makeCurrent(); + _program = loadDefaultShader(); + _plane = loadPlane(_program); + _cubeProgram = loadCubemapShader(); + _skybox = loadSkybox(_cubeProgram); + _framebuffer = std::make_shared(); + _framebuffer->Init({ 100, 100 }); + _framebuffer->fbo.Bind(oglplus::FramebufferTarget::Draw); +#endif +} + +bool GLTextureTransferHelper::processQueueItems(const Queue& messages) { + for (auto package : messages) { + glWaitSync(package.fence, 0, GL_TIMEOUT_IGNORED); + glDeleteSync(package.fence); + TexturePointer texturePointer = package.texture.lock(); + // Texture no longer exists, move on to the next + if (!texturePointer) { + continue; + } + + GLBackend::GLTexture* object = Backend::getGPUObject(*texturePointer); + object->transfer(); + + // Now force a draw using the texture + try { + switch (texturePointer->getType()) { + case Texture::TEX_2D: + _program->Use(); + _plane->Use(); + _plane->Draw(); + break; + + case Texture::TEX_CUBE: + _cubeProgram->Use(); + _skybox->Use(); + _skybox->Draw(); + break; + + default: + qCWarning(gpulogging) << __FUNCTION__ << " case for Texture Type " << texturePointer->getType() << " not supported"; + break; + } + } catch (const std::runtime_error& error) { + qWarning() << "Failed to render texture on background thread: " << error.what(); + } + + glBindTexture(object->_target, 0); + glFinish(); + object->_contentStamp = texturePointer->getDataStamp(); + object->setSyncState(GLBackend::GLTexture::Transferred); + } + return true; +} diff --git a/libraries/gpu/src/gpu/GLBackendTextureTransfer.h b/libraries/gpu/src/gpu/GLBackendTextureTransfer.h new file mode 100644 index 0000000000..3a147defdf --- /dev/null +++ b/libraries/gpu/src/gpu/GLBackendTextureTransfer.h @@ -0,0 +1,61 @@ +// +// Created by Bradley Austin Davis on 2016/04/03 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include "GLBackendShared.h" + +#define THREADED_TEXTURE_TRANSFER + +class OffscreenGLCanvas; + +namespace gpu { + +struct TextureTransferPackage { + std::weak_ptr texture; + GLsync fence; +}; + +class GLTextureTransferHelper : public GenericQueueThread { +public: + GLTextureTransferHelper(); + void transferTexture(const gpu::TexturePointer& texturePointer); + void postTransfer(const gpu::TexturePointer& texturePointer); + +protected: + void setup() override; + bool processQueueItems(const Queue& messages) override; + void transferTextureSynchronous(const gpu::Texture& texture); + +private: + std::shared_ptr _canvas; +}; + +template +void withPreservedTexture(GLenum target, F f) { + GLint boundTex = -1; + switch (target) { + case GL_TEXTURE_2D: + glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); + break; + + case GL_TEXTURE_CUBE_MAP: + glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex); + break; + + default: + qFatal("Unsupported texture type"); + } + (void)CHECK_GL_ERROR(); + + f(); + + glBindTexture(target, boundTex); + (void)CHECK_GL_ERROR(); +} + +} diff --git a/libraries/gpu/src/gpu/GLTexelFormat.h b/libraries/gpu/src/gpu/GLTexelFormat.h index 274b5eeba3..189189f68b 100644 --- a/libraries/gpu/src/gpu/GLTexelFormat.h +++ b/libraries/gpu/src/gpu/GLTexelFormat.h @@ -14,6 +14,9 @@ public: GLenum format; GLenum type; + static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat) { + return evalGLTexelFormat(dstFormat, dstFormat); + } static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat, const gpu::Element& srcFormat) { using namespace gpu; if (dstFormat != srcFormat) { diff --git a/libraries/shared/src/GenericThread.cpp b/libraries/shared/src/GenericThread.cpp index c1c31ab50a..00a80a2864 100644 --- a/libraries/shared/src/GenericThread.cpp +++ b/libraries/shared/src/GenericThread.cpp @@ -46,6 +46,8 @@ void GenericThread::initialize(bool isThreaded, QThread::Priority priority) { _thread->start(); _thread->setPriority(priority); + } else { + setup(); } } @@ -60,10 +62,16 @@ void GenericThread::terminate() { _thread->deleteLater(); _thread = NULL; } + } else { + shutdown(); } } void GenericThread::threadRoutine() { + if (_isThreaded) { + setup(); + } + while (!_stopThread) { // override this function to do whatever your class actually does, return false to exit thread early @@ -78,8 +86,13 @@ void GenericThread::threadRoutine() { } } - // If we were on a thread, then quit our thread - if (_isThreaded && _thread) { - _thread->quit(); + if (_isThreaded) { + shutdown(); + + // If we were on a thread, then quit our thread + if (_thread) { + _thread->quit(); + } } + } diff --git a/libraries/shared/src/GenericThread.h b/libraries/shared/src/GenericThread.h index 8362d3ba57..47f6d9dacd 100644 --- a/libraries/shared/src/GenericThread.h +++ b/libraries/shared/src/GenericThread.h @@ -33,9 +33,6 @@ public: /// Call to stop the thread void terminate(); - /// Override this function to do whatever your class actually does, return false to exit thread early. - virtual bool process() = 0; - virtual void terminating() { }; // lets your subclass know we're terminating, and it should respond appropriately bool isThreaded() const { return _isThreaded; } @@ -48,6 +45,10 @@ signals: void finished(); protected: + /// Override this function to do whatever your class actually does, return false to exit thread early. + virtual bool process() = 0; + virtual void setup() {}; + virtual void shutdown() {}; /// Locks all the resources of the thread. void lock() { _mutex.lock(); } From d1898eeac6f27fb9fb214e3795eb9b6412fe8f6d Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 4 Apr 2016 10:31:36 -0700 Subject: [PATCH 28/55] ModelCache: reset thread priority back to normal Based on PR feedback on https://github.com/highfidelity/hifi/pull/7550 --- .../model-networking/src/model-networking/ModelCache.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 4985859c40..852e3d9e81 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -10,6 +10,7 @@ // #include "ModelCache.h" +#include #include #include "FBXReader.h" #include "OBJReader.h" @@ -117,6 +118,9 @@ void GeometryReader::run() { originalPriority = QThread::NormalPriority; } QThread::currentThread()->setPriority(QThread::LowPriority); + Finally setPriorityBackToNormal([originalPriority]() { + QThread::currentThread()->setPriority(originalPriority); + }); if (!_resource.data()) { qCWarning(modelnetworking) << "Abandoning load of" << _url << "; resource was deleted"; @@ -167,8 +171,6 @@ void GeometryReader::run() { QMetaObject::invokeMethod(resource.data(), "finishedLoading", Qt::BlockingQueuedConnection, Q_ARG(bool, false)); } } - - QThread::currentThread()->setPriority(originalPriority); } class GeometryDefinitionResource : public GeometryResource { From e70319d83dce7a0ed7b93018b7f54cdd56908630 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Apr 2016 10:53:16 -0700 Subject: [PATCH 29/55] don't re-connect multiple times to QNetworkAccessManager signal --- ice-server/src/IceServer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index c1e92f276f..b66ccaa057 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -53,6 +53,10 @@ IceServer::IceServer(int argc, char* argv[]) : QTimer* inactivePeerTimer = new QTimer(this); connect(inactivePeerTimer, &QTimer::timeout, this, &IceServer::clearInactivePeers); inactivePeerTimer->start(CLEAR_INACTIVE_PEERS_INTERVAL_MSECS); + + // handle public keys when they arrive from the QNetworkAccessManager + auto& networkAccessManager = NetworkAccessManager::getInstance(); + connect(&networkAccessManager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished); } bool IceServer::packetVersionMatch(const udt::Packet& packet) { @@ -200,7 +204,6 @@ bool IceServer::isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& pla void IceServer::requestDomainPublicKey(const QUuid& domainID) { // send a request to the metaverse API for the public key for this domain auto& networkAccessManager = NetworkAccessManager::getInstance(); - connect(&networkAccessManager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished); QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL }; QString publicKeyPath = QString("/api/v1/domains/%1/public_key").arg(uuidStringWithoutCurlyBraces(domainID)); From d23d0f64326efc4ebb6cb41afa69ebafd4e54ffa Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Apr 2016 10:57:04 -0700 Subject: [PATCH 30/55] Restore thread priority after tex parsing --- .../src/model-networking/TextureCache.cpp | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index ff189b46f7..bbe907694a 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -11,20 +11,22 @@ #include "TextureCache.h" +#include +#include +#include +#include +#include + #include #include #include -#include -#include -#include -#include -#include -#include - #include +#include +#include + #include "ModelNetworkingLogging.h" TextureCache::TextureCache() { @@ -283,10 +285,12 @@ void ImageReader::run() { originalPriority = QThread::NormalPriority; } QThread::currentThread()->setPriority(QThread::LowPriority); + Finally restorePriority([originalPriority]{ + QThread::currentThread()->setPriority(originalPriority); + }); if (!_resource.data()) { qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; - QThread::currentThread()->setPriority(originalPriority); return; } @@ -318,7 +322,6 @@ void ImageReader::run() { auto resource = _resource.toStrongRef(); if (!resource) { qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; - QThread::currentThread()->setPriority(originalPriority); return; } @@ -336,8 +339,6 @@ void ImageReader::run() { Q_ARG(void*, texture), Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); } - - QThread::currentThread()->setPriority(originalPriority); } void NetworkTexture::setImage(void* voidTexture, int originalWidth, From 0bd747fa06a8186cb6729d9178d190409fec32f2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 4 Apr 2016 11:00:27 -0700 Subject: [PATCH 31/55] remove code that sends entity 'touch' events --- examples/controllers/handControllerGrab.js | 67 ---------------------- 1 file changed, 67 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index a3bed0a256..1945ff09ff 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -7,7 +7,6 @@ // Copyright 2015 High Fidelity, Inc. // // Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. -// Also supports touch and equipping objects. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -305,7 +304,6 @@ function MyController(hand) { switch (this.state) { case STATE_OFF: this.off(); - this.touchTest(); break; case STATE_SEARCHING: case STATE_HOLD_SEARCHING: @@ -1675,71 +1673,6 @@ function MyController(hand) { this.callEntityMethodOnGrabbed("continueFarTrigger"); }; - _this.allTouchedIDs = {}; - - this.touchTest = function() { - var maxDistance = 0.05; - var leftHandPosition = MyAvatar.getLeftPalmPosition(); - var rightHandPosition = MyAvatar.getRightPalmPosition(); - var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); - var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); - var ids = []; - - if (leftEntities.length !== 0) { - leftEntities.forEach(function(entity) { - ids.push(entity); - }); - - } - - if (rightEntities.length !== 0) { - rightEntities.forEach(function(entity) { - ids.push(entity); - }); - } - - ids.forEach(function(id) { - var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); - if (!props || - !props.boundingBox || - props.name === 'pointer') { - return; - } - var entityMinPoint = props.boundingBox.brn; - var entityMaxPoint = props.boundingBox.tfl; - var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); - var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); - - if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { - // we haven't been touched before, but either right or left is touching us now - _this.allTouchedIDs[id] = true; - _this.startTouch(id); - } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { - // we have been touched before and are still being touched - // continue touch - _this.continueTouch(id); - } else if (_this.allTouchedIDs[id]) { - delete _this.allTouchedIDs[id]; - _this.stopTouch(id); - } - }); - }; - - this.startTouch = function(entityID) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(entityID, "startTouch", args); - }; - - this.continueTouch = function(entityID) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(entityID, "continueTouch", args); - }; - - this.stopTouch = function(entityID) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(entityID, "stopTouch", args); - }; - this.release = function() { this.turnLightsOff(); this.turnOffVisualizations(); From a53cb2e532e568caed6f6e1b40d8cccecf2a4fa1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 4 Apr 2016 11:10:50 -0700 Subject: [PATCH 32/55] use _gravity rather than _acceleration also tweaks and comments about supporting low gravity --- libraries/entities/src/EntityItem.cpp | 74 +++++++++++++++++++-------- 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5b9791ca7b..578d57273f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -895,9 +895,9 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { angularVelocity *= powf(1.0f - _angularDamping, timeElapsed); } - const float EPSILON_ANGULAR_VELOCITY_LENGTH_SQUARED = 0.0017453f * 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec - if (glm::length2(angularVelocity) < EPSILON_ANGULAR_VELOCITY_LENGTH_SQUARED) { - angularVelocity = ENTITY_ITEM_ZERO_VEC3; + const float MIN_KINEMATIC_ANGULAR_SPEED_SQUARED = 0.0017453f * 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec + if (glm::length2(angularVelocity) < MIN_KINEMATIC_ANGULAR_SPEED_SQUARED) { + angularVelocity = Vectors::ZERO; } else { // for improved agreement with the way Bullet integrates rotations we use an approximation // and break the integration into bullet-sized substeps @@ -912,43 +912,75 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { isMoving = true; } } - if (glm::length2(linearVelocity) > 0.0f) { + glm::vec3 position = transform.getTranslation(); + + const float MIN_KINEMATIC_LINEAR_SPEED_SQUARED = 1.0e-6f; // 1mm/sec ^2 + bool hasLinearVelocity = (glm::length2(linearVelocity) > MIN_KINEMATIC_LINEAR_SPEED_SQUARED ); + if (hasLinearVelocity) { // linear damping if (_damping > 0.0f) { linearVelocity *= powf(1.0f - _damping, timeElapsed); } - glm::vec3 linearAcceleration = _acceleration; - bool nonZeroAcceleration = (glm::length2(_acceleration) > 0.0f); - if (nonZeroAcceleration) { - // acceleration is in world-frame but we need it in local-frame - bool success; - Transform parentTransform = getParentTransform(success); - if (success) { - linearAcceleration = glm::inverse(parentTransform.getRotation()) * linearAcceleration; - } + // integrate position forward sans acceleration + position += linearVelocity * timeElapsed; + } + + const float MIN_KINEMATIC_GRAVITY_MOTION_SQUARED = 1.0e-6f; // 0.001 mm/sec^2 + bool hasGravity = (glm::length2(_gravity) > MIN_KINEMATIC_GRAVITY_MOTION_SQUARED); + if (hasGravity) { + // acceleration is in world-frame but we need it in local-frame + glm::vec3 linearAcceleration = _gravity; + bool success; + Transform parentTransform = getParentTransform(success); + if (success) { + linearAcceleration = glm::inverse(parentTransform.getRotation()) * linearAcceleration; } - // integrate position forward - glm::vec3 position = transform.getTranslation() + (linearVelocity * timeElapsed) + 0.5f * linearAcceleration * timeElapsed * timeElapsed; - transform.setTranslation(position); + // integrate position's acceleration term + position += 0.5f * linearAcceleration * timeElapsed * timeElapsed; // integrate linearVelocity linearVelocity += linearAcceleration * timeElapsed; + } - const float EPSILON_LINEAR_VELOCITY_LENGTH_SQUARED = 1.0e-6f; // 1mm/sec ^2 - if (glm::length2(linearVelocity) < EPSILON_LINEAR_VELOCITY_LENGTH_SQUARED) { - setVelocity(ENTITY_ITEM_ZERO_VEC3); - if (nonZeroAcceleration) { + if (hasLinearVelocity || hasGravity) { + // We MUST eventually stop kinematic motion for slow entities otherwise they will take + // a looooong time to settle down, so we remeasure linear speed and zero the velocity + // if it is too small. + if (glm::length2(linearVelocity) < MIN_KINEMATIC_LINEAR_SPEED_SQUARED) { + linearVelocity = Vectors::ZERO; + if (!hasLinearVelocity) { + // Despite some gravity the final linear velocity is still too small to defeat the + // "effective resistance of free-space" which means we must reset position back to + // where it started since otherwise the entity may creep vveerrryy sslloowwllyy at + // a constant speed. + position = transform.getTranslation(); + + // Ultimately what this means is that there is some minimum gravity we can + // fully support for kinematic motion. It's exact value is a function of this + // entity's linearDamping and the hardcoded MIN_KINEMATIC_FOO parameters above, + // but the theoretical minimum gravity for zero damping at 90Hz is: + // + // minGravity = minSpeed / dt = 0.001 m/sec * 90 /sec = 0.09 m/sec^2 + // + // In practice the true minimum is half that value, since if the frame rate is ever + // less than the expected then sometimes dt will be twice as long. + // + // Since we don't set isMoving true here this entity is destined to transition to + // STATIC unless it has some angular motion keeping it alive. + } else { isMoving = true; } } else { isMoving = true; } } + transform.setTranslation(position); setLocalTransformAndVelocities(transform, linearVelocity, angularVelocity); + if (!isMoving) { - // flag this entity to be removed from kinematic motion + // flag this entity to transition from KINEMATIC to STATIC _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } } From a08ab8e127d066aacf73ca12cac9679f1a8b19f1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 4 Apr 2016 11:48:45 -0700 Subject: [PATCH 33/55] restore setFlag in simulateKinematicMotion() --- libraries/entities/src/EntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 578d57273f..9fa58c9187 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -979,7 +979,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { transform.setTranslation(position); setLocalTransformAndVelocities(transform, linearVelocity, angularVelocity); - if (!isMoving) { + if (setFlags && !isMoving) { // flag this entity to transition from KINEMATIC to STATIC _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } From aa0245b9c24822410a8e32cac698a6828d9ff1e7 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Apr 2016 12:20:45 -0700 Subject: [PATCH 34/55] Debug when limit of checkins reached --- libraries/networking/src/NodeList.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 02bb17e870..63189abb3e 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -336,6 +336,7 @@ void NodeList::sendDomainServerCheckIn() { if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { // we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS // so emit our signal that says that + qDebug() << "Limit of silent domain checkins reached"; emit limitOfSilentDomainCheckInsReached(); } From a9197385b5437f160e656867e8b6fea66d40e9e5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 4 Apr 2016 12:24:26 -0700 Subject: [PATCH 35/55] Make debug builds work again. Only run mt.exe on the manifest in non development builds. --- interface/CMakeLists.txt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index b7aeb7696e..2e50502840 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -107,12 +107,15 @@ elseif(WIN32) # add an executable that also has the icon itself and the configured rc file as resources add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT}) - add_custom_command( - TARGET ${TARGET_NAME} - POST_BUILD - COMMAND "mt.exe" -manifest "${CMAKE_CURRENT_SOURCE_DIR}/interface.exe.manifest" -inputresource:"$"\;\#1 -outputresource:"$"\;\#1 - COMMENT "Adding OS version support manifest to exe" - ) + if ( NOT DEV_BUILD ) + add_custom_command( + TARGET ${TARGET_NAME} + POST_BUILD + COMMAND "mt.exe" -manifest "${CMAKE_CURRENT_SOURCE_DIR}/interface.exe.manifest" -inputresource:"$"\;\#1 -outputresource:"$"\;\#1 + COMMENT "Adding OS version support manifest to exe" + ) + endif() + else() add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM}) endif() From d7b13d226f5b469098c7556ebef75199165d0d7d Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 4 Apr 2016 12:36:18 -0700 Subject: [PATCH 36/55] Application: fix for jittery hands when moving. The issue was that the hands are sampled in sensor coordinates. But when the avatar is moved via physics, the sensor to world matrix must be updated to move the hands in the world by the correct amount. These new hand positions are then computed before IK is performed. --- interface/src/Application.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0172b3ce3a..9e97fba466 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1470,10 +1470,6 @@ void Application::paintGL() { // update the avatar with a fresh HMD pose getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose()); - // update sensorToWorldMatrix for camera and hand controllers - getMyAvatar()->updateSensorToWorldMatrix(); - - auto lodManager = DependencyManager::get(); @@ -3406,6 +3402,9 @@ void Application::update(float deltaTime) { avatarManager->updateOtherAvatars(deltaTime); } + // update sensorToWorldMatrix for camera and hand controllers + getMyAvatar()->updateSensorToWorldMatrix(); + qApp->updateMyAvatarLookAtPosition(); { From ace4546dec1a5fcbb064baefbd52d266febba836 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 4 Apr 2016 12:49:03 -0700 Subject: [PATCH 37/55] make handGrabController search ray follow controller rather than IK driven hand --- examples/controllers/handControllerGrab.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index a3bed0a256..d8795341bb 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -495,7 +495,8 @@ function MyController(hand) { } }; - this.searchIndicatorOn = function(handPosition, distantPickRay) { + this.searchIndicatorOn = function(distantPickRay) { + var handPosition = distantPickRay.origin; var SEARCH_SPHERE_SIZE = 0.011; var SEARCH_SPHERE_FOLLOW_RATE = 0.50; @@ -857,7 +858,9 @@ function MyController(hand) { var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; var currentHandRotation = Controller.getPoseValue(controllerHandInput).rotation; - var currentControllerPosition = Controller.getPoseValue(controllerHandInput).position; + var currentControllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, + Controller.getPoseValue(controllerHandInput).translation), + MyAvatar.position); var handDeltaRotation = Quat.multiply(currentHandRotation, Quat.inverse(this.startingHandRotation)); var avatarControllerPose = Controller.getPoseValue((this.hand === RIGHT_HAND) ? @@ -865,19 +868,13 @@ function MyController(hand) { var controllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation); var distantPickRay = { - origin: PICK_WITH_HAND_RAY ? handPosition : Camera.position, + origin: PICK_WITH_HAND_RAY ? currentControllerPosition : Camera.position, direction: PICK_WITH_HAND_RAY ? Quat.getUp(controllerRotation) : Vec3.mix(Quat.getUp(controllerRotation), Quat.getFront(Camera.orientation), HAND_HEAD_MIX_RATIO), length: PICK_MAX_DISTANCE }; - var searchVisualizationPickRay = { - origin: currentControllerPosition, - direction: Quat.getUp(this.getHandRotation()), - length: PICK_MAX_DISTANCE - }; - // Pick at some maximum rate, not always var pickRays = []; var now = Date.now(); @@ -1086,7 +1083,7 @@ function MyController(hand) { this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); } - this.searchIndicatorOn(handPosition, distantPickRay); + this.searchIndicatorOn(distantPickRay); Reticle.setVisible(false); }; @@ -1668,7 +1665,7 @@ function MyController(hand) { if (intersection.intersects) { this.intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); } - this.searchIndicatorOn(handPosition, pickRay); + this.searchIndicatorOn(pickRay); } } From b3b5c5d1eacee6d761034477d16b5c256f5d711b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 4 Apr 2016 13:14:52 -0700 Subject: [PATCH 38/55] small change to trigger a build --- interface/src/Application.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 61d0f4f995..fdd31ed579 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -169,9 +169,7 @@ #include "Util.h" #include "InterfaceParentFinder.h" - - -// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU +// ON Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. #if defined(Q_OS_WIN) extern "C" { From f34e951c3f06de3c04b27c2553a5cab82e4b8880 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Apr 2016 13:28:13 -0700 Subject: [PATCH 39/55] Make resource cache props thread-safe --- libraries/networking/src/ResourceCache.cpp | 32 ++++++++++++++++------ libraries/networking/src/ResourceCache.h | 31 +++++++++++++-------- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 1f687593bb..2e2b89046b 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -38,6 +38,7 @@ ResourceCache::~ResourceCache() { void ResourceCache::refreshAll() { // Clear all unused resources so we don't have to reload them clearUnusedResource(); + resetResourceCounters(); // Refresh all remaining resources in use foreach (auto resource, _resources) { @@ -53,16 +54,24 @@ void ResourceCache::refresh(const QUrl& url) { resource->refresh(); } else { _resources.remove(url); + resetResourceCounters(); } } -const QVariantList ResourceCache::getResourceList() const { +QVariantList ResourceCache::getResourceList() { QVariantList list; - auto resources = _resources.uniqueKeys(); - list.reserve(resources.size()); - for (auto& resource : resources) { - list << resource; + if (QThread::currentThread() != thread()) { + // NOTE: invokeMethod does not allow a const QObject* + QMetaObject::invokeMethod(this, "getResourceList", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QVariantList, list)); + } else { + auto resources = _resources.uniqueKeys(); + list.reserve(resources.size()); + for (auto& resource : resources) { + list << resource; + } } + return list; } @@ -124,7 +133,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) { _unusedResourcesMaxSize = clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE); reserveUnusedResource(0); - emit dirty(); + resetResourceCounters(); } void ResourceCache::addUnusedResource(const QSharedPointer& resource) { @@ -138,7 +147,8 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) resource->setLRUKey(++_lastLRUKey); _unusedResources.insert(resource->getLRUKey(), resource); _unusedResourcesSize += resource->getBytes(); - emit dirty(); + + resetResourceCounters(); } void ResourceCache::removeUnusedResource(const QSharedPointer& resource) { @@ -146,7 +156,7 @@ void ResourceCache::removeUnusedResource(const QSharedPointer& resourc _unusedResources.remove(resource->getLRUKey()); _unusedResourcesSize -= resource->getBytes(); } - emit dirty(); + resetResourceCounters(); } void ResourceCache::reserveUnusedResource(qint64 resourceSize) { @@ -177,6 +187,12 @@ void ResourceCache::clearUnusedResource() { } } +void ResourceCache::resetResourceCounters() { + _numTotalResources = _resources.size(); + _numUnusedResources = _unusedResources.size(); + emit dirty(); +} + void ResourceCache::updateTotalSize(const qint64& oldSize, const qint64& newSize) { _totalResourcesSize += (newSize - oldSize); emit dirty(); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 3f930a1f11..933eb1a6d9 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -12,7 +12,9 @@ #ifndef hifi_ResourceCache_h #define hifi_ResourceCache_h +#include #include + #include #include #include @@ -29,6 +31,8 @@ #include "ResourceManager.h" +Q_DECLARE_METATYPE(size_t) + class QNetworkReply; class QTimer; @@ -79,20 +83,19 @@ private: /// Base class for resource caches. class ResourceCache : public QObject { Q_OBJECT - Q_PROPERTY(int numTotal READ getNumTotalResources NOTIFY dirty) - Q_PROPERTY(int numCached READ getNumCachedResources NOTIFY dirty) - Q_PROPERTY(qint64 sizeTotal READ getSizeTotalResources NOTIFY dirty) - Q_PROPERTY(qint64 sizeCached READ getSizeCachedResources NOTIFY dirty) - Q_PROPERTY(QVariantList resources READ getResourceList NOTIFY dirty) + Q_PROPERTY(size_t numTotal READ getNumTotalResources NOTIFY dirty) + Q_PROPERTY(size_t numCached READ getNumCachedResources NOTIFY dirty) + Q_PROPERTY(size_t sizeTotal READ getSizeTotalResources NOTIFY dirty) + Q_PROPERTY(size_t sizeCached READ getSizeCachedResources NOTIFY dirty) public: - int getNumTotalResources() const { return _resources.size(); } - qint64 getSizeTotalResources() const { return _totalResourcesSize; } + size_t getNumTotalResources() const { return _numTotalResources; } + size_t getSizeTotalResources() const { return _totalResourcesSize; } - int getNumCachedResources() const { return _unusedResources.size(); } - qint64 getSizeCachedResources() const { return _unusedResourcesSize; } + size_t getNumCachedResources() const { return _numUnusedResources; } + size_t getSizeCachedResources() const { return _unusedResourcesSize; } - const QVariantList getResourceList() const; + Q_INVOKABLE QVariantList getResourceList(); static void setRequestLimit(int limit); static int getRequestLimit() { return _requestLimit; } @@ -149,6 +152,7 @@ private: void reserveUnusedResource(qint64 resourceSize); void clearUnusedResource(); + void resetResourceCounters(); QHash> _resources; int _lastLRUKey = 0; @@ -160,8 +164,11 @@ private: QReadWriteLock _resourcesToBeGottenLock; QQueue _resourcesToBeGotten; - qint64 _totalResourcesSize { 0 }; - qint64 _unusedResourcesSize { 0 }; + std::atomic _numTotalResources { 0 }; + std::atomic _numUnusedResources { 0 }; + + std::atomic _totalResourcesSize { 0 }; + std::atomic _unusedResourcesSize { 0 }; qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; QMap> _unusedResources; From 107cfcf10b5acf675a9fb5102b25c737f29663d2 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Apr 2016 13:28:30 -0700 Subject: [PATCH 40/55] Change Resource setBytes->setSize --- .../model-networking/src/model-networking/TextureCache.cpp | 2 +- libraries/networking/src/ResourceCache.cpp | 4 ++-- libraries/networking/src/ResourceCache.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 3ba36dc2da..2ffd7e18a0 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -338,7 +338,7 @@ void NetworkTexture::setImage(void* voidTexture, int originalWidth, if (gpuTexture) { _width = gpuTexture->getWidth(); _height = gpuTexture->getHeight(); - setBytes(gpuTexture->getStoredSize()); + setSize(gpuTexture->getStoredSize()); } else { // FIXME: If !gpuTexture, we failed to load! _width = _height = 0; diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 2e2b89046b..c661c2f32a 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -416,7 +416,7 @@ void Resource::finishedLoading(bool success) { emit finished(success); } -void Resource::setBytes(const qint64& bytes) { +void Resource::setSize(const qint64& bytes) { QMetaObject::invokeMethod(_cache.data(), "updateTotalSize", Q_ARG(qint64, _bytes), Q_ARG(qint64, bytes)); _bytes = bytes; } @@ -456,7 +456,7 @@ void Resource::handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTota void Resource::handleReplyFinished() { Q_ASSERT_X(_request, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished"); - setBytes(_bytesTotal); + setSize(_bytesTotal); if (!_request || _request != sender()) { // This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted. diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 933eb1a6d9..84eba1cdc0 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -255,7 +255,7 @@ protected: virtual void downloadFinished(const QByteArray& data) { finishedLoading(true); } /// Called when the download is finished and processed, sets the number of actual bytes. - void setBytes(const qint64& bytes); + void setSize(const qint64& bytes); /// Called when the download is finished and processed. /// This should be called by subclasses that override downloadFinished to mark the end of processing. From 69bb0ebd741f56f388e560728359d759b8d9d5ff Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 4 Apr 2016 16:11:54 -0700 Subject: [PATCH 41/55] Revert "faster kinematic motion for entities" --- libraries/entities/src/EntityItem.cpp | 161 ++++++++++-------- libraries/physics/src/EntityMotionState.cpp | 19 ++- libraries/physics/src/EntityMotionState.h | 6 +- libraries/physics/src/ObjectMotionState.cpp | 21 +-- libraries/physics/src/ObjectMotionState.h | 10 +- libraries/physics/src/PhysicsEngine.cpp | 31 +--- libraries/physics/src/PhysicsEngine.h | 6 +- .../physics/src/ThreadSafeDynamicsWorld.cpp | 26 +-- .../physics/src/ThreadSafeDynamicsWorld.h | 1 - libraries/shared/src/GLMHelpers.cpp | 8 + libraries/shared/src/GLMHelpers.h | 4 +- libraries/shared/src/PhysicsCollisionGroups.h | 4 +- libraries/shared/src/SharedUtil.cpp | 17 +- libraries/shared/src/SharedUtil.h | 6 +- libraries/shared/src/SpatiallyNestable.cpp | 50 ++---- libraries/shared/src/SpatiallyNestable.h | 7 - libraries/shared/src/Transform.cpp | 4 + libraries/shared/src/Transform.h | 2 +- 18 files changed, 164 insertions(+), 219 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 9fa58c9187..431d638063 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -876,112 +876,123 @@ void EntityItem::simulate(const quint64& now) { } void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { - if (hasActions() || timeElapsed < 0.0f) { +#ifdef WANT_DEBUG + qCDebug(entities) << "EntityItem::simulateKinematicMotion timeElapsed" << timeElapsed; +#endif + + const float MIN_TIME_SKIP = 0.0f; + const float MAX_TIME_SKIP = 1.0f; // in seconds + + timeElapsed = glm::clamp(timeElapsed, MIN_TIME_SKIP, MAX_TIME_SKIP); + + if (hasActions()) { return; } - const float MAX_TIME_ELAPSED = 1.0f; // seconds - timeElapsed = glm::min(timeElapsed, MAX_TIME_ELAPSED); + if (hasLocalAngularVelocity()) { + glm::vec3 localAngularVelocity = getLocalAngularVelocity(); - Transform transform; - glm::vec3 linearVelocity; - glm::vec3 angularVelocity; - getLocalTransformAndVelocities(transform, linearVelocity, angularVelocity); - - bool isMoving = false; - if (glm::length2(angularVelocity) > 0.0f) { // angular damping if (_angularDamping > 0.0f) { - angularVelocity *= powf(1.0f - _angularDamping, timeElapsed); + localAngularVelocity *= powf(1.0f - _angularDamping, timeElapsed); + #ifdef WANT_DEBUG + qCDebug(entities) << " angularDamping :" << _angularDamping; + qCDebug(entities) << " newAngularVelocity:" << localAngularVelocity; + #endif } - const float MIN_KINEMATIC_ANGULAR_SPEED_SQUARED = 0.0017453f * 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec - if (glm::length2(angularVelocity) < MIN_KINEMATIC_ANGULAR_SPEED_SQUARED) { - angularVelocity = Vectors::ZERO; + float angularSpeed = glm::length(localAngularVelocity); + + const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec + if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) { + if (setFlags && angularSpeed > 0.0f) { + _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; + } + localAngularVelocity = ENTITY_ITEM_ZERO_VEC3; } else { // for improved agreement with the way Bullet integrates rotations we use an approximation // and break the integration into bullet-sized substeps - glm::quat rotation = transform.getRotation(); + glm::quat rotation = getRotation(); float dt = timeElapsed; - while (dt > 0.0f) { - glm::quat dQ = computeBulletRotationStep(angularVelocity, glm::min(dt, PHYSICS_ENGINE_FIXED_SUBSTEP)); + while (dt > PHYSICS_ENGINE_FIXED_SUBSTEP) { + glm::quat dQ = computeBulletRotationStep(localAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP); rotation = glm::normalize(dQ * rotation); dt -= PHYSICS_ENGINE_FIXED_SUBSTEP; } - transform.setRotation(rotation); - isMoving = true; - } - } - glm::vec3 position = transform.getTranslation(); + // NOTE: this final partial substep can drift away from a real Bullet simulation however + // it only becomes significant for rapidly rotating objects + // (e.g. around PI/4 radians per substep, or 7.5 rotations/sec at 60 substeps/sec). + glm::quat dQ = computeBulletRotationStep(localAngularVelocity, dt); + rotation = glm::normalize(dQ * rotation); - const float MIN_KINEMATIC_LINEAR_SPEED_SQUARED = 1.0e-6f; // 1mm/sec ^2 - bool hasLinearVelocity = (glm::length2(linearVelocity) > MIN_KINEMATIC_LINEAR_SPEED_SQUARED ); - if (hasLinearVelocity) { - // linear damping - if (_damping > 0.0f) { - linearVelocity *= powf(1.0f - _damping, timeElapsed); + setRotation(rotation); } - // integrate position forward sans acceleration - position += linearVelocity * timeElapsed; + setLocalAngularVelocity(localAngularVelocity); } - const float MIN_KINEMATIC_GRAVITY_MOTION_SQUARED = 1.0e-6f; // 0.001 mm/sec^2 - bool hasGravity = (glm::length2(_gravity) > MIN_KINEMATIC_GRAVITY_MOTION_SQUARED); - if (hasGravity) { - // acceleration is in world-frame but we need it in local-frame - glm::vec3 linearAcceleration = _gravity; + if (hasLocalVelocity()) { + + // acceleration is in the global frame, so transform it into the local frame. + // TODO: Move this into SpatiallyNestable. bool success; - Transform parentTransform = getParentTransform(success); + Transform transform = getParentTransform(success); + glm::vec3 localAcceleration(glm::vec3::_null); if (success) { - linearAcceleration = glm::inverse(parentTransform.getRotation()) * linearAcceleration; + localAcceleration = glm::inverse(transform.getRotation()) * getAcceleration(); + } else { + localAcceleration = getAcceleration(); } - // integrate position's acceleration term - position += 0.5f * linearAcceleration * timeElapsed * timeElapsed; + // linear damping + glm::vec3 localVelocity = getLocalVelocity(); + if (_damping > 0.0f) { + localVelocity *= powf(1.0f - _damping, timeElapsed); + #ifdef WANT_DEBUG + qCDebug(entities) << " damping:" << _damping; + qCDebug(entities) << " velocity AFTER dampingResistance:" << localVelocity; + qCDebug(entities) << " glm::length(velocity):" << glm::length(localVelocity); + #endif + } - // integrate linearVelocity - linearVelocity += linearAcceleration * timeElapsed; - } + // integrate position forward + glm::vec3 localPosition = getLocalPosition(); + glm::vec3 newLocalPosition = localPosition + (localVelocity * timeElapsed) + 0.5f * localAcceleration * timeElapsed * timeElapsed; - if (hasLinearVelocity || hasGravity) { - // We MUST eventually stop kinematic motion for slow entities otherwise they will take - // a looooong time to settle down, so we remeasure linear speed and zero the velocity - // if it is too small. - if (glm::length2(linearVelocity) < MIN_KINEMATIC_LINEAR_SPEED_SQUARED) { - linearVelocity = Vectors::ZERO; - if (!hasLinearVelocity) { - // Despite some gravity the final linear velocity is still too small to defeat the - // "effective resistance of free-space" which means we must reset position back to - // where it started since otherwise the entity may creep vveerrryy sslloowwllyy at - // a constant speed. - position = transform.getTranslation(); + #ifdef WANT_DEBUG + qCDebug(entities) << " EntityItem::simulate()...."; + qCDebug(entities) << " timeElapsed:" << timeElapsed; + qCDebug(entities) << " old AACube:" << getMaximumAACube(); + qCDebug(entities) << " old position:" << localPosition; + qCDebug(entities) << " old velocity:" << localVelocity; + qCDebug(entities) << " old getAABox:" << getAABox(); + qCDebug(entities) << " newPosition:" << newPosition; + qCDebug(entities) << " glm::distance(newPosition, position):" << glm::distance(newLocalPosition, localPosition); + #endif - // Ultimately what this means is that there is some minimum gravity we can - // fully support for kinematic motion. It's exact value is a function of this - // entity's linearDamping and the hardcoded MIN_KINEMATIC_FOO parameters above, - // but the theoretical minimum gravity for zero damping at 90Hz is: - // - // minGravity = minSpeed / dt = 0.001 m/sec * 90 /sec = 0.09 m/sec^2 - // - // In practice the true minimum is half that value, since if the frame rate is ever - // less than the expected then sometimes dt will be twice as long. - // - // Since we don't set isMoving true here this entity is destined to transition to - // STATIC unless it has some angular motion keeping it alive. - } else { - isMoving = true; + localPosition = newLocalPosition; + + // apply effective acceleration, which will be the same as gravity if the Entity isn't at rest. + localVelocity += localAcceleration * timeElapsed; + + float speed = glm::length(localVelocity); + const float EPSILON_LINEAR_VELOCITY_LENGTH = 0.001f; // 1mm/sec + if (speed < EPSILON_LINEAR_VELOCITY_LENGTH) { + setVelocity(ENTITY_ITEM_ZERO_VEC3); + if (setFlags && speed > 0.0f) { + _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } } else { - isMoving = true; + setLocalPosition(localPosition); + setLocalVelocity(localVelocity); } - } - transform.setTranslation(position); - setLocalTransformAndVelocities(transform, linearVelocity, angularVelocity); - if (setFlags && !isMoving) { - // flag this entity to transition from KINEMATIC to STATIC - _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; + #ifdef WANT_DEBUG + qCDebug(entities) << " new position:" << position; + qCDebug(entities) << " new velocity:" << velocity; + qCDebug(entities) << " new AACube:" << getMaximumAACube(); + qCDebug(entities) << " old getAABox:" << getAABox(); + #endif } } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 5f168d2e33..e3952ba1d6 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -94,7 +94,7 @@ void EntityMotionState::updateServerPhysicsVariables() { } // virtual -void EntityMotionState::handleEasyChanges(uint32_t& flags) { +bool EntityMotionState::handleEasyChanges(uint32_t& flags) { assert(entityTreeIsLocked()); updateServerPhysicsVariables(); ObjectMotionState::handleEasyChanges(flags); @@ -137,6 +137,8 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) { if ((flags & Simulation::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) { _body->activate(); } + + return true; } @@ -173,13 +175,11 @@ bool EntityMotionState::isMoving() const { // (2) at the beginning of each simulation step for KINEMATIC RigidBody's -- // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { - BT_PROFILE("getWorldTransform"); if (!_entity) { return; } assert(entityTreeIsLocked()); if (_motionType == MOTION_TYPE_KINEMATIC) { - BT_PROFILE("kinematicIntegration"); // This is physical kinematic motion which steps strictly by the subframe count // of the physics simulation. uint32_t thisStep = ObjectMotionState::getWorldSimulationStep(); @@ -420,18 +420,19 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { // acceleration measured during the most recent simulation step was close to gravity. - if (_accelerationNearlyGravityCount < STEPS_TO_DECIDE_BALLISTIC) { - // only increment this if we haven't reached the threshold yet, to avoid overflowing the counter - ++_accelerationNearlyGravityCount; + if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { + // only increment this if we haven't reached the threshold yet. this is to avoid + // overflowing the counter. + incrementAccelerationNearlyGravityCount(); } } else { - // acceleration wasn't similar to this entity's gravity, reset the counter - _accelerationNearlyGravityCount = 0; + // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter + resetAccelerationNearlyGravityCount(); } // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let // the entity server's estimates include gravity. - if (_accelerationNearlyGravityCount >= STEPS_TO_DECIDE_BALLISTIC) { + if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { _entity->setAcceleration(_entity->getGravity()); } else { _entity->setAcceleration(glm::vec3(0.0f)); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index eb42d03b52..ac16ec6d5d 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -29,7 +29,7 @@ public: virtual ~EntityMotionState(); void updateServerPhysicsVariables(); - virtual void handleEasyChanges(uint32_t& flags) override; + virtual bool handleEasyChanges(uint32_t& flags) override; virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) override; /// \return PhysicsMotionType based on params set in EntityItem @@ -51,6 +51,10 @@ public: virtual uint32_t getIncomingDirtyFlags() override; virtual void clearIncomingDirtyFlags() override; + void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; } + void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } + uint8_t getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } + virtual float getObjectRestitution() const override { return _entity->getRestitution(); } virtual float getObjectFriction() const override { return _entity->getFriction(); } virtual float getObjectLinearDamping() const override { return _entity->getDamping(); } diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index e902758461..482c3146f8 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -38,11 +38,8 @@ const glm::vec3& ObjectMotionState::getWorldOffset() { return _worldOffset; } -// We init worldSimulationStep to 1 instead of 0 because we initialize _lastKineticStep to (worldSimulationStep - 1) -// so that the object starts moving on the first frame that it was set kinematic. -static uint32_t worldSimulationStep { 1 }; - // static +uint32_t worldSimulationStep = 0; void ObjectMotionState::setWorldSimulationStep(uint32_t step) { assert(step > worldSimulationStep); worldSimulationStep = step; @@ -167,7 +164,7 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { } } -void ObjectMotionState::handleEasyChanges(uint32_t& flags) { +bool ObjectMotionState::handleEasyChanges(uint32_t& flags) { if (flags & Simulation::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); btVector3 newPosition = glmToBullet(getObjectPosition()); @@ -186,10 +183,6 @@ void ObjectMotionState::handleEasyChanges(uint32_t& flags) { worldTrans.setRotation(newRotation); } _body->setWorldTransform(worldTrans); - if (!(flags & HARD_DIRTY_PHYSICS_FLAGS) && _body->isStaticObject()) { - // force activate static body so its Aabb is updated later - _body->activate(true); - } } else if (flags & Simulation::DIRTY_ROTATION) { btTransform worldTrans = _body->getWorldTransform(); btQuaternion newRotation = glmToBullet(getObjectRotation()); @@ -199,10 +192,6 @@ void ObjectMotionState::handleEasyChanges(uint32_t& flags) { } worldTrans.setRotation(newRotation); _body->setWorldTransform(worldTrans); - if (!(flags & HARD_DIRTY_PHYSICS_FLAGS) && _body->isStaticObject()) { - // force activate static body so its Aabb is updated later - _body->activate(true); - } } if (flags & Simulation::DIRTY_LINEAR_VELOCITY) { @@ -243,6 +232,8 @@ void ObjectMotionState::handleEasyChanges(uint32_t& flags) { if (flags & Simulation::DIRTY_MASS) { updateBodyMassProperties(); } + + return true; } bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) { @@ -301,10 +292,6 @@ void ObjectMotionState::updateBodyVelocities() { _body->setActivationState(ACTIVE_TAG); } -void ObjectMotionState::updateLastKinematicStep() { - _lastKinematicStep = ObjectMotionState::getWorldSimulationStep() - 1; -} - void ObjectMotionState::updateBodyMassProperties() { float mass = getMass(); btVector3 inertia(0.0f, 0.0f, 0.0f); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 44cb88721c..bb78eb12d6 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -50,12 +50,11 @@ const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_MOTION_TY Simulation::DIRTY_COLLISION_GROUP); const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES | Simulation::DIRTY_MASS | Simulation::DIRTY_MATERIAL | - Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY | - Simulation::DIRTY_PHYSICS_ACTIVATION); - + Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY); // These are the set of incoming flags that the PhysicsEngine needs to hear about: -const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS); +const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS | + Simulation::DIRTY_PHYSICS_ACTIVATION); // These are the outgoing flags that the PhysicsEngine can affect: const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES; @@ -81,12 +80,11 @@ public: ObjectMotionState(btCollisionShape* shape); ~ObjectMotionState(); - virtual void handleEasyChanges(uint32_t& flags); + virtual bool handleEasyChanges(uint32_t& flags); virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine); void updateBodyMaterialProperties(); void updateBodyVelocities(); - void updateLastKinematicStep(); virtual void updateBodyMassProperties(); MotionStateType getType() const { return _type; } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index be80149c96..0040c19c3d 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -50,13 +50,6 @@ void PhysicsEngine::init() { // default gravity of the world is zero, so each object must specify its own gravity // TODO: set up gravity zones _dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f)); - - // By default Bullet will update the Aabb's of all objects every frame, even statics. - // This can waste CPU cycles so we configure Bullet to only update ACTIVE objects here. - // However, this means when a static object is moved we must manually update its Aabb - // in order for its broadphase collision queries to work correctly. Look at how we use - // _activeStaticBodies to track and update the Aabb's of moved static objects. - _dynamicsWorld->setForceUpdateAllAabbs(false); } } @@ -87,7 +80,6 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); body->updateInertiaTensor(); motionState->updateBodyVelocities(); - motionState->updateLastKinematicStep(); const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); @@ -197,18 +189,12 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob stillNeedChange.push_back(object); } } else if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - object->handleEasyChanges(flags); - object->clearIncomingDirtyFlags(); + if (object->handleEasyChanges(flags)) { + object->clearIncomingDirtyFlags(); + } else { + stillNeedChange.push_back(object); + } } - if (object->getMotionType() == MOTION_TYPE_STATIC && object->isActive()) { - _activeStaticBodies.push_back(object->getRigidBody()); - } - } - // active static bodies have changed (in an Easy way) and need their Aabbs updated - // but we've configured Bullet to NOT update them automatically (for improved performance) - // so we must do it ourselves - for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { - _dynamicsWorld->updateSingleAabb(_activeStaticBodies[i]); } return stillNeedChange; } @@ -254,7 +240,6 @@ void PhysicsEngine::stepSimulation() { float timeStep = btMin(dt, MAX_TIMESTEP); if (_myAvatarController) { - BT_PROFILE("avatarController"); // TODO: move this stuff outside and in front of stepSimulation, because // the updateShapeIfNecessary() call needs info from MyAvatar and should // be done on the main thread during the pre-simulation stuff @@ -403,12 +388,6 @@ const CollisionEvents& PhysicsEngine::getCollisionEvents() { const VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() { BT_PROFILE("copyOutgoingChanges"); - // Bullet will not deactivate static objects (it doesn't expect them to be active) - // so we must deactivate them ourselves - for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { - _activeStaticBodies[i]->forceActivationState(ISLAND_SLEEPING); - } - _activeStaticBodies.clear(); _dynamicsWorld->synchronizeMotionStates(); _hasOutgoingChanges = false; return _dynamicsWorld->getChangedMotionStates(); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 18e4016fec..f644d6f5b2 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -13,9 +13,9 @@ #define hifi_PhysicsEngine_h #include -#include #include +#include #include #include @@ -41,7 +41,7 @@ public: }; typedef std::map ContactMap; -typedef std::vector CollisionEvents; +typedef QVector CollisionEvents; class PhysicsEngine { public: @@ -110,7 +110,6 @@ private: ContactMap _contactMap; CollisionEvents _collisionEvents; QHash _objectActions; - std::vector _activeStaticBodies; glm::vec3 _originOffset; QUuid _sessionID; @@ -122,6 +121,7 @@ private: bool _dumpNextStats = false; bool _hasOutgoingChanges = false; + }; typedef std::shared_ptr PhysicsEnginePointer; diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index 5fe99f137c..b6f3487f1a 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -67,10 +67,7 @@ int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep saveKinematicState(fixedTimeStep*clampedSimulationSteps); - { - BT_PROFILE("applyGravity"); - applyGravity(); - } + applyGravity(); for (int i=0;igetActivationState() != ISLAND_SLEEPING) - { - if (body->isKinematicObject()) - { - //to calculate velocities next frame - body->saveKinematicState(timeStep); - } - } - } -} - - diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h index 68062d8d29..e9708149da 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.h +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h @@ -41,7 +41,6 @@ public: btScalar fixedTimeStep = btScalar(1.)/btScalar(60.), SubStepCallback onSubStep = []() { }); virtual void synchronizeMotionStates() override; - virtual void saveKinematicState(btScalar timeStep) override; // btDiscreteDynamicsWorld::m_localTime is the portion of real-time that has not yet been simulated // but is used for MotionState::setWorldTransform() extrapolation (a feature that Bullet uses to provide diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 53abb3827d..d21d88d212 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -463,6 +463,14 @@ glm::vec2 getFacingDir2D(const glm::mat4& m) { } } +bool isNaN(glm::vec3 value) { + return isNaN(value.x) || isNaN(value.y) || isNaN(value.z); +} + +bool isNaN(glm::quat value) { + return isNaN(value.w) || isNaN(value.x) || isNaN(value.y) || isNaN(value.z); +} + glm::mat4 orthoInverse(const glm::mat4& m) { glm::mat4 r = m; r[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 8b1446d4e5..469ca1fc81 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -229,8 +229,8 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda glm::vec2 getFacingDir2D(const glm::quat& rot); glm::vec2 getFacingDir2D(const glm::mat4& m); -inline bool isNaN(const glm::vec3& value) { return isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } -inline bool isNaN(const glm::quat& value) { return isNaN(value.w) || isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } +bool isNaN(glm::vec3 value); +bool isNaN(glm::quat value); glm::mat4 orthoInverse(const glm::mat4& m); diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index 794f338dc5..6d320e69cb 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -51,10 +51,10 @@ const int16_t BULLET_COLLISION_GROUP_COLLISIONLESS = 1 << 14; const int16_t BULLET_COLLISION_MASK_DEFAULT = ~ BULLET_COLLISION_GROUP_COLLISIONLESS; // STATIC does not collide with itself (as optimization of physics simulation) -const int16_t BULLET_COLLISION_MASK_STATIC = ~ (BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_KINEMATIC | BULLET_COLLISION_GROUP_STATIC); +const int16_t BULLET_COLLISION_MASK_STATIC = ~ (BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_STATIC); const int16_t BULLET_COLLISION_MASK_DYNAMIC = BULLET_COLLISION_MASK_DEFAULT; -const int16_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_STATIC; +const int16_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_DEFAULT; // MY_AVATAR does not collide with itself const int16_t BULLET_COLLISION_MASK_MY_AVATAR = ~(BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_MY_AVATAR); diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index d48bddbd88..30d4726bcc 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -247,6 +247,12 @@ int getNthBit(unsigned char byte, int ordinal) { return ERROR_RESULT; } +bool isBetween(int64_t value, int64_t max, int64_t min) { + return ((value <= max) && (value >= min)); +} + + + void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { //assert(value <= 3 && value >= 0); byte |= ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 @@ -254,7 +260,12 @@ void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { bool isInEnvironment(const char* environment) { char* environmentString = getenv("HIFI_ENVIRONMENT"); - return (environmentString && strcmp(environmentString, environment) == 0); + + if (environmentString && strcmp(environmentString, environment) == 0) { + return true; + } else { + return false; + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -621,6 +632,10 @@ void debug::checkDeadBeef(void* memoryVoid, int size) { assert(memcmp((unsigned char*)memoryVoid, DEADBEEF, std::min(size, DEADBEEF_SIZE)) != 0); } +bool isNaN(float value) { + return value != value; +} + QString formatUsecTime(float usecs, int prec) { static const quint64 SECONDS_PER_MINUTE = 60; static const quint64 USECS_PER_MINUTE = USECS_PER_SECOND * SECONDS_PER_MINUTE; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index e9201b4a92..8fb65a5247 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -180,11 +180,11 @@ private: static int DEADBEEF_SIZE; }; -/// \return true when value is between max and min -inline bool isBetween(int64_t value, int64_t max, int64_t min) { return ((value <= max) && (value >= min)); } +bool isBetween(int64_t value, int64_t max, int64_t min); + /// \return bool is the float NaN -inline bool isNaN(float value) { return value != value; } +bool isNaN(float value); QString formatUsecTime(float usecs, int prec = 3); QString formatSecondsElapsed(float seconds); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 3cbd3c5ac9..13bf5d9054 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -90,9 +90,11 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) cons return parent; } + SpatiallyNestablePointer thisPointer = getThisPointer(); + if (parent) { // we have a parent pointer but our _parentID doesn't indicate this parent. - parent->forgetChild(getThisPointer()); + parent->forgetChild(thisPointer); _parentKnowsMe = false; _parent.reset(); } @@ -110,11 +112,16 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) cons parent = _parent.lock(); if (parent) { - parent->beParentOfChild(getThisPointer()); + parent->beParentOfChild(thisPointer); _parentKnowsMe = true; } - success = (parent || parentID.isNull()); + if (parent || parentID.isNull()) { + success = true; + } else { + success = false; + } + return parent; } @@ -842,40 +849,3 @@ AACube SpatiallyNestable::getQueryAACube() const { } return result; } - -void SpatiallyNestable::getLocalTransformAndVelocities( - Transform& transform, - glm::vec3& velocity, - glm::vec3& angularVelocity) const { - // transform - _transformLock.withReadLock([&] { - transform = _transform; - }); - // linear velocity - _velocityLock.withReadLock([&] { - velocity = _velocity; - }); - // angular velocity - _angularVelocityLock.withReadLock([&] { - angularVelocity = _angularVelocity; - }); -} - -void SpatiallyNestable::setLocalTransformAndVelocities( - const Transform& localTransform, - const glm::vec3& localVelocity, - const glm::vec3& localAngularVelocity) { - // transform - _transformLock.withWriteLock([&] { - _transform = localTransform; - }); - // linear velocity - _velocityLock.withWriteLock([&] { - _velocity = localVelocity; - }); - // angular velocity - _angularVelocityLock.withWriteLock([&] { - _angularVelocity = localAngularVelocity; - }); - locationChanged(); -} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index ef70d0231b..379f2facd7 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -149,13 +149,6 @@ protected: quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer(bool& success) const; - void getLocalTransformAndVelocities(Transform& localTransform, glm::vec3& localVelocity, glm::vec3& localAngularVelocity) const; - - void setLocalTransformAndVelocities( - const Transform& localTransform, - const glm::vec3& localVelocity, - const glm::vec3& localAngularVelocity); - mutable SpatiallyNestableWeakPointer _parent; virtual void beParentOfChild(SpatiallyNestablePointer newChild) const; diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index c51b3dae4b..a3a3c05731 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -150,3 +150,7 @@ QJsonObject Transform::toJson(const Transform& transform) { } return result; } + +bool Transform::containsNaN() const { + return isNaN(_rotation) || isNaN(_scale) || isNaN(_translation); +} diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 1e1d10c54b..1024173cbd 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -145,7 +145,7 @@ public: Vec4 transform(const Vec4& pos) const; Vec3 transform(const Vec3& pos) const; - bool containsNaN() const { return isNaN(_rotation) || isNaN(glm::dot(_scale, _translation)); } + bool containsNaN() const; protected: From c168e2cc5894be2d612b50f15d9bfebcb8e8de40 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 4 Apr 2016 13:37:18 -0700 Subject: [PATCH 42/55] PR feedback --- libraries/gpu/src/gpu/GLBackend.h | 6 ++-- libraries/gpu/src/gpu/GLBackendTexture.cpp | 23 +++++++-------- .../gpu/src/gpu/GLBackendTextureTransfer.cpp | 29 +++++++++++++++---- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 4f22a68631..f9fd299827 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -103,13 +103,13 @@ public: SyncState getSyncState() const { return _syncState; } // Is the storage out of date relative to the gpu texture? - bool invalid() const; + bool isInvalid() const; // Is the content out of date relative to the gpu texture? - bool outdated() const; + bool isOutdated() const; // Is the texture in a state where it can be rendered with no work? - bool ready() const; + bool isReady() const; // Move the image bits from the CPU to the GPU void transfer() const; diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 92123a68be..f38cc89a8c 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -19,8 +19,6 @@ using namespace gpu; GLenum gpuToGLTextureType(const Texture& texture) { - // If we get here, we need to allocate and or update the content of the texture - // or it's already being transferred switch (texture.getType()) { case Texture::TEX_2D: return GL_TEXTURE_2D; @@ -94,17 +92,17 @@ GLBackend::GLTexture::~GLTexture() { Backend::decrementTextureGPUCount(); } -bool GLBackend::GLTexture::invalid() const { +bool GLBackend::GLTexture::isInvalid() const { return _storageStamp < _gpuTexture.getStamp(); } -bool GLBackend::GLTexture::outdated() const { +bool GLBackend::GLTexture::isOutdated() const { return _contentStamp < _gpuTexture.getDataStamp(); } -bool GLBackend::GLTexture::ready() const { +bool GLBackend::GLTexture::isReady() const { // If we have an invalid texture, we're never ready - if (invalid()) { + if (isInvalid()) { return false; } @@ -112,7 +110,7 @@ bool GLBackend::GLTexture::ready() const { // as a special case auto syncState = _syncState.load(); - if (outdated()) { + if (isOutdated()) { return Pending == syncState; } @@ -167,7 +165,7 @@ void GLBackend::GLTexture::transfer() const { case Texture::TEX_CUBE: // transfer pixels from each faces - for (int f = 0; f < CUBE_NUM_FACES; f++) { + for (uint8_t f = 0; f < CUBE_NUM_FACES; f++) { if (_gpuTexture.isStoredMipFaceAvailable(0, f)) { transferMip(CUBE_FACE_LAYOUT[f], _gpuTexture.accessStoredMipFace(0, f)); } @@ -188,15 +186,14 @@ void GLBackend::GLTexture::transfer() const { // Do any post-transfer operations that might be required on the main context / rendering thread void GLBackend::GLTexture::postTransfer() { setSyncState(GLTexture::Idle); + // At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory switch (_gpuTexture.getType()) { case Texture::TEX_2D: - // At this point the mip piels have been loaded, we can notify _gpuTexture.notifyMipFaceGPULoaded(0, 0); break; case Texture::TEX_CUBE: for (uint8_t f = 0; f < CUBE_NUM_FACES; ++f) { - // At this point the mip piels have been loaded, we can notify _gpuTexture.notifyMipFaceGPULoaded(0, f); } break; @@ -216,7 +213,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin // If the object hasn't been created, or the object definition is out of date, drop and re-create GLTexture* object = Backend::getGPUObject(texture); - if (object && object->ready()) { + if (object && object->isReady()) { return object; } @@ -224,7 +221,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin // Create the texture if need be (force re-creation if the storage stamp changes // for easier use of immutable storage) - if (!object || object->invalid()) { + if (!object || object->isInvalid()) { // This automatically destroys the old texture object = new GLTexture(texture); } @@ -236,7 +233,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin // Object might be outdated, if so, start the transfer // (outdated objects that are already in transfer will have reported 'true' for ready() - if (object->outdated()) { + if (object->isOutdated()) { _textureTransferHelper->transferTexture(texturePointer); } diff --git a/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp index aa5839b5b2..2610d9bc4a 100644 --- a/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp +++ b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp @@ -12,12 +12,15 @@ #include "GLTexelFormat.h" #ifdef THREADED_TEXTURE_TRANSFER -#include -#include -#include -#endif -using namespace gpu; +#include +#include + +//#define FORCE_DRAW_AFTER_TRANSFER + +#ifdef FORCE_DRAW_AFTER_TRANSFER + +#include static ProgramPtr _program; static ProgramPtr _cubeProgram; @@ -25,6 +28,12 @@ static ShapeWrapperPtr _plane; static ShapeWrapperPtr _skybox; static BasicFramebufferWrapperPtr _framebuffer; +#endif + +#endif + +using namespace gpu; + GLTextureTransferHelper::GLTextureTransferHelper() { #ifdef THREADED_TEXTURE_TRANSFER _canvas = std::make_shared(); @@ -54,6 +63,8 @@ void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texture void GLTextureTransferHelper::setup() { #ifdef THREADED_TEXTURE_TRANSFER _canvas->makeCurrent(); + +#ifdef FORCE_DRAW_AFTER_TRANSFER _program = loadDefaultShader(); _plane = loadPlane(_program); _cubeProgram = loadCubemapShader(); @@ -62,6 +73,8 @@ void GLTextureTransferHelper::setup() { _framebuffer->Init({ 100, 100 }); _framebuffer->fbo.Bind(oglplus::FramebufferTarget::Draw); #endif + +#endif } bool GLTextureTransferHelper::processQueueItems(const Queue& messages) { @@ -77,6 +90,7 @@ bool GLTextureTransferHelper::processQueueItems(const Queue& messages) { GLBackend::GLTexture* object = Backend::getGPUObject(*texturePointer); object->transfer(); +#ifdef FORCE_DRAW_AFTER_TRANSFER // Now force a draw using the texture try { switch (texturePointer->getType()) { @@ -99,9 +113,12 @@ bool GLTextureTransferHelper::processQueueItems(const Queue& messages) { } catch (const std::runtime_error& error) { qWarning() << "Failed to render texture on background thread: " << error.what(); } +#endif glBindTexture(object->_target, 0); - glFinish(); + auto writeSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glClientWaitSync(writeSync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); + glDeleteSync(writeSync); object->_contentStamp = texturePointer->getDataStamp(); object->setSyncState(GLBackend::GLTexture::Transferred); } From ac30aed9482d9a4117b8d4c5a94b57a6ed8aa55f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Apr 2016 17:52:41 -0700 Subject: [PATCH 43/55] Hold onto octree child after creation --- libraries/octree/src/Octree.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index ffbc2e6709..051e4f8791 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -384,9 +384,10 @@ int Octree::readElementData(OctreeElementPointer destinationElement, const unsig // check the exists mask to see if we have a child to traverse into if (oneAtBit(childInBufferMask, childIndex)) { - if (!destinationElement->getChildAtIndex(childIndex)) { + auto childAt = destinationElement->getChildAtIndex(childIndex); + if (!childAt) { // add a child at that index, if it doesn't exist - destinationElement->addChildAtIndex(childIndex); + childAt = destinationElement->addChildAtIndex(childIndex); bool nodeIsDirty = destinationElement->isDirty(); if (nodeIsDirty) { _isDirty = true; @@ -394,8 +395,7 @@ int Octree::readElementData(OctreeElementPointer destinationElement, const unsig } // tell the child to read the subsequent data - int lowerLevelBytes = readElementData(destinationElement->getChildAtIndex(childIndex), - nodeData + bytesRead, bytesLeftToRead, args); + int lowerLevelBytes = readElementData(childAt, nodeData + bytesRead, bytesLeftToRead, args); bytesRead += lowerLevelBytes; bytesLeftToRead -= lowerLevelBytes; From ffc2c75534345f0bc099004e847e96b3b8b23e9b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 5 Apr 2016 09:59:12 -0700 Subject: [PATCH 44/55] Don't release the Oculus plugin when disabling the plugin --- plugins/oculus/src/OculusHelpers.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index c9e702ecd0..9d3f95a979 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -90,12 +90,14 @@ ovrSession acquireOculusSession() { void releaseOculusSession() { Q_ASSERT(refCount > 0 && session); +#if 0 if (!--refCount) { qCDebug(oculus) << "oculus: zero refcount, shutdown SDK and session"; ovr_Destroy(session); ovr_Shutdown(); session = nullptr; } +#endif } From 6a7a572b53206ad3aa4b118dbc6e1da36e87274b Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 5 Apr 2016 11:06:24 -0700 Subject: [PATCH 45/55] Model: Toggling Physics > Draw Collision Hulls works again Collision renderItems were never getting removed when shouldShowCollisionHull became false. --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index a9dcb3883c..b510f58b12 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -434,6 +434,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) { _showCollisionHull = shouldShowCollisionHull; render::PendingChanges pendingChanges; + _model->removeFromScene(scene, pendingChanges); + render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); _model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull); From 71e6f9bdd67f2f97f9c6e49452fd420a8c9a1c76 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 5 Apr 2016 13:03:14 -0700 Subject: [PATCH 46/55] Display a blank frame before switching away from oculus --- plugins/oculus/src/OculusDisplayPlugin.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index a53643ba21..78a38d2b6a 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -52,6 +52,16 @@ void OculusDisplayPlugin::customizeContext() { } void OculusDisplayPlugin::uncustomizeContext() { + using namespace oglplus; + + // Present a final black frame to the HMD + _compositeFramebuffer->Bound(FramebufferTarget::Draw, [] { + Context::ClearColor(0, 0, 0, 1); + Context::Clear().ColorBuffer(); + }); + + hmdPresent(); + #if (OVR_MAJOR_VERSION >= 6) _sceneFbo.reset(); #endif From fd4a374e088decbaca7780b692519d449032eef0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 5 Apr 2016 13:04:17 -0700 Subject: [PATCH 47/55] Add comment --- plugins/oculus/src/OculusHelpers.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 9d3f95a979..71342f6e1b 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -90,6 +90,8 @@ ovrSession acquireOculusSession() { void releaseOculusSession() { Q_ASSERT(refCount > 0 && session); + // HACK the Oculus runtime doesn't seem to play well with repeated shutdown / restart. + // So for now we'll just hold on to the session #if 0 if (!--refCount) { qCDebug(oculus) << "oculus: zero refcount, shutdown SDK and session"; From d8282ae79993d36946919a879e955b7a4e0ec7c5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 5 Apr 2016 13:56:39 -0700 Subject: [PATCH 48/55] log value of QTWEBENGINE_REMOTE_DEBUGGING before exit --- interface/src/Application.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 311583acb7..86925429ab 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -38,6 +38,8 @@ #include +#include + #include #include @@ -1120,6 +1122,11 @@ void Application::aboutToQuit() { } void Application::cleanupBeforeQuit() { + // add a logline indicating if QTWEBENGINE_REMOTE_DEBUGGING is set or not + QProcessEnvironment env; + bool webengineRemoteDebuggingSet = env.keys().contains("QTWEBENGINE_REMOTE_DEBUGGING"); + qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebuggingSet; + // Stop third party processes so that they're not left running in the event of a subsequent shutdown crash. #ifdef HAVE_DDE DependencyManager::get()->setEnabled(false); From 4c632cb4c4cad30eb799ccbe1729feae3a3058a7 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 5 Apr 2016 14:00:43 -0700 Subject: [PATCH 49/55] Application: focusOut keyboard device when clicking on web entity. --- interface/src/Application.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 311583acb7..80e34f3ae9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1008,6 +1008,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : RenderableWebEntityItem* webEntity = dynamic_cast(entity.get()); if (webEntity) { webEntity->setProxyWindow(_window->windowHandle()); + if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) { + _keyboardMouseDevice->pluginFocusOutEvent(); + } _keyboardFocusedItem = entityItemID; _lastAcceptedKeyPress = usecTimestampNow(); if (_keyboardFocusHighlightID < 0 || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) { From f42e968dda7096a93b95707a93d27ab8688c3b0d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 5 Apr 2016 14:12:46 -0700 Subject: [PATCH 50/55] commit to repush to see if github is working yet --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 86925429ab..b50fe1292b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1122,7 +1122,7 @@ void Application::aboutToQuit() { } void Application::cleanupBeforeQuit() { - // add a logline indicating if QTWEBENGINE_REMOTE_DEBUGGING is set or not + // add a logline indicating if QTWEBENGINE_REMOTE_DEBUGGING is set or not. QProcessEnvironment env; bool webengineRemoteDebuggingSet = env.keys().contains("QTWEBENGINE_REMOTE_DEBUGGING"); qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebuggingSet; From bda8761e00bfede783f80c5171e700db5ff5d68e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 5 Apr 2016 14:30:41 -0700 Subject: [PATCH 51/55] fix how env variable is accessed --- interface/src/Application.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b50fe1292b..b4bc5fa665 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1122,10 +1122,9 @@ void Application::aboutToQuit() { } void Application::cleanupBeforeQuit() { - // add a logline indicating if QTWEBENGINE_REMOTE_DEBUGGING is set or not. - QProcessEnvironment env; - bool webengineRemoteDebuggingSet = env.keys().contains("QTWEBENGINE_REMOTE_DEBUGGING"); - qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebuggingSet; + // add a logline indicating if QTWEBENGINE_REMOTE_DEBUGGING is set or not + QString webengineRemoteDebugging = QProcessEnvironment::systemEnvironment().value("QTWEBENGINE_REMOTE_DEBUGGING", "false"); + qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebugging; // Stop third party processes so that they're not left running in the event of a subsequent shutdown crash. #ifdef HAVE_DDE From 91126037e0e81007657b2bb369a2214d561b962b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Apr 2016 14:18:08 -0700 Subject: [PATCH 52/55] Fix showDesktop SIGNAL --- libraries/ui/src/OffscreenUi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 745a28eb0b..269cf86e2d 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -447,7 +447,7 @@ void OffscreenUi::createDesktop(const QUrl& url) { new KeyboardFocusHack(); - connect(_desktop, SIGNAL(showDesktop()), this, SLOT(showDesktop())); + connect(_desktop, SIGNAL(showDesktop()), this, SIGNAL(showDesktop())); } QQuickItem* OffscreenUi::getDesktop() { From cba866b3758fcfdfb400963ab0e82a4d1412769a Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Apr 2016 14:44:56 -0700 Subject: [PATCH 53/55] Do not warn if no bookmarks file --- interface/src/Bookmarks.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/Bookmarks.cpp b/interface/src/Bookmarks.cpp index 2620451538..0e7941a5a4 100644 --- a/interface/src/Bookmarks.cpp +++ b/interface/src/Bookmarks.cpp @@ -63,6 +63,11 @@ bool Bookmarks::contains(const QString& name) const { void Bookmarks::readFromFile() { QFile loadFile(_bookmarksFilename); + if (!loadFile.exists()) { + // User has not yet saved bookmarks + return; + } + if (!loadFile.open(QIODevice::ReadOnly)) { qWarning("Couldn't open bookmarks file for reading"); return; From 29c287227c60689932b8a45e5dba9425aeb52142 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 5 Apr 2016 15:30:53 -0700 Subject: [PATCH 54/55] Fix AssignmentClient unpacking an assignment when it already has one --- assignment-client/src/AssignmentClient.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 85a2c95b4d..0455377d89 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -235,6 +235,11 @@ void AssignmentClient::sendAssignmentRequest() { void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer message) { qCDebug(assigmnentclient) << "Received a PacketType::CreateAssignment - attempting to unpack."; + if (_currentAssignment) { + qCWarning(assigmnentclient) << "Received a PacketType::CreateAssignment while still running an active assignment. Ignoring."; + return; + } + // construct the deployed assignment from the packet data _currentAssignment = AssignmentFactory::unpackAssignment(*message); From 07ff687bfec0c8ff742ea6619f5b35dad2c3c306 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 5 Apr 2016 18:12:02 -0700 Subject: [PATCH 55/55] Application: change keyboard input focus when using ui overlay. call focusOutEvent on keyboard input plugin when an offscreen ui has activeFocus. --- interface/src/Application.cpp | 9 +++++++++ interface/src/Application.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 311583acb7..66039cf41c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2564,6 +2564,15 @@ void Application::idle(uint64_t now) { _overlayConductor.setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Overlays)); } + // If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus. + auto offscreenUi = DependencyManager::get(); + if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) { + _keyboardMouseDevice->pluginFocusOutEvent(); + _keyboardDeviceHasFocus = false; + } else if (offscreenUi && offscreenUi->getWindow()->activeFocusItem() == offscreenUi->getRootItem()) { + _keyboardDeviceHasFocus = true; + } + auto displayPlugin = getActiveDisplayPlugin(); // depending on whether we're throttling or not. // Once rendering is off on another thread we should be able to have Application::idle run at start(0) in diff --git a/interface/src/Application.h b/interface/src/Application.h index e3196febd5..f2b6edeea4 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -518,6 +518,8 @@ private: std::mutex _preRenderLambdasLock; std::atomic _processOctreeStatsCounter { 0 }; + + bool _keyboardDeviceHasFocus { true }; }; #endif // hifi_Application_h