mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 06:59:03 +02:00
possible fix for qml texture leak
This commit is contained in:
parent
3bc764a020
commit
d38dadaf58
5 changed files with 36 additions and 29 deletions
|
@ -135,10 +135,8 @@ void EntityRenderer::makeStatusGetters(const EntityItemPointer& entity, Item::St
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::shared_ptr<T> make_renderer(const EntityItemPointer& entity) {
|
std::shared_ptr<T> make_renderer(const EntityItemPointer& entity) {
|
||||||
T* rawResult = new T(entity);
|
|
||||||
|
|
||||||
// We want to use deleteLater so that renderer destruction gets pushed to the main thread
|
// We want to use deleteLater so that renderer destruction gets pushed to the main thread
|
||||||
return std::shared_ptr<T>(rawResult, std::bind(&QObject::deleteLater, rawResult));
|
return std::shared_ptr<T>(new T(entity), [](T* ptr) { ptr->deleteLater(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _entity(entity) {
|
EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _entity(entity) {
|
||||||
|
|
|
@ -34,7 +34,7 @@ static const QString WEB_ENTITY_QML = "controls/WebEntityView.qml";
|
||||||
|
|
||||||
const float METERS_TO_INCHES = 39.3701f;
|
const float METERS_TO_INCHES = 39.3701f;
|
||||||
static uint32_t _currentWebCount{ 0 };
|
static uint32_t _currentWebCount{ 0 };
|
||||||
// Don't allow more than 100 concurrent web views
|
// Don't allow more than 20 concurrent web views
|
||||||
static const uint32_t MAX_CONCURRENT_WEB_VIEWS = 20;
|
static const uint32_t MAX_CONCURRENT_WEB_VIEWS = 20;
|
||||||
// If a web-view hasn't been rendered for 30 seconds, de-allocate the framebuffer
|
// If a web-view hasn't been rendered for 30 seconds, de-allocate the framebuffer
|
||||||
static uint64_t MAX_NO_RENDER_INTERVAL = 30 * USECS_PER_SECOND;
|
static uint64_t MAX_NO_RENDER_INTERVAL = 30 * USECS_PER_SECOND;
|
||||||
|
@ -88,8 +88,14 @@ bool WebEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointe
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uvec2(getWindowSize(entity)) != toGlm(_webSurface->size())) {
|
{
|
||||||
return true;
|
QSharedPointer<OffscreenQmlSurface> webSurface;
|
||||||
|
withReadLock([&] {
|
||||||
|
webSurface = _webSurface;
|
||||||
|
});
|
||||||
|
if (webSurface && uvec2(getWindowSize(entity)) != toGlm(webSurface->size())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_lastSourceUrl != entity->getSourceUrl()) {
|
if (_lastSourceUrl != entity->getSourceUrl()) {
|
||||||
|
@ -108,9 +114,15 @@ bool WebEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointe
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebEntityRenderer::needsRenderUpdate() const {
|
bool WebEntityRenderer::needsRenderUpdate() const {
|
||||||
if (!_webSurface) {
|
{
|
||||||
// If we have rendered recently, and there is no web surface, we're going to create one
|
QSharedPointer<OffscreenQmlSurface> webSurface;
|
||||||
return true;
|
withReadLock([&] {
|
||||||
|
webSurface = _webSurface;
|
||||||
|
});
|
||||||
|
if (!webSurface) {
|
||||||
|
// If we have rendered recently, and there is no web surface, we're going to create one
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parent::needsRenderUpdate();
|
return Parent::needsRenderUpdate();
|
||||||
|
|
|
@ -37,9 +37,8 @@ static const int MIN_TIMER_MS = 5;
|
||||||
using namespace hifi::qml;
|
using namespace hifi::qml;
|
||||||
using namespace hifi::qml::impl;
|
using namespace hifi::qml::impl;
|
||||||
|
|
||||||
TextureCache offscreenTextures;
|
|
||||||
|
|
||||||
TextureCache& SharedObject::getTextureCache() {
|
TextureCache& SharedObject::getTextureCache() {
|
||||||
|
static TextureCache offscreenTextures;
|
||||||
return offscreenTextures;
|
return offscreenTextures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +242,7 @@ void SharedObject::releaseTextureAndFence() {
|
||||||
QMutexLocker lock(&_mutex);
|
QMutexLocker lock(&_mutex);
|
||||||
// If the most recent texture was unused, we can directly recycle it
|
// If the most recent texture was unused, we can directly recycle it
|
||||||
if (_latestTextureAndFence.first) {
|
if (_latestTextureAndFence.first) {
|
||||||
offscreenTextures.releaseTexture(_latestTextureAndFence);
|
getTextureCache().releaseTexture(_latestTextureAndFence);
|
||||||
_latestTextureAndFence = TextureAndFence{ 0, 0 };
|
_latestTextureAndFence = TextureAndFence{ 0, 0 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,7 +306,10 @@ bool SharedObject::preRender() {
|
||||||
void SharedObject::shutdownRendering(OffscreenGLCanvas& canvas, const QSize& size) {
|
void SharedObject::shutdownRendering(OffscreenGLCanvas& canvas, const QSize& size) {
|
||||||
QMutexLocker locker(&_mutex);
|
QMutexLocker locker(&_mutex);
|
||||||
if (size != QSize(0, 0)) {
|
if (size != QSize(0, 0)) {
|
||||||
offscreenTextures.releaseSize(size);
|
getTextureCache().releaseSize(size);
|
||||||
|
if (_latestTextureAndFence.first) {
|
||||||
|
getTextureCache().releaseTexture(_latestTextureAndFence);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_renderControl->invalidate();
|
_renderControl->invalidate();
|
||||||
canvas.doneCurrent();
|
canvas.doneCurrent();
|
||||||
|
@ -403,7 +405,7 @@ void SharedObject::onRender() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedObject::onTimer() {
|
void SharedObject::onTimer() {
|
||||||
offscreenTextures.report();
|
getTextureCache().report();
|
||||||
if (!_renderRequested) {
|
if (!_renderRequested) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -436,7 +438,7 @@ void SharedObject::updateTextureAndFence(const TextureAndFence& newTextureAndFen
|
||||||
QMutexLocker locker(&_mutex);
|
QMutexLocker locker(&_mutex);
|
||||||
// If the most recent texture was unused, we can directly recycle it
|
// If the most recent texture was unused, we can directly recycle it
|
||||||
if (_latestTextureAndFence.first) {
|
if (_latestTextureAndFence.first) {
|
||||||
offscreenTextures.releaseTexture(_latestTextureAndFence);
|
getTextureCache().releaseTexture(_latestTextureAndFence);
|
||||||
_latestTextureAndFence = { 0, 0 };
|
_latestTextureAndFence = { 0, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,6 @@
|
||||||
|
|
||||||
using namespace hifi::qml::impl;
|
using namespace hifi::qml::impl;
|
||||||
|
|
||||||
#if defined(Q_OS_ANDROID)
|
|
||||||
#define USE_GLES 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint64_t uvec2ToUint64(const QSize& size) {
|
uint64_t uvec2ToUint64(const QSize& size) {
|
||||||
uint64_t result = size.width();
|
uint64_t result = size.width();
|
||||||
result <<= 32;
|
result <<= 32;
|
||||||
|
@ -31,26 +27,23 @@ void TextureCache::acquireSize(const QSize& size) {
|
||||||
|
|
||||||
void TextureCache::releaseSize(const QSize& size) {
|
void TextureCache::releaseSize(const QSize& size) {
|
||||||
auto sizeKey = uvec2ToUint64(size);
|
auto sizeKey = uvec2ToUint64(size);
|
||||||
ValueList texturesToDelete;
|
|
||||||
{
|
{
|
||||||
Lock lock(_mutex);
|
Lock lock(_mutex);
|
||||||
assert(_textures.count(sizeKey));
|
assert(_textures.count(sizeKey));
|
||||||
auto& textureSet = _textures[sizeKey];
|
auto& textureSet = _textures[sizeKey];
|
||||||
if (0 == --textureSet.clientCount) {
|
if (0 == --textureSet.clientCount) {
|
||||||
texturesToDelete.swap(textureSet.returnedTextures);
|
for (const auto& textureAndFence : textureSet.returnedTextures) {
|
||||||
|
destroy(textureAndFence);
|
||||||
|
}
|
||||||
_textures.erase(sizeKey);
|
_textures.erase(sizeKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto& textureAndFence : texturesToDelete) {
|
|
||||||
destroy(textureAndFence);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t TextureCache::acquireTexture(const QSize& size) {
|
uint32_t TextureCache::acquireTexture(const QSize& size) {
|
||||||
Lock lock(_mutex);
|
Lock lock(_mutex);
|
||||||
recycle();
|
recycle();
|
||||||
|
|
||||||
|
|
||||||
++_activeTextureCount;
|
++_activeTextureCount;
|
||||||
auto sizeKey = uvec2ToUint64(size);
|
auto sizeKey = uvec2ToUint64(size);
|
||||||
assert(_textures.count(sizeKey));
|
assert(_textures.count(sizeKey));
|
||||||
|
@ -83,7 +76,12 @@ void TextureCache::report() {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t TextureCache::getUsedTextureMemory() {
|
size_t TextureCache::getUsedTextureMemory() {
|
||||||
return _totalTextureUsage;
|
size_t toReturn;
|
||||||
|
{
|
||||||
|
Lock lock(_mutex);
|
||||||
|
toReturn = _totalTextureUsage;
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t TextureCache::getMemoryForSize(const QSize& size) {
|
size_t TextureCache::getMemoryForSize(const QSize& size) {
|
||||||
|
@ -122,8 +120,6 @@ uint32_t TextureCache::createTexture(const QSize& size) {
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f);
|
|
||||||
#if !defined(USE_GLES)
|
#if !defined(USE_GLES)
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.2f);
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.2f);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -41,7 +41,6 @@ public:
|
||||||
ValueList returnedTextures;
|
ValueList returnedTextures;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void releaseSize(const QSize& size);
|
void releaseSize(const QSize& size);
|
||||||
void acquireSize(const QSize& size);
|
void acquireSize(const QSize& size);
|
||||||
uint32_t acquireTexture(const QSize& size);
|
uint32_t acquireTexture(const QSize& size);
|
||||||
|
|
Loading…
Reference in a new issue