Optimize RGBA64PM->RGBA64 for SSE4

And remove direct conversion to take advantage of both the SIMD, but
also threading on all platforms.

Change-Id: I782ae7c80e82b694e23abee28d69cecd0d28c32f
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Allan Sandfeld Jensen 2021-01-26 17:14:15 +01:00
parent 9505bd84db
commit 0c5d9b953e
3 changed files with 102 additions and 56 deletions

View File

@ -1259,55 +1259,6 @@ static bool convert_RGBA64_to_RGBx64_inplace(QImageData *data, Qt::ImageConversi
return true;
}
template<bool MaskAlpha>
static void convert_RGBA64PM_to_RGBA64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(src->format == QImage::Format_RGBA64_Premultiplied);
Q_ASSERT(dest->format == QImage::Format_RGBA64 || dest->format == QImage::Format_RGBX64);
Q_ASSERT(src->width == dest->width);
Q_ASSERT(src->height == dest->height);
const int src_pad = (src->bytes_per_line >> 3) - src->width;
const int dest_pad = (dest->bytes_per_line >> 3) - dest->width;
const QRgba64 *src_data = reinterpret_cast<const QRgba64 *>(src->data);
QRgba64 *dest_data = reinterpret_cast<QRgba64 *>(dest->data);
for (int i = 0; i < src->height; ++i) {
const QRgba64 *end = src_data + src->width;
while (src_data < end) {
*dest_data = src_data->unpremultiplied();
if (MaskAlpha)
dest_data->setAlpha(65535);
++src_data;
++dest_data;
}
src_data += src_pad;
dest_data += dest_pad;
}
}
template<bool MaskAlpha>
static bool convert_RGBA64PM_to_RGBA64_inplace(QImageData *data, Qt::ImageConversionFlags)
{
Q_ASSERT(data->format == QImage::Format_RGBA64_Premultiplied);
const int pad = (data->bytes_per_line >> 3) - data->width;
QRgba64 *rgb_data = reinterpret_cast<QRgba64 *>(data->data);
for (int i = 0; i < data->height; ++i) {
const QRgba64 *end = rgb_data + data->width;
while (rgb_data < end) {
*rgb_data = rgb_data->unpremultiplied();
if (MaskAlpha)
rgb_data->setAlpha(65535);
++rgb_data;
}
rgb_data += pad;
}
data->format = MaskAlpha ? QImage::Format_RGBX64 : QImage::Format_RGBA64;
return true;
}
static void convert_gray16_to_RGBA64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(src->format == QImage::Format_Grayscale16);
@ -2326,8 +2277,6 @@ static void qInitImageConversions()
qimage_converter_map[QImage::Format_RGBA64][QImage::Format_RGBA8888] = convert_RGBA64_to_ARGB32<true>;
qimage_converter_map[QImage::Format_RGBA64][QImage::Format_RGBX64] = convert_RGBA64_to_RGBx64;
qimage_converter_map[QImage::Format_RGBA64_Premultiplied][QImage::Format_RGBX64] = convert_RGBA64PM_to_RGBA64<true>;
qimage_converter_map[QImage::Format_RGBA64_Premultiplied][QImage::Format_RGBA64] = convert_RGBA64PM_to_RGBA64<false>;
qimage_converter_map[QImage::Format_RGBA64_Premultiplied][QImage::Format_Grayscale16] = convert_RGBA64_to_gray16;
qimage_converter_map[QImage::Format_Grayscale16][QImage::Format_RGBX64] = convert_gray16_to_RGBA64;
@ -2443,11 +2392,6 @@ static void qInitImageConversions()
qimage_inplace_converter_map[QImage::Format_RGBA64][QImage::Format_RGBX64] =
convert_RGBA64_to_RGBx64_inplace;
qimage_inplace_converter_map[QImage::Format_RGBA64_Premultiplied][QImage::Format_RGBX64] =
convert_RGBA64PM_to_RGBA64_inplace<true>;
qimage_inplace_converter_map[QImage::Format_RGBA64_Premultiplied][QImage::Format_RGBA64] =
convert_RGBA64PM_to_RGBA64_inplace<false>;
qimage_inplace_converter_map[QImage::Format_BGR888][QImage::Format_RGB888] =
convert_rgbswap_generic_inplace;

View File

@ -5141,6 +5141,8 @@ static void qInitDrawhelperFunctions()
const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL storeRGBA8888FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL storeRGBA64FromRGBA64PM_sse4(uchar *, const QRgba64 *, int, int, const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL storeRGBx64FromRGBA64PM_sse4(uchar *, const QRgba64 *, int, int, const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL destStore64ARGB32_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
extern void QT_FASTCALL destStore64RGBA8888_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
# ifndef __AVX2__
@ -5162,6 +5164,8 @@ static void qInitDrawhelperFunctions()
qPixelLayouts[QImage::Format_A2RGB30_Premultiplied].storeFromARGB32PM = storeA2RGB30PMFromARGB32PM_sse4<PixelOrderRGB>;
qStoreFromRGBA64PM[QImage::Format_ARGB32] = storeARGB32FromRGBA64PM_sse4;
qStoreFromRGBA64PM[QImage::Format_RGBA8888] = storeRGBA8888FromRGBA64PM_sse4;
qStoreFromRGBA64PM[QImage::Format_RGBX64] = storeRGBx64FromRGBA64PM_sse4;
qStoreFromRGBA64PM[QImage::Format_RGBA64] = storeRGBA64FromRGBA64PM_sse4;
#if QT_CONFIG(raster_64bit)
destStoreProc64[QImage::Format_ARGB32] = destStore64ARGB32_sse4;
destStoreProc64[QImage::Format_RGBA8888] = destStore64RGBA8888_sse4;

View File

@ -327,6 +327,90 @@ static inline void convertARGBFromRGBA64PM_sse4(uint *buffer, const QRgba64 *src
}
}
template<bool mask>
static inline void convertRGBA64FromRGBA64PM_sse4(QRgba64 *buffer, const QRgba64 *src, int count)
{
int i = 0;
if ((_MM_GET_EXCEPTION_MASK() & _MM_MASK_INVALID) == 0) {
for (; i < count; ++i) {
QRgba64 v = src[i].unpremultiplied();
if (mask)
v.setAlpha(65535);
buffer[i] = v;
}
return;
}
const __m128i alphaMask = _mm_set1_epi64x(qint64(Q_UINT64_C(0xffff) << 48));
const __m128i zero = _mm_setzero_si128();
for (; i < count - 3; i += 4) {
__m128i srcVector1 = _mm_loadu_si128((const __m128i *)&src[i + 0]);
__m128i srcVector2 = _mm_loadu_si128((const __m128i *)&src[i + 2]);
bool transparent1 = _mm_testz_si128(srcVector1, alphaMask);
bool opaque1 = _mm_testc_si128(srcVector1, alphaMask);
bool transparent2 = _mm_testz_si128(srcVector2, alphaMask);
bool opaque2 = _mm_testc_si128(srcVector2, alphaMask);
if (!(transparent1 && transparent2)) {
if (!(opaque1 && opaque2)) {
__m128i srcVector1Alpha = _mm_srli_epi64(srcVector1, 48);
__m128i srcVector2Alpha = _mm_srli_epi64(srcVector2, 48);
__m128i srcVectorAlpha = _mm_packus_epi32(srcVector1Alpha, srcVector2Alpha);
const __m128 a = _mm_cvtepi32_ps(srcVectorAlpha);
const __m128 ia = reciprocal_mul_ps(a, 65535.0f);
__m128i src1 = _mm_unpacklo_epi16(srcVector1, zero);
__m128i src2 = _mm_unpackhi_epi16(srcVector1, zero);
__m128i src3 = _mm_unpacklo_epi16(srcVector2, zero);
__m128i src4 = _mm_unpackhi_epi16(srcVector2, zero);
__m128 ia1 = _mm_shuffle_ps(ia, ia, _MM_SHUFFLE(0, 0, 0, 0));
__m128 ia2 = _mm_shuffle_ps(ia, ia, _MM_SHUFFLE(1, 1, 1, 1));
__m128 ia3 = _mm_shuffle_ps(ia, ia, _MM_SHUFFLE(2, 2, 2, 2));
__m128 ia4 = _mm_shuffle_ps(ia, ia, _MM_SHUFFLE(3, 3, 3, 3));
src1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(src1), ia1));
src2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(src2), ia2));
src3 = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(src3), ia3));
src4 = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(src4), ia4));
src1 = _mm_packus_epi32(src1, src2);
src3 = _mm_packus_epi32(src3, src4);
// Handle potential alpha == 0 values:
__m128i srcVector1AlphaMask = _mm_cmpeq_epi64(srcVector1Alpha, zero);
__m128i srcVector2AlphaMask = _mm_cmpeq_epi64(srcVector2Alpha, zero);
src1 = _mm_andnot_si128(srcVector1AlphaMask, src1);
src3 = _mm_andnot_si128(srcVector2AlphaMask, src3);
// Fixup alpha values:
if (mask) {
src1 = _mm_or_si128(src1, alphaMask);
src3 = _mm_or_si128(src3, alphaMask);
} else {
src1 = _mm_blendv_epi8(src1, srcVector1, alphaMask);
src3 = _mm_blendv_epi8(src3, srcVector2, alphaMask);
}
_mm_storeu_si128((__m128i *)&buffer[i + 0], src1);
_mm_storeu_si128((__m128i *)&buffer[i + 2], src3);
} else {
if (mask) {
srcVector1 = _mm_or_si128(srcVector1, alphaMask);
srcVector2 = _mm_or_si128(srcVector2, alphaMask);
}
if (mask || src != buffer) {
_mm_storeu_si128((__m128i *)&buffer[i + 0], srcVector1);
_mm_storeu_si128((__m128i *)&buffer[i + 2], srcVector2);
}
}
} else {
_mm_storeu_si128((__m128i *)&buffer[i + 0], zero);
_mm_storeu_si128((__m128i *)&buffer[i + 2], zero);
}
}
SIMD_EPILOGUE(i, count, 3) {
QRgba64 v = src[i].unpremultiplied();
if (mask)
v.setAlpha(65535);
buffer[i] = v;
}
}
#ifndef __AVX2__
void QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, int count, const QList<QRgb> *)
{
@ -446,6 +530,20 @@ void QT_FASTCALL storeRGBA8888FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src,
convertARGBFromRGBA64PM_sse4<true>(d, src, count);
}
void QT_FASTCALL storeRGBA64FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgba64 *d = (QRgba64 *)dest + index;
convertRGBA64FromRGBA64PM_sse4<false>(d, src, count);
}
void QT_FASTCALL storeRGBx64FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgba64 *d = (QRgba64 *)dest + index;
convertRGBA64FromRGBA64PM_sse4<true>(d, src, count);
}
template
void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4<PixelOrderBGR>(uchar *dest, const uint *src, int index, int count,
const QList<QRgb> *, QDitherInfo *);