mirror of
https://github.com/overte-org/overte.git
synced 2025-04-14 04:07:11 +02:00
Merge pull request #7549 from zzmp/feat/resource-vis
Add a visualization of cacheable resource usage
This commit is contained in:
commit
891cc12d3f
9 changed files with 220 additions and 57 deletions
21
examples/utilities/cache/cacheStats.js
vendored
Normal file
21
examples/utilities/cache/cacheStats.js
vendored
Normal file
|
@ -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('stats.qml');
|
||||
var window = new OverlayWindow({
|
||||
title: 'Cache Stats',
|
||||
source: qml,
|
||||
width: 300,
|
||||
height: 200
|
||||
});
|
||||
window.setPosition(500, 50);
|
||||
window.closed.connect(function() { Script.stop(); });
|
77
examples/utilities/cache/stats.qml
vendored
Normal file
77
examples/utilities/cache/stats.qml
vendored
Normal file
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// 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: [["Animation", AnimationCache], ["Model", ModelCache], ["Texture", TextureCache], ["Sound", SoundCache]]
|
||||
|
||||
Grid {
|
||||
id: grid
|
||||
rows: root.caches.length; columns: 1; spacing: 8
|
||||
anchors.fill: parent
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
|
||||
model: root.caches
|
||||
|
||||
Row {
|
||||
PlotPerf {
|
||||
title: modelData[0] + " Count"
|
||||
anchors.left: parent
|
||||
height: (grid.height - (grid.spacing * (root.caches.length + 1))) / root.caches.length
|
||||
width: grid.width / 2 - grid.spacing * 1.5
|
||||
object: modelData[1]
|
||||
valueNumDigits: "1"
|
||||
plots: [
|
||||
{
|
||||
prop: "numTotal",
|
||||
label: "total",
|
||||
color: "#00B4EF"
|
||||
},
|
||||
{
|
||||
prop: "numCached",
|
||||
label: "cached",
|
||||
color: "#1AC567"
|
||||
}
|
||||
]
|
||||
}
|
||||
PlotPerf {
|
||||
title: modelData[0] + " Size"
|
||||
anchors.right: parent
|
||||
height: (grid.height - (grid.spacing * (root.caches.length + 1))) / root.caches.length
|
||||
width: grid.width / 2 - grid.spacing * 1.5
|
||||
object: modelData[1]
|
||||
valueScale: 1048576
|
||||
valueUnit: "Mb"
|
||||
valueNumDigits: "1"
|
||||
plots: [
|
||||
{
|
||||
prop: "sizeTotal",
|
||||
label: "total",
|
||||
color: "#00B4EF"
|
||||
},
|
||||
{
|
||||
prop: "sizeCached",
|
||||
label: "cached",
|
||||
color: "#1AC567"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,12 +19,8 @@ Item {
|
|||
// The title of the graph
|
||||
property string title
|
||||
|
||||
// THe object used as the default source object for the prop plots
|
||||
// The object used as the default source object for the prop plots
|
||||
property var object
|
||||
|
||||
// THis is my hack to get a property and assign it to a trigger var in order to get
|
||||
// a signal called whenever the value changed
|
||||
property var trigger
|
||||
|
||||
// Plots is an array of plot descriptor
|
||||
// a default plot descriptor expects the following object:
|
||||
|
@ -55,45 +51,38 @@ Item {
|
|||
property var tick : 0
|
||||
|
||||
function createValues() {
|
||||
print("trigger is: " + JSON.stringify(trigger))
|
||||
if (Array.isArray(plots)) {
|
||||
for (var i =0; i < plots.length; i++) {
|
||||
var plot = plots[i];
|
||||
print(" a pnew Plot:" + JSON.stringify(plot));
|
||||
_values.push( {
|
||||
object: (plot["object"] !== undefined ? plot["object"] : root.object),
|
||||
value: plot["prop"],
|
||||
valueMax: 1,
|
||||
numSamplesConstantMax: 0,
|
||||
valueHistory: new Array(),
|
||||
label: (plot["label"] !== undefined ? plot["label"] : ""),
|
||||
color: (plot["color"] !== undefined ? plot["color"] : "white"),
|
||||
scale: (plot["scale"] !== undefined ? plot["scale"] : 1),
|
||||
unit: (plot["unit"] !== undefined ? plot["unit"] : valueUnit)
|
||||
})
|
||||
}
|
||||
for (var i =0; i < plots.length; i++) {
|
||||
var plot = plots[i];
|
||||
_values.push( {
|
||||
object: (plot["object"] !== undefined ? plot["object"] : root.object),
|
||||
value: plot["prop"],
|
||||
valueMax: 1,
|
||||
numSamplesConstantMax: 0,
|
||||
valueHistory: new Array(),
|
||||
label: (plot["label"] !== undefined ? plot["label"] : ""),
|
||||
color: (plot["color"] !== undefined ? plot["color"] : "white"),
|
||||
scale: (plot["scale"] !== undefined ? plot["scale"] : 1),
|
||||
unit: (plot["unit"] !== undefined ? plot["unit"] : valueUnit)
|
||||
})
|
||||
}
|
||||
print("in creator" + JSON.stringify(_values));
|
||||
|
||||
pullFreshValues();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
createValues();
|
||||
print(JSON.stringify(_values));
|
||||
|
||||
}
|
||||
|
||||
function pullFreshValues() {
|
||||
//print("pullFreshValues");
|
||||
// Wait until values are created to begin pulling
|
||||
if (!_values) { return; }
|
||||
|
||||
var VALUE_HISTORY_SIZE = 100;
|
||||
var UPDATE_CANVAS_RATE = 20;
|
||||
tick++;
|
||||
|
||||
|
||||
var currentValueMax = 0
|
||||
for (var i = 0; i < _values.length; i++) {
|
||||
|
||||
var currentVal = _values[i].object[_values[i].value] * _values[i].scale;
|
||||
var currentVal = (+_values[i].object[_values[i].value]) * _values[i].scale;
|
||||
|
||||
_values[i].valueHistory.push(currentVal)
|
||||
_values[i].numSamplesConstantMax++;
|
||||
|
@ -125,11 +114,13 @@ Item {
|
|||
valueMax = currentValueMax;
|
||||
}
|
||||
|
||||
if (tick % UPDATE_CANVAS_RATE == 0) {
|
||||
mycanvas.requestPaint()
|
||||
}
|
||||
mycanvas.requestPaint()
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 100; running: true; repeat: true
|
||||
onTriggered: pullFreshValues()
|
||||
}
|
||||
onTriggerChanged: pullFreshValues()
|
||||
|
||||
Canvas {
|
||||
id: mycanvas
|
||||
|
@ -165,9 +156,9 @@ Item {
|
|||
ctx.fillStyle = val.color;
|
||||
var bestValue = val.valueHistory[val.valueHistory.length -1];
|
||||
ctx.textAlign = "right";
|
||||
ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1.5);
|
||||
ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1);
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1.5);
|
||||
ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1);
|
||||
}
|
||||
|
||||
function displayTitle(ctx, text, maxVal) {
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "plotperf"
|
||||
import "../lib/plotperf"
|
||||
|
||||
Item {
|
||||
id: statsUI
|
||||
|
@ -32,7 +32,6 @@ Item {
|
|||
title: "Num Buffers"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
trigger: stats.config["bufferCPUCount"]
|
||||
plots: [
|
||||
{
|
||||
prop: "bufferCPUCount",
|
||||
|
@ -50,7 +49,6 @@ Item {
|
|||
title: "gpu::Buffer Memory"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
trigger: stats.config["bufferCPUMemoryUsage"]
|
||||
valueScale: 1048576
|
||||
valueUnit: "Mb"
|
||||
valueNumDigits: "1"
|
||||
|
@ -71,7 +69,6 @@ Item {
|
|||
title: "Num Textures"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
trigger: stats.config["textureCPUCount"]
|
||||
plots: [
|
||||
{
|
||||
prop: "textureCPUCount",
|
||||
|
@ -94,7 +91,6 @@ Item {
|
|||
title: "gpu::Texture Memory"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
trigger: stats.config["textureCPUMemoryUsage"]
|
||||
valueScale: 1048576
|
||||
valueUnit: "Mb"
|
||||
valueNumDigits: "1"
|
||||
|
@ -116,7 +112,6 @@ Item {
|
|||
title: "Triangles"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
trigger: stats.config["frameTriangleCount"]
|
||||
valueScale: 1000
|
||||
valueUnit: "K"
|
||||
plots: [
|
||||
|
@ -138,7 +133,6 @@ Item {
|
|||
title: "Drawcalls"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
trigger: stats.config["frameDrawcallCount"]
|
||||
plots: [
|
||||
{
|
||||
prop: "frameAPIDrawcallCount",
|
||||
|
@ -168,7 +162,6 @@ Item {
|
|||
title: "Items"
|
||||
height: parent.evalEvenHeight()
|
||||
object: parent.drawOpaqueConfig
|
||||
trigger: Render.getConfig("DrawOpaqueDeferred")["numDrawn"]
|
||||
plots: [
|
||||
{
|
||||
object: Render.getConfig("DrawOpaqueDeferred"),
|
||||
|
|
|
@ -561,9 +561,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
// Model background downloads need to happen on the Datagram Processor Thread. The idle loop will
|
||||
// emit checkBackgroundDownloads to cause the ModelCache to check it's queue for requested background
|
||||
// downloads.
|
||||
QSharedPointer<ModelCache> modelCacheP = DependencyManager::get<ModelCache>();
|
||||
ResourceCache* modelCache = modelCacheP.data();
|
||||
connect(this, &Application::checkBackgroundDownloads, modelCache, &ResourceCache::checkAsynchronousGets);
|
||||
auto modelCache = DependencyManager::get<ModelCache>();
|
||||
connect(this, &Application::checkBackgroundDownloads, modelCache.data(), &ModelCache::checkAsynchronousGets);
|
||||
|
||||
// put the audio processing on a separate thread
|
||||
QThread* audioThread = new QThread();
|
||||
|
@ -1329,7 +1328,6 @@ void Application::initializeUi() {
|
|||
// though I can't find it. Hence, "ApplicationInterface"
|
||||
rootContext->setContextProperty("SnapshotUploader", new SnapshotUploader());
|
||||
rootContext->setContextProperty("ApplicationInterface", this);
|
||||
rootContext->setContextProperty("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||
rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance());
|
||||
rootContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
|
||||
rootContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
|
||||
|
@ -1359,8 +1357,13 @@ void Application::initializeUi() {
|
|||
rootContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
|
||||
rootContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
|
||||
rootContext->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance());
|
||||
|
||||
// Caches
|
||||
rootContext->setContextProperty("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||
rootContext->setContextProperty("TextureCache", DependencyManager::get<TextureCache>().data());
|
||||
rootContext->setContextProperty("ModelCache", DependencyManager::get<ModelCache>().data());
|
||||
rootContext->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
|
||||
rootContext->setContextProperty("Account", AccountScriptingInterface::getInstance());
|
||||
rootContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface);
|
||||
rootContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
||||
|
@ -4353,8 +4356,13 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGlobalObject("Stats", Stats::getInstance());
|
||||
scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance());
|
||||
|
||||
// Caches
|
||||
scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||
scriptEngine->registerGlobalObject("TextureCache", DependencyManager::get<TextureCache>().data());
|
||||
scriptEngine->registerGlobalObject("ModelCache", DependencyManager::get<ModelCache>().data());
|
||||
scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("DialogsManager", _dialogsManagerScriptingInterface);
|
||||
|
||||
|
|
|
@ -360,7 +360,7 @@ void NetworkTexture::setImage(void* voidTexture, int originalWidth,
|
|||
if (gpuTexture) {
|
||||
_width = gpuTexture->getWidth();
|
||||
_height = gpuTexture->getHeight();
|
||||
setBytes(gpuTexture->getStoredSize());
|
||||
setSize(gpuTexture->getStoredSize());
|
||||
} else {
|
||||
// FIXME: If !gpuTexture, we failed to load!
|
||||
_width = _height = 0;
|
||||
|
|
|
@ -38,6 +38,7 @@ ResourceCache::~ResourceCache() {
|
|||
void ResourceCache::refreshAll() {
|
||||
// Clear all unused resources so we don't have to reload them
|
||||
clearUnusedResource();
|
||||
resetResourceCounters();
|
||||
|
||||
// Refresh all remaining resources in use
|
||||
foreach (auto resource, _resources) {
|
||||
|
@ -53,9 +54,27 @@ void ResourceCache::refresh(const QUrl& url) {
|
|||
resource->refresh();
|
||||
} else {
|
||||
_resources.remove(url);
|
||||
resetResourceCounters();
|
||||
}
|
||||
}
|
||||
|
||||
QVariantList ResourceCache::getResourceList() {
|
||||
QVariantList list;
|
||||
if (QThread::currentThread() != thread()) {
|
||||
// NOTE: invokeMethod does not allow a const QObject*
|
||||
QMetaObject::invokeMethod(this, "getResourceList", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QVariantList, list));
|
||||
} else {
|
||||
auto resources = _resources.uniqueKeys();
|
||||
list.reserve(resources.size());
|
||||
for (auto& resource : resources) {
|
||||
list << resource;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void ResourceCache::setRequestLimit(int limit) {
|
||||
_requestLimit = limit;
|
||||
|
||||
|
@ -114,6 +133,7 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
|
|||
void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) {
|
||||
_unusedResourcesMaxSize = clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE);
|
||||
reserveUnusedResource(0);
|
||||
resetResourceCounters();
|
||||
}
|
||||
|
||||
void ResourceCache::addUnusedResource(const QSharedPointer<Resource>& resource) {
|
||||
|
@ -127,6 +147,8 @@ void ResourceCache::addUnusedResource(const QSharedPointer<Resource>& resource)
|
|||
resource->setLRUKey(++_lastLRUKey);
|
||||
_unusedResources.insert(resource->getLRUKey(), resource);
|
||||
_unusedResourcesSize += resource->getBytes();
|
||||
|
||||
resetResourceCounters();
|
||||
}
|
||||
|
||||
void ResourceCache::removeUnusedResource(const QSharedPointer<Resource>& resource) {
|
||||
|
@ -134,6 +156,7 @@ void ResourceCache::removeUnusedResource(const QSharedPointer<Resource>& resourc
|
|||
_unusedResources.remove(resource->getLRUKey());
|
||||
_unusedResourcesSize -= resource->getBytes();
|
||||
}
|
||||
resetResourceCounters();
|
||||
}
|
||||
|
||||
void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
|
||||
|
@ -142,8 +165,13 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
|
|||
// unload the oldest resource
|
||||
QMap<int, QSharedPointer<Resource> >::iterator it = _unusedResources.begin();
|
||||
|
||||
_unusedResourcesSize -= it.value()->getBytes();
|
||||
it.value()->setCache(nullptr);
|
||||
auto size = it.value()->getBytes();
|
||||
|
||||
_totalResourcesSize -= size;
|
||||
_resources.remove(it.value()->getURL());
|
||||
|
||||
_unusedResourcesSize -= size;
|
||||
_unusedResources.erase(it);
|
||||
}
|
||||
}
|
||||
|
@ -159,6 +187,17 @@ void ResourceCache::clearUnusedResource() {
|
|||
}
|
||||
}
|
||||
|
||||
void ResourceCache::resetResourceCounters() {
|
||||
_numTotalResources = _resources.size();
|
||||
_numUnusedResources = _unusedResources.size();
|
||||
emit dirty();
|
||||
}
|
||||
|
||||
void ResourceCache::updateTotalSize(const qint64& oldSize, const qint64& newSize) {
|
||||
_totalResourcesSize += (newSize - oldSize);
|
||||
emit dirty();
|
||||
}
|
||||
|
||||
void ResourceCacheSharedItems::appendActiveRequest(Resource* resource) {
|
||||
Lock lock(_mutex);
|
||||
_loadingRequests.append(resource);
|
||||
|
@ -377,6 +416,11 @@ void Resource::finishedLoading(bool success) {
|
|||
emit finished(success);
|
||||
}
|
||||
|
||||
void Resource::setSize(const qint64& bytes) {
|
||||
QMetaObject::invokeMethod(_cache.data(), "updateTotalSize", Q_ARG(qint64, _bytes), Q_ARG(qint64, bytes));
|
||||
_bytes = bytes;
|
||||
}
|
||||
|
||||
void Resource::reinsert() {
|
||||
_cache->_resources.insert(_url, _self);
|
||||
}
|
||||
|
@ -412,7 +456,7 @@ void Resource::handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTota
|
|||
void Resource::handleReplyFinished() {
|
||||
Q_ASSERT_X(_request, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished");
|
||||
|
||||
_bytes = _bytesTotal;
|
||||
setSize(_bytesTotal);
|
||||
|
||||
if (!_request || _request != sender()) {
|
||||
// This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted.
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
#ifndef hifi_ResourceCache_h
|
||||
#define hifi_ResourceCache_h
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QObject>
|
||||
|
@ -29,6 +31,8 @@
|
|||
|
||||
#include "ResourceManager.h"
|
||||
|
||||
Q_DECLARE_METATYPE(size_t)
|
||||
|
||||
class QNetworkReply;
|
||||
class QTimer;
|
||||
|
||||
|
@ -79,8 +83,20 @@ private:
|
|||
/// Base class for resource caches.
|
||||
class ResourceCache : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(size_t numTotal READ getNumTotalResources NOTIFY dirty)
|
||||
Q_PROPERTY(size_t numCached READ getNumCachedResources NOTIFY dirty)
|
||||
Q_PROPERTY(size_t sizeTotal READ getSizeTotalResources NOTIFY dirty)
|
||||
Q_PROPERTY(size_t sizeCached READ getSizeCachedResources NOTIFY dirty)
|
||||
|
||||
public:
|
||||
size_t getNumTotalResources() const { return _numTotalResources; }
|
||||
size_t getSizeTotalResources() const { return _totalResourcesSize; }
|
||||
|
||||
size_t getNumCachedResources() const { return _numUnusedResources; }
|
||||
size_t getSizeCachedResources() const { return _unusedResourcesSize; }
|
||||
|
||||
Q_INVOKABLE QVariantList getResourceList();
|
||||
|
||||
static void setRequestLimit(int limit);
|
||||
static int getRequestLimit() { return _requestLimit; }
|
||||
|
||||
|
@ -101,15 +117,21 @@ public:
|
|||
void refreshAll();
|
||||
void refresh(const QUrl& url);
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
|
||||
public slots:
|
||||
void checkAsynchronousGets();
|
||||
|
||||
protected slots:
|
||||
void updateTotalSize(const qint64& oldSize, const qint64& newSize);
|
||||
|
||||
protected:
|
||||
/// Loads a resource from the specified URL.
|
||||
/// \param fallback a fallback URL to load if the desired one is unavailable
|
||||
/// \param delayLoad if true, don't load the resource immediately; wait until load is first requested
|
||||
/// \param extra extra data to pass to the creator, if appropriate
|
||||
Q_INVOKABLE QSharedPointer<Resource> getResource(const QUrl& url, const QUrl& fallback = QUrl(),
|
||||
QSharedPointer<Resource> getResource(const QUrl& url, const QUrl& fallback = QUrl(),
|
||||
bool delayLoad = false, void* extra = NULL);
|
||||
|
||||
/// Creates a new resource.
|
||||
|
@ -118,18 +140,20 @@ protected:
|
|||
|
||||
void addUnusedResource(const QSharedPointer<Resource>& resource);
|
||||
void removeUnusedResource(const QSharedPointer<Resource>& resource);
|
||||
void reserveUnusedResource(qint64 resourceSize);
|
||||
void clearUnusedResource();
|
||||
|
||||
/// 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 bool attemptRequest(Resource* resource);
|
||||
static void requestCompleted(Resource* resource);
|
||||
static bool attemptHighestPriorityRequest();
|
||||
|
||||
private:
|
||||
friend class Resource;
|
||||
|
||||
void reserveUnusedResource(qint64 resourceSize);
|
||||
void clearUnusedResource();
|
||||
void resetResourceCounters();
|
||||
|
||||
QHash<QUrl, QWeakPointer<Resource>> _resources;
|
||||
int _lastLRUKey = 0;
|
||||
|
||||
|
@ -140,8 +164,13 @@ private:
|
|||
QReadWriteLock _resourcesToBeGottenLock;
|
||||
QQueue<QUrl> _resourcesToBeGotten;
|
||||
|
||||
std::atomic<size_t> _numTotalResources { 0 };
|
||||
std::atomic<size_t> _numUnusedResources { 0 };
|
||||
|
||||
std::atomic<qint64> _totalResourcesSize { 0 };
|
||||
std::atomic<qint64> _unusedResourcesSize { 0 };
|
||||
|
||||
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
|
||||
qint64 _unusedResourcesSize = 0;
|
||||
QMap<int, QSharedPointer<Resource>> _unusedResources;
|
||||
};
|
||||
|
||||
|
@ -226,7 +255,7 @@ protected:
|
|||
virtual void downloadFinished(const QByteArray& data) { finishedLoading(true); }
|
||||
|
||||
/// Called when the download is finished and processed, sets the number of actual bytes.
|
||||
void setBytes(qint64 bytes) { _bytes = bytes; }
|
||||
void setSize(const qint64& bytes);
|
||||
|
||||
/// Called when the download is finished and processed.
|
||||
/// This should be called by subclasses that override downloadFinished to mark the end of processing.
|
||||
|
|
Loading…
Reference in a new issue