set up a way to request ResourceCache downloads from a non-networking thread.

This commit is contained in:
Seth Alves 2015-03-26 18:37:55 -07:00
parent 43b30c7ffa
commit 7da87d6e15
8 changed files with 73 additions and 29 deletions

View file

@ -344,6 +344,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// put the NodeList and datagram processing on the node thread // put the NodeList and datagram processing on the node thread
nodeList->moveToThread(nodeThread); nodeList->moveToThread(nodeThread);
// geometry background downloads need to happen on the Datagram Processor Thread. The idle loop will
// emit checkBackgroundDownloads to cause the GeometryCache to check it's queue for requested background
// downloads.
QSharedPointer<GeometryCache> geometryCacheP = DependencyManager::get<GeometryCache>();
ResourceCache *geometryCache = geometryCacheP.data();
connect(this, &Application::checkBackgroundDownloads, geometryCache, &ResourceCache::checkAsynchronousGets);
// connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal // connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _datagramProcessor, &DatagramProcessor::processDatagrams); connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _datagramProcessor, &DatagramProcessor::processDatagrams);
@ -1569,6 +1576,9 @@ void Application::idle() {
idleTimer->start(2); idleTimer->start(2);
} }
} }
// check for any requested background downloads.
emit checkBackgroundDownloads();
} }
void Application::setFullscreen(bool fullscreen) { void Application::setFullscreen(bool fullscreen) {
@ -3140,7 +3150,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
int viewport[4]; int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport); glGetIntegerv(GL_VIEWPORT, viewport);
bool eyeRelativeCamera = false; // bool eyeRelativeCamera = false;
if (billboard) { if (billboard) {
_mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW); // degees _mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW); // degees
_mirrorCamera.setPosition(_myAvatar->getPosition() + _mirrorCamera.setPosition(_myAvatar->getPosition() +

View file

@ -333,6 +333,8 @@ signals:
void svoImportRequested(const QString& url); void svoImportRequested(const QString& url);
void checkBackgroundDownloads();
public slots: public slots:
void domainChanged(const QString& domainHostname); void domainChanged(const QString& domainHostname);
void updateWindowTitle(); void updateWindowTitle();

View file

@ -18,6 +18,7 @@
#include <QTimer> #include <QTimer>
#include <SharedUtil.h> #include <SharedUtil.h>
#include <assert.h>
#include "NetworkAccessManager.h" #include "NetworkAccessManager.h"
#include "ResourceCache.h" #include "ResourceCache.h"
@ -48,32 +49,42 @@ void ResourceCache::refresh(const QUrl& url) {
} }
} }
QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl& fallback, void ResourceCache::getResourceAsynchronously(const QUrl& url) {
bool delayLoad, void* extra, bool block) { qDebug() << "ResourceCache::getResourceAsynchronously" << url.toString();
if (QThread::currentThread() != thread()) { _resourcesToBeGottenLock.lockForWrite();
// This will re-call this method in the main thread. If block is true and the main thread _resourcesToBeGotten.enqueue(QUrl(url));
// is waiting on a lock, we'll deadlock here. _resourcesToBeGottenLock.unlock();
if (block) {
QSharedPointer<Resource> result;
QMetaObject::invokeMethod(this, "getResource", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QSharedPointer<Resource>, result), Q_ARG(const QUrl&, url),
Q_ARG(const QUrl&, fallback), Q_ARG(bool, delayLoad), Q_ARG(void*, extra));
return result;
} else {
// Queue the re-invocation of this method, but if the main thread is blocked, don't wait. The
// return value may be NULL -- it's expected that this will be called again later, in order
// to receive the actual Resource.
QMetaObject::invokeMethod(this, "getResource", Qt::QueuedConnection,
Q_ARG(const QUrl&, url),
Q_ARG(const QUrl&, fallback), Q_ARG(bool, delayLoad), Q_ARG(void*, extra));
return _resources.value(url);
} }
void ResourceCache::checkAsynchronousGets() {
assert(QThread::currentThread() == thread());
_resourcesToBeGottenLock.lockForRead();
if (_resourcesToBeGotten.isEmpty()) {
_resourcesToBeGottenLock.unlock();
return;
}
QUrl url = _resourcesToBeGotten.dequeue();
_resourcesToBeGottenLock.unlock();
getResource(url);
}
QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl& fallback,
bool delayLoad, void* extra) {
QSharedPointer<Resource> resource = _resources.value(url);
if (!resource.isNull()) {
return resource;
}
if (QThread::currentThread() != thread()) {
assert(delayLoad);
getResourceAsynchronously(url);
return QSharedPointer<Resource>();
} }
if (!url.isValid() && !url.isEmpty() && fallback.isValid()) { if (!url.isValid() && !url.isEmpty() && fallback.isValid()) {
return getResource(fallback, QUrl(), delayLoad); return getResource(fallback, QUrl(), delayLoad);
} }
QSharedPointer<Resource> resource = _resources.value(url);
if (resource.isNull()) { if (resource.isNull()) {
resource = createResource(url, fallback.isValid() ? resource = createResource(url, fallback.isValid() ?
getResource(fallback, QUrl(), true) : QSharedPointer<Resource>(), delayLoad, extra); getResource(fallback, QUrl(), true) : QSharedPointer<Resource>(), delayLoad, extra);

View file

@ -21,6 +21,8 @@
#include <QSharedPointer> #include <QSharedPointer>
#include <QUrl> #include <QUrl>
#include <QWeakPointer> #include <QWeakPointer>
#include <QReadWriteLock>
#include <QQueue>
#include <DependencyManager.h> #include <DependencyManager.h>
@ -79,6 +81,9 @@ public:
void refresh(const QUrl& url); void refresh(const QUrl& url);
public slots:
void checkAsynchronousGets();
protected: protected:
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
qint64 _unusedResourcesSize = 0; qint64 _unusedResourcesSize = 0;
@ -89,7 +94,7 @@ protected:
/// \param delayLoad if true, don't load the resource immediately; wait until load is first requested /// \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 /// \param extra extra data to pass to the creator, if appropriate
Q_INVOKABLE QSharedPointer<Resource> getResource(const QUrl& url, const QUrl& fallback = QUrl(), Q_INVOKABLE QSharedPointer<Resource> getResource(const QUrl& url, const QUrl& fallback = QUrl(),
bool delayLoad = false, void* extra = NULL, bool block = true); bool delayLoad = false, void* extra = NULL);
/// Creates a new resource. /// Creates a new resource.
virtual QSharedPointer<Resource> createResource(const QUrl& url, virtual QSharedPointer<Resource> createResource(const QUrl& url,
@ -109,6 +114,11 @@ private:
int _lastLRUKey = 0; int _lastLRUKey = 0;
static int _requestLimit; static int _requestLimit;
void getResourceAsynchronously(const QUrl& url);
QReadWriteLock _resourcesToBeGottenLock;
QQueue<QUrl> _resourcesToBeGotten;
}; };
/// Base class for resources. /// Base class for resources.

View file

@ -1770,8 +1770,8 @@ void GeometryCache::renderLine(const glm::vec2& p1, const glm::vec2& p2,
} }
QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad, bool block) { QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad) {
return getResource(url, fallback, delayLoad, NULL, block).staticCast<NetworkGeometry>(); return getResource(url, fallback, delayLoad, NULL).staticCast<NetworkGeometry>();
} }
QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url,

View file

@ -203,8 +203,7 @@ public:
/// Loads geometry from the specified URL. /// Loads geometry from the specified URL.
/// \param fallback a fallback URL to load if the desired one is unavailable /// \param fallback a fallback URL to load if the desired one is unavailable
/// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested /// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
bool delayLoad = false, bool block = true);
protected: protected:

View file

@ -325,6 +325,8 @@ void Model::init() {
_skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel)); _skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel));
makeResult = gpu::Shader::makeProgram(*_skinTranslucentProgram, slotBindings); makeResult = gpu::Shader::makeProgram(*_skinTranslucentProgram, slotBindings);
initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations); initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations);
(void) makeResult; // quiet compiler
} }
} }
@ -1032,12 +1034,22 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo
} }
} }
void Model::setCollisionModelURL(const QUrl& url, const QUrl& fallback, bool delayLoad) {
const QSharedPointer<NetworkGeometry> Model::getCollisionGeometry(bool delayLoad)
{
if (_collisionGeometry.isNull() && !_collisionUrl.isEmpty()) {
_collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(_collisionUrl, QUrl(), delayLoad);
}
return _collisionGeometry;
}
void Model::setCollisionModelURL(const QUrl& url) {
if (_collisionUrl == url) { if (_collisionUrl == url) {
return; return;
} }
_collisionUrl = url; _collisionUrl = url;
_collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, fallback, delayLoad); _collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, QUrl(), true);
} }
bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const { bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const {

View file

@ -109,7 +109,7 @@ public:
const QUrl& getURL() const { return _url; } const QUrl& getURL() const { return _url; }
// Set the model to use for collisions // Set the model to use for collisions
Q_INVOKABLE void setCollisionModelURL(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false); Q_INVOKABLE void setCollisionModelURL(const QUrl& url);
const QUrl& getCollisionURL() const { return _collisionUrl; } const QUrl& getCollisionURL() const { return _collisionUrl; }
/// Sets the distance parameter used for LOD computations. /// Sets the distance parameter used for LOD computations.
@ -134,7 +134,7 @@ public:
const QSharedPointer<NetworkGeometry>& getGeometry() const { return _geometry; } const QSharedPointer<NetworkGeometry>& getGeometry() const { return _geometry; }
/// Returns a reference to the shared collision geometry. /// Returns a reference to the shared collision geometry.
const QSharedPointer<NetworkGeometry> getCollisionGeometry() {return _collisionGeometry; } const QSharedPointer<NetworkGeometry> getCollisionGeometry(bool delayLoad = true);
/// Returns the number of joint states in the model. /// Returns the number of joint states in the model.
int getJointStateCount() const { return _jointStates.size(); } int getJointStateCount() const { return _jointStates.size(); }