Merge pull request #5276 from Atlante45/clear_cache_and_restart

Reload content menu item
This commit is contained in:
Stephen Birarda 2015-07-14 15:30:33 -07:00
commit 6cd584ddd9
21 changed files with 155 additions and 79 deletions

View file

@ -53,7 +53,7 @@ AnimationDetails ScriptableAvatar::getAnimationDetails() {
void ScriptableAvatar::update(float deltatime) {
// Run animation
if (_animation != NULL && _animation->isValid() && _animation->getFrames().size() > 0) {
if (_animation && _animation->isLoaded() && _animation->getFrames().size() > 0) {
QStringList modelJoints = getJointNames();
QStringList animationJoints = _animation->getJointNames();

View file

@ -702,6 +702,14 @@ void Application::cleanupBeforeQuit() {
#endif
}
void Application::emptyLocalCache() {
QNetworkDiskCache* cache = qobject_cast<QNetworkDiskCache*>(NetworkAccessManager::getInstance().cache());
if (cache) {
qDebug() << "DiskCacheEditor::clear(): Clearing disk cache.";
cache->clear();
}
}
Application::~Application() {
EntityTree* tree = _entities.getTree();
tree->lockForWrite();
@ -2407,6 +2415,15 @@ void Application::cameraMenuChanged() {
}
}
void Application::reloadResourceCaches() {
emptyLocalCache();
DependencyManager::get<AnimationCache>()->refreshAll();
DependencyManager::get<GeometryCache>()->refreshAll();
DependencyManager::get<SoundCache>()->refreshAll();
DependencyManager::get<TextureCache>()->refreshAll();
}
void Application::rotationModeChanged() {
if (!Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {
_myAvatar->setHeadPitch(0);

View file

@ -442,6 +442,8 @@ public slots:
void domainConnectionDenied(const QString& reason);
void cameraMenuChanged();
void reloadResourceCaches();
private slots:
void clearDomainOctreeDetails();
@ -487,6 +489,8 @@ private:
void init();
void cleanupBeforeQuit();
void emptyLocalCache();
void update(float deltaTime);

View file

@ -256,6 +256,8 @@ Menu::Menu() {
avatar, SLOT(updateMotionBehavior()));
MenuWrapper* viewMenu = addMenu("View");
addActionToQMenuAndActionHash(viewMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()));
addCheckableActionToQMenuAndActionHash(viewMenu,
MenuOption::Fullscreen,

View file

@ -229,6 +229,7 @@ namespace MenuOption {
const QString Preferences = "Preferences...";
const QString Quit = "Quit";
const QString ReloadAllScripts = "Reload All Scripts";
const QString ReloadContent = "Reload Content (Clears all caches)";
const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes";
const QString RenderFocusIndicator = "Show Eye Focus";
const QString RenderHeadCollisionShapes = "Show Head Collision Shapes";

View file

@ -636,7 +636,7 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) {
_billboardTexture = DependencyManager::get<TextureCache>()->getTexture(
uniqueUrl, DEFAULT_TEXTURE, false, _billboard);
}
if (!_billboardTexture->isLoaded()) {
if (!_billboardTexture || !_billboardTexture->isLoaded()) {
return;
}
// rotate about vertical to face the camera

View file

@ -28,12 +28,12 @@ BillboardOverlay::BillboardOverlay(const BillboardOverlay* billboardOverlay) :
}
void BillboardOverlay::render(RenderArgs* args) {
if (!_isLoaded) {
if (!_texture) {
_isLoaded = true;
_texture = DependencyManager::get<TextureCache>()->getTexture(_url);
}
if (!_visible || !_texture->isLoaded()) {
if (!_visible || !_texture || !_texture->isLoaded()) {
return;
}
@ -170,7 +170,7 @@ void BillboardOverlay::setBillboardURL(const QString& url) {
bool BillboardOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face) {
if (_texture) {
if (_texture && _texture->isLoaded()) {
glm::quat rotation = getRotation();
if (_isFacingAvatar) {
// rotate about vertical to face the camera

View file

@ -38,10 +38,7 @@ QSharedPointer<Resource> AnimationCache::createResource(const QUrl& url, const Q
return QSharedPointer<Resource>(new Animation(url), &Resource::allReferencesCleared);
}
Animation::Animation(const QUrl& url) :
Resource(url),
_isValid(false) {
}
Animation::Animation(const QUrl& url) : Resource(url) {}
class AnimationReader : public QRunnable {
public:
@ -97,7 +94,6 @@ QVector<FBXAnimationFrame> Animation::getFrames() const {
void Animation::setGeometry(const FBXGeometry& geometry) {
_geometry = geometry;
finishedLoading(true);
_isValid = true;
}
void Animation::downloadFinished(QNetworkReply* reply) {

View file

@ -57,8 +57,6 @@ public:
Q_INVOKABLE QStringList getJointNames() const;
Q_INVOKABLE QVector<FBXAnimationFrame> getFrames() const;
bool isValid() const { return _isValid; }
protected:
@ -69,7 +67,6 @@ protected:
private:
FBXGeometry _geometry;
bool _isValid;
};

View file

@ -294,7 +294,7 @@ AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float vol
if (soundCache.isNull()) {
return NULL;
}
SharedSoundPointer sound = soundCache.data()->getSound(QUrl(soundUrl));
SharedSoundPointer sound = soundCache->getSound(QUrl(soundUrl));
if (sound.isNull() || !sound->isReady()) {
return NULL;
}

View file

@ -546,7 +546,7 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemP
Model* model = modelEntityItem->getModel(this);
if (model) {
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = model->getCollisionGeometry();
if (!collisionNetworkGeometry.isNull()) {
if (collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) {
result = &collisionNetworkGeometry->getFBXGeometry();
}
}

View file

@ -401,8 +401,8 @@ bool RenderableModelEntityItem::isReadyToComputeShape() {
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();
if ((! collisionNetworkGeometry.isNull() && collisionNetworkGeometry->isLoaded()) &&
(! renderNetworkGeometry.isNull() && renderNetworkGeometry->isLoaded())) {
if ((collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) &&
(renderNetworkGeometry && renderNetworkGeometry->isLoaded())) {
// we have both URLs AND both geometries AND they are both fully loaded.
return true;
}
@ -423,7 +423,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
// should never fall in here when collision model not fully loaded
// hence we assert collisionNetworkGeometry is not NULL
assert(!collisionNetworkGeometry.isNull());
assert(collisionNetworkGeometry);
const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry();
const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();

View file

@ -184,7 +184,7 @@ void ModelEntityItem::cleanupLoadedAnimations() {
_loadedAnimations.clear();
}
Animation* ModelEntityItem::getAnimation(const QString& url) {
AnimationPointer ModelEntityItem::getAnimation(const QString& url) {
AnimationPointer animation;
// if we don't already have this model then create it and initialize it
@ -194,7 +194,7 @@ Animation* ModelEntityItem::getAnimation(const QString& url) {
} else {
animation = _loadedAnimations[url];
}
return animation.data();
return animation;
}
void ModelEntityItem::mapJoints(const QStringList& modelJointNames) {
@ -203,9 +203,8 @@ void ModelEntityItem::mapJoints(const QStringList& modelJointNames) {
return;
}
Animation* myAnimation = getAnimation(_animationURL);
if (!_jointMappingCompleted) {
AnimationPointer myAnimation = getAnimation(_animationURL);
if (myAnimation && myAnimation->isLoaded()) {
QStringList animationJointNames = myAnimation->getJointNames();
if (modelJointNames.size() > 0 && animationJointNames.size() > 0) {
@ -220,8 +219,12 @@ void ModelEntityItem::mapJoints(const QStringList& modelJointNames) {
QVector<glm::quat> ModelEntityItem::getAnimationFrame() {
QVector<glm::quat> frameData;
if (hasAnimation() && _jointMappingCompleted) {
Animation* myAnimation = getAnimation(_animationURL);
if (!hasAnimation() || !_jointMappingCompleted) {
return frameData;
}
AnimationPointer myAnimation = getAnimation(_animationURL);
if (myAnimation && myAnimation->isLoaded()) {
QVector<FBXAnimationFrame> frames = myAnimation->getFrames();
int frameCount = frames.size();
if (frameCount > 0) {

View file

@ -141,7 +141,7 @@ protected:
bool _jointMappingCompleted;
QVector<int> _jointMapping;
static Animation* getAnimation(const QString& url);
static AnimationPointer getAnimation(const QString& url);
static QMap<QString, AnimationPointer> _loadedAnimations;
static AnimationCache _animationCache;

View file

@ -34,13 +34,18 @@ ResourceCache::ResourceCache(QObject* parent) :
}
ResourceCache::~ResourceCache() {
// the unused resources may themselves reference resources that will be added to the unused
// list on destruction, so keep clearing until there are no references left
while (!_unusedResources.isEmpty()) {
foreach (const QSharedPointer<Resource>& resource, _unusedResources) {
resource->setCache(nullptr);
clearUnusedResource();
}
void ResourceCache::refreshAll() {
// Clear all unused resources so we don't have to reload them
clearUnusedResource();
// Refresh all remaining resources in use
foreach (auto resource, _resources) {
if (!resource.isNull()) {
resource.data()->refresh();
}
_unusedResources.clear();
}
}
@ -48,6 +53,8 @@ void ResourceCache::refresh(const QUrl& url) {
QSharedPointer<Resource> resource = _resources.value(url);
if (!resource.isNull()) {
resource->refresh();
} else {
_resources.remove(url);
}
}
@ -134,6 +141,17 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
}
}
void ResourceCache::clearUnusedResource() {
// the unused resources may themselves reference resources that will be added to the unused
// list on destruction, so keep clearing until there are no references left
while (!_unusedResources.isEmpty()) {
foreach (const QSharedPointer<Resource>& resource, _unusedResources) {
resource->setCache(nullptr);
}
_unusedResources.clear();
}
}
void ResourceCache::attemptRequest(Resource* resource) {
auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>();
if (_requestLimit <= 0) {
@ -253,19 +271,20 @@ void Resource::refresh() {
_replyTimer->deleteLater();
_replyTimer = nullptr;
}
init();
_request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
if (!_startedLoading) {
attemptRequest();
}
ensureLoading();
emit onRefresh();
}
void Resource::allReferencesCleared() {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "allReferencesCleared");
return;
}
if (_cache) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "allReferencesCleared");
return;
}
// create and reinsert new shared pointer
QSharedPointer<Resource> self(this, &Resource::allReferencesCleared);
setSelf(self);
@ -312,8 +331,7 @@ void Resource::reinsert() {
_cache->_resources.insert(_url, _self);
}
const int REPLY_TIMEOUT_MS = 5000;
static const int REPLY_TIMEOUT_MS = 5000;
void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
if (!_reply->isFinished()) {
_bytesReceived = bytesReceived;

View file

@ -51,7 +51,7 @@ static const qint64 MAX_UNUSED_MAX_SIZE = 10 * BYTES_PER_GIGABYTES;
class ResourceCacheSharedItems : public Dependency {
SINGLETON_DEPENDENCY
public:
QList<QPointer<Resource> > _pendingRequests;
QList<QPointer<Resource>> _pendingRequests;
QList<Resource*> _loadingRequests;
private:
ResourceCacheSharedItems() { }
@ -78,17 +78,14 @@ public:
ResourceCache(QObject* parent = NULL);
virtual ~ResourceCache();
void refreshAll();
void refresh(const QUrl& url);
public slots:
void checkAsynchronousGets();
protected:
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
qint64 _unusedResourcesSize = 0;
QMap<int, QSharedPointer<Resource> > _unusedResources;
/// 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
@ -103,6 +100,7 @@ protected:
void addUnusedResource(const QSharedPointer<Resource>& resource);
void removeUnusedResource(const QSharedPointer<Resource>& resource);
void reserveUnusedResource(qint64 resourceSize);
void clearUnusedResource();
static void attemptRequest(Resource* resource);
static void requestCompleted(Resource* resource);
@ -110,7 +108,7 @@ protected:
private:
friend class Resource;
QHash<QUrl, QWeakPointer<Resource> > _resources;
QHash<QUrl, QWeakPointer<Resource>> _resources;
int _lastLRUKey = 0;
static int _requestLimit;
@ -118,7 +116,10 @@ private:
void getResourceAsynchronously(const QUrl& url);
QReadWriteLock _resourcesToBeGottenLock;
QQueue<QUrl> _resourcesToBeGotten;
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
qint64 _unusedResourcesSize = 0;
QMap<int, QSharedPointer<Resource>> _unusedResources;
};
/// Base class for resources.
@ -172,12 +173,11 @@ public:
const QUrl& getURL() const { return _url; }
signals:
/// Fired when the resource has been loaded.
void loaded();
void onRefresh();
protected slots:
void attemptRequest();
/// Refreshes the resource if the last modified date on the network
@ -185,7 +185,6 @@ protected slots:
void maybeRefresh();
protected:
virtual void init();
/// Called when the download has finished. The recipient should delete the reply when done with it.
@ -207,14 +206,12 @@ protected:
QPointer<ResourceCache> _cache;
private slots:
void handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void handleReplyError();
void handleReplyFinished();
void handleReplyTimeout();
private:
void setLRUKey(int lruKey) { _lruKey = lruKey; }
void makeRequest();

View file

@ -15,6 +15,7 @@
void AnimationHandle::setURL(const QUrl& url) {
if (_url != url) {
_animation = DependencyManager::get<AnimationCache>()->getAnimation(_url = url);
QObject::connect(_animation.data(), &Resource::onRefresh, this, &AnimationHandle::clearJoints);
_jointMappings.clear();
}
}
@ -110,11 +111,15 @@ void AnimationHandle::setAnimationDetails(const AnimationDetails& details) {
void AnimationHandle::simulate(float deltaTime) {
if (!_animation || !_animation->isLoaded()) {
return;
}
_animationLoop.simulate(deltaTime);
// update the joint mappings if necessary/possible
if (_jointMappings.isEmpty()) {
if (_model->isActive()) {
if (_model && _model->isActive()) {
_jointMappings = _model->getGeometry()->getJointMappings(_animation);
}
if (_jointMappings.isEmpty()) {
@ -146,6 +151,10 @@ void AnimationHandle::simulate(float deltaTime) {
}
void AnimationHandle::applyFrame(float frameIndex) {
if (!_animation || !_animation->isLoaded()) {
return;
}
const FBXGeometry& animationGeometry = _animation->getGeometry();
int frameCount = animationGeometry.animationFrames.size();
const FBXAnimationFrame& floorFrame = animationGeometry.animationFrames.at((int)glm::floor(frameIndex) % frameCount);

View file

@ -94,6 +94,8 @@ private:
void replaceMatchingPriorities(float newPriority);
void restoreJoints();
void clearJoints() { _jointMappings.clear(); }
Model* _model;
WeakAnimationHandlePointer _self;
AnimationPointer _animation;

View file

@ -1942,7 +1942,7 @@ QSharedPointer<NetworkGeometry> NetworkGeometry::getLODOrFallback(float distance
}
}
}
if (lod->isLoaded()) {
if (lod && lod->isLoaded()) {
hysteresis = lodDistance;
return lod;
}
@ -2061,21 +2061,16 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u
QSharedPointer<NetworkTexture> matchingTexture = QSharedPointer<NetworkTexture>();
if (part.diffuseTextureName == name) {
part.diffuseTexture =
textureCache->getTexture(url, DEFAULT_TEXTURE,
_geometry.meshes[i].isEye, QByteArray());
part.diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE, _geometry.meshes[i].isEye);
part.diffuseTexture->setLoadPriorities(_loadPriorities);
} else if (part.normalTextureName == name) {
part.normalTexture = textureCache->getTexture(url, DEFAULT_TEXTURE,
false, QByteArray());
part.normalTexture = textureCache->getTexture(url);
part.normalTexture->setLoadPriorities(_loadPriorities);
} else if (part.specularTextureName == name) {
part.specularTexture = textureCache->getTexture(url, DEFAULT_TEXTURE,
false, QByteArray());
part.specularTexture = textureCache->getTexture(url);
part.specularTexture->setLoadPriorities(_loadPriorities);
} else if (part.emissiveTextureName == name) {
part.emissiveTexture = textureCache->getTexture(url, DEFAULT_TEXTURE,
false, QByteArray());
part.emissiveTexture = textureCache->getTexture(url);
part.emissiveTexture->setLoadPriorities(_loadPriorities);
}
}
@ -2095,22 +2090,22 @@ QStringList NetworkGeometry::getTextureNames() const {
for (int j = 0; j < mesh.parts.size(); j++) {
const NetworkMeshPart& part = mesh.parts[j];
if (!part.diffuseTextureName.isEmpty()) {
if (!part.diffuseTextureName.isEmpty() && part.diffuseTexture) {
QString textureURL = part.diffuseTexture->getURL().toString();
result << part.diffuseTextureName + ":" + textureURL;
}
if (!part.normalTextureName.isEmpty()) {
if (!part.normalTextureName.isEmpty() && part.normalTexture) {
QString textureURL = part.normalTexture->getURL().toString();
result << part.normalTextureName + ":" + textureURL;
}
if (!part.specularTextureName.isEmpty()) {
if (!part.specularTextureName.isEmpty() && part.specularTexture) {
QString textureURL = part.specularTexture->getURL().toString();
result << part.specularTextureName + ":" + textureURL;
}
if (!part.emissiveTextureName.isEmpty()) {
if (!part.emissiveTextureName.isEmpty() && part.emissiveTexture) {
QString textureURL = part.emissiveTexture->getURL().toString();
result << part.emissiveTextureName + ":" + textureURL;
}

View file

@ -457,7 +457,8 @@ bool Model::updateGeometry() {
}
deleteGeometry();
_dilatedTextures.clear();
_geometry = geometry;
setGeometry(geometry);
_meshGroupsKnown = false;
_readyWhenAdded = false; // in case any of our users are using scenes
invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
@ -1142,13 +1143,32 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo
onInvalidate();
// if so instructed, keep the current geometry until the new one is loaded
_nextBaseGeometry = _nextGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, fallback, delayLoad);
_nextGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, fallback, delayLoad);
_nextLODHysteresis = NetworkGeometry::NO_HYSTERESIS;
if (!retainCurrent || !isActive() || (_nextGeometry && _nextGeometry->isLoaded())) {
applyNextGeometry();
}
}
void Model::geometryRefreshed() {
QObject* sender = QObject::sender();
if (sender == _geometry) {
_readyWhenAdded = false; // reset out render items.
_needsReload = true;
invalidCalculatedMeshBoxes();
onInvalidate();
// if so instructed, keep the current geometry until the new one is loaded
_nextGeometry = DependencyManager::get<GeometryCache>()->getGeometry(_url);
_nextLODHysteresis = NetworkGeometry::NO_HYSTERESIS;
applyNextGeometry();
} else {
sender->disconnect(this, SLOT(geometryRefreshed()));
}
}
const QSharedPointer<NetworkGeometry> Model::getCollisionGeometry(bool delayLoad)
{
@ -1156,7 +1176,11 @@ const QSharedPointer<NetworkGeometry> Model::getCollisionGeometry(bool delayLoad
_collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(_collisionUrl, QUrl(), delayLoad);
}
return _collisionGeometry;
if (_collisionGeometry && _collisionGeometry->isLoaded()) {
return _collisionGeometry;
}
return QSharedPointer<NetworkGeometry>();
}
void Model::setCollisionModelURL(const QUrl& url) {
@ -1776,6 +1800,18 @@ void Model::setBlendedVertices(int blendNumber, const QWeakPointer<NetworkGeomet
}
}
void Model::setGeometry(const QSharedPointer<NetworkGeometry>& newGeometry) {
if (_geometry == newGeometry) {
return;
}
if (_geometry) {
_geometry->disconnect(_geometry.data(), &Resource::onRefresh, this, &Model::geometryRefreshed);
}
_geometry = newGeometry;
QObject::connect(_geometry.data(), &Resource::onRefresh, this, &Model::geometryRefreshed);
}
void Model::applyNextGeometry() {
// delete our local geometry and custom textures
deleteGeometry();
@ -1783,13 +1819,12 @@ void Model::applyNextGeometry() {
_lodHysteresis = _nextLODHysteresis;
// we retain a reference to the base geometry so that its reference count doesn't fall to zero
_baseGeometry = _nextBaseGeometry;
_geometry = _nextGeometry;
setGeometry(_nextGeometry);
_meshGroupsKnown = false;
_readyWhenAdded = false; // in case any of our users are using scenes
_needsReload = false; // we are loaded now!
invalidCalculatedMeshBoxes();
_nextBaseGeometry.reset();
_nextGeometry.reset();
}

View file

@ -246,6 +246,7 @@ public:
protected:
QSharedPointer<NetworkGeometry> _geometry;
void setGeometry(const QSharedPointer<NetworkGeometry>& newGeometry);
glm::vec3 _scale;
glm::vec3 _offset;
@ -322,6 +323,9 @@ protected:
// hook for derived classes to be notified when setUrl invalidates the current model.
virtual void onInvalidate() {};
protected slots:
void geometryRefreshed();
private:
friend class AnimationHandle;
@ -331,15 +335,12 @@ private:
QVector<JointState> createJointStates(const FBXGeometry& geometry);
void initJointTransforms();
QSharedPointer<NetworkGeometry> _baseGeometry; ///< reference required to prevent collection of base
QSharedPointer<NetworkGeometry> _nextBaseGeometry;
QSharedPointer<NetworkGeometry> _nextGeometry;
float _lodDistance;
float _lodHysteresis;
float _nextLODHysteresis;
QSharedPointer<NetworkGeometry> _collisionGeometry;
QSharedPointer<NetworkGeometry> _saveNonCollisionGeometry;
float _pupilDilation;
QVector<float> _blendshapeCoefficients;
@ -525,7 +526,6 @@ private:
QMap<render::ItemID, render::PayloadPointer> _renderItems;
bool _readyWhenAdded = false;
bool _needsReload = true;
};
Q_DECLARE_METATYPE(QPointer<Model>)