From c48be75a377a9c9557f4282c7d36046d7a634ebf Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 21 Mar 2016 14:49:42 -0700 Subject: [PATCH 01/12] Make sure everyone calls sendPeriod's setter --- .../networking/src/udt/CongestionControl.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index bac178377e..8eff5e3a01 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -39,7 +39,7 @@ DefaultCC::DefaultCC() : _mss = udt::MAX_PACKET_SIZE_WITH_UDP_HEADER; _congestionWindowSize = 16.0; - _packetSendPeriod = 1.0; + setPacketSendPeriod(1.0); } void DefaultCC::onACK(SequenceNumber ackNum) { @@ -73,10 +73,10 @@ void DefaultCC::onACK(SequenceNumber ackNum) { if (_receiveRate > 0) { // if we have a valid receive rate we set the send period to whatever the receive rate dictates - _packetSendPeriod = USECS_PER_SECOND / _receiveRate; + setPacketSendPeriod(USECS_PER_SECOND / _receiveRate); } else { // no valid receive rate, packet send period is dictated by estimated RTT and current congestion window size - _packetSendPeriod = (_rtt + synInterval()) / _congestionWindowSize; + setPacketSendPeriod((_rtt + synInterval()) / _congestionWindowSize); } } } else { @@ -148,8 +148,8 @@ void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { if (rangeStart > _lastDecreaseMaxSeq) { _lastDecreasePeriod = _packetSendPeriod; - - _packetSendPeriod = ceil(_packetSendPeriod * INTER_PACKET_ARRIVAL_INCREASE); + + setPacketSendPeriod(ceil(_packetSendPeriod * INTER_PACKET_ARRIVAL_INCREASE)); // use EWMA to update the average number of NAKs per congestion static const double NAK_EWMA_ALPHA = 0.125; @@ -175,7 +175,7 @@ void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { // there have been fewer than MAX_DECREASES_PER_CONGESTION_EPOCH AND this NAK matches the random count at which we // decided we would decrease the packet send period - _packetSendPeriod = ceil(_packetSendPeriod * INTER_PACKET_ARRIVAL_INCREASE); + setPacketSendPeriod(ceil(_packetSendPeriod * INTER_PACKET_ARRIVAL_INCREASE)); _lastDecreaseMaxSeq = _sendCurrSeqNum; } } @@ -198,12 +198,12 @@ void DefaultCC::stopSlowStart() { if (_receiveRate > 0) { // Set the sending rate to the receiving rate. - _packetSendPeriod = USECS_PER_SECOND / _receiveRate; + setPacketSendPeriod(USECS_PER_SECOND / _receiveRate); } else { // If no receiving rate is observed, we have to compute the sending // rate according to the current window size, and decrease it // using the method below. - _packetSendPeriod = _congestionWindowSize / (_rtt + synInterval()); + setPacketSendPeriod(_congestionWindowSize / (_rtt + synInterval())); } } From 6d2498b4f23503ae2c2a3bdaa30626f3e8ad1ac6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Mar 2016 16:56:40 -0700 Subject: [PATCH 02/12] Remove debug print --- libraries/shared/src/LogHandler.cpp | 1 - libraries/ui/src/QmlWindowClass.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index a338dfe8c2..b67c86ecef 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -82,7 +82,6 @@ void LogHandler::flushRepeatedMessages() { } QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& context, const QString& message) { - if (message.isEmpty()) { return QString(); } diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 5bd40b10a9..c0826420c6 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -114,7 +114,6 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, } } else { auto argumentObject = context->argument(0); - qDebug() << argumentObject.toString(); if (!argumentObject.property(TITLE_PROPERTY).isUndefined()) { title = argumentObject.property(TITLE_PROPERTY).toString(); } From d5f6ca5e1ce9f9ab6f3ac41be3b27bb5d8ef4e98 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 17 Mar 2016 09:49:59 -0700 Subject: [PATCH 03/12] Add max bandwidth setting --- assignment-client/src/assets/AssetServer.cpp | 12 ++++++++++++ domain-server/resources/describe-settings.json | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index f5f83399d6..fad8ece7bf 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -77,6 +77,18 @@ void AssetServer::completeSetup() { auto assetServerObject = settingsObject[ASSET_SERVER_SETTINGS_KEY].toObject(); + static const QString MAX_BANDWIDTH_OPTION = "max_bandwidth"; + auto maxBandwidthValue = assetServerObject[MAX_BANDWIDTH_OPTION]; + auto maxBandwidthFloat = maxBandwidthValue.toDouble(-1); + + if (maxBandwidthFloat > 0.0) { + const int BYTES_PER_MEGABITS = (1024 * 1024) / 8; + int maxBandwidth = maxBandwidthFloat * BYTES_PER_MEGABITS; + nodeList->setConnectionMaxBandwidth(maxBandwidth); + qInfo() << "Set maximum bandwith per connection to" << maxBandwidthFloat << "Mb/s." + " (" << maxBandwidth << "bytes/sec)"; + } + // get the path to the asset folder from the domain server settings static const QString ASSETS_PATH_OPTION = "assets_path"; auto assetsJSONValue = assetServerObject[ASSETS_PATH_OPTION]; diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index cde398e01f..80ee32efa1 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -186,6 +186,15 @@ "help": "The path to the directory assets are stored in.
If this path is relative, it will be relative to the application data directory.
If you change this path you will need to manually copy any existing assets from the previous directory.", "default": "", "advanced": true + }, + { + "name": "max_bandwidth", + "type": "double", + "label": "Max Bandwidth Per User", + "help": "The maximum upstream bandwidth each user can use (in Mb/s).", + "placeholder": "10.0", + "default": "", + "advanced": true } ] }, From 170433997c45e9b399461c22c725d0cc9d4e799f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 17 Mar 2016 13:26:01 -0700 Subject: [PATCH 04/12] Set Asset server max bandwidth wiring --- libraries/networking/src/LimitedNodeList.h | 2 ++ .../networking/src/udt/CongestionControl.cpp | 12 +++++++++--- libraries/networking/src/udt/CongestionControl.h | 5 +++-- libraries/networking/src/udt/Connection.cpp | 4 ++++ libraries/networking/src/udt/Connection.h | 2 ++ libraries/networking/src/udt/Socket.cpp | 15 ++++++++++++++- libraries/networking/src/udt/Socket.h | 7 +++++-- 7 files changed, 39 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 43393ef69c..0cbe9668b3 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -219,6 +219,8 @@ public: udt::Socket::StatsVector sampleStatsForAllConnections() { return _nodeSocket.sampleStatsForAllConnections(); } + void setConnectionMaxBandwidth(int maxBandwidth) { _nodeSocket.setConnectionMaxBandwidth(maxBandwidth); } + public slots: void reset(); void eraseAllNodes(); diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 8eff5e3a01..1d1a6628fe 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -20,13 +20,19 @@ using namespace std::chrono; static const double USECS_PER_SECOND = 1000000.0; +void CongestionControl::setMaxBandwidth(int maxBandwidth) { + _maxBandwidth = maxBandwidth; + setPacketSendPeriod(_packetSendPeriod); +} + void CongestionControl::setPacketSendPeriod(double newSendPeriod) { Q_ASSERT_X(newSendPeriod >= 0, "CongestionControl::setPacketPeriod", "Can not set a negative packet send period"); - - if (_maxBandwidth > 0) { + + auto maxBandwidth = _maxBandwidth.load(); + if (maxBandwidth > 0) { // anytime the packet send period is about to be increased, make sure it stays below the minimum period, // calculated based on the maximum desired bandwidth - double minPacketSendPeriod = USECS_PER_SECOND / (((double) _maxBandwidth) / _mss); + double minPacketSendPeriod = USECS_PER_SECOND / (((double) maxBandwidth) / _mss); _packetSendPeriod = std::max(newSendPeriod, minPacketSendPeriod); } else { _packetSendPeriod = newSendPeriod; diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 3a5c8d0d00..8297b5f6bd 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -12,6 +12,7 @@ #ifndef hifi_CongestionControl_h #define hifi_CongestionControl_h +#include #include #include #include @@ -37,6 +38,7 @@ public: virtual ~CongestionControl() {} int synInterval() const { return _synInterval; } + void setMaxBandwidth(int maxBandwidth); virtual void init() {} virtual void onACK(SequenceNumber ackNum) {} @@ -49,7 +51,6 @@ protected: void setMSS(int mss) { _mss = mss; } void setMaxCongestionWindowSize(int window) { _maxCongestionWindowSize = window; } void setBandwidth(int bandwidth) { _bandwidth = bandwidth; } - void setMaxBandwidth(int maxBandwidth) { _maxBandwidth = maxBandwidth; } virtual void setInitialSendSequenceNumber(SequenceNumber seqNum) = 0; void setSendCurrentSequenceNumber(SequenceNumber seqNum) { _sendCurrSeqNum = seqNum; } void setReceiveRate(int rate) { _receiveRate = rate; } @@ -60,7 +61,7 @@ protected: double _congestionWindowSize { 16.0 }; // Congestion window size, in packets int _bandwidth { 0 }; // estimated bandwidth, packets per second - int _maxBandwidth { -1 }; // Maximum desired bandwidth, packets per second + std::atomic _maxBandwidth { -1 }; // Maximum desired bandwidth, bytes per second double _maxCongestionWindowSize { 0.0 }; // maximum cwnd size, in packets int _mss { 0 }; // Maximum Packet Size, including all packet headers diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index f75a9535f5..e5f3508b81 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -80,6 +80,10 @@ void Connection::resetRTT() { _rttVariance = _rtt / 2; } +void Connection::setMaxBandwidth(int maxBandwidth) { + _congestionControl->setMaxBandwidth(maxBandwidth); +} + SendQueue& Connection::getSendQueue() { if (!_sendQueue) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 8d80e736af..4f5a8793e7 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -76,6 +76,8 @@ public: HifiSockAddr getDestination() const { return _destination; } + void setMaxBandwidth(int maxBandwidth); + signals: void packetSent(); void connectionInactive(const HifiSockAddr& sockAddr); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 1eb7c04331..e9af1577fb 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -176,7 +176,9 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { auto it = _connectionsHash.find(sockAddr); if (it == _connectionsHash.end()) { - auto connection = std::unique_ptr(new Connection(this, sockAddr, _ccFactory->create())); + auto congestionControl = _ccFactory->create(); + congestionControl->setMaxBandwidth(_maxBandwidth); + auto connection = std::unique_ptr(new Connection(this, sockAddr, std::move(congestionControl))); // we queue the connection to cleanup connection in case it asks for it during its own rate control sync QObject::connect(connection.get(), &Connection::connectionInactive, this, &Socket::cleanupConnection); @@ -350,6 +352,17 @@ void Socket::setCongestionControlFactory(std::unique_ptrsynInterval(); } + +void Socket::setConnectionMaxBandwidth(int maxBandwidth) { + qInfo() << "Setting socket's maximum bandwith to" << maxBandwidth << ". (" + << _connectionsHash.size() << "live connections)"; + _maxBandwidth = maxBandwidth; + for (auto& pair : _connectionsHash) { + auto& connection = pair.second; + connection->setMaxBandwidth(_maxBandwidth); + } +} + ConnectionStats::Stats Socket::sampleStatsForConnection(const HifiSockAddr& destination) { auto it = _connectionsHash.find(destination); if (it != _connectionsHash.end()) { diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 88db8e3d86..424158045f 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -72,6 +72,7 @@ public: { _unfilteredHandlers[senderSockAddr] = handler; } void setCongestionControlFactory(std::unique_ptr ccFactory); + void setConnectionMaxBandwidth(int maxBandwidth); void messageReceived(std::unique_ptr packet); void messageFailed(Connection* connection, Packet::MessageNumber messageNumber); @@ -109,8 +110,10 @@ private: std::unordered_map _unreliableSequenceNumbers; std::unordered_map> _connectionsHash; - int _synInterval = 10; // 10ms - QTimer* _synTimer; + int _synInterval { 10 }; // 10ms + QTimer* _synTimer { nullptr }; + + int _maxBandwidth { -1 }; std::unique_ptr _ccFactory { new CongestionControlFactory() }; From 1a2f74f43a5013b023a3f7a47a1a28fa7be19672 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 22 Mar 2016 11:26:10 -0700 Subject: [PATCH 05/12] Add protection around ScriptEngine::runInThread being called twice --- libraries/script-engine/src/ScriptEngine.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 61ebfe4515..3f403b3677 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -158,6 +158,13 @@ void ScriptEngine::disconnectNonEssentialSignals() { } void ScriptEngine::runInThread() { + Q_ASSERT_X(!_isThreaded, "ScriptEngine::runInThread()", "runInThread should not be called more than once"); + + if (_isThreaded) { + qCWarning(scriptengine) << "ScriptEngine already running in thread: " << getFilename(); + return; + } + _isThreaded = true; QThread* workerThread = new QThread(); // thread is not owned, so we need to manage the delete QString scriptEngineName = QString("Script Thread:") + getFilename(); From b41c106f3c84ae84c51e3f83d70548f4f3f08c5e Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 22 Mar 2016 18:40:26 -0700 Subject: [PATCH 06/12] Only set the context once per QML surface --- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 22 +++------------------ 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index 563c590874..6056e8234f 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -214,22 +214,19 @@ void OffscreenQmlRenderThread::init() { connect(_renderControl, &QQuickRenderControl::sceneChanged, _surface, &OffscreenQmlSurface::requestUpdate); if (!_canvas.makeCurrent()) { - qWarning("Failed to make context current on render thread"); + // Failed to make GL context current, this OffscreenQmlSurface is basically dead + qWarning("Failed to make context current on QML Renderer Thread"); return; } + _renderControl->initialize(_canvas.getContext()); setupFbo(); _escrow.setRecycler([this](GLuint texture){ _textures.recycleTexture(texture); }); - _canvas.doneCurrent(); } void OffscreenQmlRenderThread::cleanup() { - if (!_canvas.makeCurrent()) { - qFatal("Failed to make context current on render thread"); - return; - } _renderControl->invalidate(); _fbo.reset(); @@ -237,7 +234,6 @@ void OffscreenQmlRenderThread::cleanup() { _textures.clear(); _canvas.doneCurrent(); - _canvas.getContextObject()->moveToThread(QCoreApplication::instance()->thread()); _quit = true; @@ -267,18 +263,11 @@ void OffscreenQmlRenderThread::resize() { } _size = newOffscreenSize; - // Clear out any fbos with the old size - if (!_canvas.makeCurrent()) { - qWarning("Failed to make context current on render thread"); - return; - } - qDebug() << "Offscreen UI resizing to " << _newSize.width() << "x" << _newSize.height() << " with pixel ratio " << pixelRatio; locker.unlock(); setupFbo(); - _canvas.doneCurrent(); } void OffscreenQmlRenderThread::render() { @@ -287,11 +276,6 @@ void OffscreenQmlRenderThread::render() { return; } - if (!_canvas.makeCurrent()) { - qWarning("Failed to make context current on render thread"); - return; - } - QMutexLocker locker(&_mutex); _renderControl->sync(); _waitCondition.wakeOne(); From fe1d8b24b40a91ba6bbcb9c2e97539b3c4ea1158 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 22 Mar 2016 18:42:46 -0700 Subject: [PATCH 07/12] Lock the QML Surface resizing better --- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 46 ++++++++++----------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index 6056e8234f..8e02ef2e4f 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -241,32 +241,32 @@ void OffscreenQmlRenderThread::cleanup() { void OffscreenQmlRenderThread::resize() { // Lock _newSize changes - QMutexLocker locker(&_mutex); + { + QMutexLocker locker(&_mutex); - // Update our members - if (_quickWindow) { - _quickWindow->setGeometry(QRect(QPoint(), _newSize)); - _quickWindow->contentItem()->setSize(_newSize); + // Update our members + if (_quickWindow) { + _quickWindow->setGeometry(QRect(QPoint(), _newSize)); + _quickWindow->contentItem()->setSize(_newSize); + } + + // Qt bug in 5.4 forces this check of pixel ratio, + // even though we're rendering offscreen. + qreal pixelRatio = 1.0; + if (_renderControl && _renderControl->_renderWindow) { + pixelRatio = _renderControl->_renderWindow->devicePixelRatio(); + } + + uvec2 newOffscreenSize = toGlm(_newSize * pixelRatio); + if (newOffscreenSize == _size) { + return; + } + + qDebug() << "Offscreen UI resizing to " << _newSize.width() << "x" << _newSize.height() << " with pixel ratio " << pixelRatio; + _size = newOffscreenSize; } - // Qt bug in 5.4 forces this check of pixel ratio, - // even though we're rendering offscreen. - qreal pixelRatio = 1.0; - if (_renderControl && _renderControl->_renderWindow) { - pixelRatio = _renderControl->_renderWindow->devicePixelRatio(); - } - - uvec2 newOffscreenSize = toGlm(_newSize * pixelRatio); - _textures.setSize(newOffscreenSize); - if (newOffscreenSize == _size) { - return; - } - _size = newOffscreenSize; - - qDebug() << "Offscreen UI resizing to " << _newSize.width() << "x" << _newSize.height() << " with pixel ratio " << pixelRatio; - - locker.unlock(); - + _textures.setSize(_size); setupFbo(); } From 40b21933a574474757008492bef4e66c16334051 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 22 Mar 2016 18:42:54 -0700 Subject: [PATCH 08/12] Clean QML Surface render log --- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index 8e02ef2e4f..49b2a6fd34 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -322,10 +322,10 @@ OffscreenQmlSurface::~OffscreenQmlSurface() { QObject::disconnect(&_updateTimer); QObject::disconnect(qApp); - qDebug() << "Stopping QML render thread " << _renderer->currentThreadId(); + qDebug() << "Stopping QML Renderer Thread " << _renderer->currentThreadId(); _renderer->_queue.add(STOP); if (!_renderer->wait(MAX_SHUTDOWN_WAIT_SECS * USECS_PER_SECOND)) { - qWarning() << "Failed to shut down the QML render thread"; + qWarning() << "Failed to shut down the QML Renderer Thread"; } delete _rootItem; From df187499ff1e0601fd9b82c8454527b2f0fe73f5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 22 Mar 2016 19:19:52 -0700 Subject: [PATCH 09/12] MyAvatar: fix jitter in hands when moving Store hand controller positions within the avatar in sensor space, not world space. Before IK the sensorToWorld matrix is updated to reflect the world space motion of the character controller during physics. This ensures the IK hand targets move properly with the character. --- interface/src/Application.cpp | 10 ++++++---- interface/src/avatar/MyAvatar.cpp | 28 ++++++++++++++++++---------- interface/src/avatar/MyAvatar.h | 10 ++++++---- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7e88ea28dc..47d008aa69 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3228,7 +3228,9 @@ void Application::update(float deltaTime) { controller::Pose leftHandPose = userInputMapper->getPoseState(controller::Action::LEFT_HAND); controller::Pose rightHandPose = userInputMapper->getPoseState(controller::Action::RIGHT_HAND); auto myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition()); - myAvatar->setHandControllerPosesInWorldFrame(leftHandPose.transform(myAvatarMatrix), rightHandPose.transform(myAvatarMatrix)); + auto worldToSensorMatrix = glm::inverse(myAvatar->getSensorToWorldMatrix()); + auto avatarToSensorMatrix = worldToSensorMatrix * myAvatarMatrix; + myAvatar->setHandControllerPosesInSensorFrame(leftHandPose.transform(avatarToSensorMatrix), rightHandPose.transform(avatarToSensorMatrix)); updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... updateDialogs(deltaTime); // update various stats dialogs if present @@ -3315,6 +3317,9 @@ void Application::update(float deltaTime) { qApp->updateMyAvatarLookAtPosition(); + // update sensorToWorldMatrix for camera and hand controllers + myAvatar->updateSensorToWorldMatrix(); + avatarManager->updateMyAvatar(deltaTime); } @@ -3374,9 +3379,6 @@ void Application::update(float deltaTime) { QMetaObject::invokeMethod(DependencyManager::get().data(), "sendDownstreamAudioStatsPacket", Qt::QueuedConnection); } } - - // update sensorToWorldMatrix for rendering camera. - myAvatar->updateSensorToWorldMatrix(); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4405204b47..8f11c635e9 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -418,7 +418,7 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { _hmdSensorFacing = getFacingDir2D(_hmdSensorOrientation); } -// best called at end of main loop, just before rendering. +// best called at end of main loop, after physics. // update sensor to world matrix from current body position and hmd sensor. // This is so the correct camera can be used for rendering. void MyAvatar::updateSensorToWorldMatrix() { @@ -1087,24 +1087,32 @@ static controller::Pose applyLowVelocityFilter(const controller::Pose& oldPose, return finalPose; } -void MyAvatar::setHandControllerPosesInWorldFrame(const controller::Pose& left, const controller::Pose& right) { +void MyAvatar::setHandControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right) { if (controller::InputDevice::getLowVelocityFilter()) { - auto oldLeftPose = getLeftHandControllerPoseInWorldFrame(); - auto oldRightPose = getRightHandControllerPoseInWorldFrame(); - _leftHandControllerPoseInWorldFrameCache.set(applyLowVelocityFilter(oldLeftPose, left)); - _rightHandControllerPoseInWorldFrameCache.set(applyLowVelocityFilter(oldRightPose, right)); + auto oldLeftPose = getLeftHandControllerPoseInSensorFrame(); + auto oldRightPose = getRightHandControllerPoseInSensorFrame(); + _leftHandControllerPoseInSensorFrameCache.set(applyLowVelocityFilter(oldLeftPose, left)); + _rightHandControllerPoseInSensorFrameCache.set(applyLowVelocityFilter(oldRightPose, right)); } else { - _leftHandControllerPoseInWorldFrameCache.set(left); - _rightHandControllerPoseInWorldFrameCache.set(right); + _leftHandControllerPoseInSensorFrameCache.set(left); + _rightHandControllerPoseInSensorFrameCache.set(right); } } +controller::Pose MyAvatar::getLeftHandControllerPoseInSensorFrame() const { + return _leftHandControllerPoseInSensorFrameCache.get(); +} + +controller::Pose MyAvatar::getRightHandControllerPoseInSensorFrame() const { + return _rightHandControllerPoseInSensorFrameCache.get(); +} + controller::Pose MyAvatar::getLeftHandControllerPoseInWorldFrame() const { - return _leftHandControllerPoseInWorldFrameCache.get(); + return _leftHandControllerPoseInSensorFrameCache.get().transform(getSensorToWorldMatrix()); } controller::Pose MyAvatar::getRightHandControllerPoseInWorldFrame() const { - return _rightHandControllerPoseInWorldFrameCache.get(); + return _rightHandControllerPoseInSensorFrameCache.get().transform(getSensorToWorldMatrix()); } controller::Pose MyAvatar::getLeftHandControllerPoseInAvatarFrame() const { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 3554d9b8bc..92bf9e7614 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -247,7 +247,9 @@ public: virtual void rebuildCollisionShape() override; - void setHandControllerPosesInWorldFrame(const controller::Pose& left, const controller::Pose& right); + void setHandControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right); + controller::Pose getLeftHandControllerPoseInSensorFrame() const; + controller::Pose getRightHandControllerPoseInSensorFrame() const; controller::Pose getLeftHandControllerPoseInWorldFrame() const; controller::Pose getRightHandControllerPoseInWorldFrame() const; controller::Pose getLeftHandControllerPoseInAvatarFrame() const; @@ -451,9 +453,9 @@ private: bool _hoverReferenceCameraFacingIsCaptured { false }; glm::vec3 _hoverReferenceCameraFacing { 0.0f, 0.0f, -1.0f }; // hmd sensor space - // These are stored in WORLD frame - ThreadSafeValueCache _leftHandControllerPoseInWorldFrameCache { controller::Pose() }; - ThreadSafeValueCache _rightHandControllerPoseInWorldFrameCache { controller::Pose() }; + // These are stored in SENSOR frame + ThreadSafeValueCache _leftHandControllerPoseInSensorFrameCache { controller::Pose() }; + ThreadSafeValueCache _rightHandControllerPoseInSensorFrameCache { controller::Pose() }; float AVATAR_MOVEMENT_ENERGY_CONSTANT { 0.001f }; float AUDIO_ENERGY_CONSTANT { 0.000001f }; From 84dc15aff62408bff63543f132282dbcc6426e51 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 23 Mar 2016 12:06:52 -0700 Subject: [PATCH 10/12] Fix potential deadlock in QML --- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 34 +++++++++++++++------ libraries/shared/src/Finally.h | 4 +++ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index d3699b54e6..e224adad07 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "OffscreenGLCanvas.h" #include "GLEscrow.h" @@ -84,6 +85,7 @@ protected: Queue _queue; QMutex _mutex; QWaitCondition _waitCondition; + std::atomic _rendering { false }; private: // Event-driven methods @@ -271,15 +273,25 @@ void OffscreenQmlRenderThread::resize() { } void OffscreenQmlRenderThread::render() { - if (_surface->_paused) { + // Ensure we always release the main thread + Finally releaseMainThread([this] { _waitCondition.wakeOne(); + }); + + if (_surface->_paused) { return; } - QMutexLocker locker(&_mutex); - _renderControl->sync(); - _waitCondition.wakeOne(); - locker.unlock(); + _rendering = true; + Finally unmarkRenderingFlag([this] { + _rendering = false; + }); + + { + QMutexLocker locker(&_mutex); + _renderControl->sync(); + releaseMainThread.trigger(); + } using namespace oglplus; @@ -292,6 +304,7 @@ void OffscreenQmlRenderThread::render() { _fbo->AttachTexture(Framebuffer::Target::Draw, FramebufferAttachment::Color, *texture, 0); _fbo->Complete(Framebuffer::Target::Draw); { + PROFILE_RANGE("qml_render->rendercontrol") _renderControl->render(); // FIXME The web browsers seem to be leaving GL in an error state. // Need a debug context with sync logging to figure out why. @@ -380,8 +393,6 @@ void OffscreenQmlSurface::resize(const QSize& newSize_) { std::max(static_cast(scale * newSize.height()), 10)); } - - QSize currentSize = _renderer->_quickWindow->geometry().size(); if (newSize == currentSize) { return; @@ -492,7 +503,12 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::functionallowNewFrame(_maxFps)) { + // If we're + // a) not set up + // b) already rendering a frame + // c) rendering too fast + // then skip this + if (!_renderer || _renderer->_rendering || !_renderer->allowNewFrame(_maxFps)) { return; } @@ -502,11 +518,11 @@ void OffscreenQmlSurface::updateQuick() { } if (_render) { + PROFILE_RANGE(__FUNCTION__); // Lock the GUI size while syncing QMutexLocker locker(&(_renderer->_mutex)); _renderer->_queue.add(RENDER); _renderer->_waitCondition.wait(&(_renderer->_mutex)); - _render = false; } diff --git a/libraries/shared/src/Finally.h b/libraries/shared/src/Finally.h index 59e8be0228..9070d49647 100644 --- a/libraries/shared/src/Finally.h +++ b/libraries/shared/src/Finally.h @@ -20,6 +20,10 @@ public: template Finally(F f) : _f(f) {} ~Finally() { _f(); } + void trigger() { + _f(); + _f = [] {}; + } private: std::function _f; }; From 17aa2845a8d8f365002ddb7c419cce7bd2739df6 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 15 Mar 2016 18:44:38 -0700 Subject: [PATCH 11/12] Add finished signal to Resource loading --- libraries/networking/src/ResourceCache.cpp | 1 + libraries/networking/src/ResourceCache.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 295af8c5ee..77ced1619c 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -380,6 +380,7 @@ void Resource::finishedLoading(bool success) { _failedToLoad = true; } _loadPriorities.clear(); + emit finished(success); } void Resource::reinsert() { diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index ed938f6cf4..b24f5bc0b4 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -201,6 +201,9 @@ signals: /// This can be used instead of downloadFinished to access data before it is processed. void loaded(const QByteArray& request); + /// Fired when the resource has finished loading. + void finished(bool success); + /// Fired when the resource failed to load. void failed(QNetworkReply::NetworkError error); From fdd7bb9f58a6cb5165e57799d084428f4cabda2a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 23 Mar 2016 13:18:46 -0700 Subject: [PATCH 12/12] Update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a2eb058ae6..48e0de03af 100644 --- a/README.md +++ b/README.md @@ -8,14 +8,14 @@ like to get paid for your work, make sure you report the bug via a job on [Worklist.net](https://worklist.net). We're hiring! We're looking for skilled developers; -send your resume to hiring@highfidelity.io +send your resume to hiring@highfidelity.com ##### Chat with us Come chat with us in [our Gitter](http://gitter.im/highfidelity/hifi) if you have any questions or just want to say hi! Documentation ========= -Documentation is available at [docs.highfidelity.io](http://docs.highfidelity.io), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project). +Documentation is available at [docs.highfidelity.com](http://docs.highfidelity.com), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project). Build Instructions =========