diff options
Diffstat (limited to 'src/openvg')
-rw-r--r-- | src/openvg/openvg.pro | 6 | ||||
-rw-r--r-- | src/openvg/qpaintengine_vg.cpp | 48 | ||||
-rw-r--r-- | src/openvg/qpixmapdata_vg.cpp | 94 | ||||
-rw-r--r-- | src/openvg/qpixmapdata_vg_p.h | 17 | ||||
-rw-r--r-- | src/openvg/qpixmapfilter_vg.cpp | 25 | ||||
-rw-r--r-- | src/openvg/qvgimagepool.cpp | 215 | ||||
-rw-r--r-- | src/openvg/qvgimagepool_p.h | 157 | ||||
-rw-r--r-- | src/openvg/qwindowsurface_vgegl.cpp | 4 |
8 files changed, 502 insertions, 64 deletions
diff --git a/src/openvg/openvg.pro b/src/openvg/openvg.pro index 8927c4c..c8c9917 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 6b829dd..117c910 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" @@ -199,6 +200,7 @@ public: QRegion scissorRegion; // Currently active scissor region. bool scissorActive; // True if scissor region is active. + bool scissorDirty; // True if scissor is dirty after native painting. QPaintEngine::DirtyFlags dirty; @@ -356,6 +358,7 @@ void QVGPaintEnginePrivate::init() rawVG = false; scissorActive = false; + scissorDirty = false; dirty = 0; @@ -983,6 +986,9 @@ static QImage colorizeBitmap(const QImage &image, const QColor &color) return dest; } +// defined in qpixmapdata_vg.cpp. +const uchar *qt_vg_imageBits(const QImage& image); + static VGImage toVGImage (const QImage & image, Qt::ImageConversionFlags flags = Qt::AutoColor) { @@ -1016,9 +1022,9 @@ static VGImage toVGImage break; } - const uchar *pixels = img.bits(); + const uchar *pixels = qt_vg_imageBits(img); - 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, @@ -1060,10 +1066,10 @@ static VGImage toVGImageSubRect break; } - const uchar *pixels = img.bits() + bpp * sr.x() + + const uchar *pixels = qt_vg_imageBits(img) + 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, @@ -1082,9 +1088,9 @@ static VGImage toVGImageWithOpacity(const QImage & image, qreal opacity) painter.drawImage(0, 0, image); painter.end(); - const uchar *pixels = img.bits(); + const uchar *pixels = qt_vg_imageBits(img); - 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, @@ -1104,9 +1110,9 @@ static VGImage toVGImageWithOpacitySubRect painter.drawImage(QPoint(0, 0), image, sr); painter.end(); - const uchar *pixels = img.bits(); + const uchar *pixels = qt_vg_imageBits(img); - 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 +1200,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 +1213,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; @@ -2075,6 +2088,7 @@ void QVGPaintEngine::updateScissor() // so there is no point doing any scissoring. vgSeti(VG_SCISSORING, VG_FALSE); d->scissorActive = false; + d->scissorDirty = false; return; } } else @@ -2092,6 +2106,7 @@ void QVGPaintEngine::updateScissor() // so there is no point doing any scissoring. vgSeti(VG_SCISSORING, VG_FALSE); d->scissorActive = false; + d->scissorDirty = false; return; } } else @@ -2101,11 +2116,12 @@ void QVGPaintEngine::updateScissor() if (region.isEmpty()) { vgSeti(VG_SCISSORING, VG_FALSE); d->scissorActive = false; + d->scissorDirty = false; return; } } - if (d->scissorActive && region == d->scissorRegion) + if (d->scissorActive && region == d->scissorRegion && !d->scissorDirty) return; QVector<QRect> rects = region.rects(); @@ -2123,6 +2139,7 @@ void QVGPaintEngine::updateScissor() vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data()); vgSeti(VG_SCISSORING, VG_TRUE); + d->scissorDirty = false; d->scissorActive = true; d->scissorRegion = region; } @@ -3158,15 +3175,15 @@ void QVGFontGlyphCache::cacheGlyphs if (!scaledImage.isNull()) { // Not a space character if (scaledImage.format() == QImage::Format_Indexed8) { vgImage = vgCreateImage(VG_A_8, scaledImage.width(), scaledImage.height(), VG_IMAGE_QUALITY_FASTER); - vgImageSubData(vgImage, scaledImage.bits(), scaledImage.bytesPerLine(), VG_A_8, 0, 0, scaledImage.width(), scaledImage.height()); + vgImageSubData(vgImage, qt_vg_imageBits(scaledImage), scaledImage.bytesPerLine(), VG_A_8, 0, 0, scaledImage.width(), scaledImage.height()); } else if (scaledImage.format() == QImage::Format_Mono) { QImage img = scaledImage.convertToFormat(QImage::Format_Indexed8); vgImage = vgCreateImage(VG_A_8, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); - vgImageSubData(vgImage, img.bits(), img.bytesPerLine(), VG_A_8, 0, 0, img.width(), img.height()); + vgImageSubData(vgImage, qt_vg_imageBits(img), img.bytesPerLine(), VG_A_8, 0, 0, img.width(), img.height()); } else { QImage img = scaledImage.convertToFormat(QImage::Format_ARGB32_Premultiplied); vgImage = vgCreateImage(VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); - vgImageSubData(vgImage, img.bits(), img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height()); + vgImageSubData(vgImage, qt_vg_imageBits(img), img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height()); } } origin[0] = -metrics.x.toReal() + 0.5f; @@ -3325,6 +3342,7 @@ void QVGPaintEngine::endNativePainting() d->brushType = (VGPaintType)0; d->clearColor = QColor(); d->fillPaint = d->brushPaint; + d->scissorDirty = true; restoreState(QPaintEngine::AllDirty); d->dirty = dirty; d->rawVG = false; @@ -3632,7 +3650,7 @@ void QVGCompositionHelper::drawCursorPixmap if (vgImage == VG_INVALID_HANDLE) return; vgImageSubData - (vgImage, img.bits() + img.bytesPerLine() * (img.height() - 1), + (vgImage, qt_vg_imageBits(img) + img.bytesPerLine() * (img.height() - 1), -(img.bytesPerLine()), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height()); @@ -3658,15 +3676,17 @@ void QVGCompositionHelper::setScissor(const QRegion& region) vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data()); vgSeti(VG_SCISSORING, VG_TRUE); + d->scissorDirty = false; d->scissorActive = true; d->scissorRegion = region; } void QVGCompositionHelper::clearScissor() { - if (d->scissorActive) { + if (d->scissorActive || d->scissorDirty) { vgSeti(VG_SCISSORING, VG_FALSE); d->scissorActive = false; + d->scissorDirty = false; } } diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index af6f0f0..7de2212 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) { @@ -218,7 +232,7 @@ QPaintEngine* QVGPixmapData::paintEngine() const // This function works around QImage::bits() making a deep copy if the // QImage is not const. We force it to be const and then get the bits. // XXX: Should add a QImage::constBits() in the future to replace this. -static inline const uchar *qt_vg_imageBits(const QImage& image) +const uchar *qt_vg_imageBits(const QImage& image) { return image.bits(); } @@ -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 c0bb098..4ff95c1 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 e17c728..aa526ed 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 0000000..93e6e03 --- /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 0000000..66a4998 --- /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 1571083..bda6096 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(); |