From 7ecfeeaba30158df3f507f2a39aee181067511b1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 3 Mar 2014 15:16:13 -0800 Subject: [PATCH 1/5] Do the actual reading of the reply on the worker thread. Otherwise, when we read from the cache, we're reading synchronously from a file. Closes #2171. --- interface/src/renderer/GeometryCache.cpp | 19 ++++++++++--------- interface/src/renderer/TextureCache.cpp | 14 ++++++++------ libraries/metavoxels/src/ScriptCache.cpp | 1 + libraries/shared/src/ResourceCache.cpp | 1 - libraries/shared/src/ResourceCache.h | 1 + 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 170ebc60e5..5b13e2da42 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -450,7 +450,7 @@ class GeometryReader : public QRunnable { public: GeometryReader(const QWeakPointer& geometry, const QUrl& url, - const QByteArray& data, const QVariantHash& mapping); + QNetworkReply* reply, const QVariantHash& mapping); virtual void run(); @@ -458,40 +458,41 @@ private: QWeakPointer _geometry; QUrl _url; - QByteArray _data; + QNetworkReply* _reply; QVariantHash _mapping; }; GeometryReader::GeometryReader(const QWeakPointer& geometry, const QUrl& url, - const QByteArray& data, const QVariantHash& mapping) : + QNetworkReply* reply, const QVariantHash& mapping) : _geometry(geometry), _url(url), - _data(data), + _reply(reply), _mapping(mapping) { } void GeometryReader::run() { QSharedPointer geometry = _geometry.toStrongRef(); if (geometry.isNull()) { + _reply->deleteLater(); return; } try { QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, - _url.path().toLower().endsWith(".svo") ? readSVO(_data) : readFBX(_data, _mapping))); + _url.path().toLower().endsWith(".svo") ? readSVO(_reply->readAll()) : readFBX(_reply->readAll(), _mapping))); } catch (const QString& error) { qDebug() << "Error reading " << _url << ": " << error; QMetaObject::invokeMethod(geometry.data(), "finishedLoading", Q_ARG(bool, false)); } + _reply->deleteLater(); } void NetworkGeometry::downloadFinished(QNetworkReply* reply) { QUrl url = reply->url(); - QByteArray data = reply->readAll(); - if (url.path().toLower().endsWith(".fst")) { // it's a mapping file; parse it and get the mesh filename - _mapping = readMapping(data); + _mapping = readMapping(reply->readAll()); + reply->deleteLater(); QString filename = _mapping.value("filename").toString(); if (filename.isNull()) { qDebug() << "Mapping file " << url << " has no filename."; @@ -525,7 +526,7 @@ void NetworkGeometry::downloadFinished(QNetworkReply* reply) { } // send the reader off to the thread pool - QThreadPool::globalInstance()->start(new GeometryReader(_self, url, data, _mapping)); + QThreadPool::globalInstance()->start(new GeometryReader(_self, url, reply, _mapping)); } void NetworkGeometry::setGeometry(const FBXGeometry& geometry) { diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp index 794516f7b7..dcaf059714 100644 --- a/interface/src/renderer/TextureCache.cpp +++ b/interface/src/renderer/TextureCache.cpp @@ -273,27 +273,28 @@ NetworkTexture::NetworkTexture(const QUrl& url, bool normalMap) : class ImageReader : public QRunnable { public: - ImageReader(const QWeakPointer& texture, const QByteArray& data); + ImageReader(const QWeakPointer& texture, QNetworkReply* reply); virtual void run(); private: QWeakPointer _texture; - QByteArray _data; + QNetworkReply* _reply; }; -ImageReader::ImageReader(const QWeakPointer& texture, const QByteArray& data) : +ImageReader::ImageReader(const QWeakPointer& texture, QNetworkReply* reply) : _texture(texture), - _data(data) { + _reply(reply) { } void ImageReader::run() { QSharedPointer texture = _texture.toStrongRef(); if (texture.isNull()) { + _reply->deleteLater(); return; } - QImage image = QImage::fromData(_data); + QImage image = QImage::fromData(_reply->readAll()); if (image.format() != QImage::Format_ARGB32) { image = image.convertToFormat(QImage::Format_ARGB32); } @@ -320,11 +321,12 @@ void ImageReader::run() { QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image), Q_ARG(const glm::vec4&, accumulated / (imageArea * EIGHT_BIT_MAXIMUM)), Q_ARG(bool, translucentPixels >= imageArea / 2)); + _reply->deleteLater(); } void NetworkTexture::downloadFinished(QNetworkReply* reply) { // send the reader off to the thread pool - QThreadPool::globalInstance()->start(new ImageReader(_self, reply->readAll())); + QThreadPool::globalInstance()->start(new ImageReader(_self, reply)); } void NetworkTexture::setImage(const QImage& image, const glm::vec4& averageColor, bool translucent) { diff --git a/libraries/metavoxels/src/ScriptCache.cpp b/libraries/metavoxels/src/ScriptCache.cpp index fd58f5b6f3..702a36de2a 100644 --- a/libraries/metavoxels/src/ScriptCache.cpp +++ b/libraries/metavoxels/src/ScriptCache.cpp @@ -61,6 +61,7 @@ NetworkProgram::NetworkProgram(ScriptCache* cache, const QUrl& url) : void NetworkProgram::downloadFinished(QNetworkReply* reply) { _program = QScriptProgram(QTextStream(reply).readAll(), reply->url().toString()); + reply->deleteLater(); finishedLoading(true); emit loaded(); } diff --git a/libraries/shared/src/ResourceCache.cpp b/libraries/shared/src/ResourceCache.cpp index 90dc5961dc..bd08b240c5 100644 --- a/libraries/shared/src/ResourceCache.cpp +++ b/libraries/shared/src/ResourceCache.cpp @@ -161,7 +161,6 @@ void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { return; } _reply->disconnect(this); - _reply->deleteLater(); QNetworkReply* reply = _reply; _reply = NULL; ResourceCache::requestCompleted(); diff --git a/libraries/shared/src/ResourceCache.h b/libraries/shared/src/ResourceCache.h index eae5e752e2..c77318aac2 100644 --- a/libraries/shared/src/ResourceCache.h +++ b/libraries/shared/src/ResourceCache.h @@ -99,6 +99,7 @@ protected slots: protected: + /// Called when the download has finished. The recipient should delete the reply when done with it. virtual void downloadFinished(QNetworkReply* reply) = 0; /// Should be called by subclasses when all the loading that will be done has been done. From 75c9e445453b0f0e58283d3fca282709d7d32ade Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 3 Mar 2014 15:33:37 -0800 Subject: [PATCH 2/5] Render the billboard if we don't have both models. Closes #2178. --- interface/src/avatar/Avatar.cpp | 9 ++++----- interface/src/avatar/AvatarManager.cpp | 3 ++- interface/src/avatar/AvatarManager.h | 4 ++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 7ada8b0764..be549beeba 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -112,7 +112,8 @@ glm::quat Avatar::getWorldAlignedOrientation () const { } float Avatar::getLODDistance() const { - return glm::distance(Application::getInstance()->getCamera()->getPosition(), _position) / _scale; + return Application::getInstance()->getAvatarManager().getLODDistanceMultiplier() * + glm::distance(Application::getInstance()->getCamera()->getPosition(), _position) / _scale; } void Avatar::simulate(float deltaTime) { @@ -305,13 +306,11 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { } void Avatar::renderBody() { - if (_shouldRenderBillboard) { + if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { + // render the billboard until both models are loaded renderBillboard(); return; } - if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { - return; // wait until both models are loaded - } _skeletonModel.render(1.0f); getHead()->render(1.0f); getHand()->render(false); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 847baf782f..def93f034b 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -23,7 +23,8 @@ const QUuid MY_AVATAR_KEY; // NULL key AvatarManager::AvatarManager(QObject* parent) : - _avatarFades() { + _avatarFades(), + _lodDistanceMultiplier(1.0f) { // register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar qRegisterMetaType >("NodeWeakPointer"); _myAvatar = QSharedPointer(new MyAvatar()); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index db24d5bf4e..47bc8fd34b 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -33,6 +33,8 @@ public: void clearOtherAvatars(); + float getLODDistanceMultiplier() const { return _lodDistanceMultiplier; } + public slots: void processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer& mixerWeakPointer); @@ -52,6 +54,8 @@ private: QVector _avatarFades; QSharedPointer _myAvatar; + + float _lodDistanceMultiplier; }; #endif /* defined(__hifi__AvatarManager__) */ From 64c4e58160a7b62a07c23521b01d547f2126b18a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 3 Mar 2014 16:34:28 -0800 Subject: [PATCH 3/5] Tie the avatar LOD distance multiplier to the LOD parameter calculated for voxels. --- interface/src/Application.cpp | 16 +++++++++------- interface/src/Application.h | 1 + interface/src/Menu.h | 1 + interface/src/avatar/Avatar.cpp | 2 +- interface/src/avatar/AvatarManager.cpp | 3 +-- interface/src/avatar/AvatarManager.h | 4 ---- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8c865f906c..b21d660452 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1612,6 +1612,13 @@ bool Application::isLookingAtMyAvatar(Avatar* avatar) { return false; } +void Application::updateLOD() { + // adjust it unless we were asked to disable this feature + if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD)) { + Menu::getInstance()->autoAdjustLOD(_fps); + } +} + void Application::updateMouseRay() { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); @@ -1852,6 +1859,8 @@ void Application::update(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::update()"); + updateLOD(); + // check what's under the mouse and update the mouse voxel updateMouseRay(); @@ -2325,14 +2334,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... voxels..."); - _voxels.render(); - - // double check that our LOD doesn't need to be auto-adjusted - // adjust it unless we were asked to disable this feature - if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD)) { - Menu::getInstance()->autoAdjustLOD(_fps); - } } // also, metavoxels diff --git a/interface/src/Application.h b/interface/src/Application.h index 78826b4fd0..8c64da86b6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -284,6 +284,7 @@ private: void update(float deltaTime); // Various helper functions called during update() + void updateLOD(); void updateMouseRay(); void updateFaceshift(); void updateVisage(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 9d4c7eaab9..e2e0d3895a 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -84,6 +84,7 @@ public: void autoAdjustLOD(float currentFPS); void setVoxelSizeScale(float sizeScale); float getVoxelSizeScale() const { return _voxelSizeScale; } + float getAvatarLODDistanceMultiplier() const { return DEFAULT_OCTREE_SIZE_SCALE / _voxelSizeScale; } void setBoundaryLevelAdjust(int boundaryLevelAdjust); int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index be549beeba..ef6975d223 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -112,7 +112,7 @@ glm::quat Avatar::getWorldAlignedOrientation () const { } float Avatar::getLODDistance() const { - return Application::getInstance()->getAvatarManager().getLODDistanceMultiplier() * + return Menu::getInstance()->getAvatarLODDistanceMultiplier() * glm::distance(Application::getInstance()->getCamera()->getPosition(), _position) / _scale; } diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index def93f034b..847baf782f 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -23,8 +23,7 @@ const QUuid MY_AVATAR_KEY; // NULL key AvatarManager::AvatarManager(QObject* parent) : - _avatarFades(), - _lodDistanceMultiplier(1.0f) { + _avatarFades() { // register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar qRegisterMetaType >("NodeWeakPointer"); _myAvatar = QSharedPointer(new MyAvatar()); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 47bc8fd34b..db24d5bf4e 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -33,8 +33,6 @@ public: void clearOtherAvatars(); - float getLODDistanceMultiplier() const { return _lodDistanceMultiplier; } - public slots: void processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer& mixerWeakPointer); @@ -54,8 +52,6 @@ private: QVector _avatarFades; QSharedPointer _myAvatar; - - float _lodDistanceMultiplier; }; #endif /* defined(__hifi__AvatarManager__) */ From 493648b56e8344c302524cc04b9716bdaa741cd0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Mar 2014 17:06:46 -0800 Subject: [PATCH 4/5] reversing some changes --- libraries/octree/src/Octree.cpp | 12 +++++------- libraries/particles/src/Particle.cpp | 2 +- libraries/particles/src/ParticleTree.cpp | 10 +++++++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 0847590720..05760ef675 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -39,12 +39,13 @@ float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeSc } Octree::Octree(bool shouldReaverage) : + _rootNode(NULL), _isDirty(true), _shouldReaverage(shouldReaverage), _stopImport(false), - _lock(QReadWriteLock::Recursive) { - _rootNode = NULL; - _isViewing = false; + _lock(), + _isViewing(false) +{ } Octree::~Octree() { @@ -552,10 +553,7 @@ OctreeElement* Octree::getOctreeElementAt(float x, float y, float z, float s) co OctreeElement* Octree::getOrCreateChildElementAt(float x, float y, float z, float s) { - lockForWrite(); - OctreeElement* result = getRoot()->getOrCreateChildElementAt(x, y, z, s); - unlock(); - return result; + return getRoot()->getOrCreateChildElementAt(x, y, z, s); } diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index b493ec6bc7..d9f0beb81a 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -385,7 +385,7 @@ Particle Particle::fromEditPacket(const unsigned char* data, int length, int& pr } else { // look up the existing particle - const Particle* existingParticle = tree->findParticleByID(editID); + const Particle* existingParticle = tree->findParticleByID(editID, true); // copy existing properties before over-writing with new properties if (existingParticle) { diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index 30270b8fcf..65a27dd325 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -370,12 +370,16 @@ bool ParticleTree::findByIDOperation(OctreeElement* element, void* extraData) { } -const Particle* ParticleTree::findParticleByID(uint32_t id) { +const Particle* ParticleTree::findParticleByID(uint32_t id, bool alreadyLocked) { FindByIDArgs args = { id, false, NULL }; - lockForRead(); + if (!alreadyLocked) { + lockForRead(); + } recurseTreeWithOperation(findByIDOperation, &args); - unlock(); + if (!alreadyLocked) { + unlock(); + } return args.foundParticle; } From d01090afbc6f5dedb4a8a736f94e06ae99e87fcd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Mar 2014 17:13:06 -0800 Subject: [PATCH 5/5] reversing some changes --- libraries/particles/src/ParticleTree.cpp | 4 +--- libraries/particles/src/ParticleTree.h | 2 +- libraries/particles/src/ParticlesScriptingInterface.cpp | 4 +++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index 65a27dd325..a254305789 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -459,6 +459,7 @@ bool ParticleTree::pruneOperation(OctreeElement* element, void* extraData) { } void ParticleTree::update() { + lockForWrite(); _isDirty = true; ParticleTreeUpdateArgs args = { }; @@ -473,9 +474,7 @@ void ParticleTree::update() { AABox treeBounds = getRoot()->getAABox(); if (!shouldDie && treeBounds.contains(args._movingParticles[i].getPosition())) { - lockForWrite(); storeParticle(args._movingParticles[i]); - unlock(); } else { uint32_t particleID = args._movingParticles[i].getID(); quint64 deletedAt = usecTimestampNow(); @@ -486,7 +485,6 @@ void ParticleTree::update() { } // prune the tree... - lockForWrite(); recurseTreeWithOperation(pruneOperation, NULL); unlock(); } diff --git a/libraries/particles/src/ParticleTree.h b/libraries/particles/src/ParticleTree.h index 08e8e51a05..f3b8f5183d 100644 --- a/libraries/particles/src/ParticleTree.h +++ b/libraries/particles/src/ParticleTree.h @@ -44,7 +44,7 @@ public: void addParticle(const ParticleID& particleID, const ParticleProperties& properties); void deleteParticle(const ParticleID& particleID); const Particle* findClosestParticle(glm::vec3 position, float targetRadius); - const Particle* findParticleByID(uint32_t id); + const Particle* findParticleByID(uint32_t id, bool alreadyLocked = false); /// finds all particles that touch a sphere /// \param center the center of the sphere diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index c2376e8d72..a25dde1b9e 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -33,7 +33,9 @@ ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& pr // If we have a local particle tree set, then also update it. if (_particleTree) { + _particleTree->lockForWrite(); _particleTree->addParticle(id, properties); + _particleTree->unlock(); } return id; @@ -64,7 +66,7 @@ ParticleProperties ParticlesScriptingInterface::getParticleProperties(ParticleID } if (_particleTree) { _particleTree->lockForRead(); - const Particle* particle = _particleTree->findParticleByID(identity.id); + const Particle* particle = _particleTree->findParticleByID(identity.id, true); if (particle) { results.copyFromParticle(*particle); } else {