mirror of
https://github.com/overte-org/overte.git
synced 2025-08-24 13:07:06 +02:00
Merge pull request #7533 from zzmp/fix/model-release-texs
Release textures from cache
This commit is contained in:
commit
ef7febfcaf
11 changed files with 82 additions and 25 deletions
|
@ -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) {}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue