diff options
Diffstat (limited to 'src/gui/painting/qdrawhelper_sse4.cpp')
-rw-r--r-- | src/gui/painting/qdrawhelper_sse4.cpp | 266 |
1 files changed, 236 insertions, 30 deletions
diff --git a/src/gui/painting/qdrawhelper_sse4.cpp b/src/gui/painting/qdrawhelper_sse4.cpp index 14bfaabf09..e3cc1dd43e 100644 --- a/src/gui/painting/qdrawhelper_sse4.cpp +++ b/src/gui/painting/qdrawhelper_sse4.cpp @@ -39,13 +39,14 @@ #include <private/qdrawhelper_p.h> #include <private/qdrawingprimitive_sse2_p.h> +#include <private/qpaintengine_raster_p.h> #if defined(QT_COMPILER_SUPPORTS_SSE4_1) QT_BEGIN_NAMESPACE template<bool RGBA> -static inline void convertARGBToARGB32PM_sse4(uint *buffer, const uint *src, int count) +static void convertARGBToARGB32PM_sse4(uint *buffer, const uint *src, int count) { int i = 0; const __m128i alphaMask = _mm_set1_epi32(0xff000000); @@ -83,7 +84,7 @@ static inline void convertARGBToARGB32PM_sse4(uint *buffer, const uint *src, int _mm_storeu_si128((__m128i *)&buffer[i], srcVector); } } else { - _mm_storeu_si128((__m128i *)&buffer[i], _mm_setzero_si128()); + _mm_storeu_si128((__m128i *)&buffer[i], zero); } } @@ -93,59 +94,264 @@ static inline void convertARGBToARGB32PM_sse4(uint *buffer, const uint *src, int } } -const uint *QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) +static inline __m128 reciprocal_mul_ps(__m128 a, float mul) { - convertARGBToARGB32PM_sse4<false>(buffer, src, count); - return buffer; + __m128 ia = _mm_rcp_ps(a); // Approximate 1/a + // Improve precision of ia using Newton-Raphson + ia = _mm_sub_ps(_mm_add_ps(ia, ia), _mm_mul_ps(ia, _mm_mul_ps(ia, a))); + ia = _mm_mul_ps(ia, _mm_set1_ps(mul)); + return ia; } -const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_sse4(uint *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) +template<bool RGBA, bool RGBx> +static inline void convertARGBFromARGB32PM_sse4(uint *buffer, const uint *src, int count) { - convertARGBToARGB32PM_sse4<true>(buffer, src, count); - return buffer; + int i = 0; + const __m128i alphaMask = _mm_set1_epi32(0xff000000); + const __m128i rgbaMask = _mm_setr_epi8(2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15); + const __m128i zero = _mm_setzero_si128(); + + for (; i < count - 3; i += 4) { + __m128i srcVector = _mm_loadu_si128((const __m128i *)&src[i]); + if (!_mm_testz_si128(srcVector, alphaMask)) { + if (!_mm_testc_si128(srcVector, alphaMask)) { + __m128i srcVectorAlpha = _mm_srli_epi32(srcVector, 24); + if (RGBA) + srcVector = _mm_shuffle_epi8(srcVector, rgbaMask); + const __m128 a = _mm_cvtepi32_ps(srcVectorAlpha); + const __m128 ia = reciprocal_mul_ps(a, 255.0f); + __m128i src1 = _mm_unpacklo_epi8(srcVector, zero); + __m128i src3 = _mm_unpackhi_epi8(srcVector, zero); + __m128i src2 = _mm_unpackhi_epi16(src1, zero); + __m128i src4 = _mm_unpackhi_epi16(src3, zero); + src1 = _mm_unpacklo_epi16(src1, zero); + src3 = _mm_unpacklo_epi16(src3, 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); + src1 = _mm_packus_epi16(src1, src3); + // Handle potential alpha == 0 values: + __m128i srcVectorAlphaMask = _mm_cmpeq_epi32(srcVectorAlpha, zero); + src1 = _mm_andnot_si128(srcVectorAlphaMask, src1); + // Fixup alpha values: + if (RGBx) + srcVector = _mm_or_si128(src1, alphaMask); + else + srcVector = _mm_blendv_epi8(src1, srcVector, alphaMask); + _mm_storeu_si128((__m128i *)&buffer[i], srcVector); + } else { + if (RGBA) + _mm_storeu_si128((__m128i *)&buffer[i], _mm_shuffle_epi8(srcVector, rgbaMask)); + else if (buffer != src) + _mm_storeu_si128((__m128i *)&buffer[i], srcVector); + } + } else { + if (RGBx) + _mm_storeu_si128((__m128i *)&buffer[i], alphaMask); + else + _mm_storeu_si128((__m128i *)&buffer[i], zero); + } + } + + SIMD_EPILOGUE(i, count, 3) { + uint v = qUnpremultiply_sse4(src[i]); + if (RGBx) + v = 0xff000000 | v; + if (RGBA) + v = ARGB2RGBA(v); + buffer[i] = v; + } } -const uint *QT_FASTCALL convertARGB32FromARGB32PM_sse4(uint *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) +template<bool RGBA> +static inline void convertARGBFromRGBA64PM_sse4(uint *buffer, const QRgba64 *src, int count) { - for (int i = 0; i < count; ++i) - buffer[i] = qUnpremultiply_sse4(src[i]); - return buffer; + int i = 0; + const __m128i alphaMask = _mm_set1_epi64x(Q_UINT64_C(0xffff) << 48); + const __m128i alphaMask32 = _mm_set1_epi32(0xff000000); + const __m128i rgbaMask = _mm_setr_epi8(2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15); + const __m128i zero = _mm_setzero_si128(); + + for (; i < count - 3; i += 4) { + __m128i srcVector1 = _mm_loadu_si128((const __m128i *)&src[i]); + __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); + // Convert srcVectorAlpha to final 8-bit alpha channel + srcVectorAlpha = _mm_add_epi32(srcVectorAlpha, _mm_set1_epi32(128)); + srcVectorAlpha = _mm_sub_epi32(srcVectorAlpha, _mm_srli_epi32(srcVectorAlpha, 8)); + srcVectorAlpha = _mm_srli_epi32(srcVectorAlpha, 8); + srcVectorAlpha = _mm_slli_epi32(srcVectorAlpha, 24); + const __m128 ia = reciprocal_mul_ps(a, 255.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); + src1 = _mm_packus_epi16(src1, src3); + // Fixup alpha values: + src1 = _mm_blendv_epi8(src1, srcVectorAlpha, alphaMask32); + // Fix RGB order + if (!RGBA) + src1 = _mm_shuffle_epi8(src1, rgbaMask); + _mm_storeu_si128((__m128i *)&buffer[i], src1); + } else { + __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); + src1 = _mm_add_epi32(src1, _mm_set1_epi32(128)); + src2 = _mm_add_epi32(src2, _mm_set1_epi32(128)); + src3 = _mm_add_epi32(src3, _mm_set1_epi32(128)); + src4 = _mm_add_epi32(src4, _mm_set1_epi32(128)); + src1 = _mm_sub_epi32(src1, _mm_srli_epi32(src1, 8)); + src2 = _mm_sub_epi32(src2, _mm_srli_epi32(src2, 8)); + src3 = _mm_sub_epi32(src3, _mm_srli_epi32(src3, 8)); + src4 = _mm_sub_epi32(src4, _mm_srli_epi32(src4, 8)); + src1 = _mm_srli_epi32(src1, 8); + src2 = _mm_srli_epi32(src2, 8); + src3 = _mm_srli_epi32(src3, 8); + src4 = _mm_srli_epi32(src4, 8); + src1 = _mm_packus_epi32(src1, src2); + src3 = _mm_packus_epi32(src3, src4); + src1 = _mm_packus_epi16(src1, src3); + if (!RGBA) + src1 = _mm_shuffle_epi8(src1, rgbaMask); + _mm_storeu_si128((__m128i *)&buffer[i], src1); + } + } else { + _mm_storeu_si128((__m128i *)&buffer[i], zero); + } + } + + SIMD_EPILOGUE(i, count, 3) { + buffer[i] = qConvertRgba64ToRgb32_sse4<RGBA ? PixelOrderRGB : PixelOrderBGR>(src[i]); + } } -const uint *QT_FASTCALL convertRGBA8888FromARGB32PM_sse4(uint *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) +void QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, int count, const QVector<QRgb> *) { - for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(qUnpremultiply_sse4(src[i])); + convertARGBToARGB32PM_sse4<false>(buffer, buffer, count); +} + +void QT_FASTCALL convertRGBA8888ToARGB32PM_sse4(uint *buffer, int count, const QVector<QRgb> *) +{ + convertARGBToARGB32PM_sse4<true>(buffer, buffer, count); +} + +const uint *QT_FASTCALL fetchARGB32ToARGB32PM_sse4(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + convertARGBToARGB32PM_sse4<false>(buffer, reinterpret_cast<const uint *>(src) + index, count); return buffer; } -const uint *QT_FASTCALL convertRGBXFromARGB32PM_sse4(uint *buffer, const uint *src, int count, +const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_sse4(uint *buffer, const uchar *src, int index, int count, const QVector<QRgb> *, QDitherInfo *) { - for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(0xff000000 | qUnpremultiply_sse4(src[i])); + convertARGBToARGB32PM_sse4<true>(buffer, reinterpret_cast<const uint *>(src) + index, count); return buffer; } +void QT_FASTCALL storeRGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + convertARGBFromARGB32PM_sse4<false,true>(d, src, count); +} + +void QT_FASTCALL storeARGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + convertARGBFromARGB32PM_sse4<false,false>(d, src, count); +} + +void QT_FASTCALL storeRGBA8888FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + convertARGBFromARGB32PM_sse4<true,false>(d, src, count); +} + +void QT_FASTCALL storeRGBXFromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + convertARGBFromARGB32PM_sse4<true,true>(d, src, count); +} + template<QtPixelOrder PixelOrder> -const uint *QT_FASTCALL convertA2RGB30PMFromARGB32PM_sse4(uint *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) +void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) { + uint *d = reinterpret_cast<uint *>(dest) + index; for (int i = 0; i < count; ++i) - buffer[i] = qConvertArgb32ToA2rgb30_sse4<PixelOrder>(src[i]); - return buffer; + d[i] = qConvertArgb32ToA2rgb30_sse4<PixelOrder>(src[i]); +} + +void QT_FASTCALL destStore64ARGB32_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) +{ + uint *dest = (uint*)rasterBuffer->scanLine(y) + x; + convertARGBFromRGBA64PM_sse4<false>(dest, buffer, length); +} + +void QT_FASTCALL destStore64RGBA8888_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) +{ + uint *dest = (uint*)rasterBuffer->scanLine(y) + x; + convertARGBFromRGBA64PM_sse4<true>(dest, buffer, length); +} + +void QT_FASTCALL storeARGB32FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = (uint*)dest + index; + convertARGBFromRGBA64PM_sse4<false>(d, src, count); +} + +void QT_FASTCALL storeRGBA8888FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = (uint*)dest + index; + convertARGBFromRGBA64PM_sse4<true>(d, src, count); } template -const uint *QT_FASTCALL convertA2RGB30PMFromARGB32PM_sse4<PixelOrderBGR>(uint *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *); +void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4<PixelOrderBGR>(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *); template -const uint *QT_FASTCALL convertA2RGB30PMFromARGB32PM_sse4<PixelOrderRGB>(uint *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *); +void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4<PixelOrderRGB>(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *); QT_END_NAMESPACE |