SSSE3 optimized store of 24-bit formats
Using shuffle and align storing our quint24 format can be done much faster. This in particular improves conversions to RGB888. Change-Id: I179748706a33a43fd6f60f5c40287317418c8867 Reviewed-by: Gunnar Sletta <gunnar@sletta.org>bb10
parent
31a880f1f3
commit
1dd0c4bf1a
|
|
@ -961,7 +961,7 @@ const FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = {
|
|||
fetchPixels<QPixelLayout::BPP32> // BPP32
|
||||
};
|
||||
|
||||
const StorePixelsFunc qStorePixels[QPixelLayout::BPPCount] = {
|
||||
StorePixelsFunc qStorePixels[QPixelLayout::BPPCount] = {
|
||||
0, // BPPNone
|
||||
storePixels<QPixelLayout::BPP1MSB>, // BPP1MSB
|
||||
storePixels<QPixelLayout::BPP1LSB>, // BPP1LSB
|
||||
|
|
@ -6375,10 +6375,12 @@ static void qInitDrawhelperFunctions()
|
|||
int w, int h,
|
||||
int const_alpha);
|
||||
|
||||
extern void QT_FASTCALL storePixelsBPP24_ssse3(uchar *dest, const uint *src, int index, int count);
|
||||
qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
|
||||
qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
|
||||
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;
|
||||
qStorePixels[QPixelLayout::BPP24] = storePixelsBPP24_ssse3;
|
||||
}
|
||||
#endif // SSSE3
|
||||
|
||||
|
|
|
|||
|
|
@ -1213,7 +1213,7 @@ typedef void (QT_FASTCALL *StorePixelsFunc)(uchar *dest, const uint *src, int in
|
|||
|
||||
extern QPixelLayout qPixelLayouts[QImage::NImageFormats];
|
||||
extern const FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount];
|
||||
extern const StorePixelsFunc qStorePixels[QPixelLayout::BPPCount];
|
||||
extern StorePixelsFunc qStorePixels[QPixelLayout::BPPCount];
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -176,6 +176,63 @@ void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl,
|
|||
}
|
||||
}
|
||||
|
||||
static inline void store_uint24_ssse3(uchar *dst, const uint *src, int len)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
quint24 *dst24 = reinterpret_cast<quint24*>(dst);
|
||||
// Align dst on 16 bytes
|
||||
for (; i < len && (reinterpret_cast<quintptr>(dst24) & 0xf); ++i)
|
||||
*dst24++ = quint24(*src++);
|
||||
|
||||
// Shuffle masks for first and second half of every output, all outputs are aligned so the shuffled ends are not used.
|
||||
const __m128i shuffleMask1 = _mm_setr_epi8(char(0x80), char(0x80), char(0x80), char(0x80), 2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12);
|
||||
const __m128i shuffleMask2 = _mm_setr_epi8(2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, char(0x80), char(0x80), char(0x80), char(0x80));
|
||||
|
||||
const __m128i *inVectorPtr = (const __m128i *)src;
|
||||
__m128i *dstVectorPtr = (__m128i *)dst24;
|
||||
|
||||
for (; i < (len - 15); i += 16) {
|
||||
// Load four vectors, store three.
|
||||
// Create each output vector by combining two shuffled input vectors.
|
||||
__m128i srcVector1 = _mm_loadu_si128(inVectorPtr);
|
||||
++inVectorPtr;
|
||||
__m128i srcVector2 = _mm_loadu_si128(inVectorPtr);
|
||||
++inVectorPtr;
|
||||
__m128i outputVector1 = _mm_shuffle_epi8(srcVector1, shuffleMask1);
|
||||
__m128i outputVector2 = _mm_shuffle_epi8(srcVector2, shuffleMask2);
|
||||
__m128i outputVector = _mm_alignr_epi8(outputVector2, outputVector1, 4);
|
||||
_mm_store_si128(dstVectorPtr, outputVector);
|
||||
++dstVectorPtr;
|
||||
|
||||
srcVector1 = _mm_loadu_si128(inVectorPtr);
|
||||
++inVectorPtr;
|
||||
outputVector1 = _mm_shuffle_epi8(srcVector2, shuffleMask1);
|
||||
outputVector2 = _mm_shuffle_epi8(srcVector1, shuffleMask2);
|
||||
outputVector = _mm_alignr_epi8(outputVector2, outputVector1, 8);
|
||||
_mm_store_si128(dstVectorPtr, outputVector);
|
||||
++dstVectorPtr;
|
||||
|
||||
srcVector2 = _mm_loadu_si128(inVectorPtr);
|
||||
++inVectorPtr;
|
||||
outputVector1 = _mm_shuffle_epi8(srcVector1, shuffleMask1);
|
||||
outputVector2 = _mm_shuffle_epi8(srcVector2, shuffleMask2);
|
||||
outputVector = _mm_alignr_epi8(outputVector2, outputVector1, 12);
|
||||
_mm_store_si128(dstVectorPtr, outputVector);
|
||||
++dstVectorPtr;
|
||||
}
|
||||
dst24 = reinterpret_cast<quint24*>(dstVectorPtr);
|
||||
src = reinterpret_cast<const uint*>(inVectorPtr);
|
||||
|
||||
for (; i < len; ++i)
|
||||
*dst24++ = quint24(*src++);
|
||||
}
|
||||
|
||||
void QT_FASTCALL storePixelsBPP24_ssse3(uchar *dest, const uint *src, int index, int count)
|
||||
{
|
||||
store_uint24_ssse3(dest + index * 3, src, count);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_COMPILER_SUPPORTS_SSSE3
|
||||
|
|
|
|||
|
|
@ -90,10 +90,8 @@ void tst_QImageConversion::convertRgb888ToRgb32()
|
|||
QFETCH(QImage, inputImage);
|
||||
|
||||
QBENCHMARK {
|
||||
volatile QImage output = inputImage.convertToFormat(QImage::Format_RGB32);
|
||||
// we need the volatile and the following to make sure the compiler does not do
|
||||
// anything stupid :)
|
||||
(void)output;
|
||||
QImage output = inputImage.convertToFormat(QImage::Format_RGB32);
|
||||
output.constBits();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,10 +105,8 @@ void tst_QImageConversion::convertRgb888ToRgbx8888()
|
|||
QFETCH(QImage, inputImage);
|
||||
|
||||
QBENCHMARK {
|
||||
volatile QImage output = inputImage.convertToFormat(QImage::Format_RGBX8888);
|
||||
// we need the volatile and the following to make sure the compiler does not do
|
||||
// anything stupid :)
|
||||
(void)output;
|
||||
QImage output = inputImage.convertToFormat(QImage::Format_RGBX8888);
|
||||
output.constBits();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,10 +136,8 @@ void tst_QImageConversion::convertRgb32ToRgb888()
|
|||
QFETCH(QImage, inputImage);
|
||||
|
||||
QBENCHMARK {
|
||||
volatile QImage output = inputImage.convertToFormat(QImage::Format_RGB888);
|
||||
// we need the volatile and the following to make sure the compiler does not do
|
||||
// anything stupid :)
|
||||
(void)output;
|
||||
QImage output = inputImage.convertToFormat(QImage::Format_RGB888);
|
||||
output.constBits();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -157,6 +151,8 @@ void tst_QImageConversion::convertRgb16_data()
|
|||
QTest::newRow("rgb888") << rgb16 << QImage::Format_RGB888;
|
||||
QTest::newRow("rgb666") << rgb16 << QImage::Format_RGB666;
|
||||
QTest::newRow("rgb555") << rgb16 << QImage::Format_RGB555;
|
||||
QTest::newRow("argb8565") << rgb16 << QImage::Format_ARGB8565_Premultiplied;
|
||||
QTest::newRow("argb8555") << rgb16 << QImage::Format_ARGB8555_Premultiplied;
|
||||
}
|
||||
|
||||
void tst_QImageConversion::convertRgb16()
|
||||
|
|
@ -189,6 +185,7 @@ void tst_QImageConversion::convertRgb32_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 -> argb8565pm") << rgb32 << QImage::Format_ARGB8565_Premultiplied;
|
||||
|
||||
QTest::newRow("argb32 -> rgb16") << argb32 << QImage::Format_RGB16;
|
||||
QTest::newRow("argb32 -> rgb32") << argb32 << QImage::Format_RGB32;
|
||||
|
|
@ -237,12 +234,14 @@ void tst_QImageConversion::convertGeneric_data()
|
|||
QImage rgba32 = argb32.convertToFormat(QImage::Format_RGBA8888);
|
||||
QImage bgr30 = rgb32.convertToFormat(QImage::Format_BGR30);
|
||||
QImage a2rgb30 = argb32.convertToFormat(QImage::Format_A2RGB30_Premultiplied);
|
||||
QImage rgb666 = rgb32.convertToFormat(QImage::Format_RGB666);
|
||||
|
||||
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 -> rgb888") << rgba32 << QImage::Format_RGB888;
|
||||
QTest::newRow("rgba8888 -> rgb30") << rgba32 << QImage::Format_RGB30;
|
||||
QTest::newRow("rgba8888 -> a2bgr30") << rgba32 << QImage::Format_A2BGR30_Premultiplied;
|
||||
|
||||
|
|
@ -264,6 +263,14 @@ void tst_QImageConversion::convertGeneric_data()
|
|||
QTest::newRow("a2rgb30 -> rgb30") << a2rgb30 << QImage::Format_RGB30;
|
||||
QTest::newRow("a2rgb30 -> bgr30") << a2rgb30 << QImage::Format_BGR30;
|
||||
QTest::newRow("a2rgb30 -> a2bgr30") << a2rgb30 << QImage::Format_A2BGR30_Premultiplied;
|
||||
|
||||
QTest::newRow("rgb666 -> rgb32") << rgb666 << QImage::Format_RGB32;
|
||||
QTest::newRow("rgb666 -> argb32") << rgb666 << QImage::Format_ARGB32;
|
||||
QTest::newRow("rgb666 -> argb32pm") << rgb666 << QImage::Format_ARGB32_Premultiplied;
|
||||
QTest::newRow("rgb666 -> rgb888") << rgb666 << QImage::Format_RGB888;
|
||||
QTest::newRow("rgb666 -> rgb16") << rgb666 << QImage::Format_RGB16;
|
||||
QTest::newRow("rgb666 -> rgb555") << rgb666 << QImage::Format_RGB555;
|
||||
QTest::newRow("rgb666 -> rgb30") << rgb666 << QImage::Format_RGB30;
|
||||
}
|
||||
|
||||
void tst_QImageConversion::convertGeneric()
|
||||
|
|
@ -285,6 +292,9 @@ void tst_QImageConversion::convertGenericInplace_data()
|
|||
QImage argb32 = generateImageArgb32(1000, 1000);
|
||||
QImage argb32pm = argb32.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
QImage rgba8888 = argb32.convertToFormat(QImage::Format_RGBA8888);
|
||||
QImage argb6666 = argb32.convertToFormat(QImage::Format_ARGB6666_Premultiplied);
|
||||
QImage argb4444 = argb32.convertToFormat(QImage::Format_ARGB4444_Premultiplied);
|
||||
QImage rgb16 = argb32.convertToFormat(QImage::Format_RGB16);
|
||||
|
||||
QTest::newRow("argb32 -> argb32pm -> argb32") << argb32 << QImage::Format_ARGB32_Premultiplied;
|
||||
QTest::newRow("argb32 -> rgb32 -> argb32") << argb32 << QImage::Format_RGB32;
|
||||
|
|
@ -301,6 +311,16 @@ void tst_QImageConversion::convertGenericInplace_data()
|
|||
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;
|
||||
|
||||
QTest::newRow("argb6666pm -> argb8565pm -> argb6666pm") << argb6666 << QImage::Format_ARGB8565_Premultiplied;
|
||||
QTest::newRow("argb6666pm -> rgb888 -> argb6666pm") << argb6666 << QImage::Format_RGB888;
|
||||
|
||||
QTest::newRow("argb4444pm -> rgb16 -> argb4444pm") << argb4444 << QImage::Format_RGB16;
|
||||
QTest::newRow("argb4444pm -> rgb444 -> argb4444pm") << argb4444 << QImage::Format_RGB444;
|
||||
|
||||
QTest::newRow("rgb16 -> rgb555 -> rgb16") << rgb16 << QImage::Format_RGB555;
|
||||
QTest::newRow("rgb16 -> rgb444 -> rgb16") << rgb16 << QImage::Format_RGB444;
|
||||
QTest::newRow("rgb16 -> argb4444pm -> rgb16") << rgb16 << QImage::Format_ARGB4444_Premultiplied;
|
||||
}
|
||||
|
||||
void tst_QImageConversion::convertGenericInplace()
|
||||
|
|
|
|||
Loading…
Reference in New Issue