diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index aa2b382c58..2dc3645be0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -152,6 +152,8 @@ #include #include #include +#include +#include "recording/ClipCache.h" #include "AudioClient.h" #include "audio/AudioScope.h" @@ -328,9 +330,9 @@ static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains #endif #if !defined(Q_OS_ANDROID) -static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16; +static const uint32_t MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16; #else -static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 4; +static const uint32_t MAX_CONCURRENT_RESOURCE_DOWNLOADS = 4; #endif // For processing on QThreadPool, we target a number of threads after reserving some @@ -1327,7 +1329,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo QString concurrentDownloadsStr = getCmdOption(argc, constArgv, "--concurrent-downloads"); bool success; - int concurrentDownloads = concurrentDownloadsStr.toInt(&success); + uint32_t concurrentDownloads = concurrentDownloadsStr.toUInt(&success); if (!success) { concurrentDownloads = MAX_CONCURRENT_RESOURCE_DOWNLOADS; } @@ -2054,7 +2056,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } properties["active_downloads"] = loadingRequests.size(); - properties["pending_downloads"] = ResourceCache::getPendingRequestCount(); + properties["pending_downloads"] = (int)ResourceCache::getPendingRequestCount(); properties["active_downloads_details"] = loadingRequestsStats; auto statTracker = DependencyManager::get(); @@ -4653,8 +4655,8 @@ void Application::idle() { PROFILE_COUNTER_IF_CHANGED(app, "present", float, displayPlugin->presentRate()); } PROFILE_COUNTER_IF_CHANGED(app, "renderLoopRate", float, _renderLoopCounter.rate()); - PROFILE_COUNTER_IF_CHANGED(app, "currentDownloads", int, ResourceCache::getLoadingRequests().length()); - PROFILE_COUNTER_IF_CHANGED(app, "pendingDownloads", int, ResourceCache::getPendingRequestCount()); + PROFILE_COUNTER_IF_CHANGED(app, "currentDownloads", uint32_t, ResourceCache::getLoadingRequestCount()); + PROFILE_COUNTER_IF_CHANGED(app, "pendingDownloads", uint32_t, ResourceCache::getPendingRequestCount()); PROFILE_COUNTER_IF_CHANGED(app, "currentProcessing", int, DependencyManager::get()->getStat("Processing").toInt()); PROFILE_COUNTER_IF_CHANGED(app, "pendingProcessing", int, DependencyManager::get()->getStat("PendingProcessing").toInt()); auto renderConfig = _renderEngine->getConfiguration(); @@ -5399,13 +5401,21 @@ void Application::reloadResourceCaches() { queryOctree(NodeType::EntityServer, PacketType::EntityQuery); + // Clear the entities and their renderables + getEntities()->clear(); + DependencyManager::get()->clearCache(); DependencyManager::get()->clearCache(); + // Clear all the resource caches + DependencyManager::get()->clear(); DependencyManager::get()->refreshAll(); - DependencyManager::get()->refreshAll(); DependencyManager::get()->refreshAll(); + MaterialCache::instance().refreshAll(); + DependencyManager::get()->refreshAll(); + ShaderCache::instance().refreshAll(); DependencyManager::get()->refreshAll(); + DependencyManager::get()->refreshAll(); DependencyManager::get()->reset(); // Force redownload of .fst models @@ -6470,9 +6480,12 @@ void Application::clearDomainOctreeDetails() { skyStage->setBackgroundMode(graphics::SunSkyStage::SKY_DEFAULT); DependencyManager::get()->clearUnusedResources(); - DependencyManager::get()->clearUnusedResources(); DependencyManager::get()->clearUnusedResources(); + MaterialCache::instance().clearUnusedResources(); + DependencyManager::get()->clearUnusedResources(); + ShaderCache::instance().clearUnusedResources(); DependencyManager::get()->clearUnusedResources(); + DependencyManager::get()->clearUnusedResources(); getMyAvatar()->setAvatarEntityDataChanged(true); } diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 8faa51bc58..495e29f986 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -267,8 +267,8 @@ void Stats::updateStats(bool force) { auto loadingRequests = ResourceCache::getLoadingRequests(); STAT_UPDATE(downloads, loadingRequests.size()); - STAT_UPDATE(downloadLimit, ResourceCache::getRequestLimit()) - STAT_UPDATE(downloadsPending, ResourceCache::getPendingRequestCount()); + STAT_UPDATE(downloadLimit, (int)ResourceCache::getRequestLimit()) + STAT_UPDATE(downloadsPending, (int)ResourceCache::getPendingRequestCount()); STAT_UPDATE(processing, DependencyManager::get()->getStat("Processing").toInt()); STAT_UPDATE(processingPending, DependencyManager::get()->getStat("PendingProcessing").toInt()); diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index f30d5605d7..04b7952ddb 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -32,12 +32,6 @@ AnimationCache::AnimationCache(QObject* parent) : } AnimationPointer AnimationCache::getAnimation(const QUrl& url) { - if (QThread::currentThread() != thread()) { - AnimationPointer result; - BLOCKING_INVOKE_METHOD(this, "getAnimation", - Q_RETURN_ARG(AnimationPointer, result), Q_ARG(const QUrl&, url)); - return result; - } return getResource(url).staticCast(); } diff --git a/libraries/audio/src/SoundCache.cpp b/libraries/audio/src/SoundCache.cpp index 162e833da2..2877de3d6f 100644 --- a/libraries/audio/src/SoundCache.cpp +++ b/libraries/audio/src/SoundCache.cpp @@ -30,12 +30,6 @@ SoundCache::SoundCache(QObject* parent) : } SharedSoundPointer SoundCache::getSound(const QUrl& url) { - if (QThread::currentThread() != thread()) { - SharedSoundPointer result; - BLOCKING_INVOKE_METHOD(this, "getSound", - Q_RETURN_ARG(SharedSoundPointer, result), Q_ARG(const QUrl&, url)); - return result; - } return getResource(url).staticCast(); } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index c914ad91af..3933e3ae56 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -75,8 +75,6 @@ protected: void makeLocalRequest(); Q_INVOKABLE void handleLocalRequestCompleted(); - virtual bool isCacheable() const override { return _loaded; } - Q_INVOKABLE virtual void downloadFinished(const QByteArray& data) override; bool handleFailedRequest(ResourceRequest::Result result) override; diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index aed9f3b0e5..076db44ea6 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -27,28 +27,35 @@ #include "NetworkLogging.h" #include "NodeList.h" - -#define clamp(x, min, max) (((x) < (min)) ? (min) :\ - (((x) > (max)) ? (max) :\ - (x))) - -void ResourceCacheSharedItems::appendActiveRequest(QWeakPointer resource) { +bool ResourceCacheSharedItems::appendRequest(QWeakPointer resource) { Lock lock(_mutex); - _loadingRequests.append(resource); + if ((uint32_t)_loadingRequests.size() < _requestLimit) { + _loadingRequests.append(resource); + return true; + } else { + _pendingRequests.append(resource); + return false; + } } -void ResourceCacheSharedItems::appendPendingRequest(QWeakPointer resource) { +void ResourceCacheSharedItems::setRequestLimit(uint32_t limit) { Lock lock(_mutex); - _pendingRequests.append(resource); + _requestLimit = limit; } -QList> ResourceCacheSharedItems::getPendingRequests() { +uint32_t ResourceCacheSharedItems::getRequestLimit() const { + Lock lock(_mutex); + return _requestLimit; +} + +QList> ResourceCacheSharedItems::getPendingRequests() const { QList> result; Lock lock(_mutex); - foreach(QSharedPointer resource, _pendingRequests) { - if (resource) { - result.append(resource); + foreach (QWeakPointer resource, _pendingRequests) { + auto locked = resource.lock(); + if (locked) { + result.append(locked); } } @@ -60,16 +67,12 @@ uint32_t ResourceCacheSharedItems::getPendingRequestsCount() const { return _pendingRequests.size(); } -QList> ResourceCacheSharedItems::getLoadingRequests() { +QList> ResourceCacheSharedItems::getLoadingRequests() const { QList> result; - Lock lock(_mutex); - - foreach(QSharedPointer resource, _loadingRequests) { - if (resource) { - result.append(resource); - } + { + Lock lock(_mutex); + result = _loadingRequests; } - return result; } @@ -131,6 +134,11 @@ QSharedPointer ResourceCacheSharedItems::getHighestPendingRequest() { return highestResource; } +void ResourceCacheSharedItems::clear() { + Lock lock(_mutex); + _pendingRequests.clear(); + _loadingRequests.clear(); +} ScriptableResourceCache::ScriptableResourceCache(QSharedPointer resourceCache) { _resourceCache = resourceCache; @@ -244,9 +252,7 @@ ResourceCache::ResourceCache(QObject* parent) : QObject(parent) { } } -ResourceCache::~ResourceCache() { - clearUnusedResources(); -} +ResourceCache::~ResourceCache() {} void ResourceCache::clearATPAssets() { { @@ -260,6 +266,7 @@ void ResourceCache::clearATPAssets() { if (auto strongRef = resource.lock()) { // Make sure the resource won't reinsert itself strongRef->setCache(nullptr); + _totalResourcesSize -= strongRef->getBytes(); } } } @@ -269,28 +276,18 @@ void ResourceCache::clearATPAssets() { for (auto& resource : _unusedResources.values()) { if (resource->getURL().scheme() == URL_SCHEME_ATP) { _unusedResources.remove(resource->getLRUKey()); - } - } - } - { - QWriteLocker locker(&_resourcesToBeGottenLock); - auto it = _resourcesToBeGotten.begin(); - while (it != _resourcesToBeGotten.end()) { - if (it->scheme() == URL_SCHEME_ATP) { - it = _resourcesToBeGotten.erase(it); - } else { - ++it; + _unusedResourcesSize -= resource->getBytes(); } } } - + resetResourceCounters(); } void ResourceCache::refreshAll() { // Clear all unused resources so we don't have to reload them clearUnusedResources(); - resetResourceCounters(); + resetUnusedResourceCounter(); QHash> resources; { @@ -306,21 +303,6 @@ void ResourceCache::refreshAll() { } } -void ResourceCache::refresh(const QUrl& url) { - QSharedPointer resource; - { - QReadLocker locker(&_resourcesLock); - resource = _resources.value(url).lock(); - } - - if (resource) { - resource->refresh(); - } else { - removeResource(url); - resetResourceCounters(); - } -} - QVariantList ResourceCache::getResourceList() { QVariantList list; if (QThread::currentThread() != thread()) { @@ -338,12 +320,13 @@ QVariantList ResourceCache::getResourceList() { return list; } -void ResourceCache::setRequestLimit(int limit) { - _requestLimit = limit; +void ResourceCache::setRequestLimit(uint32_t limit) { + auto sharedItems = DependencyManager::get(); + sharedItems->setRequestLimit(limit); // Now go fill any new request spots - while (attemptHighestPriorityRequest()) { - // just keep looping until we reach the new limit or no more pending requests + while (sharedItems->getLoadingRequestsCount() < limit && sharedItems->getPendingRequestsCount() > 0) { + attemptHighestPriorityRequest(); } } @@ -381,9 +364,9 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& } void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) { - _unusedResourcesMaxSize = clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE); + _unusedResourcesMaxSize = glm::clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE); reserveUnusedResource(0); - resetResourceCounters(); + resetUnusedResourceCounter(); } void ResourceCache::addUnusedResource(const QSharedPointer& resource) { @@ -391,18 +374,20 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) if (resource->getBytes() == 0 || resource->getBytes() > _unusedResourcesMaxSize) { resource->setCache(nullptr); removeResource(resource->getURL(), resource->getBytes()); - resetResourceCounters(); + resetTotalResourceCounter(); return; } reserveUnusedResource(resource->getBytes()); resource->setLRUKey(++_lastLRUKey); - _unusedResourcesSize += resource->getBytes(); - resetResourceCounters(); + { + QWriteLocker locker(&_unusedResourcesLock); + _unusedResources.insert(resource->getLRUKey(), resource); + _unusedResourcesSize += resource->getBytes(); + } - QWriteLocker locker(&_unusedResourcesLock); - _unusedResources.insert(resource->getLRUKey(), resource); + resetUnusedResourceCounter(); } void ResourceCache::removeUnusedResource(const QSharedPointer& resource) { @@ -412,7 +397,7 @@ void ResourceCache::removeUnusedResource(const QSharedPointer& resourc _unusedResourcesSize -= resource->getBytes(); locker.unlock(); - resetResourceCounters(); + resetUnusedResourceCounter(); } } @@ -445,14 +430,19 @@ void ResourceCache::clearUnusedResources() { } _unusedResources.clear(); } + _unusedResourcesSize = 0; } -void ResourceCache::resetResourceCounters() { +void ResourceCache::resetTotalResourceCounter() { { QReadLocker locker(&_resourcesLock); _numTotalResources = _resources.size(); } + emit dirty(); +} + +void ResourceCache::resetUnusedResourceCounter() { { QReadLocker locker(&_unusedResourcesLock); _numUnusedResources = _unusedResources.size(); @@ -461,6 +451,13 @@ void ResourceCache::resetResourceCounters() { emit dirty(); } +void ResourceCache::resetResourceCounters() { + resetTotalResourceCounter(); + resetUnusedResourceCounter(); + + emit dirty(); +} + void ResourceCache::removeResource(const QUrl& url, qint64 size) { QWriteLocker locker(&_resourcesLock); _resources.remove(url); @@ -481,38 +478,34 @@ QList> ResourceCache::getLoadingRequests() { return DependencyManager::get()->getLoadingRequests(); } -int ResourceCache::getPendingRequestCount() { +uint32_t ResourceCache::getPendingRequestCount() { return DependencyManager::get()->getPendingRequestsCount(); } -int ResourceCache::getLoadingRequestCount() { +uint32_t ResourceCache::getLoadingRequestCount() { return DependencyManager::get()->getLoadingRequestsCount(); } bool ResourceCache::attemptRequest(QSharedPointer resource) { Q_ASSERT(!resource.isNull()); - auto sharedItems = DependencyManager::get(); - if (_requestsActive >= _requestLimit) { - // wait until a slot becomes available - sharedItems->appendPendingRequest(resource); - return false; + if (sharedItems->appendRequest(resource)) { + resource->makeRequest(); + return true; } - - ++_requestsActive; - sharedItems->appendActiveRequest(resource); - resource->makeRequest(); - return true; + return false; } void ResourceCache::requestCompleted(QWeakPointer resource) { auto sharedItems = DependencyManager::get(); sharedItems->removeRequest(resource); - --_requestsActive; - attemptHighestPriorityRequest(); + // Now go fill any new request spots + while (sharedItems->getLoadingRequestsCount() < sharedItems->getRequestLimit() && sharedItems->getPendingRequestsCount() > 0) { + attemptHighestPriorityRequest(); + } } bool ResourceCache::attemptHighestPriorityRequest() { @@ -521,10 +514,6 @@ bool ResourceCache::attemptHighestPriorityRequest() { return (resource && attemptRequest(resource)); } -const int DEFAULT_REQUEST_LIMIT = 10; -int ResourceCache::_requestLimit = DEFAULT_REQUEST_LIMIT; -int ResourceCache::_requestsActive = 0; - static int requestID = 0; Resource::Resource(const QUrl& url) : @@ -550,7 +539,7 @@ void Resource::ensureLoading() { } void Resource::setLoadPriority(const QPointer& owner, float priority) { - if (!(_failedToLoad)) { + if (!_failedToLoad) { _loadPriorities.insert(owner, priority); } } @@ -566,7 +555,7 @@ void Resource::setLoadPriorities(const QHash, float>& prioriti } void Resource::clearLoadPriority(const QPointer& owner) { - if (!(_failedToLoad)) { + if (!_failedToLoad) { _loadPriorities.remove(owner); } } @@ -592,6 +581,7 @@ void Resource::refresh() { if (_request && !(_loaded || _failedToLoad)) { return; } + if (_request) { _request->disconnect(this); _request->deleteLater(); @@ -613,7 +603,7 @@ void Resource::allReferencesCleared() { if (_cache && isCacheable()) { // create and reinsert new shared pointer - QSharedPointer self(this, &Resource::allReferencesCleared); + QSharedPointer self(this, &Resource::deleter); setSelf(self); reinsert(); @@ -623,7 +613,7 @@ void Resource::allReferencesCleared() { if (_cache) { // remove from the cache _cache->removeResource(getURL(), getBytes()); - _cache->resetResourceCounters(); + _cache->resetTotalResourceCounter(); } deleteLater(); @@ -732,6 +722,7 @@ void Resource::handleReplyFinished() { { "from_cache", false }, { "size_mb", _bytesTotal / 1000000.0 } }); + ResourceCache::requestCompleted(_self); return; } diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 2c0baad3f7..33490301d7 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -66,21 +66,25 @@ class ResourceCacheSharedItems : public Dependency { using Lock = std::unique_lock; public: - void appendPendingRequest(QWeakPointer newRequest); - void appendActiveRequest(QWeakPointer newRequest); + bool appendRequest(QWeakPointer newRequest); void removeRequest(QWeakPointer doneRequest); - QList> getPendingRequests(); - uint32_t getPendingRequestsCount() const; - QList> getLoadingRequests(); + void setRequestLimit(uint32_t limit); + uint32_t getRequestLimit() const; + QList> getPendingRequests() const; QSharedPointer getHighestPendingRequest(); + uint32_t getPendingRequestsCount() const; + QList> getLoadingRequests() const; uint32_t getLoadingRequestsCount() const; + void clear(); private: ResourceCacheSharedItems() = default; mutable Mutex _mutex; QList> _pendingRequests; - QList> _loadingRequests; + QList> _loadingRequests; + const uint32_t DEFAULT_REQUEST_LIMIT = 10; + uint32_t _requestLimit { DEFAULT_REQUEST_LIMIT }; }; /// Wrapper to expose resources to JS/QML @@ -200,25 +204,20 @@ public: Q_INVOKABLE QVariantList getResourceList(); - static void setRequestLimit(int limit); - static int getRequestLimit() { return _requestLimit; } - - static int getRequestsActive() { return _requestsActive; } + static void setRequestLimit(uint32_t limit); + static uint32_t getRequestLimit() { return DependencyManager::get()->getRequestLimit(); } void setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize); qint64 getUnusedResourceCacheSize() const { return _unusedResourcesMaxSize; } static QList> getLoadingRequests(); - - static int getPendingRequestCount(); - - static int getLoadingRequestCount(); + static uint32_t getPendingRequestCount(); + static uint32_t getLoadingRequestCount(); ResourceCache(QObject* parent = nullptr); virtual ~ResourceCache(); void refreshAll(); - void refresh(const QUrl& url); void clearUnusedResources(); signals: @@ -272,11 +271,11 @@ private: friend class ScriptableResourceCache; void reserveUnusedResource(qint64 resourceSize); - void resetResourceCounters(); void removeResource(const QUrl& url, qint64 size = 0); - static int _requestLimit; - static int _requestsActive; + void resetTotalResourceCounter(); + void resetUnusedResourceCounter(); + void resetResourceCounters(); // Resources QHash> _resources; @@ -293,10 +292,6 @@ private: std::atomic _numUnusedResources { 0 }; std::atomic _unusedResourcesSize { 0 }; - - // Pending resources - QQueue _resourcesToBeGotten; - QReadWriteLock _resourcesToBeGottenLock { QReadWriteLock::Recursive }; }; /// Wrapper to expose resource caches to JS/QML @@ -455,7 +450,7 @@ protected: virtual void makeRequest(); /// Checks whether the resource is cacheable. - virtual bool isCacheable() const { return true; } + virtual bool isCacheable() const { return _loaded; } /// Called when the download has finished. /// This should be overridden by subclasses that need to process the data once it is downloaded.