diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-02-05 16:09:00 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-02-13 13:20:52 +0000 |
commit | 22b5c39e8e0f4d8cb8a2b2d661e0451e01b75929 (patch) | |
tree | 554d84acb212c909154da63063ada27c1d6fbbd5 | |
parent | e9f30968ad777bc2d7fcd85adc4e9d38d70398d8 (diff) |
Optimize generic conversion and remove now obsolete direct conversions
There are many direct QImage conversions that doesn't need to be direct
but only are because they are faster than the generic conversion. This
patch optimizes the generic conversions and then removes all the direct
conversions that are now no faster than the generic.
Change-Id: I3dc5f44cc7f6358fd66420e9974eebaf2c7ca59c
Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
-rw-r--r-- | src/gui/image/qimage.cpp | 4 | ||||
-rw-r--r-- | src/gui/image/qimage_conversions.cpp | 537 | ||||
-rw-r--r-- | src/gui/image/qimage_sse2.cpp | 7 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper.cpp | 62 | ||||
-rw-r--r-- | tests/benchmarks/gui/image/qimageconversion/qimageconversion.pro | 1 | ||||
-rw-r--r-- | tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp | 83 |
6 files changed, 270 insertions, 424 deletions
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 86e739dd4f..57e7c9a7ab 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -4595,7 +4595,9 @@ bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFla InPlace_Image_Converter converter = *converterPtr; if (converter) return converter(this, flags); - else if (format > QImage::Format_Indexed8 && newFormat > QImage::Format_Indexed8) + else if (format > QImage::Format_Indexed8 && newFormat > QImage::Format_Indexed8 && !qimage_converter_map[format][newFormat]) + // Convert inplace generic, but only if there are no direct converters, + // any direct ones are probably better even if not inplace. return convert_generic_inplace(this, newFormat, flags); else return false; diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index ff729981c0..a4c02bbbbe 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -32,6 +32,7 @@ ****************************************************************************/ #include <private/qdrawhelper_p.h> +#include <private/qdrawingprimitive_sse2_p.h> #include <private/qguiapplication_p.h> #include <private/qsimd_p.h> @@ -100,9 +101,37 @@ void qGamma_correct_back_to_linear_cs(QImage *image) Internal routines for converting image depth. *****************************************************************************/ -// Cannot be used with indexed formats. +// The drawhelper conversions from/to RGB32 are passthroughs which is not always correct for general image conversion. +static const uint *QT_FASTCALL convertRGB32FromARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = 0xff000000 | qUnpremultiply(src[i]); + return buffer; +} + +#if QT_COMPILER_SUPPORTS_HERE(SSE4_1) +QT_FUNCTION_TARGET(SSE4_1) +static const uint *QT_FASTCALL convertRGB32FromARGB32PM_sse4(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = 0xff000000 | qUnpremultiply_sse4(src[i]); + return buffer; +} +#endif + +static const uint *QT_FASTCALL convertRGB32ToARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = 0xff000000 |src[i]; + return buffer; +} + void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { + // Cannot be used with indexed formats. Q_ASSERT(dest->format > QImage::Format_Indexed8); Q_ASSERT(src->format > QImage::Format_Indexed8); const int buffer_size = 2048; @@ -112,16 +141,33 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio const uchar *srcData = src->data; uchar *destData = dest->data; - FetchPixelsFunc fetch = qFetchPixels[srcLayout->bpp]; - StorePixelsFunc store = qStorePixels[destLayout->bpp]; + const FetchPixelsFunc fetch = qFetchPixels[srcLayout->bpp]; + const StorePixelsFunc store = qStorePixels[destLayout->bpp]; + ConvertFunc convertToARGB32PM = srcLayout->convertToARGB32PM; + ConvertFunc convertFromARGB32PM = destLayout->convertFromARGB32PM; + if (srcLayout->alphaWidth == 0 && destLayout->convertFromRGB32) { + // If the source doesn't have an alpha channel, we can use the faster convertFromRGB32 method. + convertFromARGB32PM = destLayout->convertFromRGB32; + } else { + if (src->format == QImage::Format_RGB32) + convertToARGB32PM = convertRGB32ToARGB32PM; + if (dest->format == QImage::Format_RGB32) { +#if QT_COMPILER_SUPPORTS_HERE(SSE4_1) + if (qCpuHasFeature(SSE4_1)) + convertFromARGB32PM = convertRGB32FromARGB32PM_sse4; + else +#endif + convertFromARGB32PM = convertRGB32FromARGB32PM; + } + } for (int y = 0; y < src->height; ++y) { int x = 0; while (x < src->width) { int l = qMin(src->width - x, buffer_size); const uint *ptr = fetch(buffer, srcData, x, l); - ptr = srcLayout->convertToARGB32PM(buffer, ptr, l, srcLayout, 0); - ptr = destLayout->convertFromARGB32PM(buffer, ptr, l, destLayout, 0); + ptr = convertToARGB32PM(buffer, ptr, l, srcLayout, 0); + ptr = convertFromARGB32PM(buffer, ptr, l, destLayout, 0); store(destData, ptr, x, l); x += l; } @@ -130,9 +176,9 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio } } -// Cannot be used with indexed formats or between formats with different pixel depths. bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags) { + // Cannot be used with indexed formats or between formats with different pixel depths. Q_ASSERT(dst_format > QImage::Format_Indexed8); Q_ASSERT(data->format > QImage::Format_Indexed8); if (data->depth != qt_depthForFormat(dst_format)) @@ -142,19 +188,35 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im uint buffer[buffer_size]; const QPixelLayout *srcLayout = &qPixelLayouts[data->format]; const QPixelLayout *destLayout = &qPixelLayouts[dst_format]; - uchar *srcData = data->data; - FetchPixelsFunc fetch = qFetchPixels[srcLayout->bpp]; - StorePixelsFunc store = qStorePixels[destLayout->bpp]; + const FetchPixelsFunc fetch = qFetchPixels[srcLayout->bpp]; + const StorePixelsFunc store = qStorePixels[destLayout->bpp]; + ConvertFunc convertToARGB32PM = srcLayout->convertToARGB32PM; + ConvertFunc convertFromARGB32PM = destLayout->convertFromARGB32PM; + if (srcLayout->alphaWidth == 0 && destLayout->convertFromRGB32) { + // If the source doesn't have an alpha channel, we can use the faster convertFromRGB32 method. + convertFromARGB32PM = destLayout->convertFromRGB32; + } else { + if (data->format == QImage::Format_RGB32) + convertToARGB32PM = convertRGB32ToARGB32PM; + if (dst_format == QImage::Format_RGB32) { +#if QT_COMPILER_SUPPORTS_HERE(SSE4_1) + if (qCpuHasFeature(SSE4_1)) + convertFromARGB32PM = convertRGB32FromARGB32PM_sse4; + else +#endif + convertFromARGB32PM = convertRGB32FromARGB32PM; + } + } for (int y = 0; y < data->height; ++y) { int x = 0; while (x < data->width) { int l = qMin(data->width - x, buffer_size); const uint *ptr = fetch(buffer, srcData, x, l); - ptr = srcLayout->convertToARGB32PM(buffer, ptr, l, srcLayout, 0); - ptr = destLayout->convertFromARGB32PM(buffer, ptr, l, destLayout, 0); + ptr = convertToARGB32PM(buffer, ptr, l, srcLayout, 0); + ptr = convertFromARGB32PM(buffer, ptr, l, destLayout, 0); // The conversions might be passthrough and not use the buffer, in that case we are already done. if (srcData != (const uchar*)ptr) store(srcData, ptr, x, l); @@ -230,27 +292,6 @@ static void convert_ARGB_to_ARGB_PM_sse4(QImageData *dest, const QImageData *src extern bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionFlags); -#ifndef __SSE2__ -static bool convert_ARGB_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_ARGB32); - - const int pad = (data->bytes_per_line >> 2) - data->width; - QRgb *rgb_data = (QRgb *) data->data; - - for (int i = 0; i < data->height; ++i) { - const QRgb *end = rgb_data + data->width; - while (rgb_data < end) { - *rgb_data = qPremultiply(*rgb_data); - ++rgb_data; - } - rgb_data += pad; - } - data->format = QImage::Format_ARGB32_Premultiplied; - return true; -} -#endif - static void convert_ARGB_to_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(src->format == QImage::Format_ARGB32); @@ -321,39 +362,6 @@ static bool convert_ARGB_to_RGBA_inplace(QImageData *data, Qt::ImageConversionFl return true; } -static inline void convert_ARGB_to_RGBA_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32); - Q_ASSERT(dest->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const quint32 *src_data = (quint32 *) src->data; - quint32 *dest_data = (quint32 *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const quint32 *end = src_data + src->width; - while (src_data < end) { - *dest_data = ARGB2RGBA(qPremultiply(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -#if QT_COMPILER_SUPPORTS_HERE(SSE4_1) && !defined(__SSE4_1__) -QT_FUNCTION_TARGET(SSE4_1) -static void convert_ARGB_to_RGBA_PM_sse4(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags) -{ - // Twice as fast autovectorized due to SSE4.1 PMULLD instructions. - convert_ARGB_to_RGBA_PM(dest, src, flags); -} -#endif - static void convert_RGBA_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(src->format == QImage::Format_RGBX8888 || src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBA8888_Premultiplied); @@ -378,70 +386,24 @@ static void convert_RGBA_to_ARGB(QImageData *dest, const QImageData *src, Qt::Im } } +template<QImage::Format DestFormat> static bool convert_RGBA_to_ARGB_inplace(QImageData *data, Qt::ImageConversionFlags) { Q_ASSERT(data->format == QImage::Format_RGBX8888 || data->format == QImage::Format_RGBA8888 || data->format == QImage::Format_RGBA8888_Premultiplied); const int pad = (data->bytes_per_line >> 2) - data->width; QRgb *rgb_data = (QRgb *) data->data; + Q_CONSTEXPR uint mask = (DestFormat == QImage::Format_RGB32) ? 0xff000000 : 0; for (int i = 0; i < data->height; ++i) { const QRgb *end = rgb_data + data->width; while (rgb_data < end) { - *rgb_data = RGBA2ARGB(*rgb_data); - ++rgb_data; - } - rgb_data += pad; - } - if (data->format == QImage::Format_RGBA8888_Premultiplied) - data->format = QImage::Format_ARGB32_Premultiplied; - else if (data->format == QImage::Format_RGBX8888) - data->format = QImage::Format_RGB32; - else - data->format = QImage::Format_ARGB32; - return true; -} - -static void convert_RGBA_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_RGBA8888); - Q_ASSERT(dest->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const quint32 *src_data = (quint32 *) src->data; - quint32 *dest_data = (quint32 *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const quint32 *end = src_data + src->width; - while (src_data < end) { - *dest_data = qPremultiply(RGBA2ARGB(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static bool convert_RGBA_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_RGBA8888); - - const int pad = (data->bytes_per_line >> 2) - data->width; - QRgb *rgb_data = (QRgb *) data->data; - - for (int i = 0; i < data->height; ++i) { - const QRgb *end = rgb_data + data->width; - while (rgb_data < end) { - *rgb_data = qPremultiply(RGBA2ARGB(*rgb_data)); + *rgb_data = mask | RGBA2ARGB(*rgb_data); ++rgb_data; } rgb_data += pad; } - data->format = QImage::Format_ARGB32_Premultiplied; + data->format = DestFormat; return true; } @@ -497,106 +459,6 @@ static void convert_RGB30_to_RGB(QImageData *dest, const QImageData *src, Qt::Im } } -template<QtPixelOrder PixelOrder> -static void convert_A2RGB30_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_A2RGB30_Premultiplied || src->format == QImage::Format_A2BGR30_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_RGB32); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const quint32 *src_data = (quint32 *) src->data; - quint32 *dest_data = (quint32 *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const quint32 *end = src_data + src->width; - while (src_data < end) { - *dest_data = 0xff000000 | qUnpremultiply(qConvertA2rgb30ToArgb32<PixelOrder>(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -template<QtPixelOrder PixelOrder> -static void convert_ARGB_PM_to_RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_BGR30 || dest->format == QImage::Format_RGB30); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const quint32 *src_data = (quint32 *) src->data; - quint32 *dest_data = (quint32 *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const quint32 *end = src_data + src->width; - while (src_data < end) { - *dest_data = qConvertRgb32ToRgb30<PixelOrder>(qUnpremultiply(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -template<QtPixelOrder PixelOrder> -static void convert_ARGB_to_A2RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_A2BGR30_Premultiplied || dest->format == QImage::Format_A2RGB30_Premultiplied); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const quint32 *src_data = (quint32 *) src->data; - quint32 *dest_data = (quint32 *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const quint32 *end = src_data + src->width; - while (src_data < end) { - *dest_data = qConvertArgb32ToA2rgb30<PixelOrder>(*src_data); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -template<QtPixelOrder PixelOrder> -static void convert_A2RGB30_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_A2BGR30_Premultiplied || src->format == QImage::Format_A2RGB30_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const quint32 *src_data = (quint32 *) src->data; - quint32 *dest_data = (quint32 *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const quint32 *end = src_data + src->width; - while (src_data < end) { - *dest_data = qConvertA2rgb30ToArgb32<PixelOrder>(*src_data); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - static inline uint qUnpremultiplyRgb30(uint rgb30) { const uint a = rgb30 >> 30; @@ -916,7 +778,7 @@ static bool convert_RGB_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFl } } -static void convert_ARGB_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +static void convert_ARGB_PM_to_ARGB(QImageData *dest, const QImageData *src) { Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied || src->format == QImage::Format_RGBA8888_Premultiplied); Q_ASSERT(dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_RGBA8888); @@ -940,78 +802,6 @@ static void convert_ARGB_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt: } } -static void convert_ARGB_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied || src->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_RGBX8888); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const QRgb *src_data = (QRgb *) src->data; - QRgb *dest_data = (QRgb *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const QRgb *end = src_data + src->width; - while (src_data < end) { - *dest_data = 0xff000000 | qUnpremultiply(*src_data); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void convert_ARGB_PM_to_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_RGBX8888); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const QRgb *src_data = (QRgb *) src->data; - QRgb *dest_data = (QRgb *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const QRgb *end = src_data + src->width; - while (src_data < end) { - *dest_data = ARGB2RGBA(0xff000000 | qUnpremultiply(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void convert_ARGB_PM_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_RGBA8888); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const QRgb *src_data = (QRgb *) src->data; - QRgb *dest_data = (QRgb *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const QRgb *end = src_data + src->width; - while (src_data < end) { - *dest_data = ARGB2RGBA(qUnpremultiply(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - static void convert_RGBA_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBX8888); @@ -1036,78 +826,6 @@ static void convert_RGBA_to_RGB(QImageData *dest, const QImageData *src, Qt::Ima } } -static void convert_RGB_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_RGB32); - Q_ASSERT(dest->format == QImage::Format_RGBX8888 || dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const uint *src_data = (const uint *)src->data; - uint *dest_data = (uint *)dest->data; - - for (int i = 0; i < src->height; ++i) { - const uint *end = src_data + src->width; - while (src_data < end) { - *dest_data = ARGB2RGBA(*src_data | 0xff000000); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void convert_RGBA_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_ARGB32); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const QRgb *src_data = (QRgb *) src->data; - QRgb *dest_data = (QRgb *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const QRgb *end = src_data + src->width; - while (src_data < end) { - *dest_data = qUnpremultiply(RGBA2ARGB(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void convert_RGBA_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_RGB32); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const QRgb *src_data = (QRgb *) src->data; - QRgb *dest_data = (QRgb *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const QRgb *end = src_data + src->width; - while (src_data < end) { - *dest_data = 0xff000000 | qUnpremultiply(RGBA2ARGB(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - static void swap_bit_order(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB); @@ -1151,6 +869,26 @@ static void mask_alpha_converter(QImageData *dest, const QImageData *src, Qt::Im } } +template<QImage::Format DestFormat> +static bool mask_alpha_converter_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_RGB32 || DestFormat == QImage::Format_RGB32); + + const int pad = (data->bytes_per_line >> 2) - data->width; + QRgb *rgb_data = (QRgb *) data->data; + + for (int i = 0; i < data->height; ++i) { + const QRgb *end = rgb_data + data->width; + while (rgb_data < end) { + *rgb_data = *rgb_data | 0xff000000; + ++rgb_data; + } + rgb_data += pad; + } + data->format = DestFormat; + return true; +} + static void mask_alpha_converter_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags) { #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN @@ -1475,7 +1213,7 @@ static void convert_X_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageC static void convert_ARGB_PM_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) { QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32)); - convert_ARGB_PM_to_ARGB(tmp.data(), src, flags); + convert_ARGB_PM_to_ARGB(tmp.data(), src); dither_to_Mono(dst, tmp.data(), flags, false); } @@ -1755,7 +1493,7 @@ static void convert_RGB_to_Indexed8(QImageData *dst, const QImageData *src, Qt:: static void convert_ARGB_PM_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) { QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32)); - convert_ARGB_PM_to_ARGB(tmp.data(), src, flags); + convert_ARGB_PM_to_ARGB(tmp.data(), src); convert_RGB_to_Indexed8(dst, tmp.data(), flags); } @@ -2113,9 +1851,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - convert_RGB_to_RGBA, - convert_RGB_to_RGBA, - convert_RGB_to_RGBA, + 0, + 0, + 0, convert_RGB_to_RGB30<PixelOrderBGR>, convert_RGB_to_RGB30<PixelOrderBGR>, convert_RGB_to_RGB30<PixelOrderRGB>, @@ -2142,7 +1880,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, convert_ARGB_to_RGBx, convert_ARGB_to_RGBA, - convert_ARGB_to_RGBA_PM, + 0, convert_RGB_to_RGB30<PixelOrderBGR>, 0, convert_RGB_to_RGB30<PixelOrderRGB>, @@ -2155,8 +1893,6 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_ARGB_PM_to_Mono, convert_ARGB_PM_to_Mono, convert_ARGB_PM_to_Indexed8, - convert_ARGB_PM_to_RGB, - convert_ARGB_PM_to_ARGB, 0, 0, 0, @@ -2167,13 +1903,15 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - convert_ARGB_PM_to_RGBx, - convert_ARGB_PM_to_RGBA, + 0, + 0, + 0, + 0, convert_ARGB_to_RGBA, - convert_ARGB_PM_to_RGB30<PixelOrderBGR>, - convert_ARGB_to_A2RGB30<PixelOrderBGR>, - convert_ARGB_PM_to_RGB30<PixelOrderRGB>, - convert_ARGB_to_A2RGB30<PixelOrderRGB>, + 0, + 0, + 0, + 0, 0, 0 }, // Format_ARGB32_Premultiplied @@ -2402,7 +2140,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, convert_RGBA_to_RGB, convert_RGBA_to_ARGB, - convert_RGBA_to_ARGB_PM, + 0, 0, 0, 0, @@ -2428,11 +2166,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - convert_RGBA_PM_to_RGB, - convert_RGBA_PM_to_ARGB, - convert_RGBA_to_ARGB, 0, 0, + convert_RGBA_to_ARGB, 0, 0, 0, @@ -2440,15 +2176,10 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - convert_ARGB_PM_to_RGB, - convert_ARGB_PM_to_ARGB, 0, -#else 0, 0, 0, -#endif 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888_Premultiplied @@ -2483,9 +2214,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - convert_A2RGB30_PM_to_RGB<PixelOrderBGR>, 0, - convert_A2RGB30_to_ARGB<PixelOrderBGR>, + 0, + 0, 0, 0, 0, @@ -2535,9 +2266,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - convert_A2RGB30_PM_to_RGB<PixelOrderRGB>, 0, - convert_A2RGB30_to_ARGB<PixelOrderRGB>, + 0, + 0, 0, 0, 0, @@ -2639,8 +2370,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, - 0, + mask_alpha_converter_inplace<QImage::Format_ARGB32>, + mask_alpha_converter_inplace<QImage::Format_ARGB32_Premultiplied>, convert_RGB_to_RGB16_inplace, 0, 0, @@ -2652,19 +2383,20 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0 + 0, + 0, 0, 0, 0, 0, 0 }, // Format_RGB32 { 0, 0, 0, 0, - 0, + mask_alpha_converter_inplace<QImage::Format_RGB32>, 0, #ifdef __SSE2__ convert_ARGB_to_ARGB_PM_inplace_sse2, #else - convert_ARGB_to_ARGB_PM_inplace, + 0, #endif 0, 0, @@ -2677,7 +2409,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, convert_ARGB_to_RGBA_inplace, - 0, 0, 0, 0, 0, 0, 0 + 0, + 0, 0, 0, 0, 0, 0 }, // Format_ARGB32 { 0, @@ -2733,9 +2466,9 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - convert_RGBA_to_ARGB_inplace, - convert_RGBA_to_ARGB_inplace, - convert_RGBA_to_ARGB_inplace, + convert_RGBA_to_ARGB_inplace<QImage::Format_RGB32>, + convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32>, + convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32_Premultiplied>, 0, 0, 0, @@ -2755,9 +2488,9 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, + convert_RGBA_to_ARGB_inplace<QImage::Format_RGB32>, + convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32>, 0, - convert_RGBA_to_ARGB_inplace, - convert_RGBA_to_ARGB_PM_inplace, 0, 0, 0, @@ -2768,8 +2501,13 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN && __SSE2__ 0, + convert_ARGB_to_ARGB_PM_inplace_sse2, +#else 0, + 0, +#endif 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888 { @@ -2779,7 +2517,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - convert_RGBA_to_ARGB_inplace, + convert_RGBA_to_ARGB_inplace<QImage::Format_ARGB32_Premultiplied>, 0, 0, 0, @@ -2967,7 +2705,6 @@ void qInitImageConversions() if (qCpuHasFeature(SSE4_1)) { qimage_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_sse4; qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_RGBA8888_Premultiplied] = convert_ARGB_to_ARGB_PM_sse4; - qimage_converter_map[QImage::Format_ARGB32][QImage::Format_RGBA8888_Premultiplied] = convert_ARGB_to_RGBA_PM_sse4; } #endif diff --git a/src/gui/image/qimage_sse2.cpp b/src/gui/image/qimage_sse2.cpp index 6424e67cfc..4a719d4c26 100644 --- a/src/gui/image/qimage_sse2.cpp +++ b/src/gui/image/qimage_sse2.cpp @@ -43,7 +43,7 @@ QT_BEGIN_NAMESPACE bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionFlags) { - Q_ASSERT(data->format == QImage::Format_ARGB32); + Q_ASSERT(data->format == QImage::Format_ARGB32 || data->format == QImage::Format_RGBA8888); // extra pixels on each line const int spare = data->width & 3; @@ -92,7 +92,10 @@ bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionF d = reinterpret_cast<__m128i*>(p+pad); } - data->format = QImage::Format_ARGB32_Premultiplied; + if (data->format == QImage::Format_ARGB32) + data->format = QImage::Format_ARGB32_Premultiplied; + else + data->format = QImage::Format_RGBA8888_Premultiplied; return true; } diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 26ddef75e1..f461dfef06 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -265,6 +265,29 @@ static const uint *QT_FASTCALL convertRGBFromRGB32(uint *buffer, const uint *src } template<QImage::Format Format> +static const uint *QT_FASTCALL convertARGBPMFromRGB32(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + Q_CONSTEXPR uint alphaMask = ((1 << alphaWidth<Format>()) - 1); + Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); + + Q_CONSTEXPR uchar redRightShift = 24 - redWidth<Format>(); + Q_CONSTEXPR uchar greenRightShift = 16 - greenWidth<Format>(); + Q_CONSTEXPR uchar blueRightShift = 8 - blueWidth<Format>(); + + for (int i = 0; i < count; ++i) { + Q_CONSTEXPR uint alpha = (0xff & alphaMask) << alphaShift<Format>(); + const uint red = ((src[i] >> redRightShift) & redMask) << redShift<Format>(); + const uint green = ((src[i] >> greenRightShift) & greenMask) << greenShift<Format>(); + const uint blue = ((src[i] >> blueRightShift) & blueMask) << blueShift<Format>(); + buffer[i] = alpha | red | green | blue; + } + return buffer; +} + +template<QImage::Format Format> static const uint *QT_FASTCALL convertARGBPMFromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) { @@ -312,7 +335,7 @@ template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixe true, bitsPerPixel<Format>(), convertARGBPMToARGB32PM<Format>, convertARGBPMFromARGB32PM<Format>, - 0 + convertARGBPMFromRGB32<Format> }; } @@ -444,12 +467,11 @@ static const uint *QT_FASTCALL convertFromRGB32(uint *buffer, const uint *src, i Q_ASSERT(layout->redWidth <= 8); Q_ASSERT(layout->greenWidth <= 8); Q_ASSERT(layout->blueWidth <= 8); - Q_ASSERT(layout->alphaWidth == 0); - Q_ASSERT(!layout->premultiplied); const uint redMask = (1 << layout->redWidth) - 1; const uint greenMask = (1 << layout->greenWidth) - 1; const uint blueMask = (1 << layout->blueWidth) - 1; + const uint alphaMask = (1 << layout->alphaWidth) - 1; const uchar redRightShift = 24 - layout->redWidth; const uchar greenRightShift = 16 - layout->greenWidth; @@ -459,7 +481,8 @@ static const uint *QT_FASTCALL convertFromRGB32(uint *buffer, const uint *src, i uint red = ((src[i] >> redRightShift) & redMask) << layout->redShift; uint green = ((src[i] >> greenRightShift) & greenMask) << layout->greenShift; uint blue = ((src[i] >> blueRightShift) & blueMask) << layout->blueShift; - buffer[i] = red | green | blue; + uint alpha = (0xff & alphaMask) << layout->alphaShift; + buffer[i] = red | green | blue | alpha; } return buffer; } @@ -814,10 +837,10 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = { { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0, 0 }, // Format_MonoLSB { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0, 0 }, // Format_Indexed8 // Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong, - // but everywhere this generic conversion would be wrong is currently overloaed. + // but everywhere this generic conversion would be wrong is currently overloaded. { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough }, // Format_RGB32 - { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM, 0 }, // Format_ARGB32 - { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, 0 }, // Format_ARGB32_Premultiplied + { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM, convertPassThrough }, // Format_ARGB32 + { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough }, // Format_ARGB32_Premultiplied #ifdef Q_COMPILER_CONSTEXPR pixelLayoutRGB<QImage::Format_RGB16>(), pixelLayoutARGBPM<QImage::Format_ARGB8565_Premultiplied>(), @@ -830,28 +853,28 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = { pixelLayoutARGBPM<QImage::Format_ARGB4444_Premultiplied>(), #else { 5, 11, 6, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertRGB16ToRGB32, convertRGB16FromARGB32PM, convertRGB16FromRGB32 }, // Format_RGB16 - { 5, 19, 6, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM, 0 }, // Format_ARGB8565_Premultiplied + { 5, 19, 6, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM, convertFromRGB32 }, // Format_ARGB8565_Premultiplied { 6, 12, 6, 6, 6, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32, convertFromARGB32PM, convertFromRGB32 }, // Format_RGB666 - { 6, 12, 6, 6, 6, 0, 6, 18, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM, 0 }, // Format_ARGB6666_Premultiplied + { 6, 12, 6, 6, 6, 0, 6, 18, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM, convertFromRGB32 }, // Format_ARGB6666_Premultiplied { 5, 10, 5, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertFromARGB32PM, convertFromRGB32 }, // Format_RGB555 - { 5, 18, 5, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM, 0 }, // Format_ARGB8555_Premultiplied + { 5, 18, 5, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM, convertFromRGB32 }, // Format_ARGB8555_Premultiplied { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32, convertFromARGB32PM, convertFromRGB32 }, // Format_RGB888 { 4, 8, 4, 4, 4, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertFromARGB32PM, convertFromRGB32 }, // Format_RGB444 - { 4, 8, 4, 4, 4, 0, 4, 12, true, QPixelLayout::BPP16, convertToARGB32PM, convertFromARGB32PM, 0 }, // Format_ARGB4444_Premultiplied + { 4, 8, 4, 4, 4, 0, 4, 12, true, QPixelLayout::BPP16, convertToARGB32PM, convertFromARGB32PM, convertFromRGB32 }, // Format_ARGB4444_Premultiplied #endif #if Q_BYTE_ORDER == Q_BIG_ENDIAN { 8, 24, 8, 16, 8, 8, 0, 0, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBX8888 - { 8, 24, 8, 16, 8, 8, 8, 0, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, 0 }, // Format_RGBA8888 - { 8, 24, 8, 16, 8, 8, 8, 0, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, 0 }, // Format_RGBA8888_Premultiplied + { 8, 24, 8, 16, 8, 8, 8, 0, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBA8888 + { 8, 24, 8, 16, 8, 8, 8, 0, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32}, // Format_RGBA8888_Premultiplied #else { 8, 0, 8, 8, 8, 16, 0, 24, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBX8888 - { 8, 0, 8, 8, 8, 16, 8, 24, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, 0 }, // Format_RGBA8888 (ABGR32) - { 8, 0, 8, 8, 8, 16, 8, 24, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, 0 }, // Format_RGBA8888_Premultiplied + { 8, 0, 8, 8, 8, 16, 8, 24, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBA8888 (ABGR32) + { 8, 0, 8, 8, 8, 16, 8, 24, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBA8888_Premultiplied #endif { 10, 20, 10, 10, 10, 0, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertRGB30FromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR> }, // Format_BGR30 - { 10, 20, 10, 10, 10, 0, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertA2RGB30PMFromARGB32PM<PixelOrderBGR>, 0 }, // Format_A2BGR30_Premultiplied + { 10, 20, 10, 10, 10, 0, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertA2RGB30PMFromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR> }, // Format_A2BGR30_Premultiplied { 10, 0, 10, 10, 10, 20, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertRGB30FromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB> }, // Format_RGB30 - { 10, 0, 10, 10, 10, 20, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertA2RGB30PMFromARGB32PM<PixelOrderRGB>, 0 }, // Format_A2RGB30_Premultiplied + { 10, 0, 10, 10, 10, 20, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertA2RGB30PMFromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB> }, // Format_A2RGB30_Premultiplied { 0, 0, 0, 0, 0, 0, 8, 0, false, QPixelLayout::BPP8, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0 }, // Format_Alpha8 { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32 } // Format_Grayscale8 }; @@ -1074,10 +1097,9 @@ static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, con while (length) { int l = qMin(length, buffer_size); const uint *ptr = 0; - if (layout->convertFromRGB32) { - Q_ASSERT(!layout->premultiplied && !layout->alphaWidth); + if (!layout->premultiplied && !layout->alphaWidth) ptr = layout->convertFromRGB32(buf, buffer, l, layout, 0); - } else + else ptr = layout->convertFromARGB32PM(buf, buffer, l, layout, 0); store(dest, ptr, x, l); length -= l; diff --git a/tests/benchmarks/gui/image/qimageconversion/qimageconversion.pro b/tests/benchmarks/gui/image/qimageconversion/qimageconversion.pro index 1c5fee0be7..c3b6e36e63 100644 --- a/tests/benchmarks/gui/image/qimageconversion/qimageconversion.pro +++ b/tests/benchmarks/gui/image/qimageconversion/qimageconversion.pro @@ -6,3 +6,4 @@ SOURCES += tst_qimageconversion.cpp !contains(QT_CONFIG, no-gif):DEFINES += QTEST_HAVE_GIF !contains(QT_CONFIG, no-jpeg):DEFINES += QTEST_HAVE_JPEG DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 +contains(QT_CONFIG, c++11): CONFIG += c++11 diff --git a/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp b/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp index ef7effae43..d4834a04e2 100644 --- a/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp +++ b/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp @@ -49,6 +49,9 @@ private slots: void convertGeneric_data(); void convertGeneric(); + void convertGenericInplace_data(); + void convertGenericInplace(); + private: QImage generateImageRgb888(int width, int height); QImage generateImageRgb16(int width, int height); @@ -131,6 +134,9 @@ void tst_QImageConversion::convertGeneric_data() QImage rgb16 = generateImageRgb16(1000, 1000); QImage rgb32 = generateImageRgb32(1000, 1000); QImage argb32 = generateImageArgb32(1000, 1000); + QImage argb32pm = argb32.convertToFormat(QImage::Format_ARGB32_Premultiplied); + QImage rgba32 = argb32.convertToFormat(QImage::Format_RGBA8888); + QImage a2rgb30 = argb32.convertToFormat(QImage::Format_A2RGB30_Premultiplied); QTest::newRow("rgb16 -> rgb32") << rgb16 << QImage::Format_RGB32; QTest::newRow("rgb16 -> rgb888") << rgb16 << QImage::Format_RGB888; @@ -141,14 +147,50 @@ void tst_QImageConversion::convertGeneric_data() QTest::newRow("rgb32 -> rgb888") << rgb32 << QImage::Format_RGB888; QTest::newRow("rgb32 -> rgb666") << rgb32 << QImage::Format_RGB666; QTest::newRow("rgb32 -> rgb555") << rgb32 << QImage::Format_RGB555; + QTest::newRow("rgb32 -> argb32") << rgb32 << QImage::Format_ARGB32; + QTest::newRow("rgb32 -> argb32pm") << rgb32 << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("rgb32 -> rgbx8888") << rgb32 << QImage::Format_RGBX8888; + QTest::newRow("rgb32 -> rgba8888") << rgb32 << QImage::Format_RGBA8888; + QTest::newRow("rgb32 -> rgba8888pm") << rgb32 << QImage::Format_RGBA8888_Premultiplied; + QTest::newRow("rgb32 -> rgb30") << rgb32 << QImage::Format_RGB30; + QTest::newRow("rgb32 -> bgr30") << rgb32 << QImage::Format_BGR30; - QTest::newRow("argb32 -> rgba8888") << argb32 << QImage::Format_RGBA8888; QTest::newRow("argb32 -> rgb888") << argb32 << QImage::Format_RGB888; QTest::newRow("argb32 -> rgb666") << argb32 << QImage::Format_RGB666; QTest::newRow("argb32 -> argb8565pm") << argb32 << QImage::Format_ARGB8565_Premultiplied; QTest::newRow("argb32 -> argb4444pm") << argb32 << QImage::Format_ARGB4444_Premultiplied; + QTest::newRow("argb32 -> rgb32") << argb32 << QImage::Format_RGB32; QTest::newRow("argb32 -> argb32pm") << argb32 << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("argb32 -> rgbx8888") << argb32 << QImage::Format_RGBX8888; + QTest::newRow("argb32 -> rgba8888") << argb32 << QImage::Format_RGBA8888; QTest::newRow("argb32 -> rgba8888pm") << argb32 << QImage::Format_RGBA8888_Premultiplied; + QTest::newRow("argb32 -> rgb30") << argb32 << QImage::Format_RGB30; + QTest::newRow("argb32 -> a2rgb30") << argb32 << QImage::Format_A2RGB30_Premultiplied; + + QTest::newRow("argb32pm -> argb4444pm") << argb32pm << QImage::Format_ARGB4444_Premultiplied; + QTest::newRow("argb32pm -> rgb32") << argb32pm << QImage::Format_RGB32; + QTest::newRow("argb32pm -> argb32") << argb32pm << QImage::Format_ARGB32; + QTest::newRow("argb32pm -> rgbx8888") << argb32pm << QImage::Format_RGBX8888; + QTest::newRow("argb32pm -> rgba8888") << argb32pm << QImage::Format_RGBA8888; + QTest::newRow("argb32pm -> rgba8888pm") << argb32pm << QImage::Format_RGBA8888_Premultiplied; + QTest::newRow("argb32pm -> rgb30") << argb32pm << QImage::Format_RGB30; + QTest::newRow("argb32pm -> a2rgb30") << argb32pm << QImage::Format_A2RGB30_Premultiplied; + + QTest::newRow("rgba8888 -> rgb32") << rgba32 << QImage::Format_RGB32; + QTest::newRow("rgba8888 -> argb32") << rgba32 << QImage::Format_ARGB32; + QTest::newRow("rgba8888 -> argb32pm") << rgba32 << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("rgba8888 -> rgbx8888") << rgba32 << QImage::Format_RGBX8888; + QTest::newRow("rgba8888 -> rgba8888pm") << rgba32 << QImage::Format_RGBA8888_Premultiplied; + QTest::newRow("rgba8888 -> rgb30") << rgba32 << QImage::Format_RGB30; + QTest::newRow("rgba8888 -> a2rgb30") << rgba32 << QImage::Format_A2RGB30_Premultiplied; + + QTest::newRow("a2rgb30 -> rgb32") << a2rgb30 << QImage::Format_RGB32; + QTest::newRow("a2rgb30 -> argb32") << a2rgb30 << QImage::Format_ARGB32; + QTest::newRow("a2rgb30 -> argb32pm") << a2rgb30 << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("a2rgb30 -> rgbx8888") << a2rgb30 << QImage::Format_RGBX8888; + QTest::newRow("a2rgb30 -> rgba8888") << a2rgb30 << QImage::Format_RGBA8888; + QTest::newRow("a2rgb30 -> rgba8888pm") << a2rgb30 << QImage::Format_RGBA8888_Premultiplied; + QTest::newRow("a2rgb30 -> bgr30") << a2rgb30 << QImage::Format_BGR30; } void tst_QImageConversion::convertGeneric() @@ -162,6 +204,45 @@ void tst_QImageConversion::convertGeneric() } } +void tst_QImageConversion::convertGenericInplace_data() +{ + QTest::addColumn<QImage>("inputImage"); + QTest::addColumn<QImage::Format>("outputFormat"); + + QImage argb32 = generateImageArgb32(1000, 1000); + QImage argb32pm = argb32.convertToFormat(QImage::Format_ARGB32_Premultiplied); + QImage rgba8888 = argb32.convertToFormat(QImage::Format_RGBA8888); + + QTest::newRow("argb32 -> argb32pm -> argb32") << argb32 << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("argb32 -> rgb32 -> argb32") << argb32 << QImage::Format_RGB32; + QTest::newRow("argb32 -> rgba8888 -> argb32") << argb32 << QImage::Format_RGBA8888; + QTest::newRow("argb32 -> rgba8888pm -> argb32") << argb32 << QImage::Format_RGBA8888_Premultiplied; + + QTest::newRow("argb32pm -> argb32 -> argb32pm") << argb32pm << QImage::Format_ARGB32; + QTest::newRow("argb32pm -> rgb32 -> argb32pm") << argb32pm << QImage::Format_RGB32; + QTest::newRow("argb32pm -> rgba8888pm -> argb32pm") << argb32pm << QImage::Format_RGBA8888_Premultiplied; + QTest::newRow("argb32pm -> rgba8888 -> argb32pm") << argb32pm << QImage::Format_RGBA8888; + QTest::newRow("argb32pm -> rgbx8888 -> argb32pm") << argb32pm << QImage::Format_RGBX8888; + + QTest::newRow("rgba8888 -> argb32 -> rgba8888") << rgba8888 << QImage::Format_ARGB32; + QTest::newRow("rgba8888 -> rgb32 -> rgba8888") << rgba8888 << QImage::Format_RGB32; + QTest::newRow("rgba8888 -> argb32pm -> rgba8888") << rgba8888 << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("rgba8888 -> rgba8888pm -> rgba8888") << rgba8888 << QImage::Format_RGBA8888_Premultiplied; +} + +void tst_QImageConversion::convertGenericInplace() +{ + QFETCH(QImage, inputImage); + QFETCH(QImage::Format, outputFormat); + + QImage::Format inputFormat = inputImage.format(); + QImage tmpImage = qMove(inputImage); + + QBENCHMARK { + tmpImage = (qMove(tmpImage).convertToFormat(outputFormat)).convertToFormat(inputFormat); + } +} + /* Fill a RGB888 image with "random" pixel values. */ |