From f92d8fd64ebbb0405363c745dbd3c084946ed039 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Fri, 5 Jul 2019 12:49:04 +0200 Subject: Combine BGR30_to_RGB30 and BGR888_to_RGB888 And let the meat of the function be shared with the rbSwap routine. Change-Id: I0ea18b30c26ff050c17dcb3ad4d654bfbb8c6221 Reviewed-by: Eirik Aavitsland --- src/gui/image/qimage.cpp | 2 +- src/gui/image/qimage_conversions.cpp | 218 +++++++-------------- src/gui/painting/qdrawhelper.cpp | 6 +- src/gui/painting/qdrawhelper_ssse3.cpp | 45 ++++- .../qimageconversion/tst_qimageconversion.cpp | 2 + 5 files changed, 127 insertions(+), 146 deletions(-) diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 86130132a4..dda407181a 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -3370,7 +3370,7 @@ void QImage::mirrored_inplace(bool horizontal, bool vertical) \sa {QImage#Image Transformations}{Image Transformations} */ -inline void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout* layout) +static inline void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout* layout) { const RbSwapFunc func = layout->rbSwap; if (!func) { diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 539bac222a..9e1df7058c 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -564,6 +564,67 @@ static bool convert_RGBA_to_ARGB_inplace(QImageData *data, Qt::ImageConversionFl return true; } +static void convert_rgbswap_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const RbSwapFunc func = qPixelLayouts[src->format].rbSwap; + Q_ASSERT(func); + + const qsizetype sbpl = src->bytes_per_line; + const qsizetype dbpl = dest->bytes_per_line; + const uchar *src_data = src->data; + uchar *dest_data = dest->data; + + for (int i = 0; i < src->height; ++i) { + func(dest_data, src_data, src->width); + + src_data += sbpl; + dest_data += dbpl; + } +} + +static bool convert_rgbswap_generic_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + const RbSwapFunc func = qPixelLayouts[data->format].rbSwap; + Q_ASSERT(func); + + const qsizetype bpl = data->bytes_per_line; + uchar *line_data = data->data; + + for (int i = 0; i < data->height; ++i) { + func(line_data, line_data, data->width); + line_data += bpl; + } + + switch (data->format) { + case QImage::Format_RGB888: + data->format = QImage::Format_BGR888; + break; + case QImage::Format_BGR888: + data->format = QImage::Format_RGB888; + break; + case QImage::Format_BGR30: + data->format = QImage::Format_RGB30; + break; + case QImage::Format_A2BGR30_Premultiplied: + data->format = QImage::Format_A2RGB30_Premultiplied; + break; + case QImage::Format_RGB30: + data->format = QImage::Format_BGR30; + break; + case QImage::Format_A2RGB30_Premultiplied: + data->format = QImage::Format_A2BGR30_Premultiplied; + break; + default: + Q_UNREACHABLE(); + data->format = QImage::Format_Invalid; + return false; + } + return true; +} + template static void convert_RGB_to_RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { @@ -693,74 +754,10 @@ static bool convert_A2RGB30_PM_to_RGB30_inplace(QImageData *data, Qt::ImageConve return true; } -static void convert_BGR30_to_RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_RGB30 || src->format == QImage::Format_BGR30 || - src->format == QImage::Format_A2RGB30_Premultiplied || src->format == QImage::Format_A2BGR30_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_RGB30 || dest->format == QImage::Format_BGR30 || - dest->format == QImage::Format_A2RGB30_Premultiplied || dest->format == QImage::Format_A2BGR30_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 = qRgbSwapRgb30(*src_data); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static bool convert_BGR30_to_RGB30_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_RGB30 || data->format == QImage::Format_BGR30 || - data->format == QImage::Format_A2RGB30_Premultiplied || data->format == QImage::Format_A2BGR30_Premultiplied); - - const int pad = (data->bytes_per_line >> 2) - data->width; - uint *rgb_data = (uint *) data->data; - - for (int i = 0; i < data->height; ++i) { - const uint *end = rgb_data + data->width; - while (rgb_data < end) { - *rgb_data = qRgbSwapRgb30(*rgb_data); - ++rgb_data; - } - rgb_data += pad; - } - - switch (data->format) { - case QImage::Format_BGR30: - data->format = QImage::Format_RGB30; - break; - case QImage::Format_A2BGR30_Premultiplied: - data->format = QImage::Format_A2RGB30_Premultiplied; - break; - case QImage::Format_RGB30: - data->format = QImage::Format_BGR30; - break; - case QImage::Format_A2RGB30_Premultiplied: - data->format = QImage::Format_A2BGR30_Premultiplied; - break; - default: - Q_UNREACHABLE(); - data->format = QImage::Format_Invalid; - return false; - } - return true; -} - static bool convert_BGR30_to_A2RGB30_inplace(QImageData *data, Qt::ImageConversionFlags flags) { Q_ASSERT(data->format == QImage::Format_RGB30 || data->format == QImage::Format_BGR30); - if (!convert_BGR30_to_RGB30_inplace(data, flags)) + if (!convert_rgbswap_generic_inplace(data, flags)) return false; if (data->format == QImage::Format_RGB30) @@ -1421,69 +1418,6 @@ static void convert_RGBA64_to_gray16(QImageData *dest, const QImageData *src, Qt } } -static void convert_RGB888_to_BGR888(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_RGB888 || src->format == QImage::Format_BGR888); - Q_ASSERT(dest->format == QImage::Format_RGB888 || dest->format == QImage::Format_BGR888); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const qsizetype sbpl = src->bytes_per_line; - const qsizetype dbpl = dest->bytes_per_line; - const uchar *src_data = src->data; - uchar *dest_data = dest->data; - - for (int i = 0; i < src->height; ++i) { - int pixel = 0; - // Handle 4 pixels (12 bytes) at a time - for (; pixel + 3 < src->width; pixel += 4) { - const uchar *src = src_data + pixel * 3; - quint32 *dest_packed = (quint32 *) (dest_data + pixel * 3); - dest_packed[0] = (src[5] << 24) | (src[0] << 16) | (src[1] << 8) | (src[2] << 0); - dest_packed[1] = (src[7] << 24) | (src[8] << 16) | (src[3] << 8) | (src[4] << 0); - dest_packed[2] = (src[9] << 24) | (src[10] << 16) | (src[11] << 8) | (src[6] << 0); - } - - // epilog: handle left over pixels - for (; pixel < src->width; ++pixel) { - dest_data[pixel * 3 + 0] = src_data[pixel * 3 + 2]; - dest_data[pixel * 3 + 1] = src_data[pixel * 3 + 1]; - dest_data[pixel * 3 + 2] = src_data[pixel * 3 + 0]; - } - - src_data += sbpl; - dest_data += dbpl; - } -} - -static bool convert_RGB888_to_BGR888_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_RGB888 || data->format == QImage::Format_BGR888); - - const qsizetype bpl = data->bytes_per_line; - uchar *line_data = data->data; - - for (int i = 0; i < data->height; ++i) { - for (int j = 0; j < data->width; ++j) - qSwap(line_data[j * 3 + 0], line_data[j * 3 + 2]); - line_data += bpl; - } - - switch (data->format) { - case QImage::Format_RGB888: - data->format = QImage::Format_BGR888; - break; - case QImage::Format_BGR888: - data->format = QImage::Format_RGB888; - break; - default: - Q_UNREACHABLE(); - data->format = QImage::Format_Invalid; - return false; - } - return true; -} - static QVector fix_color_table(const QVector &ctbl, QImage::Format format) { QVector colorTable = ctbl; @@ -2635,7 +2569,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_RGB888_to_RGB, convert_RGB888_to_RGB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - convert_RGB888_to_BGR888, + convert_rgbswap_generic, }, // Format_RGB888 { @@ -2781,8 +2715,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, convert_passthrough, - convert_BGR30_to_RGB30, - convert_BGR30_to_RGB30, + convert_rgbswap_generic, + convert_rgbswap_generic, 0, 0, 0, 0, 0, 0, 0 }, // Format_BGR30 @@ -2809,7 +2743,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_A2RGB30_PM_to_RGB30, 0, convert_A2RGB30_PM_to_RGB30, - convert_BGR30_to_RGB30, + convert_rgbswap_generic, 0, 0, 0, 0, 0, 0, 0 }, // Format_A2BGR30_Premultiplied @@ -2833,8 +2767,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - convert_BGR30_to_RGB30, - convert_BGR30_to_RGB30, + convert_rgbswap_generic, + convert_rgbswap_generic, 0, convert_passthrough, 0, 0, 0, 0, 0, 0, 0 @@ -2860,7 +2794,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_A2RGB30_PM_to_ARGB, 0, convert_A2RGB30_PM_to_RGB30, - convert_BGR30_to_RGB30, + convert_rgbswap_generic, convert_A2RGB30_PM_to_RGB30, 0, 0, 0, @@ -3013,7 +2947,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - convert_RGB888_to_BGR888, + convert_rgbswap_generic, 0, 0, #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN @@ -3161,7 +3095,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma }, // Format_ARGB8555_Premultiplied { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - convert_RGB888_to_BGR888_inplace + convert_rgbswap_generic_inplace }, // Format_RGB888 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 @@ -3267,7 +3201,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, // self convert_passthrough_inplace, - convert_BGR30_to_RGB30_inplace, + convert_rgbswap_generic_inplace, convert_BGR30_to_A2RGB30_inplace, 0, 0, 0, 0, 0, 0, 0 @@ -3295,7 +3229,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_A2RGB30_PM_to_RGB30_inplace, 0, // self convert_A2RGB30_PM_to_RGB30_inplace, - convert_BGR30_to_RGB30_inplace, + convert_rgbswap_generic_inplace, 0, 0, 0, 0, 0, 0, 0 }, // Format_A2BGR30_Premultiplied { @@ -3318,7 +3252,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - convert_BGR30_to_RGB30_inplace, + convert_rgbswap_generic_inplace, convert_BGR30_to_A2RGB30_inplace, 0, // self convert_passthrough_inplace, @@ -3345,7 +3279,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_A2RGB30_PM_to_ARGB_inplace, 0, convert_A2RGB30_PM_to_RGB30_inplace, - convert_BGR30_to_RGB30_inplace, + convert_rgbswap_generic_inplace, convert_A2RGB30_PM_to_RGB30_inplace, 0, // self 0, 0, @@ -3427,7 +3361,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma }, // Format_Grayscale16 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - convert_RGB888_to_BGR888_inplace, + convert_rgbswap_generic_inplace, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_BGR888 }; diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index c17bf2ddfd..edb363ac69 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -669,8 +669,7 @@ static void QT_FASTCALL rbSwap_rgb30(uchar *d, const uchar *s, int count) { const uint *src = reinterpret_cast(s); uint *dest = reinterpret_cast(d); - for (int i = 0; i < count; ++i) - dest[i] = qRgbSwapRgb30(src[i]); + UNALIASED_CONVERSION_LOOP(dest, src, count, qRgbSwapRgb30); } template Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutRGB() @@ -6774,6 +6773,9 @@ static void qInitDrawhelperFunctions() qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3; qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3; sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_ssse3; + extern void QT_FASTCALL rbSwap_888_ssse3(uchar *dst, const uchar *src, int count); + qPixelLayouts[QImage::Format_RGB888].rbSwap = rbSwap_888_ssse3; + qPixelLayouts[QImage::Format_BGR888].rbSwap = rbSwap_888_ssse3; } #endif // SSSE3 diff --git a/src/gui/painting/qdrawhelper_ssse3.cpp b/src/gui/painting/qdrawhelper_ssse3.cpp index 35d61c3e6c..14d7047bb6 100644 --- a/src/gui/painting/qdrawhelper_ssse3.cpp +++ b/src/gui/painting/qdrawhelper_ssse3.cpp @@ -40,7 +40,7 @@ #include -#ifdef QT_COMPILER_SUPPORTS_SSSE3 +#if defined(QT_COMPILER_SUPPORTS_SSSE3) #include @@ -254,6 +254,49 @@ void qt_memfill24_ssse3(quint24 *dest, quint24 color, qsizetype count) } } +void QT_FASTCALL rbSwap_888_ssse3(uchar *dst, const uchar *src, int count) +{ + int i = 0; + + const static __m128i shuffleMask1 = _mm_setr_epi8(2, 1, 0, 5, 4, 3, 8, 7, 6, 11, 10, 9, 14, 13, 12, /*!!*/15); + const static __m128i shuffleMask2 = _mm_setr_epi8(0, /*!!*/1, 4, 3, 2, 7, 6, 5, 10, 9, 8, 13, 12, 11, /*!!*/14, 15); + const static __m128i shuffleMask3 = _mm_setr_epi8(/*!!*/0, 3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, 15, 14, 13); + + for (; i + 15 < count; i += 16) { + __m128i s1 = _mm_loadu_si128((const __m128i *)src); + __m128i s2 = _mm_loadu_si128((const __m128i *)(src + 16)); + __m128i s3 = _mm_loadu_si128((const __m128i *)(src + 32)); + s1 = _mm_shuffle_epi8(s1, shuffleMask1); + s2 = _mm_shuffle_epi8(s2, shuffleMask2); + s3 = _mm_shuffle_epi8(s3, shuffleMask3); + _mm_storeu_si128((__m128i *)dst, s1); + _mm_storeu_si128((__m128i *)(dst + 16), s2); + _mm_storeu_si128((__m128i *)(dst + 32), s3); + + // Now fix the last four misplaced values + std::swap(dst[15], dst[17]); + std::swap(dst[30], dst[32]); + + src += 48; + dst += 48; + } + + if (src != dst) { + SIMD_EPILOGUE(i, count, 15) { + dst[0] = src[2]; + dst[1] = src[1]; + dst[2] = src[0]; + dst += 3; + src += 3; + } + } else { + SIMD_EPILOGUE(i, count, 15) { + std::swap(dst[0], dst[2]); + dst += 3; + } + } +} + QT_END_NAMESPACE #endif // QT_COMPILER_SUPPORTS_SSSE3 diff --git a/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp b/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp index b88669e9ce..b8afb3bc05 100644 --- a/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp +++ b/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp @@ -342,6 +342,7 @@ void tst_QImageConversion::convertGenericInplace_data() QImage argb6666 = argb32.convertToFormat(QImage::Format_ARGB6666_Premultiplied); QImage argb4444 = argb32.convertToFormat(QImage::Format_ARGB4444_Premultiplied); QImage rgb16 = argb32.convertToFormat(QImage::Format_RGB16); + QImage rgb30 = argb32.convertToFormat(QImage::Format_RGB30); QImage rgb888 = argb32.convertToFormat(QImage::Format_RGB888); QTest::newRow("argb32 -> argb32pm -> argb32") << argb32 << QImage::Format_ARGB32_Premultiplied; @@ -370,6 +371,7 @@ void tst_QImageConversion::convertGenericInplace_data() QTest::newRow("rgb16 -> rgb444 -> rgb16") << rgb16 << QImage::Format_RGB444; QTest::newRow("rgb16 -> argb4444pm -> rgb16") << rgb16 << QImage::Format_ARGB4444_Premultiplied; + QTest::newRow("rgb30 -> bgr30 -> rgb30") << rgb30 << QImage::Format_BGR30; QTest::newRow("rgb888 -> bgr888 -> rgb888") << rgb888 << QImage::Format_BGR888; } -- cgit v1.2.3