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 <eirik.aavitsland@qt.io>
This commit is contained in:
Allan Sandfeld Jensen 2019-07-05 12:49:04 +02:00
parent 236d4637b2
commit f92d8fd64e
5 changed files with 127 additions and 146 deletions

View File

@ -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) {

View File

@ -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<QtPixelOrder PixelOrder, bool RGBA>
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<QRgb> fix_color_table(const QVector<QRgb> &ctbl, QImage::Format format)
{
QVector<QRgb> colorTable = ctbl;
@ -2635,7 +2569,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_RGB888_to_RGB<true>,
convert_RGB888_to_RGB<true>,
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<false>,
0,
convert_A2RGB30_PM_to_RGB30<true>,
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<PixelOrderRGB, true>,
0,
convert_A2RGB30_PM_to_RGB30<true>,
convert_BGR30_to_RGB30,
convert_rgbswap_generic,
convert_A2RGB30_PM_to_RGB30<false>,
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<QImage::Format_A2BGR30_Premultiplied>,
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<false>,
0, // self
convert_A2RGB30_PM_to_RGB30_inplace<true>,
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<QImage::Format_A2RGB30_Premultiplied>,
@ -3345,7 +3279,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderRGB, true>,
0,
convert_A2RGB30_PM_to_RGB30_inplace<true>,
convert_BGR30_to_RGB30_inplace,
convert_rgbswap_generic_inplace,
convert_A2RGB30_PM_to_RGB30_inplace<false>,
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
};

View File

@ -669,8 +669,7 @@ static void QT_FASTCALL rbSwap_rgb30(uchar *d, const uchar *s, int count)
{
const uint *src = reinterpret_cast<const uint *>(s);
uint *dest = reinterpret_cast<uint *>(d);
for (int i = 0; i < count; ++i)
dest[i] = qRgbSwapRgb30(src[i]);
UNALIASED_CONVERSION_LOOP(dest, src, count, qRgbSwapRgb30);
}
template<QImage::Format Format> 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

View File

@ -40,7 +40,7 @@
#include <private/qdrawhelper_x86_p.h>
#ifdef QT_COMPILER_SUPPORTS_SSSE3
#if defined(QT_COMPILER_SUPPORTS_SSSE3)
#include <private/qdrawingprimitive_sse2_p.h>
@ -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

View File

@ -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;
}