From 7e9ea596a086fd0a1512938ae1cd7e60742b359b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 7 Jul 2017 19:07:19 -0700 Subject: [PATCH 1/3] Add more efficient overlay getters, don't use blocking calls --- interface/src/ui/overlays/Overlays.cpp | 41 +++++++++++++++++++++----- interface/src/ui/overlays/Overlays.h | 4 +++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index bcf9897dd8..2f22b62306 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -414,20 +414,47 @@ OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) { } OverlayPropertyResult Overlays::getProperty(OverlayID id, const QString& property) { - if (QThread::currentThread() != thread()) { - OverlayPropertyResult result; - BLOCKING_INVOKE_METHOD(this, "getProperty", Q_RETURN_ARG(OverlayPropertyResult, result), Q_ARG(OverlayID, id), Q_ARG(QString, property)); - return result; - } - - OverlayPropertyResult result; Overlay::Pointer thisOverlay = getOverlay(id); + OverlayPropertyResult result; if (thisOverlay && thisOverlay->supportsGetProperty()) { result.value = thisOverlay->getProperty(property); } return result; } +OverlayPropertyResult Overlays::getProperties(const OverlayID& id, const QStringList& properties) { + Overlay::Pointer thisOverlay = getOverlay(id); + OverlayPropertyResult result; + if (thisOverlay && thisOverlay->supportsGetProperty()) { + QVariantMap mapResult; + for (const auto& property : properties) { + mapResult.insert(property, thisOverlay->getProperty(property)); + } + result.value = mapResult; + } + return result; +} + +OverlayPropertyResult Overlays::getOverlaysProperties(const QVariant& propertiesById) { + QVariantMap map = propertiesById.toMap(); + OverlayPropertyResult result; + QVariantMap resultMap; + for (const auto& key : map.keys()) { + OverlayID id = OverlayID(key); + QVariantMap overlayResult; + Overlay::Pointer thisOverlay = getOverlay(id); + if (thisOverlay && thisOverlay->supportsGetProperty()) { + QStringList propertiesToFetch = map[key].toStringList(); + for (const auto& property : propertiesToFetch) { + overlayResult[property] = thisOverlay->getProperty(property); + } + } + resultMap[key] = overlayResult; + } + result.value = resultMap; + return result; +} + OverlayPropertyResult::OverlayPropertyResult() { } diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index bfb775b041..100f853a96 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -190,6 +190,10 @@ public slots: */ OverlayPropertyResult getProperty(OverlayID id, const QString& property); + OverlayPropertyResult getProperties(const OverlayID& id, const QStringList& properties); + + OverlayPropertyResult getOverlaysProperties(const QVariant& overlaysProperties); + /*jsdoc * Find the closest 3D overlay hit by a pick ray. * From 148eece065c3a8c2dc34daac1f6c8d098d3b0f96 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 7 Jul 2017 13:56:28 -0700 Subject: [PATCH 2/3] Tweak frame timing to avoid overloading the main thread --- interface/src/Application.cpp | 67 ++++++++++++++--------------------- 1 file changed, 26 insertions(+), 41 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7d397adf96..3cbc6208ad 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2729,56 +2729,41 @@ bool Application::importSVOFromURL(const QString& urlString) { return true; } +bool _renderRequested { false }; + bool Application::event(QEvent* event) { if (!Menu::getInstance()) { return false; } - // Presentation/painting logic - // TODO: Decouple presentation and painting loops - static bool isPaintingThrottled = false; - if ((int)event->type() == (int)Present) { - if (isPaintingThrottled) { - // If painting (triggered by presentation) is hogging the main thread, - // repost as low priority to avoid hanging the GUI. - // This has the effect of allowing presentation to exceed the paint budget by X times and - // only dropping every (1/X) frames, instead of every ceil(X) frames - // (e.g. at a 60FPS target, painting for 17us would fall to 58.82FPS instead of 30FPS). - removePostedEvents(this, Present); - postEvent(this, new QEvent(static_cast(Present)), Qt::LowEventPriority); - isPaintingThrottled = false; + int type = event->type(); + switch (type) { + case Event::Lambda: + static_cast(event)->call(); return true; - } - float nsecsElapsed = (float)_lastTimeUpdated.nsecsElapsed(); - if (shouldPaint(nsecsElapsed)) { - _lastTimeUpdated.start(); - idle(nsecsElapsed); - postEvent(this, new QEvent(static_cast(Paint)), Qt::HighEventPriority); - } - isPaintingThrottled = true; + case Event::Present: + if (!_renderRequested) { + float nsecsElapsed = (float)_lastTimeUpdated.nsecsElapsed(); + if (shouldPaint(nsecsElapsed)) { + _renderRequested = true; + _lastTimeUpdated.start(); + idle(nsecsElapsed); + postEvent(this, new QEvent(static_cast(Paint)), Qt::HighEventPriority); + } + } + return true; - return true; - } else if ((int)event->type() == (int)Paint) { - // NOTE: This must be updated as close to painting as possible, - // or AvatarInputs will mysteriously move to the bottom-right - AvatarInputs::getInstance()->update(); + case Event::Paint: + // NOTE: This must be updated as close to painting as possible, + // or AvatarInputs will mysteriously move to the bottom-right + AvatarInputs::getInstance()->update(); + paintGL(); + _renderRequested = false; + return true; - paintGL(); - - isPaintingThrottled = false; - - return true; - } else if ((int)event->type() == (int)Idle) { - float nsecsElapsed = (float)_lastTimeUpdated.nsecsElapsed(); - idle(nsecsElapsed); - - return true; - } - - if ((int)event->type() == (int)Lambda) { - static_cast(event)->call(); - return true; + default: + break; } { From cd11f5cfa6edda943b9015e13d0bc645a6f83024 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 7 Jul 2017 22:02:56 -0700 Subject: [PATCH 3/3] More tweaks for improved script performance --- interface/src/Application.cpp | 4 ++- interface/src/ui/overlays/Overlays.cpp | 37 +++++++++++--------------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3cbc6208ad..565d86cc69 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2751,7 +2751,7 @@ bool Application::event(QEvent* event) { idle(nsecsElapsed); postEvent(this, new QEvent(static_cast(Paint)), Qt::HighEventPriority); } - } + } return true; case Event::Paint: @@ -2759,6 +2759,8 @@ bool Application::event(QEvent* event) { // or AvatarInputs will mysteriously move to the bottom-right AvatarInputs::getInstance()->update(); paintGL(); + // wait for the next present event before starting idle / paint again + removePostedEvents(this, Present); _renderRequested = false; return true; diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 2f22b62306..72682fcb8c 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -152,6 +152,7 @@ Overlay::Pointer Overlays::getOverlay(OverlayID id) const { OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) { if (QThread::currentThread() != thread()) { OverlayID result; + PROFILE_RANGE(script, __FUNCTION__); BLOCKING_INVOKE_METHOD(this, "addOverlay", Q_RETURN_ARG(OverlayID, result), Q_ARG(QString, type), Q_ARG(QVariant, properties)); return result; } @@ -220,6 +221,7 @@ OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) { OverlayID Overlays::cloneOverlay(OverlayID id) { if (QThread::currentThread() != thread()) { OverlayID result; + PROFILE_RANGE(script, __FUNCTION__); BLOCKING_INVOKE_METHOD(this, "cloneOverlay", Q_RETURN_ARG(OverlayID, result), Q_ARG(OverlayID, id)); return result; } @@ -315,6 +317,7 @@ void Overlays::deleteOverlay(OverlayID id) { QString Overlays::getOverlayType(OverlayID overlayId) { if (QThread::currentThread() != thread()) { QString result; + PROFILE_RANGE(script, __FUNCTION__); BLOCKING_INVOKE_METHOD(this, "getOverlayType", Q_RETURN_ARG(QString, result), Q_ARG(OverlayID, overlayId)); return result; } @@ -329,6 +332,7 @@ QString Overlays::getOverlayType(OverlayID overlayId) { QObject* Overlays::getOverlayObject(OverlayID id) { if (QThread::currentThread() != thread()) { QObject* result; + PROFILE_RANGE(script, __FUNCTION__); BLOCKING_INVOKE_METHOD(this, "getOverlayObject", Q_RETURN_ARG(QObject*, result), Q_ARG(OverlayID, id)); return result; } @@ -384,12 +388,6 @@ void Overlays::setParentPanel(OverlayID childId, OverlayID panelId) { #endif OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) { - if (QThread::currentThread() != thread()) { - OverlayID result; - BLOCKING_INVOKE_METHOD(this, "getOverlayAtPoint", Q_RETURN_ARG(OverlayID, result), Q_ARG(glm::vec2, point)); - return result; - } - if (!_enabled) { return UNKNOWN_OVERLAY_ID; } @@ -486,18 +484,6 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR const QVector& overlaysToInclude, const QVector& overlaysToDiscard, bool visibleOnly, bool collidableOnly) { - if (QThread::currentThread() != thread()) { - RayToOverlayIntersectionResult result; - BLOCKING_INVOKE_METHOD(this, "findRayIntersectionInternal", Q_RETURN_ARG(RayToOverlayIntersectionResult, result), - Q_ARG(PickRay, ray), - Q_ARG(bool, precisionPicking), - Q_ARG(QVector, overlaysToInclude), - Q_ARG(QVector, overlaysToDiscard), - Q_ARG(bool, visibleOnly), - Q_ARG(bool, collidableOnly)); - return result; - } - float bestDistance = std::numeric_limits::max(); bool bestIsFront = false; @@ -616,6 +602,7 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& objectVar bool Overlays::isLoaded(OverlayID id) { if (QThread::currentThread() != thread()) { bool result; + PROFILE_RANGE(script, __FUNCTION__); BLOCKING_INVOKE_METHOD(this, "isLoaded", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id)); return result; } @@ -630,6 +617,7 @@ bool Overlays::isLoaded(OverlayID id) { QSizeF Overlays::textSize(OverlayID id, const QString& text) { if (QThread::currentThread() != thread()) { QSizeF result; + PROFILE_RANGE(script, __FUNCTION__); BLOCKING_INVOKE_METHOD(this, "textSize", Q_RETURN_ARG(QSizeF, result), Q_ARG(OverlayID, id), Q_ARG(QString, text)); return result; } @@ -708,6 +696,7 @@ void Overlays::deletePanel(OverlayID panelId) { bool Overlays::isAddedOverlay(OverlayID id) { if (QThread::currentThread() != thread()) { bool result; + PROFILE_RANGE(script, __FUNCTION__); BLOCKING_INVOKE_METHOD(this, "isAddedOverlay", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id)); return result; } @@ -743,6 +732,7 @@ void Overlays::sendHoverLeaveOverlay(OverlayID id, PointerEvent event) { OverlayID Overlays::getKeyboardFocusOverlay() { if (QThread::currentThread() != thread()) { OverlayID result; + PROFILE_RANGE(script, __FUNCTION__); BLOCKING_INVOKE_METHOD(this, "getKeyboardFocusOverlay", Q_RETURN_ARG(OverlayID, result)); return result; } @@ -762,6 +752,7 @@ void Overlays::setKeyboardFocusOverlay(OverlayID id) { float Overlays::width() { if (QThread::currentThread() != thread()) { float result; + PROFILE_RANGE(script, __FUNCTION__); BLOCKING_INVOKE_METHOD(this, "width", Q_RETURN_ARG(float, result)); return result; } @@ -773,6 +764,7 @@ float Overlays::width() { float Overlays::height() { if (QThread::currentThread() != thread()) { float result; + PROFILE_RANGE(script, __FUNCTION__); BLOCKING_INVOKE_METHOD(this, "height", Q_RETURN_ARG(float, result)); return result; } @@ -982,10 +974,11 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) { QVector Overlays::findOverlays(const glm::vec3& center, float radius) { QVector result; - if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "findOverlays", Q_RETURN_ARG(QVector, result), Q_ARG(glm::vec3, center), Q_ARG(float, radius)); - return result; - } + //if (QThread::currentThread() != thread()) { + // PROFILE_RANGE(script, __FUNCTION__); + // BLOCKING_INVOKE_METHOD(this, "findOverlays", Q_RETURN_ARG(QVector, result), Q_ARG(glm::vec3, center), Q_ARG(float, radius)); + // return result; + //} QMutexLocker locker(&_mutex); QMapIterator i(_overlaysWorld);