Merge pull request #7533 from zzmp/fix/model-release-texs

Release textures from cache
This commit is contained in:
Brad Davis 2016-03-31 18:58:01 -07:00
commit ef7febfcaf
11 changed files with 82 additions and 25 deletions

View file

@ -36,7 +36,7 @@ AnimationPointer AnimationCache::getAnimation(const QUrl& url) {
QSharedPointer<Resource> AnimationCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
bool delayLoad, const void* extra) {
return QSharedPointer<Resource>(new Animation(url), &Resource::allReferencesCleared);
return QSharedPointer<Resource>(new Animation(url), &Resource::deleter);
}
Animation::Animation(const QUrl& url) : Resource(url) {}

View file

@ -36,5 +36,5 @@ SharedSoundPointer SoundCache::getSound(const QUrl& url) {
QSharedPointer<Resource> SoundCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
bool delayLoad, const void* extra) {
qCDebug(audio) << "Requesting sound at" << url.toString();
return QSharedPointer<Resource>(new Sound(url), &Resource::allReferencesCleared);
return QSharedPointer<Resource>(new Sound(url), &Resource::deleter);
}

View file

@ -457,6 +457,14 @@ uint32 Texture::getStoredMipSize(uint16 level) const {
return 0;
}
gpu::Resource::Size Texture::getStoredSize() const {
auto size = 0;
for (int level = 0; level < evalNumMips(); ++level) {
size += getStoredMipSize(level);
}
return size;
}
uint16 Texture::evalNumSamplesUsed(uint16 numSamplesTried) {
uint16 sample = numSamplesTried;
if (numSamplesTried <= 1)

View file

@ -288,9 +288,12 @@ public:
Stamp getStamp() const { return _stamp; }
Stamp getDataStamp() const { return _storage->getStamp(); }
// The size in bytes of data stored in the texture
// The theoretical size in bytes of data stored in the texture
Size getSize() const { return _size; }
// The actual size in bytes of data stored in the texture
Size getStoredSize() const;
// Resize, unless auto mips mode would destroy all the sub mips
Size resize1D(uint16 width, uint16 numSamples);
Size resize2D(uint16 width, uint16 height, uint16 numSamples);

View file

@ -67,15 +67,14 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) {
// Get the raw GeometryResource, not the wrapped NetworkGeometry
_geometryResource = modelCache->getResource(url, QUrl(), false, &extra).staticCast<GeometryResource>();
// Avoid caching nested resources - their references will be held by the parent
_geometryResource->_isCacheable = false;
if (_geometryResource->isLoaded()) {
onGeometryMappingLoaded(!_geometryResource->getURL().isEmpty());
} else {
connect(_geometryResource.data(), &Resource::finished, this, &GeometryMappingResource::onGeometryMappingLoaded);
}
// Avoid caching nested resources - their references will be held by the parent
_geometryResource->_isCacheable = false;
}
}
@ -86,6 +85,10 @@ void GeometryMappingResource::onGeometryMappingLoaded(bool success) {
_meshes = _geometryResource->_meshes;
_materials = _geometryResource->_materials;
}
// Avoid holding onto extra references
_geometryResource.reset();
finishedLoading(success);
}
@ -157,7 +160,7 @@ class GeometryDefinitionResource : public GeometryResource {
Q_OBJECT
public:
GeometryDefinitionResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) :
GeometryResource(url), _mapping(mapping), _textureBaseUrl(textureBaseUrl.isValid() ? textureBaseUrl : url) {}
GeometryResource(url, textureBaseUrl.isValid() ? textureBaseUrl : url), _mapping(mapping) {}
virtual void downloadFinished(const QByteArray& data) override;
@ -166,7 +169,6 @@ protected:
private:
QVariantHash _mapping;
QUrl _textureBaseUrl;
};
void GeometryDefinitionResource::downloadFinished(const QByteArray& data) {
@ -220,13 +222,20 @@ QSharedPointer<Resource> ModelCache::createResource(const QUrl& url, const QShar
resource = new GeometryDefinitionResource(url, geometryExtra->mapping, geometryExtra->textureBaseUrl);
}
return QSharedPointer<Resource>(resource, &Resource::allReferencesCleared);
return QSharedPointer<Resource>(resource, &Resource::deleter);
}
std::shared_ptr<NetworkGeometry> ModelCache::getGeometry(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) {
GeometryExtra geometryExtra = { mapping, textureBaseUrl };
GeometryResource::Pointer resource = getResource(url, QUrl(), true, &geometryExtra).staticCast<GeometryResource>();
return resource ? std::make_shared<NetworkGeometry>(resource) : NetworkGeometry::Pointer();
if (resource) {
if (resource->isLoaded() && !resource->hasTextures()) {
resource->setTextures();
}
return std::make_shared<NetworkGeometry>(resource);
} else {
return NetworkGeometry::Pointer();
}
}
const QVariantMap Geometry::getTextures() const {
@ -313,6 +322,21 @@ const std::shared_ptr<const NetworkMaterial> Geometry::getShapeMaterial(int shap
return nullptr;
}
void GeometryResource::deleter() {
resetTextures();
Resource::deleter();
}
void GeometryResource::setTextures() {
for (const FBXMaterial& material : _geometry->materials) {
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl));
}
}
void GeometryResource::resetTextures() {
_materials.clear();
}
NetworkGeometry::NetworkGeometry(const GeometryResource::Pointer& networkGeometry) : _resource(networkGeometry) {
connect(_resource.data(), &Resource::finished, this, &NetworkGeometry::resourceFinished);
connect(_resource.data(), &Resource::onRefresh, this, &NetworkGeometry::resourceRefreshed);

View file

@ -99,15 +99,24 @@ class GeometryResource : public Resource, public Geometry {
public:
using Pointer = QSharedPointer<GeometryResource>;
GeometryResource(const QUrl& url) : Resource(url) {}
GeometryResource(const QUrl& url, const QUrl& textureBaseUrl = QUrl()) : Resource(url) {}
virtual bool areTexturesLoaded() const { return isLoaded() && Geometry::areTexturesLoaded(); }
virtual void deleter() override;
protected:
friend class ModelCache;
friend class GeometryMappingResource;
virtual bool isCacheable() const override { return _loaded && _isCacheable; }
// Geometries may not hold onto textures while cached - that is for the texture cache
bool hasTextures() const { return !_materials.empty(); }
void setTextures();
void resetTextures();
QUrl _textureBaseUrl;
virtual bool isCacheable() const override { return _loaded && _isCacheable; }
bool _isCacheable { true };
};

View file

@ -28,6 +28,6 @@ NetworkShaderPointer ShaderCache::getShader(const QUrl& url) {
}
QSharedPointer<Resource> ShaderCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
return QSharedPointer<Resource>(new NetworkShader(url, delayLoad), &Resource::allReferencesCleared);
return QSharedPointer<Resource>(new NetworkShader(url, delayLoad), &Resource::deleter);
}

View file

@ -166,12 +166,11 @@ gpu::TexturePointer TextureCache::getImageTexture(const QString& path) {
return texture;
}
QSharedPointer<Resource> TextureCache::createResource(const QUrl& url,
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
const TextureExtra* textureExtra = static_cast<const TextureExtra*>(extra);
return QSharedPointer<Resource>(new NetworkTexture(url, textureExtra->type, textureExtra->content),
&Resource::allReferencesCleared);
&Resource::deleter);
}
NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content) :
@ -339,10 +338,13 @@ void NetworkTexture::setImage(void* voidTexture, int originalWidth,
if (gpuTexture) {
_width = gpuTexture->getWidth();
_height = gpuTexture->getHeight();
setBytes(gpuTexture->getStoredSize());
} else {
// FIXME: If !gpuTexture, we failed to load!
_width = _height = 0;
qWarning() << "Texture did not load";
}
finishedLoading(true);
emit networkTextureCreated(qWeakPointerCast<NetworkTexture, Resource> (_self));

View file

@ -117,22 +117,22 @@ void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) {
}
void ResourceCache::addUnusedResource(const QSharedPointer<Resource>& resource) {
if (resource->getBytesTotal() > _unusedResourcesMaxSize) {
// If it doesn't fit anyway, let's leave whatever is already in the cache.
// If it doesn't fit or its size is unknown, leave the cache alone.
if (resource->getBytes() == 0 || resource->getBytes() > _unusedResourcesMaxSize) {
resource->setCache(nullptr);
return;
}
reserveUnusedResource(resource->getBytesTotal());
reserveUnusedResource(resource->getBytes());
resource->setLRUKey(++_lastLRUKey);
_unusedResources.insert(resource->getLRUKey(), resource);
_unusedResourcesSize += resource->getBytesTotal();
_unusedResourcesSize += resource->getBytes();
}
void ResourceCache::removeUnusedResource(const QSharedPointer<Resource>& resource) {
if (_unusedResources.contains(resource->getLRUKey())) {
_unusedResources.remove(resource->getLRUKey());
_unusedResourcesSize -= resource->getBytesTotal();
_unusedResourcesSize -= resource->getBytes();
}
}
@ -142,7 +142,7 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
// unload the oldest resource
QMap<int, QSharedPointer<Resource> >::iterator it = _unusedResources.begin();
_unusedResourcesSize -= it.value()->getBytesTotal();
_unusedResourcesSize -= it.value()->getBytes();
it.value()->setCache(nullptr);
_unusedResources.erase(it);
}
@ -399,7 +399,7 @@ void Resource::makeRequest() {
connect(_request, &ResourceRequest::progress, this, &Resource::handleDownloadProgress);
connect(_request, &ResourceRequest::finished, this, &Resource::handleReplyFinished);
_bytesReceived = _bytesTotal = 0;
_bytesReceived = _bytesTotal = _bytes = 0;
_request->send();
}
@ -412,6 +412,8 @@ 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;
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.
qWarning(networking) << "Received signal Resource::handleReplyFinished from ResourceRequest that is not the current"

View file

@ -181,6 +181,9 @@ public:
/// For loading resources, returns the number of total bytes (<= zero if unknown).
qint64 getBytesTotal() const { return _bytesTotal; }
/// For loaded resources, returns the number of actual bytes (defaults to total bytes if not explicitly set).
qint64 getBytes() const { return _bytes; }
/// For loading resources, returns the load progress.
float getProgress() const { return (_bytesTotal <= 0) ? 0.0f : (float)_bytesReceived / _bytesTotal; }
@ -191,7 +194,7 @@ public:
void setCache(ResourceCache* cache) { _cache = cache; }
Q_INVOKABLE void allReferencesCleared();
virtual void deleter() { allReferencesCleared(); }
const QUrl& getURL() const { return _url; }
@ -222,10 +225,15 @@ protected:
/// This should be overridden by subclasses that need to process the data once it is downloaded.
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; }
/// Called when the download is finished and processed.
/// This should be called by subclasses that override downloadFinished to mark the end of processing.
Q_INVOKABLE void finishedLoading(bool success);
Q_INVOKABLE void allReferencesCleared();
QUrl _url;
QUrl _activeUrl;
bool _startedLoading = false;
@ -253,6 +261,7 @@ private:
QTimer* _replyTimer = nullptr;
qint64 _bytesReceived = 0;
qint64 _bytesTotal = 0;
qint64 _bytes = 0;
int _attempts = 0;
};

View file

@ -36,6 +36,6 @@ NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) {
}
QSharedPointer<Resource> ClipCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
return QSharedPointer<Resource>(new NetworkClipLoader(url, delayLoad), &Resource::allReferencesCleared);
return QSharedPointer<Resource>(new NetworkClipLoader(url, delayLoad), &Resource::deleter);
}