From 6d7f8f4a6f2f7a9ce5f29a7e748b385806d0fe3c Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 18 Apr 2016 16:46:37 -0700 Subject: [PATCH 01/21] Make RateCounter rate atomic --- libraries/shared/src/shared/RateCounter.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/shared/RateCounter.h b/libraries/shared/src/shared/RateCounter.h index e24b1e6eca..2a06c5d09c 100644 --- a/libraries/shared/src/shared/RateCounter.h +++ b/libraries/shared/src/shared/RateCounter.h @@ -11,6 +11,7 @@ #define hifi_Shared_RateCounter_h #include +#include #include #include @@ -42,7 +43,7 @@ public: private: uint64_t _start { usecTimestampNow() }; size_t _count { 0 }; - float _rate { 0 }; + std::atomic _rate { 0 }; const float _scale { powf(10, PRECISION) }; }; From f48541961d461cc8eca524f18e1228c778de23d5 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 18 Apr 2016 17:26:29 -0700 Subject: [PATCH 02/21] Expose Rates to JS/QML --- interface/src/Application.cpp | 28 ++++++++++++++++++++++++++++ interface/src/Application.h | 1 + 2 files changed, 29 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 41eb7a305d..5383d130ab 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -508,6 +508,26 @@ Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); Setting::Handle sessionRunTime{ "sessionRunTime", 0 }; +class Rates : public QObject { + Q_OBJECT + + Q_PROPERTY(float render READ getRenderRate) + Q_PROPERTY(float present READ getPresentRate) + Q_PROPERTY(float newFrame READ getNewFrameRate) + Q_PROPERTY(float dropped READ getDropRate) + Q_PROPERTY(float simulation READ getSimulationRate) + Q_PROPERTY(float avatar READ getAvatarRate) + +public: + Rates(QObject* parent) : QObject(parent) {} + float getRenderRate() { return qApp->getFps(); } + float getPresentRate() { return qApp->getActiveDisplayPlugin()->presentRate(); } + float getNewFrameRate() { return qApp->getActiveDisplayPlugin()->newFramePresentRate(); } + float getDropRate() { return qApp->getActiveDisplayPlugin()->droppedFrameRate(); } + float getSimulationRate() { return qApp->getAverageSimsPerSecond(); } + float getAvatarRate() { return qApp->getAvatarSimrate(); } +}; + Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : QApplication(argc, argv), _window(new MainWindow(desktop())), @@ -531,6 +551,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _notifiedPacketVersionMismatchThisDomain(false), _maxOctreePPS(maxOctreePacketsPerSecond.get()), _lastFaceTrackerUpdate(0) + { // FIXME this may be excessively conservative. On the other hand // maybe I'm used to having an 8-core machine @@ -766,6 +787,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : ResourceCache::setRequestLimit(3); + _rates = new Rates(this); + _glWidget = new GLCanvas(); getApplicationCompositor().setRenderingWidget(_glWidget); _window->setCentralWidget(_glWidget); @@ -1390,6 +1413,7 @@ void Application::initializeUi() { rootContext->setContextProperty("Preferences", DependencyManager::get().data()); rootContext->setContextProperty("AddressManager", DependencyManager::get().data()); rootContext->setContextProperty("FrameTimings", &_frameTimingsScriptingInterface); + rootContext->setContextProperty("Rates", _rates); rootContext->setContextProperty("TREE_SCALE", TREE_SCALE); rootContext->setContextProperty("Quat", new Quat()); @@ -4443,6 +4467,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri // AvatarManager has some custom types AvatarManager::registerMetaTypes(scriptEngine); + scriptEngine->registerGlobalObject("Rates", _rates); + // hook our avatar and avatar hash map object into this script engine scriptEngine->registerGlobalObject("MyAvatar", getMyAvatar()); qScriptRegisterMetaType(scriptEngine, audioListenModeToScriptValue, audioListenModeFromScriptValue); @@ -5270,3 +5296,5 @@ void Application::showDesktop() { CompositorHelper& Application::getApplicationCompositor() const { return *DependencyManager::get(); } + +#include "Application.moc" diff --git a/interface/src/Application.h b/interface/src/Application.h index 6bfad21525..78424d0f57 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -399,6 +399,7 @@ private: uint32_t _frameCount { 0 }; // Frame Rate Measurement + QObject* _rates; RateCounter<> _frameCounter; RateCounter<> _avatarSimCounter; RateCounter<> _simCounter; From b11d6ca1c6723d04703055ed08f25937e8dbf1ae Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 18 Apr 2016 16:28:27 -0700 Subject: [PATCH 03/21] Make Render Rates qml script --- examples/utilities/render/rates.qml | 49 ++++++++++++++++++++++++ examples/utilities/render/renderRates.js | 21 ++++++++++ 2 files changed, 70 insertions(+) create mode 100644 examples/utilities/render/rates.qml create mode 100644 examples/utilities/render/renderRates.js diff --git a/examples/utilities/render/rates.qml b/examples/utilities/render/rates.qml new file mode 100644 index 0000000000..f4a4ee2c6c --- /dev/null +++ b/examples/utilities/render/rates.qml @@ -0,0 +1,49 @@ +// +// 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: [ ["Present", "present"], ["Present", "present"], ["New", "newFrame"], ["Dropped", "dropped"], ["Simulation", "simulation"], ["Avatar", "avatar"] ] + property var colors: [ "#1AC567", "#00B4EF" ] + + Grid { + id: grid + rows: (root.caches.length / 2); columns: 2; spacing: 8 + anchors.fill: parent + + Repeater { + id: repeater + + model: root.caches + + Row { + PlotPerf { + title: modelData[0] + " Rate" + height: (grid.height - (grid.spacing * ((root.caches.length / 2) + 1))) / (root.caches.length / 2) + width: grid.width / 2 - grid.spacing * 1.5 + object: Rates + valueScale: 1 + valueUnit: "fps" + valueNumDigits: "2" + plots: [{ + prop: modelData[1], + color: root.colors[index % 2] + }] + } + } + } + } +} diff --git a/examples/utilities/render/renderRates.js b/examples/utilities/render/renderRates.js new file mode 100644 index 0000000000..1d15f4041c --- /dev/null +++ b/examples/utilities/render/renderRates.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('rates.qml'); +var window = new OverlayWindow({ + title: 'Render Rates', + source: qml, + width: 300, + height: 200 +}); +window.setPosition(500, 50); +window.closed.connect(function() { Script.stop(); }); From 4dacb04ee17fa8ad35b5c836ae8821dde7462eb1 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 19 Apr 2016 16:01:55 -0700 Subject: [PATCH 04/21] Rm myAvatar motion states on shutdown --- interface/src/avatar/AvatarManager.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index efd1bede47..402245d0c3 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -254,10 +254,7 @@ void AvatarManager::clearAllAvatars() { QWriteLocker locker(&_hashLock); - _myAvatar->die(); - _myAvatar.reset(); - - _avatarHash.clear(); + handleRemovedAvatar(_myAvatar); } void AvatarManager::setLocalLights(const QVector& localLights) { From a7d2373f3eeb542e4c4995fe66630a97453ccabd Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 19 Apr 2016 16:17:39 -0700 Subject: [PATCH 05/21] Use our ShutdownEventListener utility in Interface, and absorb quit signal when we handle it. --- interface/src/Application.cpp | 7 +++++++ libraries/shared/src/ShutdownEventListener.cpp | 1 + 2 files changed, 8 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4e01fe85c3..ded414ceab 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -717,6 +718,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle); connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress); + // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us +#ifdef _WIN32 + installNativeEventFilter(&ShutdownEventListener::getInstance()); +#else + ShutdownEventListener::getInstance(); +#endif // Save avatar location immediately after a teleport. connect(getMyAvatar(), &MyAvatar::positionGoneTo, diff --git a/libraries/shared/src/ShutdownEventListener.cpp b/libraries/shared/src/ShutdownEventListener.cpp index e640126b7b..fa2209f9b7 100644 --- a/libraries/shared/src/ShutdownEventListener.cpp +++ b/libraries/shared/src/ShutdownEventListener.cpp @@ -47,6 +47,7 @@ bool ShutdownEventListener::nativeEventFilter(const QByteArray &eventType, void* if (message->message == WM_CLOSE) { // tell our registered application to quit QMetaObject::invokeMethod(qApp, "quit"); + return true; // Don't zombify the application by OS-exitting. Let the application quit in the normal quit-signal way. } } #endif From 712c0bdf9d2b6a4c4b2516f9e408ad5d019f7cd6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 20 Apr 2016 10:00:38 -0700 Subject: [PATCH 06/21] Update 'model' icon in edit.js --- examples/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/edit.js b/examples/edit.js index e3bea2e954..c58bdb8110 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -201,7 +201,7 @@ var toolBar = (function() { }, true, false); newModelButton = toolBar.addTool({ - imageURL: toolIconUrl + "upload-01.svg", + imageURL: toolIconUrl + "model-01.svg", subImage: { x: 0, y: Tool.IMAGE_WIDTH, From b22123211776ed6aac994430f40ff7ac7b49b100 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 20 Apr 2016 10:31:26 -0700 Subject: [PATCH 07/21] Windows-only version, without changing assignment-client/domain-server classes. --- interface/src/Application.cpp | 12 ++++++------ libraries/shared/src/ShutdownEventListener.cpp | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ded414ceab..fff65a6955 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -366,6 +366,12 @@ public: return true; } } + + if (message->message == WM_CLOSE) { + // tell our registered application to quit + QMetaObject::invokeMethod(qApp, "quit"); + return true; // Don't zombify the application by OS-exitting. Let the application quit in the normal quit-signal way. + } } return false; } @@ -718,12 +724,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle); connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress); - // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us -#ifdef _WIN32 - installNativeEventFilter(&ShutdownEventListener::getInstance()); -#else - ShutdownEventListener::getInstance(); -#endif // Save avatar location immediately after a teleport. connect(getMyAvatar(), &MyAvatar::positionGoneTo, diff --git a/libraries/shared/src/ShutdownEventListener.cpp b/libraries/shared/src/ShutdownEventListener.cpp index fa2209f9b7..e640126b7b 100644 --- a/libraries/shared/src/ShutdownEventListener.cpp +++ b/libraries/shared/src/ShutdownEventListener.cpp @@ -47,7 +47,6 @@ bool ShutdownEventListener::nativeEventFilter(const QByteArray &eventType, void* if (message->message == WM_CLOSE) { // tell our registered application to quit QMetaObject::invokeMethod(qApp, "quit"); - return true; // Don't zombify the application by OS-exitting. Let the application quit in the normal quit-signal way. } } #endif From 77d6e0e3e9e02cf8ced35e822e76f6f7a9051ab1 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 20 Apr 2016 10:34:10 -0700 Subject: [PATCH 08/21] Remove include. --- interface/src/Application.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fff65a6955..21cb4c8ec2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -91,7 +91,6 @@ #include #include #include -#include #include #include #include From 2cc48a6ca6ec0cb7cbd16a339a821579cf72b929 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 18 Apr 2016 17:53:58 -0700 Subject: [PATCH 09/21] Add url to resource retry debug --- libraries/networking/src/ResourceCache.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 68d9a61226..b6f482dbe7 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -606,8 +606,9 @@ void Resource::handleReplyFinished() { const int BASE_DELAY_MS = 1000; if (_attempts++ < MAX_ATTEMPTS) { auto waitTime = BASE_DELAY_MS * (int)pow(2.0, _attempts); - qCDebug(networking).nospace() << "Retrying to load the asset in " << waitTime - << "ms, attempt " << _attempts << " of " << MAX_ATTEMPTS; + qCDebug(networking) << "Server unavailable for" << _url << + "retrying in " << waitTime << "ms," << + "attempt " << _attempts + 1 << "of" << MAX_ATTEMPTS; QTimer::singleShot(waitTime, this, &Resource::attemptRequest); break; } From 948af75f8a6f342a65c5b281b3994c5a15f8ad70 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 20 Apr 2016 11:51:02 -0700 Subject: [PATCH 10/21] Transfer loaded resources with smart ptrs to avoid shutdown deadlock --- libraries/animation/src/AnimationCache.cpp | 10 +++---- libraries/animation/src/AnimationCache.h | 6 ++-- libraries/fbx/src/FBXReader.cpp | 2 ++ libraries/fbx/src/FBXReader.h | 2 ++ libraries/gpu/src/gpu/Texture.cpp | 5 ++-- libraries/gpu/src/gpu/Texture.h | 5 ++-- .../src/model-networking/ModelCache.cpp | 28 +++++++++---------- .../src/model-networking/TextureCache.cpp | 24 +++++++--------- .../src/model-networking/TextureCache.h | 5 +--- 9 files changed, 42 insertions(+), 45 deletions(-) diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index a502e608e2..9364045857 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -64,9 +64,9 @@ void AnimationReader::run() { if (urlValid) { // Parse the FBX directly from the QNetworkReply - FBXGeometry* fbxgeo = nullptr; + FBXGeometry::Pointer fbxgeo; if (_url.path().toLower().endsWith(".fbx")) { - fbxgeo = readFBX(_data, QVariantHash(), _url.path()); + fbxgeo.reset(readFBX(_data, QVariantHash(), _url.path())); } else { QString errorStr("usupported format"); emit onError(299, errorStr); @@ -117,16 +117,16 @@ const QVector& Animation::getFramesReference() const { void Animation::downloadFinished(const QByteArray& data) { // parse the animation/fbx file on a background thread. AnimationReader* animationReader = new AnimationReader(_url, data); - connect(animationReader, SIGNAL(onSuccess(FBXGeometry*)), SLOT(animationParseSuccess(FBXGeometry*))); + connect(animationReader, SIGNAL(onSuccess(FBXGeometry::Pointer)), SLOT(animationParseSuccess(FBXGeometry::Pointer))); connect(animationReader, SIGNAL(onError(int, QString)), SLOT(animationParseError(int, QString))); QThreadPool::globalInstance()->start(animationReader); } -void Animation::animationParseSuccess(FBXGeometry* geometry) { +void Animation::animationParseSuccess(FBXGeometry::Pointer geometry) { qCDebug(animation) << "Animation parse success" << _url.toDisplayString(); - _geometry.reset(geometry); + _geometry = geometry; finishedLoading(true); } diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index e6a795c864..59a4ad0498 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -68,12 +68,12 @@ protected: virtual void downloadFinished(const QByteArray& data) override; protected slots: - void animationParseSuccess(FBXGeometry* geometry); + void animationParseSuccess(FBXGeometry::Pointer geometry); void animationParseError(int error, QString str); private: - std::unique_ptr _geometry; + FBXGeometry::Pointer _geometry; }; /// Reads geometry in a worker thread. @@ -85,7 +85,7 @@ public: virtual void run(); signals: - void onSuccess(FBXGeometry* geometry); + void onSuccess(FBXGeometry::Pointer geometry); void onError(int error, QString str); private: diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 65acedfc96..2df388e1d4 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -39,6 +39,8 @@ using namespace std; +static int FBXGeometryPointerMetaTypeId = qRegisterMetaType(); + QStringList FBXGeometry::getJointNames() const { QStringList names; foreach (const FBXJoint& joint, joints) { diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index a1fc30d1f4..c1952fc550 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -270,6 +270,7 @@ inline bool operator!=(const SittingPoint& lhs, const SittingPoint& rhs) /// A set of meshes extracted from an FBX document. class FBXGeometry { public: + using Pointer = std::shared_ptr; QString author; QString applicationName; ///< the name of the application that generated the model @@ -330,6 +331,7 @@ public: }; Q_DECLARE_METATYPE(FBXGeometry) +Q_DECLARE_METATYPE(FBXGeometry::Pointer) /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 822c1392df..2a19dc926b 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -17,6 +17,7 @@ using namespace gpu; +static int TexturePointerMetaTypeId = qRegisterMetaType(); std::atomic Texture::_textureCPUCount{ 0 }; std::atomic Texture::_textureCPUMemoryUsage{ 0 }; @@ -857,8 +858,8 @@ void TextureSource::reset(const QUrl& url) { _imageUrl = url; } -void TextureSource::resetTexture(gpu::Texture* texture) { - _gpuTexture.reset(texture); +void TextureSource::resetTexture(gpu::TexturePointer texture) { + _gpuTexture = texture; } bool TextureSource::isDefined() const { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 4715170cef..69d50617bf 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -16,6 +16,7 @@ #include //min max and more #include +#include #include namespace gpu { @@ -469,7 +470,6 @@ protected: typedef std::shared_ptr TexturePointer; typedef std::vector< TexturePointer > Textures; - // TODO: For now TextureView works with Texture as a place holder for the Texture. // The overall logic should be about the same except that the Texture will be a real GL Texture under the hood class TextureView { @@ -526,7 +526,7 @@ public: void reset(const QUrl& url); - void resetTexture(gpu::Texture* texture); + void resetTexture(gpu::TexturePointer texture); bool isDefined() const; @@ -538,5 +538,6 @@ typedef std::shared_ptr< TextureSource > TextureSourcePointer; }; +Q_DECLARE_METATYPE(gpu::TexturePointer) #endif diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index a565b249d8..6dd1d97d7f 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -143,40 +143,38 @@ void GeometryReader::run() { QString urlname = _url.path().toLower(); if (!urlname.isEmpty() && !_url.path().isEmpty() && (_url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".obj"))) { - FBXGeometry* fbxGeometry = nullptr; + FBXGeometry::Pointer fbxGeometry; if (_url.path().toLower().endsWith(".fbx")) { - fbxGeometry = readFBX(_data, _mapping, _url.path()); + fbxGeometry.reset(readFBX(_data, _mapping, _url.path())); if (fbxGeometry->meshes.size() == 0 && fbxGeometry->joints.size() == 0) { throw QString("empty geometry, possibly due to an unsupported FBX version"); } } else if (_url.path().toLower().endsWith(".obj")) { - fbxGeometry = OBJReader().readOBJ(_data, _mapping, _url); + fbxGeometry.reset(OBJReader().readOBJ(_data, _mapping, _url)); } else { throw QString("unsupported format"); } - // Ensure the resource has not been deleted, and won't be while invokeMethod is in flight. + // Ensure the resource has not been deleted auto resource = _resource.toStrongRef(); if (!resource) { qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; - delete fbxGeometry; } else { - QMetaObject::invokeMethod(resource.data(), "setGeometryDefinition", Qt::BlockingQueuedConnection, Q_ARG(void*, fbxGeometry)); + QMetaObject::invokeMethod(resource.data(), "setGeometryDefinition", + Q_ARG(FBXGeometry::Pointer, fbxGeometry)); } } else { throw QString("url is invalid"); } } catch (const QString& error) { - qCDebug(modelnetworking) << "Error reading " << _url << ": " << error; + qCDebug(modelnetworking) << "Error parsing model for" << _url << ":" << error; auto resource = _resource.toStrongRef(); - // Ensure the resoruce has not been deleted, and won't be while invokeMethod is in flight. - if (!resource) { - qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; - } else { - QMetaObject::invokeMethod(resource.data(), "finishedLoading", Qt::BlockingQueuedConnection, Q_ARG(bool, false)); + if (resource) { + QMetaObject::invokeMethod(resource.data(), "finishedLoading", + Q_ARG(bool, false)); } } } @@ -190,7 +188,7 @@ public: virtual void downloadFinished(const QByteArray& data) override; protected: - Q_INVOKABLE void setGeometryDefinition(void* fbxGeometry); + Q_INVOKABLE void setGeometryDefinition(FBXGeometry::Pointer fbxGeometry); private: QVariantHash _mapping; @@ -200,9 +198,9 @@ void GeometryDefinitionResource::downloadFinished(const QByteArray& data) { QThreadPool::globalInstance()->start(new GeometryReader(_self, _url, _mapping, data)); } -void GeometryDefinitionResource::setGeometryDefinition(void* fbxGeometry) { +void GeometryDefinitionResource::setGeometryDefinition(FBXGeometry::Pointer fbxGeometry) { // Assume ownership of the geometry pointer - _geometry.reset(static_cast(fbxGeometry)); + _geometry = fbxGeometry; // Copy materials QHash materialIDAtlas; diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 0e93119fe3..7d18151f2c 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -330,7 +330,7 @@ void ImageReader::run() { return; } - gpu::Texture* texture = nullptr; + gpu::TexturePointer texture = nullptr; { // Double-check the resource still exists between long operations. auto resource = _resource.toStrongRef(); @@ -342,36 +342,32 @@ void ImageReader::run() { auto url = _url.toString().toStdString(); PROFILE_RANGE_EX(__FUNCTION__"::textureLoader", 0xffffff00, nullptr); - texture = resource.dynamicCast()->getTextureLoader()(image, url); + texture.reset(resource.dynamicCast()->getTextureLoader()(image, url)); } - // Ensure the resource has not been deleted, and won't be while invokeMethod is in flight. + // Ensure the resource has not been deleted 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), + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, texture), Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); } } -void NetworkTexture::setImage(void* voidTexture, int originalWidth, +void NetworkTexture::setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight) { _originalWidth = originalWidth; _originalHeight = originalHeight; - gpu::Texture* texture = static_cast(voidTexture); - // Passing ownership _textureSource->resetTexture(texture); - auto gpuTexture = _textureSource->getGPUTexture(); - if (gpuTexture) { - _width = gpuTexture->getWidth(); - _height = gpuTexture->getHeight(); - setSize(gpuTexture->getStoredSize()); + if (texture) { + _width = texture->getWidth(); + _height = texture->getHeight(); + setSize(texture->getStoredSize()); } else { // FIXME: If !gpuTexture, we failed to load! _width = _height = 0; diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index a392117958..c614a7ceb3 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -128,7 +128,6 @@ public: signals: void networkTextureCreated(const QWeakPointer& self); - protected: virtual bool isCacheable() const override { return _loaded; } @@ -136,9 +135,7 @@ protected: virtual void downloadFinished(const QByteArray& data) override; Q_INVOKABLE void loadContent(const QByteArray& content); - // FIXME: This void* should be a gpu::Texture* but i cannot get it to work for now, moving on... - Q_INVOKABLE void setImage(void* texture, int originalWidth, int originalHeight); - + Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight); private: TextureType _type; From 1fe12e70294a95535c1374cdd7c728aa3a66bdfe Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 20 Apr 2016 13:24:55 -0700 Subject: [PATCH 11/21] Mv Rates to RatesScriptingInterface.h --- interface/src/Application.cpp | 30 ++-------------- interface/src/Application.h | 1 - .../src/scripting/RatesScriptingInterface.h | 35 +++++++++++++++++++ 3 files changed, 38 insertions(+), 28 deletions(-) create mode 100644 interface/src/scripting/RatesScriptingInterface.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5383d130ab..88f06cb00a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -131,6 +131,7 @@ #include "scripting/WebWindowClass.h" #include "scripting/WindowScriptingInterface.h" #include "scripting/ControllerScriptingInterface.h" +#include "scripting/RatesScriptingInterface.h" #if defined(Q_OS_MAC) || defined(Q_OS_WIN) #include "SpeechRecognizer.h" #endif @@ -508,26 +509,6 @@ Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); Setting::Handle sessionRunTime{ "sessionRunTime", 0 }; -class Rates : public QObject { - Q_OBJECT - - Q_PROPERTY(float render READ getRenderRate) - Q_PROPERTY(float present READ getPresentRate) - Q_PROPERTY(float newFrame READ getNewFrameRate) - Q_PROPERTY(float dropped READ getDropRate) - Q_PROPERTY(float simulation READ getSimulationRate) - Q_PROPERTY(float avatar READ getAvatarRate) - -public: - Rates(QObject* parent) : QObject(parent) {} - float getRenderRate() { return qApp->getFps(); } - float getPresentRate() { return qApp->getActiveDisplayPlugin()->presentRate(); } - float getNewFrameRate() { return qApp->getActiveDisplayPlugin()->newFramePresentRate(); } - float getDropRate() { return qApp->getActiveDisplayPlugin()->droppedFrameRate(); } - float getSimulationRate() { return qApp->getAverageSimsPerSecond(); } - float getAvatarRate() { return qApp->getAvatarSimrate(); } -}; - Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : QApplication(argc, argv), _window(new MainWindow(desktop())), @@ -551,7 +532,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _notifiedPacketVersionMismatchThisDomain(false), _maxOctreePPS(maxOctreePacketsPerSecond.get()), _lastFaceTrackerUpdate(0) - { // FIXME this may be excessively conservative. On the other hand // maybe I'm used to having an 8-core machine @@ -787,8 +767,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : ResourceCache::setRequestLimit(3); - _rates = new Rates(this); - _glWidget = new GLCanvas(); getApplicationCompositor().setRenderingWidget(_glWidget); _window->setCentralWidget(_glWidget); @@ -1413,7 +1391,7 @@ void Application::initializeUi() { rootContext->setContextProperty("Preferences", DependencyManager::get().data()); rootContext->setContextProperty("AddressManager", DependencyManager::get().data()); rootContext->setContextProperty("FrameTimings", &_frameTimingsScriptingInterface); - rootContext->setContextProperty("Rates", _rates); + rootContext->setContextProperty("Rates", new RatesScriptingInterface(this)); rootContext->setContextProperty("TREE_SCALE", TREE_SCALE); rootContext->setContextProperty("Quat", new Quat()); @@ -4467,7 +4445,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri // AvatarManager has some custom types AvatarManager::registerMetaTypes(scriptEngine); - scriptEngine->registerGlobalObject("Rates", _rates); + scriptEngine->registerGlobalObject("Rates", new RatesScriptingInterface(this)); // hook our avatar and avatar hash map object into this script engine scriptEngine->registerGlobalObject("MyAvatar", getMyAvatar()); @@ -5296,5 +5274,3 @@ void Application::showDesktop() { CompositorHelper& Application::getApplicationCompositor() const { return *DependencyManager::get(); } - -#include "Application.moc" diff --git a/interface/src/Application.h b/interface/src/Application.h index 78424d0f57..6bfad21525 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -399,7 +399,6 @@ private: uint32_t _frameCount { 0 }; // Frame Rate Measurement - QObject* _rates; RateCounter<> _frameCounter; RateCounter<> _avatarSimCounter; RateCounter<> _simCounter; diff --git a/interface/src/scripting/RatesScriptingInterface.h b/interface/src/scripting/RatesScriptingInterface.h new file mode 100644 index 0000000000..d849fe3f8c --- /dev/null +++ b/interface/src/scripting/RatesScriptingInterface.h @@ -0,0 +1,35 @@ +// +// RatesScriptingInterface.h +// interface/src/scripting +// +// Created by Zach Pomerantz on 4/20/16. +// 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 +// + +#ifndef HIFI_RATES_SCRIPTING_INTERFACE_H +#define HIFI_RATES_SCRIPTING_INTERFACE_H + +class RatesScriptingInterface : public QObject { + Q_OBJECT + + Q_PROPERTY(float render READ getRenderRate) + Q_PROPERTY(float present READ getPresentRate) + Q_PROPERTY(float newFrame READ getNewFrameRate) + Q_PROPERTY(float dropped READ getDropRate) + Q_PROPERTY(float simulation READ getSimulationRate) + Q_PROPERTY(float avatar READ getAvatarRate) + +public: + Rates(QObject* parent) : QObject(parent) {} + float getRenderRate() { return qApp->getFps(); } + float getPresentRate() { return qApp->getActiveDisplayPlugin()->presentRate(); } + float getNewFrameRate() { return qApp->getActiveDisplayPlugin()->newFramePresentRate(); } + float getDropRate() { return qApp->getActiveDisplayPlugin()->droppedFrameRate(); } + float getSimulationRate() { return qApp->getAverageSimsPerSecond(); } + float getAvatarRate() { return qApp->getAvatarSimrate(); } +}; + +#endif // HIFI_INTERFACE_RATES_SCRIPTING_INTERFACE_H From 477d6f40e4bd1292ecdf4c4e6eaf0f636354c31f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 20 Apr 2016 13:39:57 -0700 Subject: [PATCH 12/21] Avoid use of atomic copy ctor in RateCounter --- libraries/shared/src/shared/RateCounter.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/shared/RateCounter.h b/libraries/shared/src/shared/RateCounter.h index 2a06c5d09c..d04d87493a 100644 --- a/libraries/shared/src/shared/RateCounter.h +++ b/libraries/shared/src/shared/RateCounter.h @@ -21,6 +21,8 @@ template class RateCounter { public: + RateCounter() { _rate = 0; } // avoid use of std::atomic copy ctor + void increment(size_t count = 1) { auto now = usecTimestampNow(); float currentIntervalMs = (now - _start) / (float) USECS_PER_MSEC; @@ -43,8 +45,8 @@ public: private: uint64_t _start { usecTimestampNow() }; size_t _count { 0 }; - std::atomic _rate { 0 }; const float _scale { powf(10, PRECISION) }; + std::atomic _rate; }; #endif From ad225b3aed6fa465992b587e836a67da87ffea74 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 20 Apr 2016 13:58:06 -0700 Subject: [PATCH 13/21] Fix RatesScriptingInterface ctor --- interface/src/scripting/RatesScriptingInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/RatesScriptingInterface.h b/interface/src/scripting/RatesScriptingInterface.h index d849fe3f8c..1da0aeb505 100644 --- a/interface/src/scripting/RatesScriptingInterface.h +++ b/interface/src/scripting/RatesScriptingInterface.h @@ -23,7 +23,7 @@ class RatesScriptingInterface : public QObject { Q_PROPERTY(float avatar READ getAvatarRate) public: - Rates(QObject* parent) : QObject(parent) {} + RatesScriptingInterface(QObject* parent) : QObject(parent) {} float getRenderRate() { return qApp->getFps(); } float getPresentRate() { return qApp->getActiveDisplayPlugin()->presentRate(); } float getNewFrameRate() { return qApp->getActiveDisplayPlugin()->newFramePresentRate(); } From 2c7cf3ea8378271970971edd91db0404cc3cd7e3 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 20 Apr 2016 14:32:25 -0700 Subject: [PATCH 14/21] Fix RateScriptingInterface headers --- interface/src/scripting/RatesScriptingInterface.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/scripting/RatesScriptingInterface.h b/interface/src/scripting/RatesScriptingInterface.h index 1da0aeb505..7bcab0ea70 100644 --- a/interface/src/scripting/RatesScriptingInterface.h +++ b/interface/src/scripting/RatesScriptingInterface.h @@ -12,6 +12,8 @@ #ifndef HIFI_RATES_SCRIPTING_INTERFACE_H #define HIFI_RATES_SCRIPTING_INTERFACE_H +#include + class RatesScriptingInterface : public QObject { Q_OBJECT From 0544bcaacd15d83485352ace2e9f5446ed3a948b Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 20 Apr 2016 15:02:41 -0700 Subject: [PATCH 15/21] Simpler cross-platform solution, with comments. --- interface/src/Application.cpp | 6 ------ libraries/ui/src/MainWindow.cpp | 9 +++++++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 21cb4c8ec2..4e01fe85c3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -365,12 +365,6 @@ public: return true; } } - - if (message->message == WM_CLOSE) { - // tell our registered application to quit - QMetaObject::invokeMethod(qApp, "quit"); - return true; // Don't zombify the application by OS-exitting. Let the application quit in the normal quit-signal way. - } } return false; } diff --git a/libraries/ui/src/MainWindow.cpp b/libraries/ui/src/MainWindow.cpp index ce23bd02a2..bc67a726bd 100644 --- a/libraries/ui/src/MainWindow.cpp +++ b/libraries/ui/src/MainWindow.cpp @@ -64,6 +64,15 @@ void MainWindow::saveGeometry() { } void MainWindow::closeEvent(QCloseEvent* event) { + // It is the job of Application::quit() to shut things down properly when it is finished with its event loop. + // But if we don't explicitly ignore this event now, the window and application event loop will close + // before we've had a chance to act on the aboutToClose signal. This will leaves a zombie process on all platforms. + // To repro: + // Open a QML modal dialog (e.g., select an avatar to wear), but don't dismiss it. + // Close the application with the operating system window close button (not the menu Quit) + // With ignore: App will wait until you accept or dismiss the dialog and log "Normal exit". + // Without ignore: App will close immediately, and nothing will log about quitting or exit. + event->ignore(); qApp->quit(); } From f90e1aaa236cb0da12c3c29aa875123d1ca51fe3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 20 Apr 2016 15:04:10 -0700 Subject: [PATCH 16/21] Remove #line from starsGrid.slf Fails to compile with certain drivers. --- libraries/render-utils/src/starsGrid.slf | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/render-utils/src/starsGrid.slf b/libraries/render-utils/src/starsGrid.slf index c52ccb54d9..ad9a45a4f5 100644 --- a/libraries/render-utils/src/starsGrid.slf +++ b/libraries/render-utils/src/starsGrid.slf @@ -1,6 +1,5 @@ <@include gpu/Config.slh@> <$VERSION_HEADER$> -#line __LINE__ // Generated on <$_SCRIBE_DATE$> // stars.frag // fragment shader From 9c9bca546cbcec2fb41603fcb05f59ad2b0cdb27 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 21 Apr 2016 11:52:03 +1200 Subject: [PATCH 17/21] Add button that opens scripts directory window --- .../resources/qml/hifi/dialogs/RunningScripts.qml | 11 ++++++++++- libraries/ui/src/FileDialogHelper.cpp | 7 +++++++ libraries/ui/src/FileDialogHelper.h | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index 215710cc81..189d5968d0 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -24,7 +24,7 @@ Window { resizable: true destroyOnInvisible: true x: 40; y: 40 - implicitWidth: 400; implicitHeight: 695 + implicitWidth: 400; implicitHeight: 742 minSize: Qt.vector2d(200, 300) HifiConstants { id: hifi } @@ -237,6 +237,15 @@ Window { } HifiControls.VerticalSpacer { } + + HifiControls.Button { + id: directoryButton + text: "Reveal Scripts Folder" + width: 200 + onClicked: fileDialogHelper.openScriptsDirectory() + } + + HifiControls.VerticalSpacer { } } } } diff --git a/libraries/ui/src/FileDialogHelper.cpp b/libraries/ui/src/FileDialogHelper.cpp index 82ad877573..9e22d7e441 100644 --- a/libraries/ui/src/FileDialogHelper.cpp +++ b/libraries/ui/src/FileDialogHelper.cpp @@ -14,6 +14,9 @@ #include #include #include +#include + +#include "PathUtils.h" QUrl FileDialogHelper::home() { @@ -103,3 +106,7 @@ QStringList FileDialogHelper::drives() { } return result; } + +void FileDialogHelper::openScriptsDirectory() { + QDesktopServices::openUrl(defaultScriptsLocation()); +} diff --git a/libraries/ui/src/FileDialogHelper.h b/libraries/ui/src/FileDialogHelper.h index 2119b77917..55bc922839 100644 --- a/libraries/ui/src/FileDialogHelper.h +++ b/libraries/ui/src/FileDialogHelper.h @@ -58,6 +58,8 @@ public: Q_INVOKABLE bool validFolder(const QString& path); Q_INVOKABLE QUrl pathToUrl(const QString& path); Q_INVOKABLE QUrl saveHelper(const QString& saveText, const QUrl& currentFolder, const QStringList& selectionFilters); + + Q_INVOKABLE void openScriptsDirectory(); }; From 6c5335cfa76f555ba494c05b16183644eefe0b55 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 21 Apr 2016 15:17:06 +1200 Subject: [PATCH 18/21] Replace button with icon and text --- .../resources/qml/controls-uit/TextAction.qml | 67 +++++++++++++++++++ .../qml/hifi/dialogs/RunningScripts.qml | 25 ++++--- 2 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 interface/resources/qml/controls-uit/TextAction.qml diff --git a/interface/resources/qml/controls-uit/TextAction.qml b/interface/resources/qml/controls-uit/TextAction.qml new file mode 100644 index 0000000000..1c66c3630a --- /dev/null +++ b/interface/resources/qml/controls-uit/TextAction.qml @@ -0,0 +1,67 @@ +// +// TextField.qml +// +// Created by David Rowe on 21 Apr 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 +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import "../styles-uit" +import "../controls-uit" as HifiControls + +Item { + property string icon: "" + property int iconSize: 30 + property string text: "" + + property int colorScheme: hifi.colorSchemes.light + readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light + + signal clicked() + + height: Math.max(glyph.visible ? glyph.height - 4 : 0, string.visible ? string.height : 0) + width: glyph.width + string.anchors.leftMargin + string.width + + HiFiGlyphs { + id: glyph + anchors.left: parent.left + anchors.top: parent.top + anchors.topMargin: -2 + text: parent.icon + size: parent.iconSize + color: isLightColorScheme + ? (mouseArea.containsMouse ? hifi.colors.baseGrayHighlight : hifi.colors.lightGray) + : (mouseArea.containsMouse ? hifi.colors.faintGray : hifi.colors.lightGrayText) + visible: text !== "" + width: visible ? implicitWidth : 0 + } + + RalewaySemiBold { + id: string + anchors { + left: glyph.visible ? glyph.right : parent.left + leftMargin: visible && glyph.visible ? hifi.dimensions.contentSpacing.x : 0 + verticalCenter: glyph.visible ? glyph.verticalCenter : undefined + } + text: parent.text + size: hifi.fontSizes.inputLabel + color: isLightColorScheme + ? (mouseArea.containsMouse ? hifi.colors.baseGrayHighlight : hifi.colors.lightGray) + : (mouseArea.containsMouse ? hifi.colors.faintGray : hifi.colors.lightGrayText) + font.underline: true; + visible: text !== "" + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: parent.clicked() + } +} diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index 189d5968d0..cd3b2fdf20 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -24,7 +24,7 @@ Window { resizable: true destroyOnInvisible: true x: 40; y: 40 - implicitWidth: 400; implicitHeight: 742 + implicitWidth: 400; implicitHeight: 728 minSize: Qt.vector2d(200, 300) HifiConstants { id: hifi } @@ -236,16 +236,23 @@ Window { } } - HifiControls.VerticalSpacer { } - - HifiControls.Button { - id: directoryButton - text: "Reveal Scripts Folder" - width: 200 - onClicked: fileDialogHelper.openScriptsDirectory() + HifiControls.VerticalSpacer { + height: hifi.dimensions.controlInterlineHeight - 3 } - HifiControls.VerticalSpacer { } + HifiControls.TextAction { + id: directoryButton + icon: hifi.glyphs.script + iconSize: 24 + text: "Reveal Scripts Folder" + onClicked: fileDialogHelper.openScriptsDirectory() + colorScheme: hifi.colorSchemes.dark + anchors.left: parent.left + } + + HifiControls.VerticalSpacer { + height: hifi.dimensions.controlInterlineHeight - 3 + } } } } From 47d0b8f28fff58bd802940415a442cceb7a4549c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 21 Apr 2016 08:55:57 -0700 Subject: [PATCH 19/21] Fix 'Go Home' not working on OSX --- server-console/src/modules/path-finder.js | 29 ++++++++++------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/server-console/src/modules/path-finder.js b/server-console/src/modules/path-finder.js index 1898db91ac..d0e4639e4a 100644 --- a/server-console/src/modules/path-finder.js +++ b/server-console/src/modules/path-finder.js @@ -1,21 +1,22 @@ var fs = require('fs'); var path = require('path'); -exports.searchPaths = function(name, binaryType, releaseType) { - function platformExtension(name) { - if (name == "Interface" || name == "High Fidelity") { - if (process.platform == "darwin") { - return ".app/Contents/MacOS/" + name - } else if (process.platform == "win32") { - return ".exe" - } else { - return "" - } +function platformExtension(name) { + if (name == "Interface") { + if (process.platform == "darwin") { + return ".app/Contents/MacOS/" + name + } else if (process.platform == "win32") { + return ".exe" } else { - return process.platform == "win32" ? ".exe" : "" + return "" } + } else { + return process.platform == "win32" ? ".exe" : "" } +} + +exports.searchPaths = function(name, binaryType, releaseType) { var extension = platformExtension(name); var devBasePath = "../build/" + name + "/"; @@ -68,6 +69,7 @@ exports.discoveredPath = function (name, binaryType, releaseType) { try { var stats = fs.lstatSync(testPath); + var extension = platformExtension(name); if (stats.isFile() || (stats.isDirectory() && extension == ".app")) { console.log("Found " + name + " at " + testPath); @@ -81,11 +83,6 @@ exports.discoveredPath = function (name, binaryType, releaseType) { return null; } - // for a released server console on OS X, assume the name of the interface executable is "High Fidelity" - if (releaseType && process.platform == "darwin" && name == "Interface") { - name = "High Fidelity"; - } - // attempt to find a binary at the usual paths, return null if it doesn't exist return binaryFromPaths(name, this.searchPaths(name, binaryType, releaseType)); } From 63d98b1b5c9a6ff9ae7e0bf89a55bbc6ee92c9a8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 21 Apr 2016 12:12:04 -0700 Subject: [PATCH 20/21] Fix AssetRequest crash where signal was not disconnected --- libraries/networking/src/AssetClient.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 0d640b4e80..8fb0001b57 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -32,7 +32,6 @@ MessageID AssetClient::_currentID = 0; AssetClient::AssetClient() { - setCustomDeleter([](Dependency* dependency){ static_cast(dependency)->deleteLater(); }); @@ -502,7 +501,18 @@ bool AssetClient::cancelGetAssetInfoRequest(MessageID id) { bool AssetClient::cancelGetAssetRequest(MessageID id) { // Search through each pending mapping request for id `id` for (auto& kv : _pendingRequests) { - if (kv.second.erase(id)) { + auto& messageCallbackMap = kv.second; + auto requestIt = messageCallbackMap.find(id); + if (requestIt != kv.second.end()) { + + auto& message = requestIt->second.message; + if (message) { + // disconnect from all signals emitting from the pending message + disconnect(message.data(), nullptr, this, nullptr); + } + + messageCallbackMap.erase(requestIt); + return true; } } From 8f91768bc0b17017d1ce7c6f21661a2e6d361de5 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 21 Apr 2016 13:47:55 -0700 Subject: [PATCH 21/21] Make the testing destination customizable --- examples/tests/playaPerformanceTest.qml | 122 +++++++++++++++--------- 1 file changed, 76 insertions(+), 46 deletions(-) diff --git a/examples/tests/playaPerformanceTest.qml b/examples/tests/playaPerformanceTest.qml index f1382358ae..6eb0061598 100644 --- a/examples/tests/playaPerformanceTest.qml +++ b/examples/tests/playaPerformanceTest.qml @@ -1,5 +1,6 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 +import Qt.labs.settings 1.0 Rectangle { id: root @@ -8,67 +9,68 @@ Rectangle { signal sendToScript(var message); property var values: []; - property var host: AddressManager.hostname + property alias destination: addressLine.text + readonly property string nullDestination: "169.254.0.1" + property bool running: false - - Component.onCompleted: { - Window.domainChanged.connect(function(newDomain){ - if (newDomain !== root.host) { - root.host = AddressManager.hostname; - } - }); + function statusReport() { + console.log("PERF status connected: " + AddressManager.isConnected); } - - onHostChanged: { - if (root.running) { - if (host !== "Dreaming" && host !== "Playa") { + + Timer { + id: readyStateTimer + interval: 500 + repeat: true + running: false + onTriggered: { + if (!root.running) { + stop(); return; } - console.log("PERF new domain " + host) - if (host === "Dreaming") { - AddressManager.handleLookupString("Playa"); + if (AddressManager.isConnected) { + console.log("PERF already connected, disconnecting"); + AddressManager.handleLookupString(root.nullDestination); return; } + + stop(); + console.log("PERF disconnected, moving to target " + root.destination); + AddressManager.handleLookupString(root.destination); - if (host === "Playa") { - console.log("PERF starting timers and frame timing"); - // If we've arrived, start running the test - FrameTimings.start(); - rotationTimer.start(); - stopTimer.start(); - } + // If we've arrived, start running the test + console.log("PERF starting timers and frame timing"); + FrameTimings.start(); + rotationTimer.start(); + stopTimer.start(); } } + function startTest() { console.log("PERF startTest()"); - root.running = true - console.log("PERF current host: " + AddressManager.hostname) - // If we're already in playa, we need to go somewhere else... - if ("Playa" === AddressManager.hostname) { - console.log("PERF Navigating to dreaming") - AddressManager.handleLookupString("Dreaming/0,0,0"); - } else { - console.log("PERF Navigating to playa") - AddressManager.handleLookupString("Playa"); + if (!root.running) { + root.running = true + readyStateTimer.start(); } } function stopTest() { console.log("PERF stopTest()"); - root.running = false; - stopTimer.stop(); - rotationTimer.stop(); - FrameTimings.finish(); - root.values = FrameTimings.getValues(); - AddressManager.handleLookupString("Dreaming/0,0,0"); - resultGraph.requestPaint(); - console.log("PERF Value Count: " + root.values.length); - console.log("PERF Max: " + FrameTimings.max); - console.log("PERF Min: " + FrameTimings.min); - console.log("PERF Avg: " + FrameTimings.mean); - console.log("PERF StdDev: " + FrameTimings.standardDeviation); + if (root.running) { + root.running = false; + stopTimer.stop(); + rotationTimer.stop(); + FrameTimings.finish(); + root.values = FrameTimings.getValues(); + AddressManager.handleLookupString(root.nullDestination); + resultGraph.requestPaint(); + console.log("PERF Value Count: " + root.values.length); + console.log("PERF Max: " + FrameTimings.max); + console.log("PERF Min: " + FrameTimings.min); + console.log("PERF Avg: " + FrameTimings.mean); + console.log("PERF StdDev: " + FrameTimings.standardDeviation); + } } function yaw(a) { @@ -82,7 +84,6 @@ Rectangle { MyAvatar.setOrientationVar(yaw(Date.now() / 1000)); } - property bool running: false Timer { id: stopTimer @@ -102,14 +103,43 @@ Rectangle { Row { id: row - anchors { left: parent.left; right: parent.right; } + anchors { left: parent.left; right: parent.right; top: parent.top; margins: 16 } spacing: 8 Button { text: root.running ? "Stop" : "Run" onClicked: root.running ? stopTest() : startTest(); } + Button { + text: "Disconnect" + onClicked: AddressManager.handleLookupString(root.nullDestination); + } + Button { + text: "Connect" + onClicked: AddressManager.handleLookupString(root.destination); + } + Button { + text: "Status" + onClicked: statusReport(); + } } + TextField { + id: addressLine + focus: true + anchors { + left: parent.left; right: parent.right; + top: row.bottom; margins: 16; + } + text: "Playa" + onTextChanged: console.log("PERF new target " + text); + } + + Settings { + category: "Qml.Performance.RenderTest" + property alias destination: addressLine.text + } + + // Rectangle { // anchors { left: parent.left; right: parent.right; top: row.bottom; topMargin: 8; bottom: parent.bottom; } // //anchors.fill: parent @@ -130,7 +160,7 @@ Rectangle { Canvas { id: resultGraph - anchors { left: parent.left; right: parent.right; top: row.bottom; margins: 16; bottom: parent.bottom; } + anchors { left: parent.left; right: parent.right; top: addressLine.bottom; margins: 16; bottom: parent.bottom; } property real maxValue: 200; property real perFrame: 10000; property real k1: (5 / maxValue) * height;