aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRobert Griebl <robert.griebl@pelagicore.com>2015-04-15 13:57:51 +0200
committerRobert Griebl <robert.griebl@pelagicore.com>2015-04-23 15:00:46 +0000
commit92433623b31388e2e8c4d532033dad6189eaab24 (patch)
tree1a20685ae0f7e5d3137ca001c2c222ae16aaf241 /src
parent3fdec636980c23b14cfc6aa74bc48bbb960ba0b4 (diff)
Fix a memory leak in the material shader cache.
There were multiple problems in the implementation of the shader cache: 1) it was not thread-safe 2) nothing was ever removed from the hash 3) since the keys into the hash are the actual shader source code, problem #2 would lead to serious memory consumption over time Change-Id: I20d1fb2074932e23f89edddba12e68ab8adcbff0 Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
Diffstat (limited to 'src')
-rw-r--r--src/quick/items/qquickshadereffectnode.cpp28
-rw-r--r--src/quick/items/qquickshadereffectnode_p.h4
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp4
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp4
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp4
5 files changed, 39 insertions, 5 deletions
diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp
index 3542fbb27f..e593112ef5 100644
--- a/src/quick/items/qquickshadereffectnode.cpp
+++ b/src/quick/items/qquickshadereffectnode.cpp
@@ -38,6 +38,7 @@
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qsgshadersourcebuilder_p.h>
#include <QtQuick/private/qsgtexture_p.h>
+#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
@@ -348,7 +349,10 @@ uint qHash(const QQuickShaderEffectMaterialKey &key)
}
-QHash<QQuickShaderEffectMaterialKey, QSharedPointer<QSGMaterialType> > QQuickShaderEffectMaterial::materialMap;
+typedef QHash<QQuickShaderEffectMaterialKey, QWeakPointer<QSGMaterialType> > MaterialHash;
+
+Q_GLOBAL_STATIC(MaterialHash, materialHash)
+Q_GLOBAL_STATIC(QMutex, materialHashMutex)
QQuickShaderEffectMaterial::QQuickShaderEffectMaterial(QQuickShaderEffectNode *node)
: cullMode(NoCulling)
@@ -403,12 +407,30 @@ int QQuickShaderEffectMaterial::compare(const QSGMaterial *o) const
void QQuickShaderEffectMaterial::setProgramSource(const QQuickShaderEffectMaterialKey &source)
{
+ QMutexLocker locker(materialHashMutex);
+ Q_UNUSED(locker);
+
m_source = source;
m_emittedLogChanged = false;
- m_type = materialMap.value(m_source);
+ QWeakPointer<QSGMaterialType> weakPtr = materialHash->value(m_source);
+ m_type = weakPtr.toStrongRef();
+
if (m_type.isNull()) {
m_type = QSharedPointer<QSGMaterialType>(new QSGMaterialType);
- materialMap.insert(m_source, m_type);
+ materialHash->insert(m_source, m_type.toWeakRef());
+ }
+}
+
+void QQuickShaderEffectMaterial::cleanupMaterialCache()
+{
+ QMutexLocker locker(materialHashMutex);
+ Q_UNUSED(locker);
+
+ for (MaterialHash::iterator it = materialHash->begin(); it != materialHash->end(); ) {
+ if (!it.value().toStrongRef())
+ it = materialHash->erase(it);
+ else
+ ++it;
}
}
diff --git a/src/quick/items/qquickshadereffectnode_p.h b/src/quick/items/qquickshadereffectnode_p.h
index 7e3cf74276..28382c483c 100644
--- a/src/quick/items/qquickshadereffectnode_p.h
+++ b/src/quick/items/qquickshadereffectnode_p.h
@@ -101,6 +101,8 @@ public:
void updateTextures() const;
void invalidateTextureProvider(QSGTextureProvider *provider);
+ static void cleanupMaterialCache();
+
protected:
friend class QQuickCustomMaterialShader;
@@ -115,8 +117,6 @@ protected:
QQuickShaderEffectNode *m_node;
bool m_emittedLogChanged;
-
- static QHash<QQuickShaderEffectMaterialKey, QSharedPointer<QSGMaterialType> > materialMap;
};
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index ce3bf7d61d..b7a6475c23 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -52,6 +52,8 @@
#include <QtQuick/private/qsgcontext_p.h>
#include <private/qquickprofiler_p.h>
+#include <private/qquickshadereffectnode_p.h>
+
#ifdef Q_OS_WIN
# include <QtCore/qt_windows.h>
#endif
@@ -293,6 +295,8 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
if (Q_UNLIKELY(!current))
qCDebug(QSG_LOG_RENDERLOOP) << "cleanup without an OpenGL context";
+ QQuickShaderEffectMaterial::cleanupMaterialCache();
+
d->cleanupNodesOnShutdown();
if (m_windows.size() == 0) {
rc->invalidate();
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 7b1e24246b..26a0e78254 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -56,6 +56,8 @@
#include <private/qquickprofiler_p.h>
#include <private/qqmldebugservice_p.h>
+#include <private/qquickshadereffectnode_p.h>
+
/*
Overall design:
@@ -449,6 +451,8 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor,
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- cleanup without an OpenGL context";
}
+ QQuickShaderEffectMaterial::cleanupMaterialCache();
+
// The canvas nodes must be cleaned up regardless if we are in the destructor..
if (wipeSG) {
QQuickWindowPrivate *dd = QQuickWindowPrivate::get(window);
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 0e22fa8b7b..309e877dae 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -48,6 +48,8 @@
#include <private/qquickprofiler_p.h>
+#include <private/qquickshadereffectnode_p.h>
+
QT_BEGIN_NAMESPACE
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
@@ -232,6 +234,8 @@ void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window)
if (Q_UNLIKELY(!current))
qCDebug(QSG_LOG_RENDERLOOP) << "cleanup without an OpenGL context";
+ QQuickShaderEffectMaterial::cleanupMaterialCache();
+
d->cleanupNodesOnShutdown();
if (m_windows.size() == 0) {
d->context->invalidate();