summaryrefslogtreecommitdiffstats
path: root/src/openvg
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvg')
-rw-r--r--src/openvg/qpaintengine_vg.cpp86
-rw-r--r--src/openvg/qpaintengine_vg_p.h1
-rw-r--r--src/openvg/qpixmapdata_vg.cpp45
-rw-r--r--src/openvg/qpixmapdata_vg_p.h6
-rw-r--r--src/openvg/qvg_symbian.cpp3
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