diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-05-06 14:23:57 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-06-03 12:01:26 +0000 |
commit | 8f760808e0fe0fe6dd89d561f118b19ed8085e7a (patch) | |
tree | 8cc259b6098d83b91b6ec8ac22745546947860c7 /src/gui/painting/qdrawingprimitive_sse2_p.h | |
parent | 754efa57d89c62d1796e01b407e9222e67450f52 (diff) |
Fix premul conversion from ARGB32 to A2RGB30 formats.
When a premultiplied alpha changes value because it is rounded to fewer
bits the premultiplied colors may need to be recalculated with the new
value. Otherwise the color will both be wrong and potentially invalid.
Change-Id: I9ec74a22aac73cd7ffab04e180cf2bf35bb4c315
Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
Diffstat (limited to 'src/gui/painting/qdrawingprimitive_sse2_p.h')
-rw-r--r-- | src/gui/painting/qdrawingprimitive_sse2_p.h | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/src/gui/painting/qdrawingprimitive_sse2_p.h b/src/gui/painting/qdrawingprimitive_sse2_p.h index 1a7dddf0d5..c74055e440 100644 --- a/src/gui/painting/qdrawingprimitive_sse2_p.h +++ b/src/gui/painting/qdrawingprimitive_sse2_p.h @@ -35,6 +35,7 @@ #define QDRAWINGPRIMITIVE_SSE2_P_H #include <private/qsimd_p.h> +#include "qdrawhelper_p.h" #ifdef __SSE2__ @@ -256,6 +257,43 @@ inline QRgb qUnpremultiply_sse4(QRgb p) vl = _mm_packus_epi16(vl, vl); return _mm_cvtsi128_si32(vl); } + +template<enum QtPixelOrder PixelOrder> +QT_FUNCTION_TARGET(SSE4_1) +inline uint qConvertArgb32ToA2rgb30_sse4(QRgb p) +{ + const uint alpha = qAlpha(p); + if (alpha == 255) + return qConvertRgb32ToRgb30<PixelOrder>(p); + if (alpha == 0) + return 0; + Q_CONSTEXPR uint mult = 255 / (255 >> 6); + const uint invAlpha = qt_inv_premul_factor[alpha]; + const uint newalpha = (alpha >> 6); + const __m128i via = _mm_set1_epi32(invAlpha); + const __m128i vna = _mm_set1_epi32(mult * newalpha); + const __m128i vr1 = _mm_set1_epi32(0x1000); + const __m128i vr2 = _mm_set1_epi32(0x80); + __m128i vl = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(p)); + vl = _mm_mullo_epi32(vl, via); + vl = _mm_add_epi32(vl, vr1); + vl = _mm_srli_epi32(vl, 14); + vl = _mm_mullo_epi32(vl, vna); + vl = _mm_add_epi32(vl, _mm_srli_epi32(vl, 8)); + vl = _mm_add_epi32(vl, vr2); + vl = _mm_srli_epi32(vl, 8); + vl = _mm_packus_epi32(vl, vl); + uint rgb30 = (newalpha << 30); + rgb30 |= ((uint)_mm_extract_epi16(vl, 1)) << 10; + if (PixelOrder == PixelOrderRGB) { + rgb30 |= ((uint)_mm_extract_epi16(vl, 2)) << 20; + rgb30 |= ((uint)_mm_extract_epi16(vl, 0)); + } else { + rgb30 |= ((uint)_mm_extract_epi16(vl, 0)) << 20; + rgb30 |= ((uint)_mm_extract_epi16(vl, 2)); + } + return rgb30; +} #endif QT_END_NAMESPACE |