diff options
author | Jani Hautakangas <jani.hautakangas@nokia.com> | 2010-10-28 08:27:02 (GMT) |
---|---|---|
committer | Jani Hautakangas <jani.hautakangas@nokia.com> | 2010-10-28 09:59:02 (GMT) |
commit | 47c12e2a4cf135faf5ac58d54d8fe87068b35d3d (patch) | |
tree | f4cafe81558c41658592e47ab8759674f3cf1778 | |
parent | 96beb59dc7fb303debbbf06beb192158ab3476c2 (diff) | |
download | Qt-47c12e2a4cf135faf5ac58d54d8fe87068b35d3d.zip Qt-47c12e2a4cf135faf5ac58d54d8fe87068b35d3d.tar.gz Qt-47c12e2a4cf135faf5ac58d54d8fe87068b35d3d.tar.bz2 |
Fallback to vgWritePixels in drawPixmap.
Use vgWritePixels, if possible, in case where VGImage
for QPixmap can't be allocated due to low GPU memory
situation. This patch also renames some VG paint engine
internal functions to clarify their purpose.
Task-number: QT-3589
Reviewed-by: Jason Barron
-rw-r--r-- | src/openvg/qpaintengine_vg.cpp | 86 | ||||
-rw-r--r-- | src/openvg/qpaintengine_vg_p.h | 1 | ||||
-rw-r--r-- | src/openvg/qpixmapdata_vg.cpp | 45 | ||||
-rw-r--r-- | src/openvg/qpixmapdata_vg_p.h | 6 | ||||
-rw-r--r-- | src/openvg/qvg_symbian.cpp | 3 |
5 files changed, 113 insertions, 28 deletions
diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index ce9d11a..9df32d9 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -55,6 +55,8 @@ #include <QtGui/private/qfontengine_p.h> #include <QtGui/private/qpainterpath_p.h> #include <QtGui/private/qstatictext_p.h> +#include <QtGui/QApplication> +#include <QtGui/QDesktopWidget> #include <QtCore/qmath.h> #include <QDebug> #include <QSet> @@ -3060,6 +3062,21 @@ void qt_vg_drawVGImageStencil vgDrawImage(vgImg); } +bool QVGPaintEngine::canVgWritePixels(const QImage &image) const +{ + Q_D(const QVGPaintEngine); + // vgWritePixels ignores masking, blending and xforms so we can only use it if + // ALL of the following conditions are true: + // - It is a simple translate, or a scale of -1 on the y-axis (inverted) + // - The opacity is totally opaque + // - The composition mode is "source" OR "source over" provided the image is opaque + return ( d->imageTransform.type() <= QTransform::TxScale + && d->imageTransform.m11() == 1.0 && qAbs(d->imageTransform.m22()) == 1.0) + && d->opacity == 1.0f + && (d->blendMode == VG_BLEND_SRC || (d->blendMode == VG_BLEND_SRC_OVER && + !image.hasAlphaChannel())); +} + void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) { QPixmapData *pd = pm.pixmapData(); @@ -3074,9 +3091,18 @@ void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF drawVGImage(d, r, vgpd->toVGImage(), vgpd->size(), sr); else drawVGImage(d, r, vgpd->toVGImage(d->opacity), vgpd->size(), sr); - } else { - drawImage(r, *(pd->buffer()), sr, Qt::AutoColor); + + if(!vgpd->failedToAlloc) + return; + + // try to reallocate next time if reasonable small pixmap + QSize screenSize = QApplication::desktop()->screenGeometry().size(); + if (pm.size().width() <= screenSize.width() + && pm.size().height() <= screenSize.height()) + vgpd->failedToAlloc = false; } + + drawImage(r, *(pd->buffer()), sr, Qt::AutoColor); } void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) @@ -3093,9 +3119,18 @@ void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) drawVGImage(d, pos, vgpd->toVGImage()); else drawVGImage(d, pos, vgpd->toVGImage(d->opacity)); - } else { - drawImage(pos, *(pd->buffer())); + + if (!vgpd->failedToAlloc) + return; + + // try to reallocate next time if reasonable small pixmap + QSize screenSize = QApplication::desktop()->screenGeometry().size(); + if (pm.size().width() <= screenSize.width() + && pm.size().height() <= screenSize.height()) + vgpd->failedToAlloc = false; } + + drawImage(pos, *(pd->buffer())); } void QVGPaintEngine::drawImage @@ -3116,9 +3151,31 @@ void QVGPaintEngine::drawImage QRectF(QPointF(0, 0), sr.size())); } } else { - // Monochrome images need to use the vgChildImage() path. - vgImg = toVGImage(image, flags); - drawVGImage(d, r, vgImg, image.size(), sr); + if (canVgWritePixels(image) && (r.size() == sr.size()) && !flags) { + // Optimization for straight blits, no blending + int x = sr.x(); + int y = sr.y(); + int bpp = image.depth() >> 3; // bytes + int offset = 0; + int bpl = image.bytesPerLine(); + if (d->imageTransform.m22() < 0) { + // inverted + offset = ((y + sr.height()) * bpl) - ((image.width() - x) * bpp); + bpl = -bpl; + } else { + offset = (y * bpl) + (x * bpp); + } + const uchar *bits = image.constBits() + offset; + + QPointF mapped = d->imageTransform.map(r.topLeft()); + vgWritePixels(bits, bpl, qt_vg_image_to_vg_format(image.format()), + mapped.x(), mapped.y() - sr.height(), r.width(), r.height()); + return; + } else { + // Monochrome images need to use the vgChildImage() path. + vgImg = toVGImage(image, flags); + drawVGImage(d, r, vgImg, image.size(), sr); + } } vgDestroyImage(vgImg); } @@ -3127,10 +3184,21 @@ void QVGPaintEngine::drawImage(const QPointF &pos, const QImage &image) { Q_D(QVGPaintEngine); VGImage vgImg; - if (d->simpleTransform || d->opacity == 1.0f) + if (canVgWritePixels(image)) { + // Optimization for straight blits, no blending + bool inverted = (d->imageTransform.m22() < 0); + const uchar *bits = inverted ? image.constBits() + image.byteCount() : image.constBits(); + int bpl = inverted ? -image.bytesPerLine() : image.bytesPerLine(); + + QPointF mapped = d->imageTransform.map(pos); + vgWritePixels(bits, bpl, qt_vg_image_to_vg_format(image.format()), + mapped.x(), mapped.y() - image.height(), image.width(), image.height()); + return; + } else if (d->simpleTransform || d->opacity == 1.0f) { vgImg = toVGImage(image); - else + } else { vgImg = toVGImageWithOpacity(image, d->opacity); + } drawVGImage(d, pos, vgImg); vgDestroyImage(vgImg); } diff --git a/src/openvg/qpaintengine_vg_p.h b/src/openvg/qpaintengine_vg_p.h index 75cf053..dc98137 100644 --- a/src/openvg/qpaintengine_vg_p.h +++ b/src/openvg/qpaintengine_vg_p.h @@ -170,6 +170,7 @@ private: bool isDefaultClipRegion(const QRegion& region); bool isDefaultClipRect(const QRect& rect); bool clearRect(const QRectF &rect, const QColor &color); + bool canVgWritePixels(const QImage &image) const; }; QT_END_NAMESPACE diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index e8ec333..724d06d 100644 --- a/src/openvg/qpixmapdata_vg.cpp +++ b/src/openvg/qpixmapdata_vg.cpp @@ -65,6 +65,7 @@ QVGPixmapData::QVGPixmapData(PixelType type) recreate = true; inImagePool = false; inLRU = false; + failedToAlloc = false; #if !defined(QT_NO_EGL) context = 0; qt_vg_register_pixmap(this); @@ -74,13 +75,13 @@ QVGPixmapData::QVGPixmapData(PixelType type) QVGPixmapData::~QVGPixmapData() { - destroyImageAndContext(); + destroyVGImageAndVGContext(); #if !defined(QT_NO_EGL) qt_vg_unregister_pixmap(this); #endif } -void QVGPixmapData::destroyImages() +void QVGPixmapData::destroyVGImages() { if (inImagePool) { QVGImagePool *pool = QVGImagePool::instance(); @@ -99,23 +100,23 @@ void QVGPixmapData::destroyImages() inImagePool = false; } -void QVGPixmapData::destroyImageAndContext() +void QVGPixmapData::destroyVGImageAndVGContext() { if (vgImage != VG_INVALID_HANDLE) { // We need to have a context current to destroy the image. #if !defined(QT_NO_EGL) if (context->isCurrent()) { - destroyImages(); + destroyVGImages(); } 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()); - destroyImages(); + destroyVGImages(); context->lazyDoneCurrent(); } #else - destroyImages(); + destroyVGImages(); #endif } #if !defined(QT_NO_EGL) @@ -155,6 +156,9 @@ void QVGPixmapData::resize(int wid, int ht) void QVGPixmapData::fromImage (const QImage &image, Qt::ImageConversionFlags flags) { + if(image.isNull()) + return; + QImage img = image; createPixmapForImage(img, flags, false); } @@ -203,10 +207,19 @@ void QVGPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags else resize(image.width(), image.height()); - if (inPlace && image.data_ptr()->convertInPlace(sourceFormat(), flags)) + QImage::Format format = sourceFormat(); + int d = image.depth(); + if (d == 1 || d == 16 || d == 24 || (d == 32 && !image.hasAlphaChannel())) + format = QImage::Format_RGB32; + else if (!(flags & Qt::NoOpaqueDetection) && const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels()) + format = sourceFormat(); + else + format = QImage::Format_RGB32; + + if (inPlace && image.data_ptr()->convertInPlace(format, flags)) source = image; else - source = image.convertToFormat(sourceFormat()); + source = image.convertToFormat(format); recreate = true; } @@ -278,7 +291,7 @@ QPaintEngine* QVGPixmapData::paintEngine() const VGImage QVGPixmapData::toVGImage() { - if (!isValid()) + if (!isValid() || failedToAlloc) return VG_INVALID_HANDLE; #if !defined(QT_NO_EGL) @@ -288,17 +301,19 @@ VGImage QVGPixmapData::toVGImage() #endif if (recreate && prevSize != QSize(w, h)) - destroyImages(); + destroyVGImages(); else if (recreate) cachedOpacity = -1.0f; // Force opacity image to be refreshed later. if (vgImage == VG_INVALID_HANDLE) { vgImage = QVGImagePool::instance()->createImageForPixmap - (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER, this); + (qt_vg_image_to_vg_format(source.format()), 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) + if (vgImage == VG_INVALID_HANDLE) { + failedToAlloc = true; return VG_INVALID_HANDLE; + } inImagePool = true; } else if (inImagePool) { @@ -309,7 +324,7 @@ VGImage QVGPixmapData::toVGImage() vgImageSubData (vgImage, source.constBits(), source.bytesPerLine(), - VG_sARGB_8888_PRE, 0, 0, w, h); + qt_vg_image_to_vg_format(source.format()), 0, 0, w, h); } recreate = false; @@ -378,7 +393,7 @@ void QVGPixmapData::hibernate() return; forceToImage(); - destroyImageAndContext(); + destroyVGImageAndVGContext(); } void QVGPixmapData::reclaimImages() @@ -386,7 +401,7 @@ void QVGPixmapData::reclaimImages() if (!inImagePool) return; forceToImage(); - destroyImages(); + destroyVGImages(); } Q_DECL_IMPORT extern int qt_defaultDpiX(); diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h index 114d545..b8f01eb 100644 --- a/src/openvg/qpixmapdata_vg_p.h +++ b/src/openvg/qpixmapdata_vg_p.h @@ -143,7 +143,9 @@ private: QVGPixmapData *nextLRU; QVGPixmapData *prevLRU; bool inLRU; + bool failedToAlloc; friend class QVGImagePool; + friend class QVGPaintEngine; #if !defined(QT_NO_EGL) QVGPixmapData *next; @@ -169,8 +171,8 @@ protected: void forceToImage(); QImage::Format sourceFormat() const; - void destroyImageAndContext(); - void destroyImages(); + void destroyVGImageAndVGContext(); + void destroyVGImages(); }; QT_END_NAMESPACE diff --git a/src/openvg/qvg_symbian.cpp b/src/openvg/qvg_symbian.cpp index 41b35fc..b6bf858 100644 --- a/src/openvg/qvg_symbian.cpp +++ b/src/openvg/qvg_symbian.cpp @@ -144,7 +144,7 @@ void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) if (type == QPixmapData::SgImage && pixmap) { #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL) RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmap); - destroyImages(); + destroyVGImages(); prevSize = QSize(); VGImage vgImage = sgImageToVGImage(context, *sgImage); @@ -164,7 +164,6 @@ void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap*>(pixmap); bool deleteSourceBitmap = false; - #ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE // Rasterize extended bitmaps |