mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-07 06:02:28 +02:00
model loading priority updates over time, takes into account out of bounds, avatar entities have higher priority, and fsts can specify to wait for wearables to load before rendering
This commit is contained in:
parent
93c1ed6446
commit
fe61d92a09
21 changed files with 156 additions and 95 deletions
|
@ -304,16 +304,16 @@ Item {
|
|||
}
|
||||
ListView {
|
||||
width: geoCol.width
|
||||
height: root.downloadUrls.length * 15
|
||||
height: root.downloadUrls.length * 30
|
||||
|
||||
visible: root.expanded && root.downloadUrls.length > 0;
|
||||
|
||||
model: root.downloadUrls
|
||||
delegate: StatText {
|
||||
visible: root.expanded;
|
||||
text: modelData.length > 30
|
||||
text: (modelData.length > 30
|
||||
? modelData.substring(0, 5) + "..." + modelData.substring(modelData.length - 22)
|
||||
: modelData
|
||||
: modelData) + "\n\t" + "Priority: " + root.downloadPriorities[index] + ", Progress: " + root.downloadProgresses[index] + "%"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2277,12 +2277,12 @@ void Application::initialize(const QCommandLineParser &parser) {
|
|||
auto loadingRequests = ResourceCache::getLoadingRequests();
|
||||
|
||||
QJsonArray loadingRequestsStats;
|
||||
for (const auto& request : loadingRequests) {
|
||||
for (const auto& requestPair : loadingRequests) {
|
||||
QJsonObject requestStats;
|
||||
requestStats["filename"] = request->getURL().fileName();
|
||||
requestStats["received"] = request->getBytesReceived();
|
||||
requestStats["total"] = request->getBytesTotal();
|
||||
requestStats["attempts"] = (int)request->getDownloadAttempts();
|
||||
requestStats["filename"] = requestPair.first->getURL().fileName();
|
||||
requestStats["received"] = requestPair.first->getBytesReceived();
|
||||
requestStats["total"] = requestPair.first->getBytesTotal();
|
||||
requestStats["attempts"] = (int)requestPair.first->getDownloadAttempts();
|
||||
loadingRequestsStats.append(requestStats);
|
||||
}
|
||||
|
||||
|
@ -5731,15 +5731,30 @@ void Application::init() {
|
|||
|
||||
getEntities()->init();
|
||||
getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) {
|
||||
auto dims = item.getScaledDimensions();
|
||||
auto maxSize = glm::compMax(dims);
|
||||
if (item.getEntityHostType() == entity::HostType::AVATAR) {
|
||||
return item.isMyAvatarEntity() ? Avatar::MYAVATAR_ENTITY_LOADING_PRIORITY : Avatar::OTHERAVATAR_ENTITY_LOADING_PRIORITY;
|
||||
}
|
||||
|
||||
const float maxSize = glm::compMax(item.getScaledDimensions());
|
||||
if (maxSize <= 0.0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
auto distance = glm::distance(getMyAvatar()->getWorldPosition(), item.getWorldPosition());
|
||||
return atan2(maxSize, distance);
|
||||
const glm::vec3 itemPosition = item.getWorldPosition();
|
||||
const float distance = glm::distance(getMyAvatar()->getWorldPosition(), itemPosition);
|
||||
float result = atan2(maxSize, distance);
|
||||
|
||||
bool isInView = true;
|
||||
{
|
||||
QMutexLocker viewLocker(&_viewMutex);
|
||||
isInView = _viewFrustum.sphereIntersectsKeyhole(itemPosition, maxSize);
|
||||
}
|
||||
if (!isInView) {
|
||||
const float OUT_OF_VIEW_PENALTY = -M_PI_2;
|
||||
result += OUT_OF_VIEW_PENALTY;
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
ObjectMotionState::setShapeManager(&_shapeManager);
|
||||
|
|
|
@ -259,7 +259,7 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
_headData = new MyHead(this);
|
||||
|
||||
_skeletonModel = std::make_shared<MySkeletonModel>(this, nullptr);
|
||||
_skeletonModel->setLoadingPriority(MYAVATAR_LOADING_PRIORITY);
|
||||
_skeletonModel->setLoadingPriorityOperator([]() { return MYAVATAR_LOADING_PRIORITY; });
|
||||
connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished);
|
||||
connect(_skeletonModel.get(), &Model::setURLFinished, this, [this](bool success) {
|
||||
if (success) {
|
||||
|
|
|
@ -44,7 +44,7 @@ OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) {
|
|||
// give the pointer to our head to inherited _headData variable from AvatarData
|
||||
_headData = new Head(this);
|
||||
_skeletonModel = std::make_shared<SkeletonModel>(this, nullptr);
|
||||
_skeletonModel->setLoadingPriority(OTHERAVATAR_LOADING_PRIORITY);
|
||||
_skeletonModel->setLoadingPriorityOperator([]() { return OTHERAVATAR_LOADING_PRIORITY; });
|
||||
connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished);
|
||||
connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady);
|
||||
connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset);
|
||||
|
|
|
@ -159,8 +159,8 @@ bool DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoRe
|
|||
|
||||
DownloadInfoResult AccountServicesScriptingInterface::getDownloadInfo() {
|
||||
DownloadInfoResult result;
|
||||
foreach(const auto& resource, ResourceCache::getLoadingRequests()) {
|
||||
result.downloading.append(resource->getProgress() * 100.0f);
|
||||
foreach(const auto& resourcePair, ResourceCache::getLoadingRequests()) {
|
||||
result.downloading.append(resourcePair.first->getProgress() * 100.0f);
|
||||
}
|
||||
result.pending = ResourceCache::getPendingRequestCount();
|
||||
return result;
|
||||
|
|
|
@ -289,8 +289,8 @@ void Stats::updateStats(bool force) {
|
|||
|
||||
STAT_UPDATE(entityPacketsInKbps, octreeServerCount ? totalEntityKbps / octreeServerCount : -1);
|
||||
|
||||
auto loadingRequests = ResourceCache::getLoadingRequests();
|
||||
STAT_UPDATE(downloads, loadingRequests.size());
|
||||
auto loadingRequestPairs = ResourceCache::getLoadingRequests();
|
||||
STAT_UPDATE(downloads, loadingRequestPairs.size());
|
||||
STAT_UPDATE(downloadLimit, (int)ResourceCache::getRequestLimit())
|
||||
STAT_UPDATE(downloadsPending, (int)ResourceCache::getPendingRequestCount());
|
||||
STAT_UPDATE(processing, DependencyManager::get<StatTracker>()->getStat("Processing").toInt());
|
||||
|
@ -298,29 +298,37 @@ void Stats::updateStats(bool force) {
|
|||
|
||||
// See if the active download urls have changed
|
||||
bool shouldUpdateUrls = _downloads != _downloadUrls.size();
|
||||
bool shouldUpdateProgresses = false;
|
||||
if (!shouldUpdateUrls) {
|
||||
for (int i = 0; i < _downloads; i++) {
|
||||
if (loadingRequests[i]->getURL().toString() != _downloadUrls[i]) {
|
||||
if (loadingRequestPairs[i].first->getURL().toString() != _downloadUrls[i]) {
|
||||
shouldUpdateUrls = true;
|
||||
break;
|
||||
} else if (loadingRequestPairs[i].first->getProgress() != _downloadProgresses[i]) {
|
||||
shouldUpdateProgresses = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the urls have changed, update the list
|
||||
if (shouldUpdateUrls) {
|
||||
_downloadUrls.clear();
|
||||
foreach (const auto& resource, loadingRequests) {
|
||||
_downloadUrls << resource->getURL().toString();
|
||||
_downloadPriorities.clear();
|
||||
foreach (const auto& resourcePair, loadingRequestPairs) {
|
||||
_downloadUrls << resourcePair.first->getURL().toString();
|
||||
_downloadPriorities << resourcePair.second;
|
||||
}
|
||||
emit downloadUrlsChanged();
|
||||
emit downloadPrioritiesChanged();
|
||||
shouldUpdateProgresses = true;
|
||||
}
|
||||
|
||||
if (shouldUpdateProgresses) {
|
||||
_downloadProgresses.clear();
|
||||
foreach (const auto& resourcePair, loadingRequestPairs) {
|
||||
_downloadProgresses << (int)(100.0f * resourcePair.first->getProgress());
|
||||
}
|
||||
emit downloadProgressesChanged();
|
||||
}
|
||||
// TODO fix to match original behavior
|
||||
//stringstream downloads;
|
||||
//downloads << "Downloads: ";
|
||||
//foreach(Resource* resource, ) {
|
||||
// downloads << (int)(resource->getProgress() * 100.0f) << "% ";
|
||||
//}
|
||||
//downloads << "(" << << " pending)";
|
||||
}
|
||||
|
||||
// Fourth column, octree stats
|
||||
|
|
|
@ -211,7 +211,10 @@ private: \
|
|||
* <em>Read-only.</em>
|
||||
* @property {string[]} downloadUrls - The download URLs.
|
||||
* <em>Read-only.</em>
|
||||
* <p><strong>Note:</strong> Property not available in the API.</p>
|
||||
* @property {number[]} downloadProgresses - The download progresses.
|
||||
* <em>Read-only.</em>
|
||||
* @property {number[]} downloadPriorities - The download priorities.
|
||||
* <em>Read-only.</em>
|
||||
* @property {number} processing - The number of completed downloads being processed.
|
||||
* <em>Read-only.</em>
|
||||
* @property {number} processingPending - The number of completed downloads waiting to be processed.
|
||||
|
@ -529,6 +532,8 @@ class Stats : public QQuickItem {
|
|||
STATS_PROPERTY(int, downloadLimit, 0)
|
||||
STATS_PROPERTY(int, downloadsPending, 0)
|
||||
Q_PROPERTY(QStringList downloadUrls READ downloadUrls NOTIFY downloadUrlsChanged)
|
||||
Q_PROPERTY(QList<int> downloadProgresses READ downloadProgresses NOTIFY downloadProgressesChanged)
|
||||
Q_PROPERTY(QList<float> downloadPriorities READ downloadPriorities NOTIFY downloadPrioritiesChanged)
|
||||
STATS_PROPERTY(int, processing, 0)
|
||||
STATS_PROPERTY(int, processingPending, 0)
|
||||
STATS_PROPERTY(int, triangles, 0)
|
||||
|
@ -622,7 +627,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
QStringList downloadUrls () { return _downloadUrls; }
|
||||
QStringList downloadUrls() { return _downloadUrls; }
|
||||
QList<int> downloadProgresses() { return _downloadProgresses; }
|
||||
QList<float> downloadPriorities() { return _downloadPriorities; }
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -1091,6 +1098,20 @@ signals:
|
|||
*/
|
||||
void downloadUrlsChanged();
|
||||
|
||||
/*@jsdoc
|
||||
* Triggered when the value of the <code>downloadProgresses</code> property changes.
|
||||
* @function Stats.downloadProgressesChanged
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void downloadProgressesChanged();
|
||||
|
||||
/*@jsdoc
|
||||
* Triggered when the value of the <code>downloadPriorities</code> property changes.
|
||||
* @function Stats.downloadPrioritiesChanged
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void downloadPrioritiesChanged();
|
||||
|
||||
/*@jsdoc
|
||||
* Triggered when the value of the <code>processing</code> property changes.
|
||||
* @function Stats.processingChanged
|
||||
|
@ -1809,14 +1830,16 @@ signals:
|
|||
*/
|
||||
|
||||
private:
|
||||
int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process
|
||||
bool _resetRecentMaxPacketsSoon{ true };
|
||||
bool _expanded{ false };
|
||||
bool _showTimingDetails{ false };
|
||||
bool _showGameUpdateStats{ false };
|
||||
int _recentMaxPackets { 0 } ; // recent max incoming voxel packets to process
|
||||
bool _resetRecentMaxPacketsSoon { true };
|
||||
bool _expanded { false };
|
||||
bool _showTimingDetails { false };
|
||||
bool _showGameUpdateStats { false };
|
||||
QString _monospaceFont;
|
||||
const AudioIOStats* _audioStats;
|
||||
QStringList _downloadUrls = QStringList();
|
||||
QStringList _downloadUrls { QStringList() };
|
||||
QList<int> _downloadProgresses { QList<int>() };
|
||||
QList<float> _downloadPriorities { QList<float>() };
|
||||
};
|
||||
|
||||
#endif // hifi_Stats_h
|
||||
|
|
|
@ -1085,7 +1085,7 @@ AnimNodeLoader::AnimNodeLoader(const QUrl& url) :
|
|||
{
|
||||
_resource = QSharedPointer<Resource>::create(url);
|
||||
_resource->setSelf(_resource);
|
||||
_resource->setLoadPriority(this, ANIM_GRAPH_LOAD_PRIORITY);
|
||||
_resource->setLoadPriorityOperator(this, []() { return ANIM_GRAPH_LOAD_PRIORITY; });
|
||||
connect(_resource.data(), &Resource::loaded, this, &AnimNodeLoader::onRequestDone);
|
||||
connect(_resource.data(), &Resource::failed, this, &AnimNodeLoader::onRequestError);
|
||||
_resource->ensureLoading();
|
||||
|
|
|
@ -35,7 +35,7 @@ SharedSoundPointer SoundCache::getSound(const QUrl& url) {
|
|||
|
||||
QSharedPointer<Resource> SoundCache::createResource(const QUrl& url) {
|
||||
auto resource = QSharedPointer<Sound>(new Sound(url), &Resource::deleter);
|
||||
resource->setLoadPriority(this, SOUNDS_LOADING_PRIORITY);
|
||||
resource->setLoadPriorityOperator(this, []() { return SOUNDS_LOADING_PRIORITY; });
|
||||
return resource;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,8 @@ const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f;
|
|||
const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
|
||||
const float Avatar::MYAVATAR_LOADING_PRIORITY = (float)M_PI; // Entity priority is computed as atan2(maxDim, distance) which is <= PI / 2
|
||||
const float Avatar::OTHERAVATAR_LOADING_PRIORITY = MYAVATAR_LOADING_PRIORITY - EPSILON;
|
||||
const float Avatar::MYAVATAR_ENTITY_LOADING_PRIORITY = MYAVATAR_LOADING_PRIORITY - EPSILON;
|
||||
const float Avatar::OTHERAVATAR_ENTITY_LOADING_PRIORITY = OTHERAVATAR_LOADING_PRIORITY - EPSILON;
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
|
||||
|
@ -841,8 +843,23 @@ bool Avatar::getEnableMeshVisible() const {
|
|||
}
|
||||
|
||||
void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
|
||||
bool canTryFade{ false };
|
||||
if (_needsWearablesLoadedCheck) {
|
||||
bool wearablesAreLoaded = true;
|
||||
// Technically, we should be checking for descendant avatar entities that are owned by this avatar.
|
||||
// But it's sufficient to just check all children entities here.
|
||||
forEachChild([&](SpatiallyNestablePointer child) {
|
||||
if (child->getNestableType() == NestableType::Entity) {
|
||||
auto entity = std::dynamic_pointer_cast<EntityItem>(child);
|
||||
if (entity && !entity->isVisuallyReady()) {
|
||||
wearablesAreLoaded = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
setEnableMeshVisible(_isMeshVisible || wearablesAreLoaded);
|
||||
_needsWearablesLoadedCheck = !wearablesAreLoaded;
|
||||
}
|
||||
|
||||
bool canTryFade = false;
|
||||
// check to see if when we added our models to the scene they were ready, if they were not ready, then
|
||||
// fix them up in the scene
|
||||
render::Transaction transaction;
|
||||
|
@ -1484,6 +1501,12 @@ void Avatar::rigReady() {
|
|||
buildSpine2SplineRatioCache();
|
||||
setSkeletonData(getSkeletonDefaultData());
|
||||
sendSkeletonData();
|
||||
|
||||
const bool prevNeedsWearablesLoadedCheck = _needsWearablesLoadedCheck;
|
||||
_needsWearablesLoadedCheck = _skeletonModel && _skeletonModel->isLoaded() && _skeletonModel->getGeometry()->shouldWaitForWearables();
|
||||
if (prevNeedsWearablesLoadedCheck != _needsWearablesLoadedCheck) {
|
||||
setEnableMeshVisible(!_needsWearablesLoadedCheck);
|
||||
}
|
||||
}
|
||||
|
||||
// rig has been reset.
|
||||
|
|
|
@ -554,6 +554,9 @@ public:
|
|||
|
||||
uint32_t appendSubMetaItems(render::ItemIDs& subItems);
|
||||
|
||||
static const float MYAVATAR_ENTITY_LOADING_PRIORITY;
|
||||
static const float OTHERAVATAR_ENTITY_LOADING_PRIORITY;
|
||||
|
||||
signals:
|
||||
/*@jsdoc
|
||||
* Triggered when the avatar's target scale is changed. The target scale is the desired scale of the avatar without any
|
||||
|
@ -742,8 +745,9 @@ protected:
|
|||
void processMaterials();
|
||||
|
||||
AABox _renderBound;
|
||||
bool _isMeshVisible{ true };
|
||||
bool _needMeshVisibleSwitch{ true };
|
||||
bool _isMeshVisible { true };
|
||||
bool _needMeshVisibleSwitch { true };
|
||||
bool _needsWearablesLoadedCheck { false };
|
||||
|
||||
static const float MYAVATAR_LOADING_PRIORITY;
|
||||
static const float OTHERAVATAR_LOADING_PRIORITY;
|
||||
|
|
|
@ -1310,6 +1310,7 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
|||
scene->enqueueTransaction(transaction);
|
||||
});
|
||||
entity->setModel(model);
|
||||
model->setLoadingPriorityOperator([entity]() { return EntityTreeRenderer::getEntityLoadingPriority(*entity); });
|
||||
withWriteLock([&] { _model = model; });
|
||||
}
|
||||
|
||||
|
@ -1317,7 +1318,6 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
|||
if (_parsedModelURL != model->getURL()) {
|
||||
_texturesLoaded = false;
|
||||
_jointMappingCompleted = false;
|
||||
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
|
||||
model->setURL(_parsedModelURL);
|
||||
}
|
||||
|
||||
|
|
|
@ -448,9 +448,9 @@ void NetworkTexture::setExtra(void* extra) {
|
|||
_shouldFailOnRedirect = _currentlyLoadingResourceType != ResourceType::KTX;
|
||||
|
||||
if (_type == image::TextureUsage::SKY_TEXTURE) {
|
||||
setLoadPriority(this, SKYBOX_LOAD_PRIORITY);
|
||||
setLoadPriorityOperator(this, []() { return SKYBOX_LOAD_PRIORITY; });
|
||||
} else if (_currentlyLoadingResourceType == ResourceType::KTX) {
|
||||
setLoadPriority(this, HIGH_MIPS_LOAD_PRIORITY);
|
||||
setLoadPriorityOperator(this, []() { return HIGH_MIPS_LOAD_PRIORITY; });
|
||||
}
|
||||
|
||||
if (!_url.isValid()) {
|
||||
|
@ -704,7 +704,7 @@ void NetworkTexture::startRequestForNextMipLevel() {
|
|||
|
||||
init(false);
|
||||
float priority = -(float)_originalKtxDescriptor->header.numberOfMipmapLevels + (float)_lowestKnownPopulatedMip;
|
||||
setLoadPriority(this, priority);
|
||||
setLoadPriorityOperator(this, [priority]() { return priority; });
|
||||
_url.setFragment(QString::number(_lowestKnownPopulatedMip - 1));
|
||||
TextureCache::attemptRequest(self);
|
||||
}
|
||||
|
|
|
@ -252,7 +252,6 @@ void GeometryResource::downloadFinished(const QByteArray& data) {
|
|||
}
|
||||
|
||||
auto animGraphVariant = _mapping.value("animGraphUrl");
|
||||
|
||||
if (animGraphVariant.isValid()) {
|
||||
QUrl fstUrl(animGraphVariant.toString());
|
||||
if (fstUrl.isValid()) {
|
||||
|
@ -264,6 +263,8 @@ void GeometryResource::downloadFinished(const QByteArray& data) {
|
|||
_animGraphOverrideUrl = QUrl();
|
||||
}
|
||||
|
||||
_waitForWearables = _mapping.value(WAIT_FOR_WEARABLES_FIELD).toBool();
|
||||
|
||||
auto modelCache = DependencyManager::get<ModelCache>();
|
||||
GeometryExtra extra { GeometryMappingPair(base, _mapping), _textureBaseURL, false };
|
||||
|
||||
|
@ -452,6 +453,7 @@ Geometry::Geometry(const Geometry& geometry) {
|
|||
}
|
||||
|
||||
_animGraphOverrideUrl = geometry._animGraphOverrideUrl;
|
||||
_waitForWearables = geometry._waitForWearables;
|
||||
_mapping = geometry._mapping;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
|
||||
virtual bool areTexturesLoaded() const;
|
||||
const QUrl& getAnimGraphOverrideUrl() const { return _animGraphOverrideUrl; }
|
||||
bool shouldWaitForWearables() const { return _waitForWearables; }
|
||||
const QVariantHash& getMapping() const { return _mapping; }
|
||||
|
||||
protected:
|
||||
|
@ -72,6 +73,7 @@ protected:
|
|||
|
||||
QUrl _animGraphOverrideUrl;
|
||||
QVariantHash _mapping; // parsed contents of FST file.
|
||||
bool _waitForWearables { false };
|
||||
|
||||
private:
|
||||
mutable bool _areTexturesLoaded { false };
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <SharedUtil.h>
|
||||
|
||||
|
||||
const QStringList SINGLE_VALUE_PROPERTIES{"name", "filename", "texdir", "script", "comment"};
|
||||
const QStringList SINGLE_VALUE_PROPERTIES { NAME_FIELD, FILENAME_FIELD, TEXDIR_FIELD, SCRIPT_FIELD, WAIT_FOR_WEARABLES_FIELD, COMMENT_FIELD };
|
||||
|
||||
hifi::VariantMultiHash FSTReader::parseMapping(QIODevice* device) {
|
||||
hifi::VariantMultiHash properties;
|
||||
|
|
|
@ -33,6 +33,7 @@ static const QString BLENDSHAPE_FIELD = "bs";
|
|||
static const QString SCRIPT_FIELD = "script";
|
||||
static const QString JOINT_NAME_MAPPING_FIELD = "jointMap";
|
||||
static const QString MATERIAL_MAPPING_FIELD = "materialMap";
|
||||
static const QString WAIT_FOR_WEARABLES_FIELD = "waitForWearables";
|
||||
static const QString COMMENT_FIELD = "comment";
|
||||
|
||||
class FSTReader {
|
||||
|
|
|
@ -33,7 +33,12 @@
|
|||
bool ResourceCacheSharedItems::appendRequest(QWeakPointer<Resource> resource) {
|
||||
Lock lock(_mutex);
|
||||
if ((uint32_t)_loadingRequests.size() < _requestLimit) {
|
||||
_loadingRequests.append(resource);
|
||||
float priority = 0.0f;
|
||||
// This should always be true, but just in case
|
||||
if (QSharedPointer<Resource> resourceStrong = resource.lock()) {
|
||||
priority = resourceStrong->getLoadPriority();
|
||||
}
|
||||
_loadingRequests.append({ resource, priority });
|
||||
return true;
|
||||
} else {
|
||||
_pendingRequests.append(resource);
|
||||
|
@ -70,14 +75,14 @@ uint32_t ResourceCacheSharedItems::getPendingRequestsCount() const {
|
|||
return _pendingRequests.size();
|
||||
}
|
||||
|
||||
QList<QSharedPointer<Resource>> ResourceCacheSharedItems::getLoadingRequests() const {
|
||||
QList<QSharedPointer<Resource>> result;
|
||||
QList<std::pair<QSharedPointer<Resource>, float>> ResourceCacheSharedItems::getLoadingRequests() const {
|
||||
QList<std::pair<QSharedPointer<Resource>, float>> result;
|
||||
Lock lock(_mutex);
|
||||
|
||||
foreach(QWeakPointer<Resource> resource, _loadingRequests) {
|
||||
auto locked = resource.lock();
|
||||
foreach(auto resourcePair, _loadingRequests) {
|
||||
auto locked = resourcePair.first.lock();
|
||||
if (locked) {
|
||||
result.append(locked);
|
||||
result.append({ locked, resourcePair.second });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +101,7 @@ void ResourceCacheSharedItems::removeRequest(QWeakPointer<Resource> resource) {
|
|||
// QWeakPointer has no operator== implementation for two weak ptrs, so
|
||||
// manually loop in case resource has been freed.
|
||||
for (int i = 0; i < _loadingRequests.size();) {
|
||||
auto request = _loadingRequests.at(i);
|
||||
auto request = _loadingRequests.at(i).first;
|
||||
// Clear our resource and any freed resources
|
||||
if (!request || request.toStrongRef().data() == resource.toStrongRef().data()) {
|
||||
_loadingRequests.removeAt(i);
|
||||
|
@ -519,7 +524,7 @@ void ResourceCache::updateTotalSize(const qint64& deltaSize) {
|
|||
emit dirty();
|
||||
}
|
||||
|
||||
QList<QSharedPointer<Resource>> ResourceCache::getLoadingRequests() {
|
||||
QList<std::pair<QSharedPointer<Resource>, float>> ResourceCache::getLoadingRequests() {
|
||||
return DependencyManager::get<ResourceCacheSharedItems>()->getLoadingRequests();
|
||||
}
|
||||
|
||||
|
@ -571,7 +576,7 @@ Resource::Resource(const Resource& other) :
|
|||
_startedLoading(other._startedLoading),
|
||||
_failedToLoad(other._failedToLoad),
|
||||
_loaded(other._loaded),
|
||||
_loadPriorities(other._loadPriorities),
|
||||
_loadPriorityOperators(other._loadPriorityOperators),
|
||||
_bytesReceived(other._bytesReceived),
|
||||
_bytesTotal(other._bytesTotal),
|
||||
_bytes(other._bytes),
|
||||
|
@ -605,40 +610,24 @@ void Resource::ensureLoading() {
|
|||
}
|
||||
}
|
||||
|
||||
void Resource::setLoadPriority(const QPointer<QObject>& owner, float priority) {
|
||||
void Resource::setLoadPriorityOperator(const QPointer<QObject>& owner, std::function<float()> priorityOperator) {
|
||||
if (!_failedToLoad) {
|
||||
_loadPriorities.insert(owner, priority);
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::setLoadPriorities(const QHash<QPointer<QObject>, float>& priorities) {
|
||||
if (_failedToLoad) {
|
||||
return;
|
||||
}
|
||||
for (QHash<QPointer<QObject>, float>::const_iterator it = priorities.constBegin();
|
||||
it != priorities.constEnd(); it++) {
|
||||
_loadPriorities.insert(it.key(), it.value());
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::clearLoadPriority(const QPointer<QObject>& owner) {
|
||||
if (!_failedToLoad) {
|
||||
_loadPriorities.remove(owner);
|
||||
_loadPriorityOperators.insert(owner, priorityOperator);
|
||||
}
|
||||
}
|
||||
|
||||
float Resource::getLoadPriority() {
|
||||
if (_loadPriorities.size() == 0) {
|
||||
if (_loadPriorityOperators.size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float highestPriority = -FLT_MAX;
|
||||
for (QHash<QPointer<QObject>, float>::iterator it = _loadPriorities.begin(); it != _loadPriorities.end(); ) {
|
||||
if (it.key().isNull()) {
|
||||
it = _loadPriorities.erase(it);
|
||||
for (QHash<QPointer<QObject>, std::function<float()>>::iterator it = _loadPriorityOperators.begin(); it != _loadPriorityOperators.end();) {
|
||||
if (it.key().isNull() || !it.value()) {
|
||||
it = _loadPriorityOperators.erase(it);
|
||||
continue;
|
||||
}
|
||||
highestPriority = qMax(highestPriority, it.value());
|
||||
highestPriority = qMax(highestPriority, it.value()());
|
||||
it++;
|
||||
}
|
||||
return highestPriority;
|
||||
|
@ -742,7 +731,7 @@ void Resource::attemptRequest() {
|
|||
|
||||
void Resource::finishedLoading(bool success) {
|
||||
if (success) {
|
||||
_loadPriorities.clear();
|
||||
_loadPriorityOperators.clear();
|
||||
_loaded = true;
|
||||
} else {
|
||||
_failedToLoad = true;
|
||||
|
|
|
@ -73,7 +73,7 @@ public:
|
|||
QList<QSharedPointer<Resource>> getPendingRequests() const;
|
||||
QSharedPointer<Resource> getHighestPendingRequest();
|
||||
uint32_t getPendingRequestsCount() const;
|
||||
QList<QSharedPointer<Resource>> getLoadingRequests() const;
|
||||
QList<std::pair<QSharedPointer<Resource>, float>> getLoadingRequests() const;
|
||||
uint32_t getLoadingRequestsCount() const;
|
||||
void clear();
|
||||
|
||||
|
@ -82,7 +82,7 @@ private:
|
|||
|
||||
mutable Mutex _mutex;
|
||||
QList<QWeakPointer<Resource>> _pendingRequests;
|
||||
QList<QWeakPointer<Resource>> _loadingRequests;
|
||||
QList<std::pair<QWeakPointer<Resource>, float>> _loadingRequests;
|
||||
const uint32_t DEFAULT_REQUEST_LIMIT = 10;
|
||||
uint32_t _requestLimit { DEFAULT_REQUEST_LIMIT };
|
||||
};
|
||||
|
@ -216,7 +216,7 @@ public:
|
|||
void setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize);
|
||||
qint64 getUnusedResourceCacheSize() const { return _unusedResourcesMaxSize; }
|
||||
|
||||
static QList<QSharedPointer<Resource>> getLoadingRequests();
|
||||
static QList<std::pair<QSharedPointer<Resource>, float>> getLoadingRequests();
|
||||
static uint32_t getPendingRequestCount();
|
||||
static uint32_t getLoadingRequestCount();
|
||||
|
||||
|
@ -424,13 +424,7 @@ public:
|
|||
void ensureLoading();
|
||||
|
||||
/// Sets the load priority for one owner.
|
||||
virtual void setLoadPriority(const QPointer<QObject>& owner, float priority);
|
||||
|
||||
/// Sets a set of priorities at once.
|
||||
virtual void setLoadPriorities(const QHash<QPointer<QObject>, float>& priorities);
|
||||
|
||||
/// Clears the load priority for one owner.
|
||||
virtual void clearLoadPriority(const QPointer<QObject>& owner);
|
||||
virtual void setLoadPriorityOperator(const QPointer<QObject>& owner, std::function<float()> priorityOperator);
|
||||
|
||||
/// Returns the highest load priority across all owners.
|
||||
float getLoadPriority();
|
||||
|
@ -451,7 +445,7 @@ public:
|
|||
qint64 getBytes() const { return _bytes; }
|
||||
|
||||
/// For loading resources, returns the load progress.
|
||||
float getProgress() const { return (_bytesTotal <= 0) ? 0.0f : (float)_bytesReceived / _bytesTotal; }
|
||||
float getProgress() const { return (_bytesTotal <= 0) ? 0.0f : ((float)_bytesReceived / _bytesTotal); }
|
||||
|
||||
/// Refreshes the resource.
|
||||
virtual void refresh();
|
||||
|
@ -537,7 +531,7 @@ protected:
|
|||
bool _failedToLoad = false;
|
||||
bool _loaded = false;
|
||||
|
||||
QHash<QPointer<QObject>, float> _loadPriorities;
|
||||
QHash<QPointer<QObject>, std::function<float()>> _loadPriorityOperators;
|
||||
QWeakPointer<Resource> _self;
|
||||
QPointer<ResourceCache> _cache;
|
||||
|
||||
|
|
|
@ -1343,7 +1343,7 @@ void Model::setURL(const QUrl& url) {
|
|||
|
||||
auto resource = DependencyManager::get<ModelCache>()->getGeometryResource(url);
|
||||
if (resource) {
|
||||
resource->setLoadPriority(this, _loadingPriority);
|
||||
resource->setLoadPriorityOperator(this, _loadingPriorityOperator);
|
||||
_renderWatcher.setResource(resource);
|
||||
}
|
||||
_rig.initFlow(false);
|
||||
|
|
|
@ -295,7 +295,7 @@ public:
|
|||
// returns 'true' if needs fullUpdate after geometry change
|
||||
virtual bool updateGeometry();
|
||||
|
||||
void setLoadingPriority(float priority) { _loadingPriority = priority; }
|
||||
void setLoadingPriorityOperator(std::function<float()> priorityOperator) { _loadingPriorityOperator = priorityOperator; }
|
||||
|
||||
size_t getRenderInfoVertexCount() const { return _renderInfoVertexCount; }
|
||||
size_t getRenderInfoTextureSize();
|
||||
|
@ -518,7 +518,7 @@ protected:
|
|||
uint64_t _created;
|
||||
|
||||
private:
|
||||
float _loadingPriority { 0.0f };
|
||||
std::function<float()> _loadingPriorityOperator { []() { return 0.0f; } };
|
||||
|
||||
void calculateTextureInfo();
|
||||
|
||||
|
|
Loading…
Reference in a new issue