summaryrefslogtreecommitdiffstats
path: root/src/openvg
diff options
context:
space:
mode:
authorRhys Weatherley <rhys.weatherley@nokia.com>2009-12-15 11:11:20 +1000
committerRhys Weatherley <rhys.weatherley@nokia.com>2009-12-15 13:48:12 +1000
commitc5ae0ffd52ee3f2964404bf85dee55712fb6bd8c (patch)
treec84a17960411bafcc9d9431928c99a86c1aa909a /src/openvg
parent36949134f109c72b8aba174ebf4d618f91a9f7ce (diff)
Add an image allocation pool to the OpenVG paint engine
Some OpenVG GPU's have limitations on the amount of memory available to create VGImage's. When the memory runs out, vgCreateImage() will fail. This change introduces QVGImagePool, which keeps track of all QVGPixmapData image allocations and ejects least-recently-used pixmaps when GPU memory is exhausted. Task-number: QT-2554 Reviewed-by: trustme
Diffstat (limited to 'src/openvg')
-rw-r--r--src/openvg/openvg.pro6
-rw-r--r--src/openvg/qpaintengine_vg.cpp16
-rw-r--r--src/openvg/qpixmapdata_vg.cpp92
-rw-r--r--src/openvg/qpixmapdata_vg_p.h17
-rw-r--r--src/openvg/qpixmapfilter_vg.cpp25
-rw-r--r--src/openvg/qvgimagepool.cpp215
-rw-r--r--src/openvg/qvgimagepool_p.h157
-rw-r--r--src/openvg/qwindowsurface_vgegl.cpp4
8 files changed, 479 insertions, 53 deletions
diff --git a/src/openvg/openvg.pro b/src/openvg/openvg.pro
index 8927c4c00f..c8c991720f 100644
--- a/src/openvg/openvg.pro
+++ b/src/openvg/openvg.pro
@@ -16,11 +16,13 @@ HEADERS += \
qpaintengine_vg_p.h \
qpixmapdata_vg_p.h \
qpixmapfilter_vg_p.h \
- qvgcompositionhelper_p.h
+ qvgcompositionhelper_p.h \
+ qvgimagepool_p.h
SOURCES += \
qpaintengine_vg.cpp \
qpixmapdata_vg.cpp \
- qpixmapfilter_vg.cpp
+ qpixmapfilter_vg.cpp \
+ qvgimagepool.cpp
contains(QT_CONFIG, egl) {
HEADERS += \
diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp
index 6b829dd45c..04fee085de 100644
--- a/src/openvg/qpaintengine_vg.cpp
+++ b/src/openvg/qpaintengine_vg.cpp
@@ -43,6 +43,7 @@
#include "qpixmapdata_vg_p.h"
#include "qpixmapfilter_vg_p.h"
#include "qvgcompositionhelper_p.h"
+#include "qvgimagepool_p.h"
#if !defined(QT_NO_EGL)
#include <QtGui/private/qegl_p.h>
#include "qwindowsurface_vgegl_p.h"
@@ -1018,7 +1019,7 @@ static VGImage toVGImage
const uchar *pixels = img.bits();
- VGImage vgImg = vgCreateImage
+ VGImage vgImg = QVGImagePool::instance()->createPermanentImage
(format, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
vgImageSubData
(vgImg, pixels, img.bytesPerLine(), format, 0, 0,
@@ -1063,7 +1064,7 @@ static VGImage toVGImageSubRect
const uchar *pixels = img.bits() + bpp * sr.x() +
img.bytesPerLine() * sr.y();
- VGImage vgImg = vgCreateImage
+ VGImage vgImg = QVGImagePool::instance()->createPermanentImage
(format, sr.width(), sr.height(), VG_IMAGE_QUALITY_FASTER);
vgImageSubData
(vgImg, pixels, img.bytesPerLine(), format, 0, 0,
@@ -1084,7 +1085,7 @@ static VGImage toVGImageWithOpacity(const QImage & image, qreal opacity)
const uchar *pixels = img.bits();
- VGImage vgImg = vgCreateImage
+ VGImage vgImg = QVGImagePool::instance()->createPermanentImage
(VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
vgImageSubData
(vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0,
@@ -1106,7 +1107,7 @@ static VGImage toVGImageWithOpacitySubRect
const uchar *pixels = img.bits();
- VGImage vgImg = vgCreateImage
+ VGImage vgImg = QVGImagePool::instance()->createPermanentImage
(VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
vgImageSubData
(vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0,
@@ -1194,6 +1195,12 @@ VGPaintType QVGPaintEnginePrivate::setBrush
if (pd->classId() == QPixmapData::OpenVGClass) {
QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
vgImg = vgpd->toVGImage();
+
+ // We don't want the pool to reclaim this image
+ // because we cannot predict when the paint object
+ // will stop using it. Replacing the image with
+ // new data will make the paint object invalid.
+ vgpd->detachImageFromPool();
} else {
vgImg = toVGImage(*(pd->buffer()));
deref = true;
@@ -1201,6 +1208,7 @@ VGPaintType QVGPaintEnginePrivate::setBrush
} else if (pd->classId() == QPixmapData::OpenVGClass) {
QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
vgImg = vgpd->toVGImage(opacity);
+ vgpd->detachImageFromPool();
} else {
vgImg = toVGImageWithOpacity(*(pd->buffer()), opacity);
deref = true;
diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp
index af6f0f0044..358ec4d825 100644
--- a/src/openvg/qpixmapdata_vg.cpp
+++ b/src/openvg/qpixmapdata_vg.cpp
@@ -43,6 +43,7 @@
#include "qpaintengine_vg_p.h"
#include <QtGui/private/qdrawhelper_p.h>
#include "qvg_p.h"
+#include "qvgimagepool_p.h"
#ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE
#include <graphics/sgimage.h>
@@ -63,6 +64,8 @@ QVGPixmapData::QVGPixmapData(PixelType type)
vgImageOpacity = VG_INVALID_HANDLE;
cachedOpacity = 1.0f;
recreate = true;
+ inImagePool = false;
+ inLRU = false;
#if !defined(QT_NO_EGL)
context = 0;
qt_vg_register_pixmap(this);
@@ -78,32 +81,43 @@ QVGPixmapData::~QVGPixmapData()
#endif
}
+void QVGPixmapData::destroyImages()
+{
+ if (inImagePool) {
+ QVGImagePool *pool = QVGImagePool::instance();
+ if (vgImage != VG_INVALID_HANDLE)
+ pool->releaseImage(this, vgImage);
+ if (vgImageOpacity != VG_INVALID_HANDLE)
+ pool->releaseImage(this, vgImageOpacity);
+ } else {
+ if (vgImage != VG_INVALID_HANDLE)
+ vgDestroyImage(vgImage);
+ if (vgImageOpacity != VG_INVALID_HANDLE)
+ vgDestroyImage(vgImageOpacity);
+ }
+ vgImage = VG_INVALID_HANDLE;
+ vgImageOpacity = VG_INVALID_HANDLE;
+ inImagePool = false;
+}
+
void QVGPixmapData::destroyImageAndContext()
{
if (vgImage != VG_INVALID_HANDLE) {
// We need to have a context current to destroy the image.
#if !defined(QT_NO_EGL)
if (context->isCurrent()) {
- vgDestroyImage(vgImage);
- if (vgImageOpacity != VG_INVALID_HANDLE)
- vgDestroyImage(vgImageOpacity);
+ destroyImages();
} else {
// We don't currently have a widget surface active, but we
// need a surface to make the context current. So use the
// shared pbuffer surface instead.
context->makeCurrent(qt_vg_shared_surface());
- vgDestroyImage(vgImage);
- if (vgImageOpacity != VG_INVALID_HANDLE)
- vgDestroyImage(vgImageOpacity);
+ destroyImages();
context->lazyDoneCurrent();
}
#else
- vgDestroyImage(vgImage);
- if (vgImageOpacity != VG_INVALID_HANDLE)
- vgDestroyImage(vgImageOpacity);
+ destroyImages();
#endif
- vgImage = VG_INVALID_HANDLE;
- vgImageOpacity = VG_INVALID_HANDLE;
}
#if !defined(QT_NO_EGL)
if (context) {
@@ -234,26 +248,22 @@ VGImage QVGPixmapData::toVGImage()
context = qt_vg_create_context(0, QInternal::Pixmap);
#endif
- if (recreate && prevSize != QSize(w, h)) {
- if (vgImage != VG_INVALID_HANDLE) {
- vgDestroyImage(vgImage);
- vgImage = VG_INVALID_HANDLE;
- }
- if (vgImageOpacity != VG_INVALID_HANDLE) {
- vgDestroyImage(vgImageOpacity);
- vgImageOpacity = VG_INVALID_HANDLE;
- }
- } else if (recreate) {
+ if (recreate && prevSize != QSize(w, h))
+ destroyImages();
+ else if (recreate)
cachedOpacity = -1.0f; // Force opacity image to be refreshed later.
- }
if (vgImage == VG_INVALID_HANDLE) {
- vgImage = vgCreateImage
- (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER);
+ vgImage = QVGImagePool::instance()->createImageForPixmap
+ (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER, this);
// Bail out if we run out of GPU memory - try again next time.
if (vgImage == VG_INVALID_HANDLE)
return VG_INVALID_HANDLE;
+
+ inImagePool = true;
+ } else if (inImagePool) {
+ QVGImagePool::instance()->useImage(this);
}
if (!source.isNull() && recreate) {
@@ -282,8 +292,13 @@ VGImage QVGPixmapData::toVGImage(qreal opacity)
// Create an alternative image for the selected opacity.
if (vgImageOpacity == VG_INVALID_HANDLE || cachedOpacity != opacity) {
if (vgImageOpacity == VG_INVALID_HANDLE) {
- vgImageOpacity = vgCreateImage
- (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER);
+ if (inImagePool) {
+ vgImageOpacity = QVGImagePool::instance()->createImageForPixmap
+ (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER, this);
+ } else {
+ vgImageOpacity = vgCreateImage
+ (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER);
+ }
// Bail out if we run out of GPU memory - try again next time.
if (vgImageOpacity == VG_INVALID_HANDLE)
@@ -308,6 +323,14 @@ VGImage QVGPixmapData::toVGImage(qreal opacity)
#endif
}
+void QVGPixmapData::detachImageFromPool()
+{
+ if (inImagePool) {
+ QVGImagePool::instance()->detachImage(this);
+ inImagePool = false;
+ }
+}
+
void QVGPixmapData::hibernate()
{
// If the image was imported (e.g, from an SgImage under Symbian),
@@ -319,6 +342,14 @@ void QVGPixmapData::hibernate()
destroyImageAndContext();
}
+void QVGPixmapData::reclaimImages()
+{
+ if (!inImagePool)
+ return;
+ forceToImage();
+ destroyImages();
+}
+
extern int qt_defaultDpiX();
extern int qt_defaultDpiY();
@@ -411,14 +442,7 @@ void QVGPixmapData::fromNativeType(void* pixmap, NativeType type)
if (!context)
context = qt_vg_create_context(0, QInternal::Pixmap);
- if (vgImage != VG_INVALID_HANDLE) {
- vgDestroyImage(vgImage);
- vgImage = VG_INVALID_HANDLE;
- }
- if (vgImageOpacity != VG_INVALID_HANDLE) {
- vgDestroyImage(vgImageOpacity);
- vgImageOpacity = VG_INVALID_HANDLE;
- }
+ destroyImages();
prevSize = QSize();
TInt err = 0;
diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h
index c0bb09852f..4ff95c1dc4 100644
--- a/src/openvg/qpixmapdata_vg_p.h
+++ b/src/openvg/qpixmapdata_vg_p.h
@@ -63,6 +63,7 @@ class RSGImage;
QT_BEGIN_NAMESPACE
class QEglContext;
+class QVGImagePool;
#if !defined(QT_NO_EGL)
class QVGPixmapData;
@@ -101,6 +102,9 @@ public:
// Return the VGImage form for a specific opacity setting.
virtual VGImage toVGImage(qreal opacity);
+ // Detach this image from the image pool.
+ virtual void detachImageFromPool();
+
// Release the VG resources associated with this pixmap and copy
// the pixmap's contents out of the GPU back into main memory.
// The VG resource will be automatically recreated the next time
@@ -109,6 +113,10 @@ public:
// process via a SgImage).
virtual void hibernate();
+ // Called when the QVGImagePool wants to reclaim this pixmap's
+ // VGImage objects to reuse storage.
+ virtual void reclaimImages();
+
QSize size() const { return QSize(w, h); }
#if defined(Q_OS_SYMBIAN)
@@ -123,8 +131,13 @@ protected:
void cleanup();
#endif
-#if !defined(QT_NO_EGL)
private:
+ QVGPixmapData *nextLRU;
+ QVGPixmapData *prevLRU;
+ bool inLRU;
+ friend class QVGImagePool;
+
+#if !defined(QT_NO_EGL)
QVGPixmapData *next;
QVGPixmapData *prev;
@@ -140,6 +153,7 @@ protected:
qreal cachedOpacity;
mutable QImage source;
mutable bool recreate;
+ bool inImagePool;
#if !defined(QT_NO_EGL)
mutable QEglContext *context;
#endif
@@ -148,6 +162,7 @@ protected:
QImage::Format sourceFormat() const;
void destroyImageAndContext();
+ void destroyImages();
};
QT_END_NAMESPACE
diff --git a/src/openvg/qpixmapfilter_vg.cpp b/src/openvg/qpixmapfilter_vg.cpp
index e17c7285ca..aa526ed99f 100644
--- a/src/openvg/qpixmapfilter_vg.cpp
+++ b/src/openvg/qpixmapfilter_vg.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qpixmapfilter_vg_p.h"
+#include "qvgimagepool_p.h"
#include <QtCore/qvarlengtharray.h>
#include <QtGui/qpainter.h>
@@ -82,9 +83,9 @@ void QVGPixmapConvolutionFilter::draw
return;
QSize size = pd->size();
- VGImage dstImage = vgCreateImage
+ VGImage dstImage = QVGImagePool::instance()->createTemporaryImage
(VG_sARGB_8888_PRE, size.width(), size.height(),
- VG_IMAGE_QUALITY_FASTER);
+ VG_IMAGE_QUALITY_FASTER, pd);
if (dstImage == VG_INVALID_HANDLE)
return;
@@ -124,7 +125,7 @@ void QVGPixmapConvolutionFilter::draw
if(child != dstImage)
vgDestroyImage(child);
- vgDestroyImage(dstImage);
+ QVGImagePool::instance()->releaseImage(0, dstImage);
}
QVGPixmapColorizeFilter::QVGPixmapColorizeFilter()
@@ -155,9 +156,9 @@ void QVGPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const
return;
QSize size = pd->size();
- VGImage dstImage = vgCreateImage
+ VGImage dstImage = QVGImagePool::instance()->createTemporaryImage
(VG_sARGB_8888_PRE, size.width(), size.height(),
- VG_IMAGE_QUALITY_FASTER);
+ VG_IMAGE_QUALITY_FASTER, pd);
if (dstImage == VG_INVALID_HANDLE)
return;
@@ -217,7 +218,7 @@ void QVGPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const
if(child != dstImage)
vgDestroyImage(child);
- vgDestroyImage(dstImage);
+ QVGImagePool::instance()->releaseImage(0, dstImage);
}
QVGPixmapDropShadowFilter::QVGPixmapDropShadowFilter()
@@ -248,9 +249,9 @@ void QVGPixmapDropShadowFilter::draw(QPainter *painter, const QPointF &dest, con
return;
QSize size = pd->size();
- VGImage dstImage = vgCreateImage
+ VGImage dstImage = QVGImagePool::instance()->createTemporaryImage
(VG_A_8, size.width(), size.height(),
- VG_IMAGE_QUALITY_FASTER);
+ VG_IMAGE_QUALITY_FASTER, pd);
if (dstImage == VG_INVALID_HANDLE)
return;
@@ -282,7 +283,7 @@ void QVGPixmapDropShadowFilter::draw(QPainter *painter, const QPointF &dest, con
if(child != dstImage)
vgDestroyImage(child);
- vgDestroyImage(dstImage);
+ QVGImagePool::instance()->releaseImage(0, dstImage);
// Now draw the actual pixmap over the top.
painter->drawPixmap(dest, src, srect);
@@ -316,9 +317,9 @@ void QVGPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPi
return;
QSize size = pd->size();
- VGImage dstImage = vgCreateImage
+ VGImage dstImage = QVGImagePool::instance()->createTemporaryImage
(VG_sARGB_8888_PRE, size.width(), size.height(),
- VG_IMAGE_QUALITY_FASTER);
+ VG_IMAGE_QUALITY_FASTER, pd);
if (dstImage == VG_INVALID_HANDLE)
return;
@@ -347,7 +348,7 @@ void QVGPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPi
if(child != dstImage)
vgDestroyImage(child);
- vgDestroyImage(dstImage);
+ QVGImagePool::instance()->releaseImage(0, dstImage);
}
#endif
diff --git a/src/openvg/qvgimagepool.cpp b/src/openvg/qvgimagepool.cpp
new file mode 100644
index 0000000000..93e6e03258
--- /dev/null
+++ b/src/openvg/qvgimagepool.cpp
@@ -0,0 +1,215 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenVG module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvgimagepool_p.h"
+#include "qpixmapdata_vg_p.h"
+
+QT_BEGIN_NAMESPACE
+
+static QVGImagePool *qt_vg_image_pool = 0;
+
+class QVGImagePoolPrivate
+{
+public:
+ QVGImagePoolPrivate() : lruFirst(0), lruLast(0) {}
+
+ QVGPixmapData *lruFirst;
+ QVGPixmapData *lruLast;
+};
+
+QVGImagePool::QVGImagePool()
+ : d_ptr(new QVGImagePoolPrivate())
+{
+}
+
+QVGImagePool::~QVGImagePool()
+{
+}
+
+QVGImagePool *QVGImagePool::instance()
+{
+ if (!qt_vg_image_pool)
+ qt_vg_image_pool = new QVGImagePool();
+ return qt_vg_image_pool;
+}
+
+void QVGImagePool::setImagePool(QVGImagePool *pool)
+{
+ if (qt_vg_image_pool != pool)
+ delete qt_vg_image_pool;
+ qt_vg_image_pool = pool;
+}
+
+VGImage QVGImagePool::createTemporaryImage(VGImageFormat format,
+ VGint width, VGint height,
+ VGbitfield allowedQuality,
+ QVGPixmapData *keepData)
+{
+ VGImage image;
+ do {
+ image = vgCreateImage(format, width, height, allowedQuality);
+ if (image != VG_INVALID_HANDLE)
+ return image;
+ } while (reclaimSpace(format, width, height, keepData));
+ qWarning("QVGImagePool: cannot reclaim sufficient space for a %dx%d temporary image",
+ width, height);
+ return VG_INVALID_HANDLE;
+}
+
+VGImage QVGImagePool::createImageForPixmap(VGImageFormat format,
+ VGint width, VGint height,
+ VGbitfield allowedQuality,
+ QVGPixmapData *data)
+{
+ VGImage image;
+ do {
+ image = vgCreateImage(format, width, height, allowedQuality);
+ if (image != VG_INVALID_HANDLE) {
+ if (data)
+ moveToHeadOfLRU(data);
+ return image;
+ }
+ } while (reclaimSpace(format, width, height, data));
+ qWarning("QVGImagePool: cannot reclaim sufficient space for a %dx%d pixmap",
+ width, height);
+ return VG_INVALID_HANDLE;
+}
+
+VGImage QVGImagePool::createPermanentImage(VGImageFormat format,
+ VGint width, VGint height,
+ VGbitfield allowedQuality)
+{
+ VGImage image;
+ do {
+ image = vgCreateImage(format, width, height, allowedQuality);
+ if (image != VG_INVALID_HANDLE)
+ return image;
+ } while (reclaimSpace(format, width, height, 0));
+ qWarning("QVGImagePool: cannot reclaim sufficient space for a %dx%d image",
+ width, height);
+ return VG_INVALID_HANDLE;
+}
+
+void QVGImagePool::releaseImage(QVGPixmapData *data, VGImage image)
+{
+ // Very simple strategy at the moment: just destroy the image.
+ if (data)
+ removeFromLRU(data);
+ vgDestroyImage(image);
+}
+
+void QVGImagePool::useImage(QVGPixmapData *data)
+{
+ moveToHeadOfLRU(data);
+}
+
+void QVGImagePool::detachImage(QVGPixmapData *data)
+{
+ removeFromLRU(data);
+}
+
+bool QVGImagePool::reclaimSpace(VGImageFormat format,
+ VGint width, VGint height,
+ QVGPixmapData *data)
+{
+ Q_UNUSED(format); // For future use in picking the best image to eject.
+ Q_UNUSED(width);
+ Q_UNUSED(height);
+
+ if (data)
+ moveToHeadOfLRU(data);
+
+ QVGPixmapData *lrudata = pixmapLRU();
+ if (lrudata && lrudata != data) {
+ lrudata->reclaimImages();
+ return true;
+ }
+
+ return false;
+}
+
+void QVGImagePool::hibernate()
+{
+ // Nothing to do here at the moment since the pool does not
+ // retain VGImage's after they have been released.
+}
+
+void QVGImagePool::moveToHeadOfLRU(QVGPixmapData *data)
+{
+ Q_D(QVGImagePool);
+ if (data->inLRU) {
+ if (!data->prevLRU)
+ return; // Already at the head of the list.
+ removeFromLRU(data);
+ }
+ data->inLRU = true;
+ data->nextLRU = d->lruFirst;
+ data->prevLRU = 0;
+ if (d->lruFirst)
+ d->lruFirst->prevLRU = data;
+ else
+ d->lruLast = data;
+ d->lruFirst = data;
+}
+
+void QVGImagePool::removeFromLRU(QVGPixmapData *data)
+{
+ Q_D(QVGImagePool);
+ if (!data->inLRU)
+ return;
+ if (data->nextLRU)
+ data->nextLRU->prevLRU = data->prevLRU;
+ else
+ d->lruLast = data->prevLRU;
+ if (data->prevLRU)
+ data->prevLRU->nextLRU = data->nextLRU;
+ else
+ d->lruFirst = data->nextLRU;
+ data->inLRU = false;
+}
+
+QVGPixmapData *QVGImagePool::pixmapLRU()
+{
+ Q_D(QVGImagePool);
+ return d->lruLast;
+}
+
+QT_END_NAMESPACE
diff --git a/src/openvg/qvgimagepool_p.h b/src/openvg/qvgimagepool_p.h
new file mode 100644
index 0000000000..66a4998fd0
--- /dev/null
+++ b/src/openvg/qvgimagepool_p.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenVG module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVGIMAGEPOOL_P_H
+#define QVGIMAGEPOOL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qvg.h"
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVGPixmapData;
+class QVGImagePoolPrivate;
+
+class Q_OPENVG_EXPORT QVGImagePool
+{
+public:
+ QVGImagePool();
+ virtual ~QVGImagePool();
+
+ static QVGImagePool *instance();
+
+ // This function can be used from system-specific graphics system
+ // plugins to alter the image allocation strategy.
+ static void setImagePool(QVGImagePool *pool);
+
+ // Create a new VGImage from the pool with the specified parameters
+ // that is not associated with a pixmap. The VGImage is returned to
+ // the pool when releaseImage() is called.
+ //
+ // This function will call reclaimSpace() when vgCreateImage() fails.
+ //
+ // This function is typically called when allocating temporary
+ // VGImage's for pixmap filters. The "keepData" object will not
+ // be reclaimed if reclaimSpace() needs to be called.
+ virtual VGImage createTemporaryImage(VGImageFormat format,
+ VGint width, VGint height,
+ VGbitfield allowedQuality,
+ QVGPixmapData *keepData = 0);
+
+ // Create a new VGImage with the specified parameters and associate
+ // it with "data". The QVGPixmapData will be notified when the
+ // VGImage needs to be reclaimed by the pool.
+ //
+ // This function will call reclaimSpace() when vgCreateImage() fails.
+ virtual VGImage createImageForPixmap(VGImageFormat format,
+ VGint width, VGint height,
+ VGbitfield allowedQuality,
+ QVGPixmapData *data);
+
+ // Create a permanent VGImage with the specified parameters.
+ // If there is insufficient space for the vgCreateImage call,
+ // then this function will call reclaimSpace() and try again.
+ //
+ // The caller is responsible for calling vgDestroyImage()
+ // when it no longer needs the VGImage, as the image is not
+ // recorded in the image pool.
+ //
+ // This function is typically used for pattern brushes where
+ // the OpenVG engine is responsible for managing the lifetime
+ // of the VGImage, destroying it automatically when the brush
+ // is no longer in use.
+ virtual VGImage createPermanentImage(VGImageFormat format,
+ VGint width, VGint height,
+ VGbitfield allowedQuality);
+
+ // Release a VGImage that is no longer required.
+ virtual void releaseImage(QVGPixmapData *data, VGImage image);
+
+ // Notify the pool that a QVGPixmapData object is using
+ // an image again. This allows the pool to move the image
+ // within a least-recently-used list of QVGPixmapData objects.
+ virtual void useImage(QVGPixmapData *data);
+
+ // Notify the pool that the VGImage's associated with a
+ // QVGPixmapData are being detached from the pool. The caller
+ // will become responsible for calling vgDestroyImage().
+ virtual void detachImage(QVGPixmapData *data);
+
+ // Reclaim space for an image allocation with the specified parameters.
+ // Returns true if space was reclaimed, or false if there is no
+ // further space that can be reclaimed. The "data" parameter
+ // indicates the pixmap that is trying to obtain space which should
+ // not itself be reclaimed.
+ virtual bool reclaimSpace(VGImageFormat format,
+ VGint width, VGint height,
+ QVGPixmapData *data);
+
+ // Hibernate the image pool because the context is about to be
+ // destroyed. All VGImage's left in the pool should be released.
+ virtual void hibernate();
+
+protected:
+ // Helper functions for managing the LRU list of QVGPixmapData objects.
+ void moveToHeadOfLRU(QVGPixmapData *data);
+ void removeFromLRU(QVGPixmapData *data);
+ QVGPixmapData *pixmapLRU();
+
+private:
+ QScopedPointer<QVGImagePoolPrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QVGImagePool)
+ Q_DISABLE_COPY(QVGImagePool)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/openvg/qwindowsurface_vgegl.cpp b/src/openvg/qwindowsurface_vgegl.cpp
index 15710830f6..bda60965f0 100644
--- a/src/openvg/qwindowsurface_vgegl.cpp
+++ b/src/openvg/qwindowsurface_vgegl.cpp
@@ -42,6 +42,7 @@
#include "qwindowsurface_vgegl_p.h"
#include "qpaintengine_vg_p.h"
#include "qpixmapdata_vg_p.h"
+#include "qvgimagepool_p.h"
#include "qvg_p.h"
#if !defined(QT_NO_EGL)
@@ -360,6 +361,9 @@ void qt_vg_hibernate_pixmaps(QVGSharedContext *shared)
pd = pd->next;
}
+ // Hibernate any remaining VGImage's in the image pool.
+ QVGImagePool::instance()->hibernate();
+
// Don't need the current context any more.
shared->context->lazyDoneCurrent();