diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index e50f43674e..696695de68 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -166,7 +166,8 @@ Item { color: root.fontColor; font.pixelSize: root.fontSize visible: root.expanded; - text: "Downloads: "; + text: "Downloads: " + root.downloads + "/" + root.downloadLimit + + ", Pending: " + root.downloadsPending; } } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ce8f4e48d9..e1f2b2a49b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2058,18 +2058,21 @@ void Application::keyPressEvent(QKeyEvent* event) { if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::MiniMirror); } else { - Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)); - if (!Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { + bool isMirrorChecked = Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror); + Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, !isMirrorChecked); + if (isMirrorChecked) { Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); } cameraMenuChanged(); } break; - case Qt::Key_P: - Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, !Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)); - Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)); - cameraMenuChanged(); - break; + case Qt::Key_P: { + bool isFirstPersonChecked = Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson); + Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, !isFirstPersonChecked); + Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, isFirstPersonChecked); + cameraMenuChanged(); + break; + } case Qt::Key_Slash: Menu::getInstance()->triggerOption(MenuOption::Stats); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index ac47c55eca..23d2b87194 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -193,6 +193,7 @@ void Stats::updateStats(bool force) { } STAT_UPDATE(downloads, ResourceCache::getLoadingRequests().size()); + STAT_UPDATE(downloadLimit, ResourceCache::getRequestLimit()) STAT_UPDATE(downloadsPending, ResourceCache::getPendingRequestCount()); // TODO fix to match original behavior //stringstream downloads; diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index ebcb80c404..c6bc13b52c 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -56,6 +56,7 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, audioMixerKbps, 0) STATS_PROPERTY(int, audioMixerPps, 0) STATS_PROPERTY(int, downloads, 0) + STATS_PROPERTY(int, downloadLimit, 0) STATS_PROPERTY(int, downloadsPending, 0) STATS_PROPERTY(int, triangles, 0) STATS_PROPERTY(int, quads, 0) @@ -135,6 +136,7 @@ signals: void audioMixerKbpsChanged(); void audioMixerPpsChanged(); void downloadsChanged(); + void downloadLimitChanged(); void downloadsPendingChanged(); void trianglesChanged(); void quadsChanged(); diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index dabf1b098b..e345bed81c 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -56,6 +56,15 @@ void ResourceCache::refresh(const QUrl& url) { } } +void ResourceCache::setRequestLimit(int limit) { + _requestLimit = limit; + + // Now go fill any new request spots + while (attemptHighestPriorityRequest()) { + // just keep looping until we reach the new limit or no more pending requests + } +} + void ResourceCache::getResourceAsynchronously(const QUrl& url) { qCDebug(networking) << "ResourceCache::getResourceAsynchronously" << url.toString(); _resourcesToBeGottenLock.lockForWrite(); @@ -150,31 +159,37 @@ void ResourceCache::clearUnusedResource() { } } -void ResourceCache::attemptRequest(Resource* resource) { +bool ResourceCache::attemptRequest(Resource* resource) { auto sharedItems = DependencyManager::get(); // Disable request limiting for ATP if (resource->getURL().scheme() != URL_SCHEME_ATP) { - if (_requestLimit <= 0) { + if (_requestsActive >= _requestLimit) { // wait until a slot becomes available sharedItems->_pendingRequests.append(resource); - return; + return false; } - --_requestLimit; - } + ++_requestsActive; + } sharedItems->_loadingRequests.append(resource); resource->makeRequest(); + return true; } void ResourceCache::requestCompleted(Resource* resource) { auto sharedItems = DependencyManager::get(); sharedItems->_loadingRequests.removeOne(resource); if (resource->getURL().scheme() != URL_SCHEME_ATP) { - ++_requestLimit; + --_requestsActive; } - + + attemptHighestPriorityRequest(); +} + +bool ResourceCache::attemptHighestPriorityRequest() { + auto sharedItems = DependencyManager::get(); // look for the highest priority pending request int highestIndex = -1; float highestPriority = -FLT_MAX; @@ -191,13 +206,12 @@ void ResourceCache::requestCompleted(Resource* resource) { } i++; } - if (highestIndex >= 0) { - attemptRequest(sharedItems->_pendingRequests.takeAt(highestIndex)); - } + return (highestIndex >= 0) && attemptRequest(sharedItems->_pendingRequests.takeAt(highestIndex)); } const int DEFAULT_REQUEST_LIMIT = 10; int ResourceCache::_requestLimit = DEFAULT_REQUEST_LIMIT; +int ResourceCache::_requestsActive = 0; Resource::Resource(const QUrl& url, bool delayLoad) : _url(url), diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 6fbf54c49d..a8ab51b7f7 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -67,8 +67,10 @@ class ResourceCache : public QObject { Q_OBJECT public: - static void setRequestLimit(int limit) { _requestLimit = limit; } + static void setRequestLimit(int limit); static int getRequestLimit() { return _requestLimit; } + + static int getRequestsActive() { return _requestsActive; } void setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize); qint64 getUnusedResourceCacheSize() const { return _unusedResourcesMaxSize; } @@ -105,8 +107,11 @@ protected: void reserveUnusedResource(qint64 resourceSize); void clearUnusedResource(); - Q_INVOKABLE static void attemptRequest(Resource* resource); + /// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading + /// \return true if the resource began loading, otherwise false if the resource is in the pending queue + Q_INVOKABLE static bool attemptRequest(Resource* resource); static void requestCompleted(Resource* resource); + static bool attemptHighestPriorityRequest(); private: friend class Resource; @@ -115,6 +120,7 @@ private: int _lastLRUKey = 0; static int _requestLimit; + static int _requestsActive; void getResourceAsynchronously(const QUrl& url); QReadWriteLock _resourcesToBeGottenLock;