summaryrefslogtreecommitdiffstats
path: root/src/gui/painting
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2018-08-03 01:00:16 +0200
committerEdward Welbourne <edward.welbourne@qt.io>2018-08-07 17:44:51 +0200
commit053e7cce79d4bef99ec85101b0d22bbb171072c5 (patch)
treec2059e82cccdea1fd0024c5942d1a834c28d39da /src/gui/painting
parenta420d02538d28854914a6978c9637a0ddd652146 (diff)
parentf271dd8f960ad9f61697dfa57b26c4071441cadc (diff)
Merge remote-tracking branch 'origin/5.11' into dev
Conflicts: .qmake.conf src/corelib/doc/src/objectmodel/signalsandslots.qdoc src/plugins/platforms/cocoa/qcocoamenuloader.mm src/plugins/platforms/xcb/qxcbconnection.cpp src/plugins/platforms/xcb/qxcbconnection.h src/plugins/platforms/xcb/qxcbconnection_xi2.cpp src/plugins/platforms/xcb/qxcbwindow.cpp tests/auto/gui/image/qimage/tst_qimage.cpp Done-with: Gatis Paeglis <gatis.paeglis@qt.io> Change-Id: I9bd24ee9b00d4f26c8f344ce3970aa6e93935ff5
Diffstat (limited to 'src/gui/painting')
-rw-r--r--src/gui/painting/qdrawhelper.cpp61
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp119
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h3
3 files changed, 181 insertions, 2 deletions
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 235bba7206..1110f951a9 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -841,6 +841,53 @@ static inline void qConvertARGB32PMToARGB64PM_sse2(QRgba64 *buffer, const uint *
*buffer++ = QRgba64::fromArgb32(s);
}
}
+#elif defined(__ARM_NEON__)
+template<bool RGBA, bool maskAlpha>
+static inline void qConvertARGB32PMToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count)
+{
+ if (count <= 0)
+ return;
+
+ const uint32x4_t amask = vdupq_n_u32(0xff000000);
+#if defined(Q_PROCESSOR_ARM_64)
+ const uint8x16_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15};
+#else
+ const uint8x8_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7 };
+#endif
+ int i = 0;
+ for (; i < count-3; i += 4) {
+ uint32x4_t vs32 = vld1q_u32(src);
+ src += 4;
+ if (maskAlpha)
+ vs32 = vorrq_u32(vs32, amask);
+ uint8x16_t vs8 = vreinterpretq_u8_u32(vs32);
+ if (!RGBA) {
+#if defined(Q_PROCESSOR_ARM_64)
+ vs8 = vqtbl1q_u8(vs8, rgbaMask);
+#else
+ // no vqtbl1q_u8
+ const uint8x8_t vlo = vtbl1_u8(vget_low_u8(vs8), rgbaMask);
+ const uint8x8_t vhi = vtbl1_u8(vget_high_u8(vs8), rgbaMask);
+ vs8 = vcombine_u8(vlo, vhi);
+#endif
+ }
+ uint8x16x2_t v = vzipq_u8(vs8, vs8);
+
+ vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[0]));
+ buffer += 2;
+ vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[1]));
+ buffer += 2;
+ }
+
+ SIMD_EPILOGUE(i, count, 3) {
+ uint s = *src++;
+ if (maskAlpha)
+ s = s | 0xff000000;
+ if (RGBA)
+ s = RGBA2ARGB(s);
+ *buffer++ = QRgba64::fromArgb32(s);
+ }
+}
#endif
static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count,
@@ -848,6 +895,8 @@ static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uin
{
#ifdef __SSE2__
qConvertARGB32PMToARGB64PM_sse2<false, true>(buffer, src, count);
+#elif defined(__ARM_NEON__)
+ qConvertARGB32PMToRGBA64PM_neon<false, true>(buffer, src, count);
#else
for (int i = 0; i < count; ++i)
buffer[i] = QRgba64::fromArgb32(0xff000000 | src[i]);
@@ -862,6 +911,10 @@ static const QRgba64 *QT_FASTCALL convertARGB32ToARGB64PM(QRgba64 *buffer, const
qConvertARGB32PMToARGB64PM_sse2<false, false>(buffer, src, count);
for (int i = 0; i < count; ++i)
buffer[i] = buffer[i].premultiplied();
+#elif defined(__ARM_NEON__)
+ qConvertARGB32PMToRGBA64PM_neon<false, false>(buffer, src, count);
+ for (int i = 0; i < count; ++i)
+ buffer[i] = buffer[i].premultiplied();
#else
for (int i = 0; i < count; ++i)
buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied();
@@ -874,6 +927,8 @@ static const QRgba64 *QT_FASTCALL convertARGB32PMToARGB64PM(QRgba64 *buffer, con
{
#ifdef __SSE2__
qConvertARGB32PMToARGB64PM_sse2<false, false>(buffer, src, count);
+#elif defined(__ARM_NEON__)
+ qConvertARGB32PMToRGBA64PM_neon<false, false>(buffer, src, count);
#else
for (int i = 0; i < count; ++i)
buffer[i] = QRgba64::fromArgb32(src[i]);
@@ -888,6 +943,10 @@ static const QRgba64 *QT_FASTCALL convertRGBA8888ToARGB64PM(QRgba64 *buffer, con
qConvertARGB32PMToARGB64PM_sse2<true, false>(buffer, src, count);
for (int i = 0; i < count; ++i)
buffer[i] = buffer[i].premultiplied();
+#elif defined(__ARM_NEON__)
+ qConvertARGB32PMToRGBA64PM_neon<true, false>(buffer, src, count);
+ for (int i = 0; i < count; ++i)
+ buffer[i] = buffer[i].premultiplied();
#else
for (int i = 0; i < count; ++i)
buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied();
@@ -900,6 +959,8 @@ static const QRgba64 *QT_FASTCALL convertRGBA8888PMToARGB64PM(QRgba64 *buffer, c
{
#ifdef __SSE2__
qConvertARGB32PMToARGB64PM_sse2<true, false>(buffer, src, count);
+#elif defined(__ARM_NEON__)
+ qConvertARGB32PMToRGBA64PM_neon<true, false>(buffer, src, count);
#else
for (int i = 0; i < count; ++i)
buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i]));
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index e0dd789dfd..7caaf3a8fa 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -1056,6 +1056,77 @@ void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
alpha);
}
+void QRasterPaintEnginePrivate::blitImage(const QPointF &pt,
+ const QImage &img,
+ const QRect &clip,
+ const QRect &sr)
+{
+ if (!clip.isValid())
+ return;
+
+ Q_ASSERT(img.depth() >= 8);
+
+ qsizetype srcBPL = img.bytesPerLine();
+ const uchar *srcBits = img.bits();
+ int srcSize = img.depth() >> 3; // This is the part that is incompatible with lower than 8-bit..
+ int iw = img.width();
+ int ih = img.height();
+
+ if (!sr.isEmpty()) {
+ iw = sr.width();
+ ih = sr.height();
+ // Adjust the image according to the source offset...
+ srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
+ }
+
+ // adapt the x parameters
+ int x = qRound(pt.x());
+ int cx1 = clip.x();
+ int cx2 = clip.x() + clip.width();
+ if (x < cx1) {
+ int d = cx1 - x;
+ srcBits += srcSize * d;
+ iw -= d;
+ x = cx1;
+ }
+ if (x + iw > cx2) {
+ int d = x + iw - cx2;
+ iw -= d;
+ }
+ if (iw <= 0)
+ return;
+
+ // adapt the y paremeters...
+ int cy1 = clip.y();
+ int cy2 = clip.y() + clip.height();
+ int y = qRound(pt.y());
+ if (y < cy1) {
+ int d = cy1 - y;
+ srcBits += srcBPL * d;
+ ih -= d;
+ y = cy1;
+ }
+ if (y + ih > cy2) {
+ int d = y + ih - cy2;
+ ih -= d;
+ }
+ if (ih <= 0)
+ return;
+
+ // blit..
+ int dstSize = rasterBuffer->bytesPerPixel();
+ qsizetype dstBPL = rasterBuffer->bytesPerLine();
+ const uint *src = (const uint *) srcBits;
+ uint *dst = reinterpret_cast<uint *>(rasterBuffer->buffer() + x * dstSize + y * dstBPL);
+
+ const int len = iw * (qt_depthForFormat(rasterBuffer->format) >> 3);
+ for (int y = 0; y < ih; ++y) {
+ memcpy(dst, src, len);
+ dst = (quint32 *)(((uchar *) dst) + dstBPL);
+ src = (const quint32 *)(((const uchar *) src) + srcBPL);
+ }
+}
+
void QRasterPaintEnginePrivate::systemStateChanged()
{
@@ -2160,7 +2231,15 @@ void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
const QClipData *clip = d->clip();
QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
- if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
+ if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img)) {
+ if (!clip) {
+ d->blitImage(pt, img, d->deviceRect);
+ return;
+ } else if (clip->hasRectClip) {
+ d->blitImage(pt, img, clip->clipRect);
+ return;
+ }
+ } else if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
if (func) {
if (!clip) {
@@ -2445,7 +2524,16 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
fillPath(path, &d->image_filler_xform);
s->matrix = m;
} else {
- if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
+ if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img)) {
+ QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
+ if (!clip) {
+ d->blitImage(pt, img, d->deviceRect, sr.toRect());
+ return;
+ } else if (clip->hasRectClip) {
+ d->blitImage(pt, img, clip->clipRect, sr.toRect());
+ return;
+ }
+ } else if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
if (func) {
QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
@@ -3668,6 +3756,33 @@ bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMod
&& !image.hasAlphaChannel()));
}
+bool QRasterPaintEnginePrivate::canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image) const
+{
+ Q_Q(const QRasterPaintEngine);
+ const QRasterPaintEngineState *s = q->state();
+
+ if (!s->flags.fast_images || s->intOpacity != 256 || qt_depthForFormat(rasterBuffer->format) < 8)
+ return false;
+
+ QImage::Format dFormat = rasterBuffer->format;
+ QImage::Format sFormat = image.format();
+ // Formats must match or source format must be a subset of destination format
+ if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha) {
+ if ((sFormat == QImage::Format_RGB32 && dFormat == QImage::Format_ARGB32)
+ || (sFormat == QImage::Format_RGBX8888 && dFormat == QImage::Format_RGBA8888))
+ sFormat = dFormat;
+ else
+ sFormat = qt_maybeAlphaVersionWithSameDepth(sFormat); // this returns premul formats
+ }
+ if (dFormat != sFormat)
+ return false;
+
+ return s->matrix.type() <= QTransform::TxTranslate
+ && (mode == QPainter::CompositionMode_Source
+ || (mode == QPainter::CompositionMode_SourceOver
+ && !image.hasAlphaChannel()));
+}
+
QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
{
Q_ASSERT(image.depth() == 1);
diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h
index 8c6f668d9d..14eddf07b1 100644
--- a/src/gui/painting/qpaintengine_raster_p.h
+++ b/src/gui/painting/qpaintengine_raster_p.h
@@ -291,6 +291,8 @@ public:
void drawImage(const QPointF &pt, const QImage &img, SrcOverBlendFunc func,
const QRect &clip, int alpha, const QRect &sr = QRect());
+ void blitImage(const QPointF &pt, const QImage &img,
+ const QRect &clip, const QRect &sr = QRect());
QTransform brushMatrix() const {
Q_Q(const QRasterPaintEngine);
@@ -313,6 +315,7 @@ public:
void recalculateFastImages();
bool canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const;
+ bool canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image) const;
QPaintDevice *device;
QScopedPointer<QOutlineMapper> outlineMapper;