Merge branch 'fix-sync-period-calc' into correct-target-frame-rate

This commit is contained in:
Howard Stearns 2015-12-09 15:43:43 -08:00
commit dd2d040253
7 changed files with 122 additions and 88 deletions

View file

@ -195,6 +195,8 @@ static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html";
static const unsigned int THROTTLED_SIM_FRAMERATE = 15; static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE; static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check for entities that aren't ready for simulation
#ifndef __APPLE__ #ifndef __APPLE__
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
#else #else
@ -1400,7 +1402,7 @@ void Application::paintGL() {
// Some LOD-like controls need to know a smoothly varying "potential" frame rate that doesn't // Some LOD-like controls need to know a smoothly varying "potential" frame rate that doesn't
// include time waiting for sync, and which can report a number above target if we've got the headroom. // include time waiting for sync, and which can report a number above target if we've got the headroom.
// In my tests, the following is mostly less than 0.5ms, and never more than 3ms. I don't think its worth measuring during runtime. // In my tests, the following is mostly less than 0.5ms, and never more than 3ms. I don't think its worth measuring during runtime.
static const float paintWaitAndQTTimerAllowance = 0.001; // seconds const float paintWaitAndQTTimerAllowance = 0.001f; // seconds
// Store both values now for use by next cycle. // Store both values now for use by next cycle.
_lastInstantaneousFps = instantaneousFps; _lastInstantaneousFps = instantaneousFps;
_lastUnsynchronizedFps = 1.0f / (((usecTimestampNow() - now) / (float)USECS_PER_SECOND) + paintWaitAndQTTimerAllowance); _lastUnsynchronizedFps = 1.0f / (((usecTimestampNow() - now) / (float)USECS_PER_SECOND) + paintWaitAndQTTimerAllowance);
@ -2886,7 +2888,7 @@ void Application::update(float deltaTime) {
_avatarUpdate->synchronousProcess(); _avatarUpdate->synchronousProcess();
{ if (true || _physicsEnabled) {
PerformanceTimer perfTimer("physics"); PerformanceTimer perfTimer("physics");
static VectorOfMotionStates motionStates; static VectorOfMotionStates motionStates;
@ -3768,6 +3770,8 @@ void Application::domainChanged(const QString& domainHostname) {
updateWindowTitle(); updateWindowTitle();
clearDomainOctreeDetails(); clearDomainOctreeDetails();
_domainConnectionRefusals.clear(); _domainConnectionRefusals.clear();
// disable physics until we have enough information about our new location to not cause craziness.
_physicsEnabled = false;
} }
void Application::handleDomainConnectionDeniedPacket(QSharedPointer<ReceivedMessage> message) { void Application::handleDomainConnectionDeniedPacket(QSharedPointer<ReceivedMessage> message) {
@ -3875,6 +3879,31 @@ void Application::trackIncomingOctreePacket(ReceivedMessage& message, SharedNode
} }
} }
bool Application::nearbyEntitiesAreReadyForPhysics() {
// this is used to avoid the following scenario:
// A table has some items sitting on top of it. The items are at rest, meaning they aren't active in bullet.
// Someone logs in close to the table. They receive information about the items on the table before they
// receive information about the table. The items are very close to the avatar's capsule, so they become
// activated in bullet. This causes them to fall to the floor, because the table's shape isn't yet in bullet.
EntityTreePointer entityTree = _entities.getTree();
if (!entityTree) {
return false;
}
QVector<EntityItemPointer> entities;
entityTree->withReadLock([&] {
AABox box(getMyAvatar()->getPosition() - glm::vec3(PHYSICS_READY_RANGE), glm::vec3(2 * PHYSICS_READY_RANGE));
entityTree->findEntities(box, entities);
});
foreach (EntityItemPointer entity, entities) {
if (!entity->isReadyToComputeShape()) {
return false;
}
}
return true;
}
int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode) { int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode) {
// But, also identify the sender, and keep track of the contained jurisdiction root for this server // But, also identify the sender, and keep track of the contained jurisdiction root for this server
@ -3920,7 +3949,12 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer
}); });
}); });
if (!_physicsEnabled && nearbyEntitiesAreReadyForPhysics()) {
// These 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
// scene is ready to compute its collision shape.
_physicsEnabled = true;
}
return statsMessageLength; return statsMessageLength;
} }

View file

@ -390,6 +390,7 @@ private:
bool importSVOFromURL(const QString& urlString); bool importSVOFromURL(const QString& urlString);
bool nearbyEntitiesAreReadyForPhysics();
int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode); int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode);
void trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket); void trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket);
@ -557,6 +558,7 @@ private:
bool _isForeground = true; // starts out assumed to be in foreground bool _isForeground = true; // starts out assumed to be in foreground
bool _inPaint = false; bool _inPaint = false;
bool _isGLInitialized { false }; bool _isGLInitialized { false };
bool _physicsEnabled { false };
}; };
#endif // hifi_Application_h #endif // hifi_Application_h

View file

@ -54,6 +54,7 @@ public:
} }
virtual void run() override { virtual void run() override {
OpenGLDisplayPlugin* currentPlugin{ nullptr };
Q_ASSERT(_context); Q_ASSERT(_context);
while (!_shutdown) { while (!_shutdown) {
if (_pendingMainThreadOperation) { if (_pendingMainThreadOperation) {
@ -81,12 +82,13 @@ public:
// Check if we have a new plugin to activate // Check if we have a new plugin to activate
if (_newPlugin != nullptr) { if (_newPlugin != nullptr) {
// Deactivate the old plugin // Deactivate the old plugin
if (_activePlugin != nullptr) { if (currentPlugin != nullptr) {
_activePlugin->uncustomizeContext(); currentPlugin->uncustomizeContext();
currentPlugin->enableDeactivate();
} }
_newPlugin->customizeContext(); _newPlugin->customizeContext();
_activePlugin = _newPlugin; currentPlugin = _newPlugin;
_newPlugin = nullptr; _newPlugin = nullptr;
} }
_context->doneCurrent(); _context->doneCurrent();
@ -94,20 +96,21 @@ public:
} }
// If there's no active plugin, just sleep // If there's no active plugin, just sleep
if (_activePlugin == nullptr) { if (currentPlugin == nullptr) {
QThread::usleep(100); QThread::usleep(100);
continue; continue;
} }
// take the latest texture and present it // take the latest texture and present it
_context->makeCurrent(); _context->makeCurrent();
_activePlugin->present(); currentPlugin->present();
_context->doneCurrent(); _context->doneCurrent();
} }
_context->makeCurrent(); _context->makeCurrent();
if (_activePlugin) { if (currentPlugin) {
_activePlugin->uncustomizeContext(); currentPlugin->uncustomizeContext();
currentPlugin->enableDeactivate();
} }
_context->doneCurrent(); _context->doneCurrent();
_context->moveToThread(qApp->thread()); _context->moveToThread(qApp->thread());
@ -147,7 +150,6 @@ private:
bool _finishedMainThreadOperation { false }; bool _finishedMainThreadOperation { false };
QThread* _mainThread { nullptr }; QThread* _mainThread { nullptr };
OpenGLDisplayPlugin* _newPlugin { nullptr }; OpenGLDisplayPlugin* _newPlugin { nullptr };
OpenGLDisplayPlugin* _activePlugin { nullptr };
QGLContext* _context { nullptr }; QGLContext* _context { nullptr };
}; };
@ -208,11 +210,16 @@ void OpenGLDisplayPlugin::stop() {
} }
void OpenGLDisplayPlugin::deactivate() { void OpenGLDisplayPlugin::deactivate() {
{
Lock lock(_mutex);
_deactivateWait.wait(lock, [&]{ return _uncustomized; });
}
_timer.stop(); _timer.stop();
DisplayPlugin::deactivate(); DisplayPlugin::deactivate();
} }
void OpenGLDisplayPlugin::customizeContext() { void OpenGLDisplayPlugin::customizeContext() {
_uncustomized = false;
auto presentThread = DependencyManager::get<PresentThread>(); auto presentThread = DependencyManager::get<PresentThread>();
Q_ASSERT(thread() == presentThread->thread()); Q_ASSERT(thread() == presentThread->thread());
@ -233,6 +240,7 @@ void OpenGLDisplayPlugin::uncustomizeContext() {
_plane.reset(); _plane.reset();
} }
// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the // Pressing Alt (and Meta) key alone activates the menubar because its style inherits the
// SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to // SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to
// receive keyPress events for the Alt (and Meta) key in a reliable manner. // receive keyPress events for the Alt (and Meta) key in a reliable manner.
@ -380,3 +388,9 @@ QImage OpenGLDisplayPlugin::getScreenshot() const {
}); });
return result; return result;
} }
void OpenGLDisplayPlugin::enableDeactivate() {
Lock lock(_mutex);
_uncustomized = true;
_deactivateWait.notify_one();
}

View file

@ -9,6 +9,8 @@
#include "DisplayPlugin.h" #include "DisplayPlugin.h"
#include <condition_variable>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <GLMHelpers.h> #include <GLMHelpers.h>
@ -18,8 +20,9 @@
class OpenGLDisplayPlugin : public DisplayPlugin { class OpenGLDisplayPlugin : public DisplayPlugin {
protected: protected:
using Mutex = std::recursive_mutex; using Mutex = std::mutex;
using Lock = std::unique_lock<Mutex>; using Lock = std::unique_lock<Mutex>;
using Condition = std::condition_variable;
public: public:
OpenGLDisplayPlugin(); OpenGLDisplayPlugin();
virtual void activate() override; virtual void activate() override;
@ -82,6 +85,12 @@ protected:
GLTextureEscrow _sceneTextureEscrow; GLTextureEscrow _sceneTextureEscrow;
bool _vsyncSupported { false }; bool _vsyncSupported { false };
private:
void enableDeactivate();
Condition _deactivateWait;
bool _uncustomized{ false };
}; };

View file

@ -628,71 +628,50 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
bool weOwnSimulation = _simulationOwner.matchesValidID(myNodeID); bool weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE) { // pack SimulationOwner and terse update properties near each other
// pack SimulationOwner and terse update properties near each other
// NOTE: the server is authoritative for changes to simOwnerID so we always unpack ownership data // NOTE: the server is authoritative for changes to simOwnerID so we always unpack ownership data
// even when we would otherwise ignore the rest of the packet. // even when we would otherwise ignore the rest of the packet.
if (propertyFlags.getHasProperty(PROP_SIMULATION_OWNER)) { if (propertyFlags.getHasProperty(PROP_SIMULATION_OWNER)) {
QByteArray simOwnerData; QByteArray simOwnerData;
int bytes = OctreePacketData::unpackDataFromBytes(dataAt, simOwnerData); int bytes = OctreePacketData::unpackDataFromBytes(dataAt, simOwnerData);
SimulationOwner newSimOwner; SimulationOwner newSimOwner;
newSimOwner.fromByteArray(simOwnerData); newSimOwner.fromByteArray(simOwnerData);
dataAt += bytes; dataAt += bytes;
bytesRead += bytes; bytesRead += bytes;
if (wantTerseEditLogging() && _simulationOwner != newSimOwner) { if (wantTerseEditLogging() && _simulationOwner != newSimOwner) {
qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << newSimOwner; qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << newSimOwner;
}
if (_simulationOwner.set(newSimOwner)) {
_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
}
} }
{ // When we own the simulation we don't accept updates to the entity's transform/velocities if (_simulationOwner.set(newSimOwner)) {
// but since we're using macros below we have to temporarily modify overwriteLocalData. _dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
bool oldOverwrite = overwriteLocalData;
overwriteLocalData = overwriteLocalData && !weOwnSimulation;
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity);
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity);
READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, setAcceleration);
overwriteLocalData = oldOverwrite;
} }
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity);
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity);
READ_ENTITY_PROPERTY(PROP_DAMPING, float, updateDamping);
READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, updateRestitution);
READ_ENTITY_PROPERTY(PROP_FRICTION, float, updateFriction);
READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime);
READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript);
READ_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp);
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
} else {
// legacy order of packing here
// TODO: purge this logic in a few months from now (2015.07)
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity);
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity);
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity);
READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, setAcceleration);
READ_ENTITY_PROPERTY(PROP_DAMPING, float, updateDamping);
READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, updateRestitution);
READ_ENTITY_PROPERTY(PROP_FRICTION, float, updateFriction);
READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime);
READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript);
READ_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp);
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity);
} }
{ // When we own the simulation we don't accept updates to the entity's transform/velocities
// but since we're using macros below we have to temporarily modify overwriteLocalData.
bool oldOverwrite = overwriteLocalData;
overwriteLocalData = overwriteLocalData && !weOwnSimulation;
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity);
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity);
READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, setAcceleration);
overwriteLocalData = oldOverwrite;
}
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity);
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity);
READ_ENTITY_PROPERTY(PROP_DAMPING, float, updateDamping);
READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, updateRestitution);
READ_ENTITY_PROPERTY(PROP_FRICTION, float, updateFriction);
READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime);
READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript);
READ_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp);
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping); READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping);
READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible);
@ -701,17 +680,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked);
READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData);
if (args.bitstreamVersion < VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE) {
// this code for when there is only simulatorID and no simulation priority
// we always accept the server's notion of simulatorID, so we fake overwriteLocalData as true
// before we try to READ_ENTITY_PROPERTY it
bool temp = overwriteLocalData;
overwriteLocalData = true;
READ_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, QUuid, updateSimulatorID);
overwriteLocalData = temp;
}
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) { if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) {
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID); READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
} }
@ -1104,7 +1072,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = false; bool somethingChanged = false;
// these affect TerseUpdate properties // these affect TerseUpdate properties
SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner); SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, updateSimulationOwner);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePosition); SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePosition);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, updateRotation); SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, updateRotation);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, updateVelocity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, updateVelocity);
@ -1324,6 +1292,13 @@ void EntityItem::updatePosition(const glm::vec3& value) {
} }
if (getLocalPosition() != value) { if (getLocalPosition() != value) {
setLocalPosition(value); setLocalPosition(value);
_dirtyFlags |= Simulation::DIRTY_POSITION;
forEachDescendant([&](SpatiallyNestablePointer object) {
if (object->getNestableType() == NestableTypes::Entity) {
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
entity->_dirtyFlags |= Simulation::DIRTY_POSITION;
}
});
} }
} }
@ -1496,12 +1471,12 @@ void EntityItem::setSimulationOwner(const SimulationOwner& owner) {
_simulationOwner.set(owner); _simulationOwner.set(owner);
} }
void EntityItem::updateSimulatorID(const QUuid& value) { void EntityItem::updateSimulationOwner(const SimulationOwner& owner) {
if (wantTerseEditLogging() && _simulationOwner.getID() != value) { if (wantTerseEditLogging() && _simulationOwner != owner) {
qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << value; qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << owner;
} }
if (_simulationOwner.setID(value)) { if (_simulationOwner.set(owner)) {
_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID; _dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
} }
} }

View file

@ -288,7 +288,7 @@ public:
quint8 getSimulationPriority() const { return _simulationOwner.getPriority(); } quint8 getSimulationPriority() const { return _simulationOwner.getPriority(); }
QUuid getSimulatorID() const { return _simulationOwner.getID(); } QUuid getSimulatorID() const { return _simulationOwner.getID(); }
void updateSimulatorID(const QUuid& value); void updateSimulationOwner(const SimulationOwner& owner);
void clearSimulationOwnership(); void clearSimulationOwnership();
const QString& getMarketplaceID() const { return _marketplaceID; } const QString& getMarketplaceID() const { return _marketplaceID; }

View file

@ -230,7 +230,7 @@ void OculusDisplayPlugin::internalPresent() {
viewScaleDesc.HmdToEyeViewOffset[1] = _eyeOffsets[1]; viewScaleDesc.HmdToEyeViewOffset[1] = _eyeOffsets[1];
ovrLayerHeader* layers = &_sceneLayer.Header; ovrLayerHeader* layers = &_sceneLayer.Header;
ovrResult result = ovr_SubmitFrame(_hmd, 0, &viewScaleDesc, &layers, 1); ovrResult result = ovr_SubmitFrame(_hmd, frameIndex, &viewScaleDesc, &layers, 1);
if (!OVR_SUCCESS(result)) { if (!OVR_SUCCESS(result)) {
qDebug() << result; qDebug() << result;
} }