diff options
-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 |