summaryrefslogtreecommitdiffstats
path: root/tests/auto/qgl
diff options
context:
space:
mode:
authorTom Cooksey <thomas.cooksey@nokia.com>2010-01-29 10:39:06 (GMT)
committerTom Cooksey <thomas.cooksey@nokia.com>2010-01-29 14:29:42 (GMT)
commit9e95ce2a68ef167e17dccc5789cbf3bf74712280 (patch)
tree1fc5e33c239a32905dfd6692292e363d6783b88e /tests/auto/qgl
parente2f9547983c15be88c0a096dd52cc7c7a0eac0c6 (diff)
downloadQt-9e95ce2a68ef167e17dccc5789cbf3bf74712280.zip
Qt-9e95ce2a68ef167e17dccc5789cbf3bf74712280.tar.gz
Qt-9e95ce2a68ef167e17dccc5789cbf3bf74712280.tar.bz2
Fix GL texture leaks when pixmaps are deleted
This fixes quite a lot of issues: * QtOpenGL only registered qpixmap destruction hooks on X11 and those only cleanup the EGL/GLX surface, not the texture object. * The QPixmap destruction hooks were only being called from the QPixmap destructor. However, this means when a QPixmap is assigned to another QPixmap, the hooks don't get called. Task-number: QTBUG-7647 Reviewed-By: Samuel Reviewed-By: Trond
Diffstat (limited to 'tests/auto/qgl')
-rw-r--r--tests/auto/qgl/qgl.pro4
-rw-r--r--tests/auto/qgl/qgl.qrc5
-rw-r--r--tests/auto/qgl/tst_qgl.cpp240
3 files changed, 247 insertions, 2 deletions
diff --git a/tests/auto/qgl/qgl.pro b/tests/auto/qgl/qgl.pro
index 420c4bb..9116f39 100644
--- a/tests/auto/qgl/qgl.pro
+++ b/tests/auto/qgl/qgl.pro
@@ -6,6 +6,6 @@ load(qttest_p4)
requires(contains(QT_CONFIG,opengl))
QT += opengl
-SOURCES += tst_qgl.cpp
-
+SOURCES += tst_qgl.cpp
+RESOURCES = qgl.qrc
diff --git a/tests/auto/qgl/qgl.qrc b/tests/auto/qgl/qgl.qrc
new file mode 100644
index 0000000..653794a
--- /dev/null
+++ b/tests/auto/qgl/qgl.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file alias="designer.png">../qpixmap/images/designer.png</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/qgl/tst_qgl.cpp b/tests/auto/qgl/tst_qgl.cpp
index cf4616e..d37d727 100644
--- a/tests/auto/qgl/tst_qgl.cpp
+++ b/tests/auto/qgl/tst_qgl.cpp
@@ -56,6 +56,7 @@
#ifdef QT_BUILD_INTERNAL
#include <QtOpenGL/private/qgl_p.h>
+#include <QtGui/private/qpixmapdata_p.h>
#endif
//TESTED_CLASS=
@@ -91,6 +92,8 @@ private slots:
void clipTest();
void destroyFBOAfterContext();
void shareRegister();
+ void qglContextDefaultBindTexture();
+ void textureCleanup();
};
tst_QGL::tst_QGL()
@@ -1938,5 +1941,242 @@ void tst_QGL::shareRegister()
#endif
}
+// Tests QGLContext::bindTexture with default options
+void tst_QGL::qglContextDefaultBindTexture()
+{
+#ifdef QT_BUILD_INTERNAL
+ QGLWidget w;
+ w.makeCurrent();
+
+ QGLContext *ctx = const_cast<QGLContext*>(w.context());
+
+ QImage *boundImage = new QImage(256, 256, QImage::Format_RGB32);
+ boundImage->fill(0xFFFFFFFF);
+ QPixmap *boundPixmap = new QPixmap(256, 256);
+ boundPixmap->fill(Qt::red);
+
+ // Check that calling QGLContext::bindTexture with default args adds textures to cache
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+ GLuint boundImageTextureId = ctx->bindTexture(*boundImage);
+ GLuint boundPixmapTextureId = ctx->bindTexture(*boundPixmap);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ // Make sure the texture IDs returned are valid:
+ QCOMPARE((bool)glIsTexture(boundImageTextureId), GL_TRUE);
+ QCOMPARE((bool)glIsTexture(boundPixmapTextureId), GL_TRUE);
+
+ // Make sure the textures are still there after we delete the image/pixmap:
+ delete boundImage;
+ boundImage = 0;
+ delete boundPixmap;
+ boundPixmap = 0;
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ // Make sure the textures are deleted from the cache after calling QGLContext::deleteTexture()
+ ctx->deleteTexture(boundImageTextureId);
+ ctx->deleteTexture(boundPixmapTextureId);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ // Finally, make sure QGLContext::deleteTexture also deleted the texture IDs:
+ QCOMPARE((bool)glIsTexture(boundImageTextureId), GL_FALSE);
+ QCOMPARE((bool)glIsTexture(boundPixmapTextureId), GL_FALSE);
+#endif
+}
+
+void tst_QGL::textureCleanup()
+{
+#ifdef QT_BUILD_INTERNAL
+ QGLWidget w;
+ w.resize(200,200);
+ w.show();
+ w.makeCurrent();
+
+ // Test pixmaps which have been loaded via QPixmapCache are removed from the texture cache
+ // when the pixmap cache is cleared
+ {
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+ QPainter p(&w);
+
+ QPixmap boundPixmap(":designer.png");
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ p.drawPixmap(0, 0, boundPixmap);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
+ p.end();
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ // Check that the texture doesn't get removed from the cache when the pixmap is cleared
+ // as it should still be in the cache:
+ boundPixmap = QPixmap();
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ QPixmapCache::clear();
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+ }
+
+ // Test pixmaps which have been loaded via QPixmapCache are removed from the texture cache
+ // when they are explicitly removed from the pixmap cache
+ {
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+ QPainter p(&w);
+
+ QPixmap boundPixmap(128, 128);
+ QString cacheKey = QString::fromLatin1("myPixmap");
+ QPixmapCache::insert(cacheKey, boundPixmap);
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ p.drawPixmap(0, 0, boundPixmap);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
+ p.end();
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ // Check that the texture doesn't get removed from the cache when the pixmap is cleared
+ // as it should still be in the cache:
+ boundPixmap = QPixmap();
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ // Finally, we check that the texture cache entry is removed when we remove the
+ // pixmap cache entry, which should hold the last reference:
+ QPixmapCache::remove(cacheKey);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+ }
+
+ // Check images & pixmaps are removed from the cache when they are deleted
+ {
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+ QPainter p(&w);
+
+ QImage *boundImage = new QImage(256, 256, QImage::Format_RGB32);
+ boundImage->fill(0xFFFFFFFF);
+ QPixmap *boundPixmap = new QPixmap(256, 256);
+ boundPixmap->fill(Qt::red);
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ p.drawImage(0, 0, *boundImage);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ p.drawPixmap(0, 0, *boundPixmap);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
+ p.end();
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ delete boundImage;
+ boundImage = 0;
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ delete boundPixmap;
+ boundPixmap = 0;
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+ }
+
+ // Check images & pixmaps are removed from the cache when they are assigned to
+ {
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+ QPainter p(&w);
+
+ QImage boundImage(256, 256, QImage::Format_RGB32);
+ boundImage.fill(0xFFFFFFFF);
+ QPixmap boundPixmap(256, 256);
+ boundPixmap.fill(Qt::red);
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ p.drawImage(0, 0, boundImage);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ p.drawPixmap(0, 0, boundPixmap);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
+ p.end();
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ boundImage = QImage(64, 64, QImage::Format_RGB32);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ boundPixmap = QPixmap(64, 64);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+ }
+
+ // Check images & pixmaps are removed from the cache when they are modified (detached)
+ {
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+ QPainter p(&w);
+
+ QImage boundImage(256, 256, QImage::Format_RGB32);
+ boundImage.fill(0xFFFFFFFF);
+ QPixmap boundPixmap(256, 256);
+ boundPixmap.fill(Qt::red);
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ p.drawImage(0, 0, boundImage);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ p.drawPixmap(0, 0, boundPixmap);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
+ p.end();
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ boundImage.fill(0x00000000);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ boundPixmap.fill(Qt::blue);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+ }
+
+ // Check that images/pixmaps aren't removed from the cache if a shallow copy has been made
+ QImage copyOfImage;
+ QPixmap copyOfPixmap;
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+ {
+ QPainter p(&w);
+
+ QImage boundImage(256, 256, QImage::Format_RGB32);
+ boundImage.fill(0xFFFFFFFF);
+ QPixmap boundPixmap(256, 256);
+ boundPixmap.fill(Qt::red);
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ p.drawImage(0, 0, boundImage);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ p.drawPixmap(0, 0, boundPixmap);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
+ p.end();
+
+ copyOfImage = boundImage;
+ copyOfPixmap = boundPixmap;
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+ } // boundImage & boundPixmap would have been deleted when they went out of scope
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ copyOfImage = QImage();
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ copyOfPixmap = QPixmap();
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+#endif
+}
+
QTEST_MAIN(tst_QGL)
#include "tst_qgl.moc"