diff options
Diffstat (limited to 'src/gui/painting')
-rw-r--r-- | src/gui/painting/qcolor.cpp | 5 | ||||
-rw-r--r-- | src/gui/painting/qcompositionfunctions.cpp | 1094 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper.cpp | 841 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_avx2.cpp | 56 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_p.h | 30 | ||||
-rw-r--r-- | src/gui/painting/qpagedpaintdevice.cpp | 65 | ||||
-rw-r--r-- | src/gui/painting/qpagedpaintdevice.h | 6 | ||||
-rw-r--r-- | src/gui/painting/qpagedpaintdevice_p.h | 40 | ||||
-rw-r--r-- | src/gui/painting/qpdfwriter.cpp | 27 | ||||
-rw-r--r-- | src/gui/painting/qrgba64_p.h | 23 |
10 files changed, 1150 insertions, 1037 deletions
diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index c55bcb12c9..1d7375d1df 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -304,11 +304,6 @@ static const int rgbTblSize = sizeof(rgbTbl) / sizeof(RGBData); #undef rgb -#if defined(Q_CC_MSVC) && _MSC_VER < 1600 -inline bool operator<(const RGBData &data1, const RGBData &data2) -{ return qstrcmp(data1.name, data2.name) < 0; } -#endif - inline bool operator<(const char *name, const RGBData &data) { return qstrcmp(name, data.name) < 0; } inline bool operator<(const RGBData &data, const char *name) diff --git a/src/gui/painting/qcompositionfunctions.cpp b/src/gui/painting/qcompositionfunctions.cpp index 339a9749b8..027bf23115 100644 --- a/src/gui/painting/qcompositionfunctions.cpp +++ b/src/gui/painting/qcompositionfunctions.cpp @@ -64,125 +64,354 @@ QT_BEGIN_NAMESPACE where the source is an array of pixels. */ -#if defined __SSE2__ -# define LOAD(ptr) _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr)) +struct Argb32OperationsC +{ + typedef QRgb Type; + typedef quint8 Scalar; + typedef QRgb OptimalType; + typedef quint8 OptimalScalar; + + static const Type clear; + static bool isOpaque(Type val) + { return qAlpha(val) == 255; } + static bool isTransparent(Type val) + { return qAlpha(val) == 0; } + static Scalar scalarFrom8bit(uint8_t a) + { return a; } + static void memfill(Type *ptr, Type value, qsizetype len) + { qt_memfill32(ptr, value, len); } + static void memcpy(Type *Q_DECL_RESTRICT dest, const Type *Q_DECL_RESTRICT src, qsizetype len) + { ::memcpy(dest, src, len * sizeof(Type)); } + + static OptimalType load(const Type *ptr) + { return *ptr; } + static OptimalType convert(const Type &val) + { return val; } + static void store(Type *ptr, OptimalType value) + { *ptr = value; } + static OptimalType add(OptimalType a, OptimalType b) + { return a + b; } + static OptimalScalar add(OptimalScalar a, OptimalScalar b) + { return a + b; } + static OptimalType plus(OptimalType a, OptimalType b) + { return comp_func_Plus_one_pixel(a, b); } + static OptimalScalar alpha(OptimalType val) + { return qAlpha(val); } + static OptimalScalar invAlpha(OptimalScalar c) + { return 255 - c; } + static OptimalScalar invAlpha(OptimalType val) + { return alpha(~val); } + static OptimalScalar scalar(Scalar v) + { return v; } + static OptimalType multiplyAlpha8bit(OptimalType val, uint8_t a) + { return BYTE_MUL(val, a); } + static OptimalType interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2) + { return INTERPOLATE_PIXEL_255(x, a1, y, a2); } + static OptimalType multiplyAlpha(OptimalType val, OptimalScalar a) + { return BYTE_MUL(val, a); } + static OptimalScalar multiplyAlpha8bit(OptimalScalar val, uint8_t a) + { return qt_div_255(val * a); } + static OptimalType interpolate(OptimalType x, OptimalScalar a1, OptimalType y, OptimalScalar a2) + { return INTERPOLATE_PIXEL_255(x, a1, y, a2); } +}; + +const Argb32OperationsC::Type Argb32OperationsC::clear = 0; + +struct Rgba64OperationsBase +{ + typedef QRgba64 Type; + typedef quint16 Scalar; + + static const Type clear; + + static bool isOpaque(Type val) + { return val.isOpaque(); } + static bool isTransparent(Type val) + { return val.isTransparent(); } + static Scalar scalarFrom8bit(uint8_t a) + { return a * 257; } + + static void memfill(Type *ptr, Type value, qsizetype len) + { qt_memfill64((quint64*)ptr, value, len); } + static void memcpy(Type *Q_DECL_RESTRICT dest, const Type *Q_DECL_RESTRICT src, qsizetype len) + { ::memcpy(dest, src, len * sizeof(Type)); } +}; + +const Rgba64OperationsBase::Type Rgba64OperationsBase::clear = QRgba64::fromRgba64(0); + +struct Rgba64OperationsC : public Rgba64OperationsBase +{ + typedef QRgba64 OptimalType; + typedef quint16 OptimalScalar; + + static OptimalType load(const Type *ptr) + { return *ptr; } + static OptimalType convert(const Type &val) + { return val; } + static void store(Type *ptr, OptimalType value) + { *ptr = value; } + static OptimalType add(OptimalType a, OptimalType b) + { return QRgba64::fromRgba64((quint64)a + (quint64)b); } + static OptimalScalar add(OptimalScalar a, OptimalScalar b) + { return a + b; } + static OptimalType plus(OptimalType a, OptimalType b) + { return addWithSaturation(a, b); } + static OptimalScalar alpha(OptimalType val) + { return val.alpha(); } + static OptimalScalar invAlpha(Scalar c) + { return 65535 - c; } + static OptimalScalar invAlpha(OptimalType val) + { return 65535 - alpha(val); } + static OptimalScalar scalar(Scalar v) + { return v; } + static OptimalType multiplyAlpha8bit(OptimalType val, uint8_t a) + { return multiplyAlpha255(val, a); } + static OptimalScalar multiplyAlpha8bit(OptimalScalar val, uint8_t a) + { return qt_div_255(val * a); } + static OptimalType interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2) + { return interpolate255(x, a1, y, a2); } + static OptimalType multiplyAlpha(OptimalType val, OptimalScalar a) + { return multiplyAlpha65535(val, a); } + static OptimalType interpolate(OptimalType x, OptimalScalar a1, OptimalType y, OptimalScalar a2) + { return interpolate65535(x, a1, y, a2); } +}; + +#if defined(__SSE2__) +struct Rgba64OperationsSSE2 : public Rgba64OperationsBase +{ + typedef __m128i OptimalType; + typedef __m128i OptimalScalar; + + static OptimalType load(const Type *ptr) + { + return _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr)); + } + static OptimalType convert(const Type &value) + { #ifdef Q_PROCESSOR_X86_64 -# define CONVERT(value) _mm_cvtsi64_si128(value) + return _mm_cvtsi64_si128(value); #else -# define CONVERT(value) LOAD(&value) + return load(&value); #endif -# define STORE(ptr, value) _mm_storel_epi64(reinterpret_cast<__m128i *>(ptr), value) -# define ADD(p, q) _mm_add_epi32(p, q) -# define ALPHA(c) _mm_shufflelo_epi16(c, _MM_SHUFFLE(3, 3, 3, 3)) -# define CONST(n) _mm_shufflelo_epi16(_mm_cvtsi32_si128(n), _MM_SHUFFLE(0, 0, 0, 0)) -# define INVALPHA(c) _mm_sub_epi32(CONST(65535), ALPHA(c)) -#elif defined __ARM_NEON__ -# define LOAD(ptr) vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(ptr))) -# define CONVERT(value) vreinterpret_u16_u64(vmov_n_u64(value)) -# define STORE(ptr, value) vst1_u64(reinterpret_cast<uint64_t *>(ptr), vreinterpret_u64_u16(value)) -# define ADD(p, q) vadd_u16(p, q) -# define ALPHA(c) vdup_lane_u16(c, 3) -# define CONST(n) vdup_n_u16(n) -# define INVALPHA(c) vmvn_u16(ALPHA(c)) -#else -# define LOAD(ptr) *ptr -# define CONVERT(value) value -# define STORE(ptr, value) *ptr = value -# define ADD(p, q) (p + q) -# define ALPHA(c) (c).alpha() -# define CONST(n) n -# define INVALPHA(c) (65535 - ALPHA(c)) + } + static void store(Type *ptr, OptimalType value) + { + _mm_storel_epi64(reinterpret_cast<__m128i *>(ptr), value); + } + static OptimalType add(OptimalType a, OptimalType b) + { + return _mm_add_epi16(a, b); + } +// same as above: +// static OptimalScalar add(OptimalScalar a, OptimalScalar b) + static OptimalType plus(OptimalType a, OptimalType b) + { + return _mm_adds_epu16(a, b); + } + static OptimalScalar alpha(OptimalType c) + { + return _mm_shufflelo_epi16(c, _MM_SHUFFLE(3, 3, 3, 3)); + } + static OptimalScalar invAlpha(Scalar c) + { + return scalar(65535 - c); + } + static OptimalScalar invAlpha(OptimalType c) + { + return _mm_xor_si128(_mm_set1_epi16(-1), alpha(c)); + } + static OptimalScalar scalar(Scalar n) + { + return _mm_shufflelo_epi16(_mm_cvtsi32_si128(n), _MM_SHUFFLE(0, 0, 0, 0)); + } + static OptimalType multiplyAlpha8bit(OptimalType val, uint8_t a) + { + return multiplyAlpha255(val, a); + } +// same as above: +// static OptimalScalar multiplyAlpha8bit(OptimalScalar a, uint8_t a) + static OptimalType interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2) + { + return interpolate255(x, a1, y, a2); + } + static OptimalType multiplyAlpha(OptimalType val, OptimalScalar a) + { + return multiplyAlpha65535(val, a); + } + // a2 is const-ref because otherwise MSVC2015@x86 complains that it can't 16-byte align the argument. + static OptimalType interpolate(OptimalType x, OptimalScalar a1, OptimalType y, const OptimalScalar &a2) + { + return interpolate65535(x, a1, y, a2); + } +}; #endif +#if defined(__ARM_NEON__) +struct Rgba64OperationsNEON : public Rgba64OperationsBase +{ + typedef uint16x4_t OptimalType; + typedef uint16x4_t OptimalScalar; + + static OptimalType load(const Type *ptr) + { + return vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(ptr))); + } + static OptimalType convert(const Type &val) + { + return vreinterpret_u16_u64(vmov_n_u64(val)); + } + static void store(Type *ptr, OptimalType value) + { + vst1_u64(reinterpret_cast<uint64_t *>(ptr), vreinterpret_u64_u16(value)); + } + static OptimalType add(OptimalType a, OptimalType b) + { + return vadd_u16(a, b); + } +// same as above: +// static OptimalScalar add(OptimalScalar a, OptimalScalar b) + static OptimalType plus(OptimalType a, OptimalType b) + { + return vqadd_u16(a, b); + } + static OptimalScalar alpha(OptimalType c) + { + return vdup_lane_u16(c, 3); + } + static OptimalScalar invAlpha(Scalar c) + { + return scalar(65535 - c); + } + static OptimalScalar invAlpha(OptimalType c) + { + return vmvn_u16(alpha(c)); + } + static OptimalScalar scalar(Scalar n) + { + return vdup_n_u16(n); + } + static OptimalType multiplyAlpha8bit(OptimalType val, uint8_t a) + { + return multiplyAlpha255(val, a); + } +// same as above: +// static OptimalScalar multiplyAlpha8bit(OptimalScalar a, uint8_t a) + static OptimalType interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2) + { + return interpolate255(x, a1, y, a2); + } + static OptimalType multiplyAlpha(OptimalType val, OptimalScalar a) + { + return multiplyAlpha65535(val, a); + } + static OptimalType interpolate(OptimalType x, OptimalScalar a1, OptimalType y, OptimalScalar a2) + { + return interpolate65535(x, a1, y, a2); + } +}; + +#endif + +typedef Argb32OperationsC Argb32Operations; +#if defined(__SSE2__) +typedef Rgba64OperationsSSE2 Rgba64Operations; +#elif defined(__ARM_NEON__) +typedef Rgba64OperationsNEON Rgba64Operations; +#else +typedef Rgba64OperationsC Rgba64Operations; +#endif /* result = 0 d = d * cia */ -void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha) +template<class Ops> +inline static void comp_func_Clear_template(typename Ops::Type *dest, int length, uint const_alpha) { - if (const_alpha == 255) { - qt_memfill32(dest, 0, length); - } else { + if (const_alpha == 255) + Ops::memfill(dest, Ops::clear, length); + else { uint ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) - dest[i] = BYTE_MUL(dest[i], ialpha); + for (int i = 0; i < length; ++i) { + Ops::store(&dest[i], Ops::multiplyAlpha8bit(Ops::load(&dest[i]), ialpha)); + } } } +void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha) +{ + comp_func_Clear_template<Argb32Operations>(dest, length, const_alpha); +} + void QT_FASTCALL comp_func_solid_Clear_rgb64(QRgba64 *dest, int length, QRgba64, uint const_alpha) { - if (const_alpha == 255) { - qt_memfill64((quint64*)dest, 0, length); - } else { - uint ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) - STORE(&dest[i], multiplyAlpha255(LOAD(&dest[i]), ialpha)); - } + comp_func_Clear_template<Rgba64Operations>(dest, length, const_alpha); } void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha) { - comp_func_solid_Clear(dest, length, 0, const_alpha); + comp_func_Clear_template<Argb32Operations>(dest, length, const_alpha); } void QT_FASTCALL comp_func_Clear_rgb64(QRgba64 *dest, const QRgba64 *, int length, uint const_alpha) { - comp_func_solid_Clear_rgb64(dest, length, QRgba64(), const_alpha); + comp_func_Clear_template<Rgba64Operations>(dest, length, const_alpha); } /* result = s dest = s * ca + d * cia */ -void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha) +template<class Ops> +inline static void comp_func_solid_Source_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha) { - if (const_alpha == 255) { - qt_memfill32(dest, color, length); - } else { - uint ialpha = 255 - const_alpha; - color = BYTE_MUL(color, const_alpha); + if (const_alpha == 255) + Ops::memfill(dest, color, length); + else { + const uint ialpha = 255 - const_alpha; + auto s = Ops::multiplyAlpha8bit(Ops::convert(color), const_alpha); for (int i = 0; i < length; ++i) { - dest[i] = color + BYTE_MUL(dest[i], ialpha); + auto d = Ops::multiplyAlpha8bit(Ops::load(&dest[i]), ialpha); + Ops::store(&dest[i], Ops::add(s, d)); } } } -void QT_FASTCALL comp_func_solid_Source_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +template<class Ops> +inline static void comp_func_Source_template(typename Ops::Type *Q_DECL_RESTRICT dest, + const typename Ops::Type *Q_DECL_RESTRICT src, + int length, uint const_alpha) { if (const_alpha == 255) - qt_memfill64((quint64*)dest, color, length); + Ops::memcpy(dest, src, length); else { - uint ialpha = 255 - const_alpha; - auto c = multiplyAlpha255(CONVERT(color), const_alpha); + const uint ialpha = 255 - const_alpha; for (int i = 0; i < length; ++i) { - STORE(&dest[i], ADD(c, multiplyAlpha255(LOAD(&dest[i]), ialpha))); + auto s = Ops::load(src + i); + auto d = Ops::load(dest + i); + Ops::store(&dest[i], Ops::interpolate8bit(s, const_alpha, d, ialpha)); } } } +void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha) +{ + comp_func_solid_Source_template<Argb32Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_solid_Source_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + comp_func_solid_Source_template<Rgba64Operations>(dest, length, color, const_alpha); +} + void QT_FASTCALL comp_func_Source(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - ::memcpy(dest, src, size_t(length) * sizeof(uint)); - } else { - uint ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha); - } - } + comp_func_Source_template<Argb32Operations>(dest, src, length, const_alpha); } void QT_FASTCALL comp_func_Source_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) - ::memcpy(dest, src, size_t(length) * sizeof(quint64)); - else { - uint ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - STORE(&dest[i], interpolate255(LOAD(&src[i]), const_alpha, LOAD(&dest[i]), ialpha)); - } - } + comp_func_Source_template<Rgba64Operations>(dest, src, length, const_alpha); } void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint) @@ -207,68 +436,66 @@ void QT_FASTCALL comp_func_Destination_rgb64(QRgba64 *, const QRgba64 *, int, ui = s * ca + d * (sia * ca + cia) = s * ca + d * (1 - sa*ca) */ -void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha) +template<class Ops> +inline static void comp_func_solid_SourceOver_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha) { - if ((const_alpha & qAlpha(color)) == 255) { - qt_memfill32(dest, color, length); - } else { + if (const_alpha == 255 && Ops::isOpaque(color)) + Ops::memfill(dest, color, length); + else { + auto c = Ops::convert(color); if (const_alpha != 255) - color = BYTE_MUL(color, const_alpha); + c = Ops::multiplyAlpha8bit(c, const_alpha); + auto cAlpha = Ops::invAlpha(c); for (int i = 0; i < length; ++i) { - dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color)); + auto d = Ops::multiplyAlpha(Ops::load(&dest[i]), cAlpha); + Ops::store(&dest[i], Ops::add(c, d)); } } } -void QT_FASTCALL comp_func_solid_SourceOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +template<class Ops> +inline static void comp_func_SourceOver_template(typename Ops::Type *Q_DECL_RESTRICT dest, + const typename Ops::Type *Q_DECL_RESTRICT src, + int length, uint const_alpha) { - if (const_alpha == 255 && color.isOpaque()) { - qt_memfill64((quint64*)dest, color, length); + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + auto c = src[i]; + if (Ops::isOpaque(c)) + Ops::store(&dest[i], Ops::convert(c)); + else if (!Ops::isTransparent(c)) { + auto s = Ops::convert(c); + auto d = Ops::multiplyAlpha(Ops::load(&dest[i]), Ops::invAlpha(s)); + Ops::store(&dest[i], Ops::add(s, d)); + } + } } else { - auto c = CONVERT(color); - if (const_alpha != 255) - c = multiplyAlpha255(c, const_alpha); - auto cAlpha = INVALPHA(c); for (int i = 0; i < length; ++i) { - STORE(&dest[i], ADD(c, multiplyAlpha65535(LOAD(&dest[i]), cAlpha))); + auto s = Ops::multiplyAlpha8bit(Ops::load(&src[i]), const_alpha); + auto d = Ops::multiplyAlpha(Ops::load(&dest[i]), Ops::invAlpha(s)); + Ops::store(&dest[i], Ops::add(s, d)); } } } +void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha) +{ + comp_func_solid_SourceOver_template<Argb32Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_solid_SourceOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + comp_func_solid_SourceOver_template<Rgba64Operations>(dest, length, color, const_alpha); +} + void QT_FASTCALL comp_func_SourceOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - uint s = src[i]; - if (s >= 0xff000000) - dest[i] = s; - else if (s != 0) - dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); - } - } else { - for (int i = 0; i < length; ++i) { - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); - } - } + comp_func_SourceOver_template<Argb32Operations>(dest, src, length, const_alpha); } void QT_FASTCALL comp_func_SourceOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - QRgba64 s = src[i]; - if (s.isOpaque()) - dest[i] = s; - else if (!s.isTransparent()) - STORE(&dest[i], ADD(CONVERT(s), multiplyAlpha65535(LOAD(&dest[i]), 65535 - s.alpha()))); - } - } else { - for (int i = 0; i < length; ++i) { - auto s = multiplyAlpha255(LOAD(&src[i]), const_alpha); - STORE(&dest[i], ADD(s, multiplyAlpha65535(LOAD(&dest[i]), INVALPHA(s)))); - } - } + comp_func_SourceOver_template<Rgba64Operations>(dest, src, length, const_alpha); } /* @@ -276,128 +503,122 @@ void QT_FASTCALL comp_func_SourceOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const dest = (d + s * dia) * ca + d * cia = d + s * dia * ca */ -void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha != 255) - color = BYTE_MUL(color, const_alpha); - for (int i = 0; i < length; ++i) { - uint d = dest[i]; - dest[i] = d + BYTE_MUL(color, qAlpha(~d)); - } -} - -void QT_FASTCALL comp_func_solid_DestinationOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +template<class Ops> +inline static void comp_func_solid_DestinationOver_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha) { - auto c = CONVERT(color); + auto c = Ops::convert(color); if (const_alpha != 255) - c = multiplyAlpha255(c, const_alpha); + c = Ops::multiplyAlpha8bit(c, const_alpha); for (int i = 0; i < length; ++i) { - auto d = LOAD(&dest[i]); - STORE(&dest[i], ADD(d, multiplyAlpha65535(c, INVALPHA(d)))); + auto d = Ops::load(&dest[i]); + auto s = Ops::multiplyAlpha(c, Ops::invAlpha(d)); + Ops::store(&dest[i], Ops::add(s, d)); } } -void QT_FASTCALL comp_func_DestinationOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +template<class Ops> +inline static void comp_func_DestinationOver_template(typename Ops::Type *Q_DECL_RESTRICT dest, + const typename Ops::Type *Q_DECL_RESTRICT src, + int length, uint const_alpha) { if (const_alpha == 255) { for (int i = 0; i < length; ++i) { - uint d = dest[i]; - dest[i] = d + BYTE_MUL(src[i], qAlpha(~d)); + auto d = Ops::load(&dest[i]); + auto s = Ops::multiplyAlpha(Ops::load(&src[i]), Ops::invAlpha(d)); + Ops::store(&dest[i], Ops::add(s, d)); } } else { for (int i = 0; i < length; ++i) { - uint d = dest[i]; - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = d + BYTE_MUL(s, qAlpha(~d)); + auto d = Ops::load(&dest[i]); + auto s = Ops::multiplyAlpha8bit(Ops::load(&src[i]), const_alpha); + s = Ops::multiplyAlpha(s, Ops::invAlpha(d)); + Ops::store(&dest[i], Ops::add(s, d)); } } } +void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha) +{ + comp_func_solid_DestinationOver_template<Argb32Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_solid_DestinationOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + comp_func_solid_DestinationOver_template<Rgba64Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_DestinationOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + comp_func_DestinationOver_template<Argb32Operations>(dest, src, length, const_alpha); +} + void QT_FASTCALL comp_func_DestinationOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - auto d = LOAD(&dest[i]); - STORE(&dest[i], ADD(d, multiplyAlpha65535(LOAD(&src[i]), INVALPHA(d)))); - } - } else { - for (int i = 0; i < length; ++i) { - auto d = LOAD(&dest[i]); - auto s = multiplyAlpha255(LOAD(&src[i]), const_alpha); - STORE(&dest[i], ADD(d, multiplyAlpha65535(s, INVALPHA(d)))); - } - } + comp_func_DestinationOver_template<Rgba64Operations>(dest, src, length, const_alpha); } /* result = s * da dest = s * da * ca + d * cia */ -void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha) +template<class Ops> +inline static void comp_func_solid_SourceIn_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha) { if (const_alpha == 255) { + auto c = Ops::convert(color); for (int i = 0; i < length; ++i) { - dest[i] = BYTE_MUL(color, qAlpha(dest[i])); + Ops::store(&dest[i], Ops::multiplyAlpha(c, Ops::alpha(Ops::load(&dest[i])))); } } else { - color = BYTE_MUL(color, const_alpha); - uint cia = 255 - const_alpha; + auto c = Ops::multiplyAlpha8bit(Ops::convert(color), const_alpha); + auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha)); for (int i = 0; i < length; ++i) { - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia); + auto d = Ops::load(&dest[i]); + Ops::store(&dest[i], Ops::interpolate(c, Ops::alpha(d), d, cia)); } } } -void QT_FASTCALL comp_func_solid_SourceIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +template<class Ops> +inline static void comp_func_SourceIn_template(typename Ops::Type *Q_DECL_RESTRICT dest, + const typename Ops::Type *Q_DECL_RESTRICT src, + int length, uint const_alpha) { if (const_alpha == 255) { - auto c = CONVERT(color); for (int i = 0; i < length; ++i) { - STORE(&dest[i], multiplyAlpha65535(c, dest[i].alpha())); + auto s = Ops::load(&src[i]); + Ops::store(&dest[i], Ops::multiplyAlpha(s, Ops::alpha(Ops::load(&dest[i])))); } } else { - uint ca = const_alpha * 257; - auto cia = CONST(65535 - ca); - auto c = multiplyAlpha65535(CONVERT(color), ca); + auto ca = Ops::scalarFrom8bit(const_alpha); + auto cia = Ops::invAlpha(ca); + auto cav = Ops::scalar(ca); for (int i = 0; i < length; ++i) { - auto d = LOAD(&dest[i]); - STORE(&dest[i], interpolate65535(c, ALPHA(d), d, cia)); + auto d = Ops::load(&dest[i]); + auto s = Ops::multiplyAlpha(Ops::load(&src[i]), cav); + Ops::store(&dest[i], Ops::interpolate(s, Ops::alpha(d), d, cia)); } } } +void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha) +{ + comp_func_solid_SourceIn_template<Argb32Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_solid_SourceIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + comp_func_solid_SourceIn_template<Rgba64Operations>(dest, length, color, const_alpha); +} + void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = BYTE_MUL(src[i], qAlpha(dest[i])); - } - } else { - uint cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - uint d = dest[i]; - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia); - } - } + comp_func_SourceIn_template<Argb32Operations>(dest, src, length, const_alpha); } void QT_FASTCALL comp_func_SourceIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - STORE(&dest[i], multiplyAlpha65535(LOAD(&src[i]), dest[i].alpha())); - } - } else { - uint ca = const_alpha * 257; - auto cia = CONST(65535 - ca); - for (int i = 0; i < length; ++i) { - auto d = LOAD(&dest[i]); - auto s = multiplyAlpha65535(LOAD(&src[i]), ca); - STORE(&dest[i], interpolate65535(s, ALPHA(d), d, cia)); - } - } + comp_func_SourceIn_template<Rgba64Operations>(dest, src, length, const_alpha); } /* @@ -405,128 +626,120 @@ void QT_FASTCALL comp_func_SourceIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const Q dest = d * sa * ca + d * cia = d * (sa * ca + cia) */ -void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha) +template<class Ops> +inline static void comp_func_solid_DestinationIn_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha) { - uint a = qAlpha(color); + auto sa = Ops::alpha(Ops::convert(color)); if (const_alpha != 255) { - a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - } - for (int i = 0; i < length; ++i) { - dest[i] = BYTE_MUL(dest[i], a); + sa = Ops::multiplyAlpha8bit(sa, const_alpha); + sa = Ops::add(sa, Ops::invAlpha(Ops::scalarFrom8bit(const_alpha))); } -} -void QT_FASTCALL comp_func_solid_DestinationIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - uint a = color.alpha(); - uint ca64k = const_alpha * 257; - if (const_alpha != 255) - a = qt_div_65535(a * ca64k) + 65535 - ca64k; for (int i = 0; i < length; ++i) { - STORE(&dest[i], multiplyAlpha65535(LOAD(&dest[i]), a)); + Ops::store(&dest[i], Ops::multiplyAlpha(Ops::load(&dest[i]), sa)); } } -void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +template<class Ops> +inline static void comp_func_DestinationIn_template(typename Ops::Type *Q_DECL_RESTRICT dest, + const typename Ops::Type *Q_DECL_RESTRICT src, + int length, uint const_alpha) { if (const_alpha == 255) { for (int i = 0; i < length; ++i) { - dest[i] = BYTE_MUL(dest[i], qAlpha(src[i])); + auto a = Ops::alpha(Ops::load(&src[i])); + Ops::store(&dest[i], Ops::multiplyAlpha(Ops::load(&dest[i]), a)); } } else { - uint cia = 255 - const_alpha; + auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha)); for (int i = 0; i < length; ++i) { - uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia; - dest[i] = BYTE_MUL(dest[i], a); + auto sa = Ops::multiplyAlpha8bit(Ops::alpha(Ops::load(&src[i])), const_alpha); + sa = Ops::add(sa, cia); + Ops::store(&dest[i], Ops::multiplyAlpha(Ops::load(&dest[i]), sa)); } } } +void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha) +{ + comp_func_solid_DestinationIn_template<Argb32Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_solid_DestinationIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + comp_func_solid_DestinationIn_template<Rgba64Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + comp_func_DestinationIn_template<Argb32Operations>(dest, src, length, const_alpha); +} + void QT_FASTCALL comp_func_DestinationIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - STORE(&dest[i], multiplyAlpha65535(LOAD(&dest[i]), src[i].alpha())); - } - } else { - uint ca = const_alpha * 257; - uint cia = 65535 - ca; - for (int i = 0; i < length; ++i) { - uint a = qt_div_65535(src[i].alpha() * ca) + cia; - STORE(&dest[i], multiplyAlpha65535(LOAD(&dest[i]), a)); - } - } + comp_func_DestinationIn_template<Rgba64Operations>(dest, src, length, const_alpha); } /* result = s * dia dest = s * dia * ca + d * cia */ - -void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha) +template<class Ops> +inline static void comp_func_solid_SourceOut_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha) { + auto c = Ops::convert(color); if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = BYTE_MUL(color, qAlpha(~dest[i])); - } + for (int i = 0; i < length; ++i) + Ops::store(&dest[i], Ops::multiplyAlpha(c, Ops::invAlpha(Ops::load(&dest[i])))); } else { - color = BYTE_MUL(color, const_alpha); - uint cia = 255 - const_alpha; + auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha)); + c = Ops::multiplyAlpha8bit(c, const_alpha); for (int i = 0; i < length; ++i) { - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia); + auto d = Ops::load(&dest[i]); + Ops::store(&dest[i], Ops::interpolate(c, Ops::invAlpha(d), d, cia)); } } } -void QT_FASTCALL comp_func_solid_SourceOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +template<class Ops> +inline static void comp_func_SourceOut_template(typename Ops::Type *Q_DECL_RESTRICT dest, + const typename Ops::Type *Q_DECL_RESTRICT src, + int length, uint const_alpha) { if (const_alpha == 255) { for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha65535(color, 65535 - dest[i].alpha()); + auto s = Ops::load(&src[i]); + auto d = Ops::load(&dest[i]); + Ops::store(&dest[i], Ops::multiplyAlpha(s, Ops::invAlpha(d))); } } else { - uint ca = const_alpha * 257; - uint cia = 65535 - ca; - color = multiplyAlpha65535(color, ca); + auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha)); for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - dest[i] = interpolate65535(color, 65535 - d.alpha(), d, cia); + auto s = Ops::multiplyAlpha8bit(Ops::load(&src[i]), const_alpha); + auto d = Ops::load(&dest[i]); + Ops::store(&dest[i], Ops::interpolate(s, Ops::invAlpha(d), d, cia)); } } } +void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha) +{ + comp_func_solid_SourceOut_template<Argb32Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_solid_SourceOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + comp_func_solid_SourceOut_template<Rgba64Operations>(dest, length, color, const_alpha); +} + void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i])); - } - } else { - uint cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - uint s = BYTE_MUL(src[i], const_alpha); - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia); - } - } + comp_func_SourceOut_template<Argb32Operations>(dest, src, length, const_alpha); } void QT_FASTCALL comp_func_SourceOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha65535(src[i], 65535 - dest[i].alpha()); - } - } else { - uint ca = const_alpha * 257; - uint cia = 65535 - ca; - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - QRgba64 s = multiplyAlpha65535(src[i], ca); - dest[i] = interpolate65535(s, 65535 - d.alpha(), d, cia); - } - } + comp_func_SourceOut_template<Rgba64Operations>(dest, src, length, const_alpha); } /* @@ -534,56 +747,58 @@ void QT_FASTCALL comp_func_SourceOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const dest = d * sia * ca + d * cia = d * (sia * ca + cia) */ -void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha) +template<class Ops> +inline static void comp_func_solid_DestinationOut_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha) { - uint a = qAlpha(~color); - if (const_alpha != 255) - a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - for (int i = 0; i < length; ++i) { - dest[i] = BYTE_MUL(dest[i], a); + auto sai = Ops::invAlpha(Ops::convert(color)); + if (const_alpha != 255) { + sai = Ops::multiplyAlpha8bit(sai, const_alpha); + sai = Ops::add(sai, Ops::invAlpha(Ops::scalarFrom8bit(const_alpha))); } -} -void QT_FASTCALL comp_func_solid_DestinationOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - uint a = 65535 - color.alpha(); - uint ca64k = const_alpha * 257; - if (const_alpha != 255) - a = qt_div_65535(a * ca64k) + 65535 - ca64k; for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha65535(dest[i], a); + Ops::store(&dest[i], Ops::multiplyAlpha(Ops::load(&dest[i]), sai)); } } -void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +template<class Ops> +inline static void comp_func_DestinationOut_template(typename Ops::Type *Q_DECL_RESTRICT dest, + const typename Ops::Type *Q_DECL_RESTRICT src, + int length, uint const_alpha) { if (const_alpha == 255) { for (int i = 0; i < length; ++i) { - dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i])); + auto sia = Ops::invAlpha(Ops::load(&src[i])); + Ops::store(&dest[i], Ops::multiplyAlpha(Ops::load(&dest[i]), sia)); } } else { - uint cia = 255 - const_alpha; + auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha)); for (int i = 0; i < length; ++i) { - uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia; - dest[i] = BYTE_MUL(dest[i], sia); + auto sia = Ops::multiplyAlpha8bit(Ops::invAlpha(Ops::load(&src[i])), const_alpha); + sia = Ops::add(sia, cia); + Ops::store(&dest[i], Ops::multiplyAlpha(Ops::load(&dest[i]), sia)); } } } +void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha) +{ + comp_func_solid_DestinationOut_template<Argb32Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_solid_DestinationOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + comp_func_solid_DestinationOut_template<Rgba64Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + comp_func_DestinationOut_template<Argb32Operations>(dest, src, length, const_alpha); +} + void QT_FASTCALL comp_func_DestinationOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha65535(dest[i], 65535 - src[i].alpha()); - } - } else { - uint ca = const_alpha * 257; - uint cia = 65535 - ca; - for (int i = 0; i < length; ++i) { - uint a = qt_div_65535((65535 - src[i].alpha()) * ca) + cia; - dest[i] = multiplyAlpha65535(dest[i], a); - } - } + comp_func_DestinationOut_template<Rgba64Operations>(dest, src, length, const_alpha); } /* @@ -592,59 +807,57 @@ void QT_FASTCALL comp_func_DestinationOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, c = s*ca * da + d * (sia*ca + cia) = s*ca * da + d * (1 - sa*ca) */ -void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha != 255) { - color = BYTE_MUL(color, const_alpha); - } - uint sia = qAlpha(~color); - for (int i = 0; i < length; ++i) { - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia); - } -} - -void QT_FASTCALL comp_func_solid_SourceAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +template<class Ops> +inline static void comp_func_solid_SourceAtop_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha) { + auto c = Ops::convert(color); if (const_alpha != 255) - color = multiplyAlpha255(color, const_alpha); - uint sia = 65535 - color.alpha(); + c = Ops::multiplyAlpha8bit(c, const_alpha); + auto sia = Ops::invAlpha(c); for (int i = 0; i < length; ++i) { - dest[i] = interpolate65535(color, dest[i].alpha(), dest[i], sia); + auto d = Ops::load(&dest[i]); + Ops::store(&dest[i], Ops::interpolate(c, Ops::alpha(d), d, sia)); } } -void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +template<class Ops> +inline static void comp_func_SourceAtop_template(typename Ops::Type *Q_DECL_RESTRICT dest, + const typename Ops::Type *Q_DECL_RESTRICT src, + int length, uint const_alpha) { if (const_alpha == 255) { for (int i = 0; i < length; ++i) { - uint s = src[i]; - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); + auto s = Ops::load(&src[i]); + auto d = Ops::load(&dest[i]); + Ops::store(&dest[i], Ops::interpolate(s, Ops::alpha(d), d, Ops::invAlpha(s))); } } else { for (int i = 0; i < length; ++i) { - uint s = BYTE_MUL(src[i], const_alpha); - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); + auto s = Ops::multiplyAlpha8bit(Ops::load(&src[i]), const_alpha); + auto d = Ops::load(&dest[i]); + Ops::store(&dest[i], Ops::interpolate(s, Ops::alpha(d), d, Ops::invAlpha(s))); } } } +void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha) +{ + comp_func_solid_SourceAtop_template<Argb32Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_solid_SourceAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + comp_func_solid_SourceAtop_template<Rgba64Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + comp_func_SourceAtop_template<Argb32Operations>(dest, src, length, const_alpha); +} + void QT_FASTCALL comp_func_SourceAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - QRgba64 s = src[i]; - QRgba64 d = dest[i]; - dest[i] = interpolate65535(s, d.alpha(), d, 65535 - s.alpha()); - } - } else { - for (int i = 0; i < length; ++i) { - QRgba64 s = multiplyAlpha255(src[i], const_alpha); - QRgba64 d = dest[i]; - dest[i] = interpolate65535(s, d.alpha(), d, 65535 - s.alpha()); - } - } + comp_func_SourceAtop_template<Rgba64Operations>(dest, src, length, const_alpha); } /* @@ -652,69 +865,63 @@ void QT_FASTCALL comp_func_SourceAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const dest = d*sa*ca + s*dia*ca + d *cia = s*ca * dia + d * (sa*ca + cia) */ -void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha) +template<class Ops> +inline static void comp_func_solid_DestinationAtop_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha) { - uint a = qAlpha(color); + auto c = Ops::convert(color); + auto sa = Ops::alpha(c); if (const_alpha != 255) { - color = BYTE_MUL(color, const_alpha); - a = qAlpha(color) + 255 - const_alpha; - } - for (int i = 0; i < length; ++i) { - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d)); + c = Ops::multiplyAlpha8bit(c, const_alpha); + auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha)); + sa = Ops::add(Ops::alpha(c), cia); } -} -void QT_FASTCALL comp_func_solid_DestinationAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - uint a = color.alpha(); - if (const_alpha != 255) { - color = multiplyAlpha255(color, const_alpha); - a = color.alpha() + 65535 - (const_alpha * 257); - } for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - dest[i] = interpolate65535(d, a, color, 65535 - d.alpha()); + auto d = Ops::load(&dest[i]); + Ops::store(&dest[i], Ops::interpolate(c, Ops::invAlpha(d), d, sa)); } } -void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +template<class Ops> +inline static void comp_func_DestinationAtop_template(typename Ops::Type *Q_DECL_RESTRICT dest, + const typename Ops::Type *Q_DECL_RESTRICT src, + int length, uint const_alpha) { if (const_alpha == 255) { for (int i = 0; i < length; ++i) { - uint s = src[i]; - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d)); + auto s = Ops::load(&src[i]); + auto d = Ops::load(&dest[i]); + Ops::store(&dest[i], Ops::interpolate(s, Ops::invAlpha(d), d, Ops::alpha(s))); } } else { - uint cia = 255 - const_alpha; + auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha)); for (int i = 0; i < length; ++i) { - uint s = BYTE_MUL(src[i], const_alpha); - uint d = dest[i]; - uint a = qAlpha(s) + cia; - dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d)); + auto s = Ops::multiplyAlpha8bit(Ops::load(&src[i]), const_alpha); + auto d = Ops::load(&dest[i]); + auto sa = Ops::add(Ops::alpha(s), cia); + Ops::store(&dest[i], Ops::interpolate(s, Ops::invAlpha(d), d, sa)); } } } +void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha) +{ + comp_func_solid_DestinationAtop_template<Argb32Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_solid_DestinationAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + comp_func_solid_DestinationAtop_template<Rgba64Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + comp_func_DestinationAtop_template<Argb32Operations>(dest, src, length, const_alpha); +} + void QT_FASTCALL comp_func_DestinationAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - QRgba64 s = src[i]; - QRgba64 d = dest[i]; - dest[i] = interpolate65535(d, s.alpha(), s, 65535 - d.alpha()); - } - } else { - uint ca = const_alpha * 257; - uint cia = 65535 - ca; - for (int i = 0; i < length; ++i) { - QRgba64 s = multiplyAlpha65535(src[i], ca); - QRgba64 d = dest[i]; - uint a = s.alpha() + cia; - dest[i] = interpolate65535(d, a, s, 65535 - d.alpha()); - } - } + comp_func_DestinationAtop_template<Rgba64Operations>(dest, src, length, const_alpha); } /* @@ -723,62 +930,58 @@ void QT_FASTCALL comp_func_DestinationAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, = s*ca * dia + d * (sia*ca + cia) = s*ca * dia + d * (1 - sa*ca) */ -void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha) +template<class Ops> +inline static void comp_func_solid_XOR_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha) { + auto c = Ops::convert(color); if (const_alpha != 255) - color = BYTE_MUL(color, const_alpha); - uint sia = qAlpha(~color); + c = Ops::multiplyAlpha8bit(c, const_alpha); + auto sia = Ops::invAlpha(c); for (int i = 0; i < length; ++i) { - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia); + auto d = Ops::load(&dest[i]); + Ops::store(&dest[i], Ops::interpolate(c, Ops::invAlpha(d), d, sia)); } } -void QT_FASTCALL comp_func_solid_XOR_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - if (const_alpha != 255) - color = multiplyAlpha255(color, const_alpha); - auto s = CONVERT(color); - auto sia = CONST(65535 - color.alpha()); - for (int i = 0; i < length; ++i) { - auto d = LOAD(&dest[i]); - STORE(&dest[i], interpolate65535(s, INVALPHA(d), d, sia)); - } -} - -void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +template<class Ops> +inline static void comp_func_XOR_template(typename Ops::Type *Q_DECL_RESTRICT dest, + const typename Ops::Type *Q_DECL_RESTRICT src, + int length, uint const_alpha) { if (const_alpha == 255) { for (int i = 0; i < length; ++i) { - uint d = dest[i]; - uint s = src[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); + auto d = Ops::load(&dest[i]); + auto s = Ops::load(&src[i]); + Ops::store(&dest[i], Ops::interpolate(s, Ops::invAlpha(d), d, Ops::invAlpha(s))); } } else { for (int i = 0; i < length; ++i) { - uint d = dest[i]; - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); + auto d = Ops::load(&dest[i]); + auto s = Ops::multiplyAlpha8bit(Ops::load(&src[i]), const_alpha); + Ops::store(&dest[i], Ops::interpolate(s, Ops::invAlpha(d), d, Ops::invAlpha(s))); } } } +void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha) +{ + comp_func_solid_XOR_template<Argb32Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_solid_XOR_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + comp_func_solid_XOR_template<Rgba64Operations>(dest, length, color, const_alpha); +} + +void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + comp_func_XOR_template<Argb32Operations>(dest, src, length, const_alpha); +} + void QT_FASTCALL comp_func_XOR_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - auto d = LOAD(&dest[i]); - auto s = LOAD(&src[i]); - STORE(&dest[i], interpolate65535(s, INVALPHA(d), d, INVALPHA(s))); - } - } else { - for (int i = 0; i < length; ++i) { - auto d = LOAD(&dest[i]); - auto s = multiplyAlpha255(LOAD(&src[i]), const_alpha); - STORE(&dest[i], interpolate65535(s, INVALPHA(d), d, INVALPHA(s))); - } - } + comp_func_XOR_template<Rgba64Operations>(dest, src, length, const_alpha); } struct QFullCoverage { @@ -827,84 +1030,67 @@ static inline uint mix_alpha_rgb64(uint da, uint sa) Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa) = Sca + Dca */ -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage) +template<class Ops> +inline static void comp_func_solid_Plus_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha) { - uint s = color; - - for (int i = 0; i < length; ++i) { - uint d = dest[i]; - d = comp_func_Plus_one_pixel(d, s); - coverage.store(&dest[i], d); + auto c = Ops::convert(color); + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + auto d = Ops::load(&dest[i]); + d = Ops::plus(d, c); + Ops::store(&dest[i], d); + } + } else { + uint ia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + auto d = Ops::load(&dest[i]); + d = Ops::interpolate8bit(Ops::plus(d, c), const_alpha, d, ia); + Ops::store(&dest[i], d); + } } } -void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha) +template<class Ops> +inline static void comp_func_Plus_template(typename Ops::Type *Q_DECL_RESTRICT dest, + const typename Ops::Type *Q_DECL_RESTRICT src, + int length, uint const_alpha) { - if (const_alpha == 255) - comp_func_solid_Plus_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -void QT_FASTCALL comp_func_solid_Plus_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - auto b = CONVERT(color); if (const_alpha == 255) { for (int i = 0; i < length; ++i) { - auto a = LOAD(&dest[i]); - a = addWithSaturation(a, b); - STORE(&dest[i], a); + auto d = Ops::load(&dest[i]); + auto s = Ops::load(&src[i]); + d = Ops::plus(d, s); + Ops::store(&dest[i], d); } } else { + uint ia = 255 - const_alpha; for (int i = 0; i < length; ++i) { - auto a = LOAD(&dest[i]); - auto d = addWithSaturation(a, b); - a = interpolate255(d, const_alpha, a, 255 - const_alpha); - STORE(&dest[i], a); + auto d = Ops::load(&dest[i]); + auto s = Ops::load(&src[i]); + d = Ops::interpolate8bit(Ops::plus(d, s), const_alpha, d, ia); + Ops::store(&dest[i], d); } } } -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha) { - for (int i = 0; i < length; ++i) { - uint d = dest[i]; - uint s = src[i]; - - d = comp_func_Plus_one_pixel(d, s); + comp_func_solid_Plus_template<Argb32Operations>(dest, length, color, const_alpha); +} - coverage.store(&dest[i], d); - } +void QT_FASTCALL comp_func_solid_Plus_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + comp_func_solid_Plus_template<Rgba64Operations>(dest, length, color, const_alpha); } void QT_FASTCALL comp_func_Plus(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) - comp_func_Plus_impl(dest, src, length, QFullCoverage()); - else - comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha)); + comp_func_Plus_template<Argb32Operations>(dest, src, length, const_alpha); } void QT_FASTCALL comp_func_Plus_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - auto a = LOAD(&dest[i]); - auto b = LOAD(&src[i]); - a = addWithSaturation(a, b); - STORE(&dest[i], a); - } - } else { - for (int i = 0; i < length; ++i) { - auto a = LOAD(&dest[i]); - auto b = LOAD(&src[i]); - auto d = addWithSaturation(a, b); - a = interpolate255(d, const_alpha, a, 255 - const_alpha); - STORE(&dest[i], a); - } - } + comp_func_Plus_template<Rgba64Operations>(dest, src, length, const_alpha); } /* diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index f3df62b855..6d55803e80 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -73,9 +73,6 @@ enum { half_point = 1 << 15 }; -// must be multiple of 4 for easier SIMD implementations -static const int buffer_size = 2048; - template<QImage::Format> Q_DECL_CONSTEXPR uint redWidth(); template<QImage::Format> Q_DECL_CONSTEXPR uint redShift(); template<QImage::Format> Q_DECL_CONSTEXPR uint greenWidth(); @@ -94,6 +91,10 @@ template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB4444_Premultiplied> template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; } template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; } template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBX8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBA8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; } + template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB16>() { return 11; } template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB444>() { return 8; } template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB555>() { return 10; } @@ -103,6 +104,15 @@ template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB4444_Premultiplied> template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8555_Premultiplied>() { return 18; } template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8565_Premultiplied>() { return 19; } template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB6666_Premultiplied>() { return 12; } +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBX8888>() { return 24; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888>() { return 24; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; } +#else +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBX8888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; } +#endif template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB16>() { return 6; } template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB444>() { return 4; } template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB555>() { return 5; } @@ -112,6 +122,10 @@ template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB4444_Premultiplie template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; } template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8565_Premultiplied>() { return 6; } template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBX8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBA8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; } + template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB16>() { return 5; } template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB444>() { return 4; } template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB555>() { return 5; } @@ -121,6 +135,15 @@ template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB4444_Premultiplie template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8555_Premultiplied>() { return 13; } template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8565_Premultiplied>() { return 13; } template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBX8888>() { return 16; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888>() { return 16; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; } +#else +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBX8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; } +#endif template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB16>() { return 5; } template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB444>() { return 4; } template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB555>() { return 5; } @@ -130,6 +153,10 @@ template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB4444_Premultiplied template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; } template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; } template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBX8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBA8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; } + template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB16>() { return 0; } template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB444>() { return 0; } template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB555>() { return 0; } @@ -139,6 +166,15 @@ template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB4444_Premultiplied template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8555_Premultiplied>() { return 8; } template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8565_Premultiplied>() { return 8; } template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB6666_Premultiplied>() { return 0; } +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBX8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; } +#else +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBX8888>() { return 16; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888>() { return 16; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; } +#endif template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB16>() { return 0; } template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB444>() { return 0; } template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB555>() { return 0; } @@ -148,6 +184,10 @@ template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB4444_Premultiplie template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8555_Premultiplied>() { return 8; } template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8565_Premultiplied>() { return 8; } template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBX8888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBA8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; } + template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB16>() { return 0; } template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB444>() { return 0; } template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB555>() { return 0; } @@ -157,6 +197,15 @@ template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB4444_Premultiplie template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8555_Premultiplied>() { return 0; } template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8565_Premultiplied>() { return 0; } template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB6666_Premultiplied>() { return 18; } +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBX8888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; } +#else +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBX8888>() { return 24; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888>() { return 24; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; } +#endif template<QImage::Format> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel(); template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB16>() { return QPixelLayout::BPP16; } @@ -168,6 +217,9 @@ template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB44 template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8555_Premultiplied>() { return QPixelLayout::BPP24; } template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8565_Premultiplied>() { return QPixelLayout::BPP24; } template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB6666_Premultiplied>() { return QPixelLayout::BPP24; } +template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBX8888>() { return QPixelLayout::BPP32; } +template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888>() { return QPixelLayout::BPP32; } +template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888_Premultiplied>() { return QPixelLayout::BPP32; } template<QImage::Format Format> @@ -450,16 +502,68 @@ static const uint *QT_FASTCALL convertARGBPMFromARGB32PM(uint *buffer, const uin return buffer; } +template<QImage::Format Format> +static const uint *QT_FASTCALL rbSwap(uint *buffer, const uint *src, int count) +{ + Q_CONSTEXPR uchar aWidth = alphaWidth<Format>(); + Q_CONSTEXPR uchar aShift = alphaShift<Format>(); + Q_CONSTEXPR uchar rWidth = redWidth<Format>(); + Q_CONSTEXPR uchar rShift = redShift<Format>(); + Q_CONSTEXPR uchar gWidth = greenWidth<Format>(); + Q_CONSTEXPR uchar gShift = greenShift<Format>(); + Q_CONSTEXPR uchar bWidth = blueWidth<Format>(); + Q_CONSTEXPR uchar bShift = blueShift<Format>(); #ifdef Q_COMPILER_CONSTEXPR + Q_STATIC_ASSERT(rWidth == bWidth); +#endif + Q_CONSTEXPR uint redBlueMask = (1 << rWidth) - 1; + Q_CONSTEXPR uint alphaGreenMask = (((1 << aWidth) - 1) << aShift) + | (((1 << gWidth) - 1) << gShift); + + for (int i = 0; i < count; ++i) { + const uint c = src[i]; + const uint r = (c >> rShift) & redBlueMask; + const uint b = (c >> bShift) & redBlueMask; + buffer[i] = (c & alphaGreenMask) + | (r << bShift) + | (b << rShift); + } + return buffer; +} + +static const uint *QT_FASTCALL rbSwap_rgb32(uint *buffer, const uint *src, int count) +{ + for (int i = 0; i < count; ++i) { + const uint c = src[i]; + const uint ag = c & 0xff00ff00; + const uint rb = c & 0x00ff00ff; + buffer[i] = ag | (rb << 16) | (rb >> 16); + } + return buffer; +} + +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN +template<> +const uint *QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uint *buffer, const uint *src, int count) +{ + return rbSwap_rgb32(buffer, src, count); +} +#endif + +static const uint *QT_FASTCALL rbSwap_rgb30(uint *buffer, const uint *src, int count) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qRgbSwapRgb30(src[i]); + return buffer; +} template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutRGB() { return QPixelLayout{ - uchar(redWidth<Format>()), uchar(redShift<Format>()), - uchar(greenWidth<Format>()), uchar(greenShift<Format>()), - uchar(blueWidth<Format>()), uchar(blueShift<Format>()), - 0, 0, - false, bitsPerPixel<Format>(), + false, + false, + bitsPerPixel<Format>(), + rbSwap<Format>, convertToRGB32<Format>, convertRGBFromARGB32PM<Format, false>, convertRGBFromARGB32PM<Format, true>, @@ -470,11 +574,10 @@ template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixe template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutARGBPM() { return QPixelLayout{ - uchar(redWidth<Format>()), uchar(redShift<Format>()), - uchar(greenWidth<Format>()), uchar(greenShift<Format>()), - uchar(blueWidth<Format>()), uchar(blueShift<Format>()), - uchar(alphaWidth<Format>()), uchar(alphaShift<Format>()), - true, bitsPerPixel<Format>(), + true, + true, + bitsPerPixel<Format>(), + rbSwap<Format>, convertARGBPMToARGB32PM<Format>, convertARGBPMFromARGB32PM<Format, false>, convertARGBPMFromARGB32PM<Format, true>, @@ -482,8 +585,6 @@ template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixe }; } -#endif - // To convert in place, let 'dest' and 'src' be the same. static const uint *QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, const uint *src, int count, const QVector<QRgb> *clut, QDitherInfo *) @@ -953,16 +1054,15 @@ inline void QT_FASTCALL storePixels<QPixelLayout::BPP32>(uchar *dest, const uint // convertFromArgb32() assumes that no color channel is more than 8 bits. // QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits. QPixelLayout qPixelLayouts[QImage::NImageFormats] = { - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPPNone, 0, 0, 0, 0 }, // Format_Invalid - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1MSB, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Mono - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_MonoLSB - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Indexed8 + { false, false, QPixelLayout::BPPNone, nullptr, nullptr, nullptr, nullptr, nullptr }, // Format_Invalid + { false, false, QPixelLayout::BPP1MSB, nullptr, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Mono + { false, false, QPixelLayout::BPP1LSB, nullptr, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_MonoLSB + { false, false, QPixelLayout::BPP8, nullptr, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Indexed8 // Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong, // but everywhere this generic conversion would be wrong is currently overloaded. - { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough, convertRGB32ToRGB64 }, // Format_RGB32 - { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM, convertPassThrough, convertARGB32ToARGB64PM }, // Format_ARGB32 - { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough, convertARGB32PMToARGB64PM }, // Format_ARGB32_Premultiplied -#ifdef Q_COMPILER_CONSTEXPR + { false, false, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough, convertPassThrough, convertPassThrough, convertRGB32ToRGB64 }, // Format_RGB32 + { true, false, QPixelLayout::BPP32, rbSwap_rgb32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM, convertPassThrough, convertARGB32ToARGB64PM }, // Format_ARGB32 + { true, true, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough, convertPassThrough, convertPassThrough, convertARGB32PMToARGB64PM }, // Format_ARGB32_Premultiplied pixelLayoutRGB<QImage::Format_RGB16>(), pixelLayoutARGBPM<QImage::Format_ARGB8565_Premultiplied>(), pixelLayoutRGB<QImage::Format_RGB666>(), @@ -972,77 +1072,15 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = { pixelLayoutRGB<QImage::Format_RGB888>(), pixelLayoutRGB<QImage::Format_RGB444>(), pixelLayoutARGBPM<QImage::Format_ARGB4444_Premultiplied>(), -#else - { 5, 11, 6, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, - convertToRGB32<QImage::Format_RGB16>, - convertRGBFromARGB32PM<QImage::Format_RGB16, false>, - convertRGBFromARGB32PM<QImage::Format_RGB16, true>, - convertToRGB64<QImage::Format_RGB16>, - }, - { 5, 19, 6, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, - convertARGBPMToARGB32PM<QImage::Format_ARGB8565_Premultiplied>, - convertARGBPMFromARGB32PM<QImage::Format_ARGB8565_Premultiplied, false>, - convertARGBPMFromARGB32PM<QImage::Format_ARGB8565_Premultiplied, true>, - convertARGBPMToARGB64PM<QImage::Format_ARGB8565_Premultiplied>, - }, - { 6, 12, 6, 6, 6, 0, 0, 0, false, QPixelLayout::BPP24, - convertToRGB32<QImage::Format_RGB666>, - convertRGBFromARGB32PM<QImage::Format_RGB666, false>, - convertRGBFromARGB32PM<QImage::Format_RGB666, true>, - convertToRGB64<QImage::Format_RGB666>, - }, - { 6, 12, 6, 6, 6, 0, 6, 18, true, QPixelLayout::BPP24, - convertARGBPMToARGB32PM<QImage::Format_ARGB6666_Premultiplied>, - convertARGBPMFromARGB32PM<QImage::Format_ARGB6666_Premultiplied, false>, - convertARGBPMFromARGB32PM<QImage::Format_ARGB6666_Premultiplied, true>, - convertARGBPMToARGB64PM<QImage::Format_ARGB6666_Premultiplied>, - }, - { 5, 10, 5, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, - convertToRGB32<QImage::Format_RGB555>, - convertRGBFromARGB32PM<QImage::Format_RGB555, false>, - convertRGBFromARGB32PM<QImage::Format_RGB555, true>, - convertToRGB64<QImage::Format_RGB555>, - }, - { 5, 18, 5, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, - convertARGBPMToARGB32PM<QImage::Format_ARGB8555_Premultiplied>, - convertARGBPMFromARGB32PM<QImage::Format_ARGB8555_Premultiplied, false>, - convertARGBPMFromARGB32PM<QImage::Format_ARGB8555_Premultiplied, true>, - convertARGBPMToARGB64PM<QImage::Format_ARGB8555_Premultiplied>, - }, - { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP24, - convertToRGB32<QImage::Format_RGB888>, - convertRGBFromARGB32PM<QImage::Format_RGB888, false>, - convertRGBFromARGB32PM<QImage::Format_RGB888, true>, - convertToRGB64<QImage::Format_RGB888>, - }, - { 4, 8, 4, 4, 4, 0, 0, 0, false, QPixelLayout::BPP16, - convertToRGB32<QImage::Format_RGB444>, - convertRGBFromARGB32PM<QImage::Format_RGB444, false>, - convertRGBFromARGB32PM<QImage::Format_RGB444, true>, - convertToRGB64<QImage::Format_RGB444>, - }, - { 4, 8, 4, 4, 4, 0, 4, 12, true, QPixelLayout::BPP16, - convertARGBPMToARGB32PM<QImage::Format_ARGB4444_Premultiplied>, - convertARGBPMFromARGB32PM<QImage::Format_ARGB4444_Premultiplied, false>, - convertARGBPMFromARGB32PM<QImage::Format_ARGB4444_Premultiplied, true>, - convertARGBPMToARGB64PM<QImage::Format_ARGB4444_Premultiplied>, - }, -#endif -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - { 8, 24, 8, 16, 8, 8, 0, 0, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBX8888 - { 8, 24, 8, 16, 8, 8, 8, 0, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32, convertRGBA8888ToARGB64PM }, // Format_RGBA8888 - { 8, 24, 8, 16, 8, 8, 8, 0, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM}, // Format_RGBA8888_Premultiplied -#else - { 8, 0, 8, 8, 8, 16, 0, 24, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBX8888 - { 8, 0, 8, 8, 8, 16, 8, 24, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32, convertRGBA8888ToARGB64PM }, // Format_RGBA8888 (ABGR32) - { 8, 0, 8, 8, 8, 16, 8, 24, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBA8888_Premultiplied -#endif - { 10, 20, 10, 10, 10, 0, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertRGB30FromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR>, convertA2RGB30PMToARGB64PM<PixelOrderBGR> }, // Format_BGR30 - { 10, 20, 10, 10, 10, 0, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertA2RGB30PMFromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR>, convertA2RGB30PMToARGB64PM<PixelOrderBGR> }, // Format_A2BGR30_Premultiplied - { 10, 0, 10, 10, 10, 20, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertRGB30FromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_RGB30 - { 10, 0, 10, 10, 10, 20, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertA2RGB30PMFromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_A2RGB30_Premultiplied - { 0, 0, 0, 0, 0, 0, 8, 0, true, QPixelLayout::BPP8, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0, convertAlpha8ToRGB64 }, // Format_Alpha8 - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32, convertGrayscale8ToRGB64 } // Format_Grayscale8 + { false, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBX8888 + { true, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32, convertRGBA8888ToARGB64PM }, // Format_RGBA8888 (ABGR32) + { true, true, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBA8888_Premultiplied + { false, false, QPixelLayout::BPP32, rbSwap_rgb30, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertRGB30FromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR>, convertA2RGB30PMToARGB64PM<PixelOrderBGR> }, // Format_BGR30 + { true, true, QPixelLayout::BPP32, rbSwap_rgb30, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertA2RGB30PMFromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR>, convertA2RGB30PMToARGB64PM<PixelOrderBGR> }, // Format_A2BGR30_Premultiplied + { false, false, QPixelLayout::BPP32, rbSwap_rgb30, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertRGB30FromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_RGB30 + { true, true, QPixelLayout::BPP32, rbSwap_rgb30, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertA2RGB30PMFromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_A2RGB30_Premultiplied + { true, true, QPixelLayout::BPP8, nullptr, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0, convertAlpha8ToRGB64 }, // Format_Alpha8 + { false, false, QPixelLayout::BPP8, nullptr, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32, convertGrayscale8ToRGB64 } // Format_Grayscale8 }; const FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = { @@ -1131,7 +1169,7 @@ static uint *QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer, in static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) { const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; - uint buffer32[buffer_size]; + uint buffer32[BufferSize]; const uint *ptr = qFetchPixels[layout->bpp](buffer32, rasterBuffer->scanLine(y), x, length); return const_cast<QRgba64 *>(layout->convertToARGB64PM(buffer, ptr, length, 0, 0)); } @@ -1304,14 +1342,14 @@ static void QT_FASTCALL destStoreRGB16(QRasterBuffer *rasterBuffer, int x, int y static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length) { - uint buf[buffer_size]; + uint buf[BufferSize]; const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; StorePixelsFunc store = qStorePixels[layout->bpp]; uchar *dest = rasterBuffer->scanLine(y); while (length) { - int l = qMin(length, buffer_size); + int l = qMin(length, BufferSize); const uint *ptr = 0; - if (!layout->premultiplied && !layout->alphaWidth) + if (!layout->premultiplied && !layout->hasAlphaChannel) ptr = layout->convertFromRGB32(buf, buffer, l, 0, 0); else ptr = layout->convertFromARGB32PM(buf, buffer, l, 0, 0); @@ -1331,15 +1369,15 @@ static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int len static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) { - uint buf[buffer_size]; + uint buf[BufferSize]; const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; StorePixelsFunc store = qStorePixels[layout->bpp]; uchar *dest = rasterBuffer->scanLine(y); while (length) { - int l = qMin(length, buffer_size); + int l = qMin(length, BufferSize); const uint *ptr = 0; convertFromRgb64(buf, buffer, l); - if (!layout->premultiplied && !layout->alphaWidth) + if (!layout->premultiplied && !layout->hasAlphaChannel) ptr = layout->convertFromRGB32(buf, buf, l, 0, 0); else ptr = layout->convertFromARGB32PM(buf, buf, l, 0, 0); @@ -1554,7 +1592,7 @@ static const QRgba64 *QT_FASTCALL fetchUntransformed64(QRgba64 *buffer, const Op { const QPixelLayout *layout = &qPixelLayouts[data->texture.format]; if (layout->bpp != QPixelLayout::BPP32) { - uint buffer32[buffer_size]; + uint buffer32[BufferSize]; const uint *ptr = qFetchPixels[layout->bpp](buffer32, data->texture.scanLine(y), x, length); return layout->convertToARGB64PM(buffer, ptr, length, data->texture.colorTable, 0); } else { @@ -1673,7 +1711,7 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper FetchPixelFunc fetch = qFetchPixel[layout->bpp]; const QVector<QRgb> *clut = data->texture.colorTable; - uint buffer32[buffer_size]; + uint buffer32[BufferSize]; QRgba64 *b = buffer; if (data->fast_matrix) { // The increment pr x in the scanline @@ -1687,9 +1725,9 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper int i = 0, j = 0; while (i < length) { - if (j == buffer_size) { - layout->convertToARGB64PM(b, buffer32, buffer_size, clut, 0); - b += buffer_size; + if (j == BufferSize) { + layout->convertToARGB64PM(b, buffer32, BufferSize, clut, 0); + b += BufferSize; j = 0; } int px = fx >> 16; @@ -1725,9 +1763,9 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper int i = 0, j = 0; while (i < length) { - if (j == buffer_size) { - layout->convertToARGB64PM(b, buffer32, buffer_size, clut, 0); - b += buffer_size; + if (j == BufferSize) { + layout->convertToARGB64PM(b, buffer32, BufferSize, clut, 0); + b += BufferSize; j = 0; } const qreal iw = fw == 0 ? 1 : 1 / fw; @@ -1921,7 +1959,7 @@ inline void fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(int, } enum FastTransformTypes { - SimpleUpscaleTransform, + SimpleScaleTransform, UpscaleTransform, DownscaleTransform, RotateTransform, @@ -1929,11 +1967,38 @@ enum FastTransformTypes { NFastTransformTypes }; +// Completes the partial interpolation stored in IntermediateBuffer. +// by performing the x-axis interpolation and joining the RB and AG buffers. +static void QT_FASTCALL intermediate_adder(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx) +{ +#if defined(QT_COMPILER_SUPPORTS_AVX2) + extern void QT_FASTCALL intermediate_adder_avx2(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx); + if (qCpuHasFeature(AVX2)) + return intermediate_adder_avx2(b, end, intermediate, offset, fx, fdx); +#endif + + // Switch to intermediate buffer coordinates + fx -= offset * fixed_scale; + + while (b < end) { + const int x = (fx >> 16); + + const uint distx = (fx & 0x0000ffff) >> 8; + const uint idistx = 256 - distx; + const uint rb = (intermediate.buffer_rb[x] * idistx + intermediate.buffer_rb[x + 1] * distx) & 0xff00ff00; + const uint ag = (intermediate.buffer_ag[x] * idistx + intermediate.buffer_ag[x + 1] * distx) & 0xff00ff00; + *b = (rb >> 8) | ag; + b++; + fx += fdx; + } + fx += offset * fixed_scale; +} + typedef void (QT_FASTCALL *BilinearFastTransformHelper)(uint *b, uint *end, const QTextureData &image, int &fx, int &fy, int fdx, int fdy); template<TextureBlendType blendType> -static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(uint *b, uint *end, const QTextureData &image, - int &fx, int &fy, int fdx, int /*fdy*/) +static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper(uint *b, uint *end, const QTextureData &image, + int &fx, int &fy, int fdx, int /*fdy*/) { int y1 = (fy >> 16); int y2; @@ -1950,16 +2015,12 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u const int offset = (fx + adjust) >> 16; int x = offset; - // The idea is first to do the interpolation between the row s1 and the row s2 - // into an intermediate buffer, then we interpolate between two pixel of this buffer. - - // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB - // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG - // +1 for the last pixel to interpolate with, and +1 for rounding errors. - quint32 intermediate_buffer[2][buffer_size + 2]; - // count is the size used in the intermediate_buffer. + IntermediateBuffer intermediate; + // count is the size used in the intermediate.buffer. int count = (qint64(length) * qAbs(fdx) + fixed_scale - 1) / fixed_scale + 2; - Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case + // length is supposed to be <= BufferSize either because data->m11 < 1 or + // data->m11 < 2, and any larger buffers split + Q_ASSERT(count <= BufferSize + 2); int f = 0; int lim = count; if (blendType == BlendTransformedBilinearTiled) { @@ -1974,8 +2035,8 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff; quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff; do { - intermediate_buffer[0][f] = rb; - intermediate_buffer[1][f] = ag; + intermediate.buffer_rb[f] = rb; + intermediate.buffer_ag[f] = ag; f++; x++; } while (x < image.x1 && f < lim); @@ -2008,10 +2069,10 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u // Add the values, and shift to only keep 8 significant bits per colors __m128i rAG =_mm_add_epi16(topAG, bottomAG); rAG = _mm_srli_epi16(rAG, 8); - _mm_storeu_si128((__m128i*)(&intermediate_buffer[1][f]), rAG); + _mm_storeu_si128((__m128i*)(&intermediate.buffer_ag[f]), rAG); __m128i rRB =_mm_add_epi16(topRB, bottomRB); rRB = _mm_srli_epi16(rRB, 8); - _mm_storeu_si128((__m128i*)(&intermediate_buffer[0][f]), rRB); + _mm_storeu_si128((__m128i*)(&intermediate.buffer_rb[f]), rRB); } #elif defined(__ARM_NEON__) const int16x8_t disty_ = vdupq_n_s16(disty); @@ -2038,10 +2099,10 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u // Add the values, and shift to only keep 8 significant bits per colors int16x8_t rAG = vaddq_s16(topAG, bottomAG); rAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rAG), 8)); - vst1q_s16((int16_t*)(&intermediate_buffer[1][f]), rAG); + vst1q_s16((int16_t*)(&intermediate.buffer_ag[f]), rAG); int16x8_t rRB = vaddq_s16(topRB, bottomRB); rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8)); - vst1q_s16((int16_t*)(&intermediate_buffer[0][f]), rRB); + vst1q_s16((int16_t*)(&intermediate.buffer_rb[f]), rRB); } #endif } @@ -2055,28 +2116,13 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u uint t = s1[x]; uint b = s2[x]; - intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff; - intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff; + intermediate.buffer_rb[f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff; + intermediate.buffer_ag[f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff; x++; } - // Now interpolate the values from the intermediate_buffer to get the final result. - fx -= offset * fixed_scale; // Switch to intermediate buffer coordinates - - while (b < end) { - int x1 = (fx >> 16); - int x2 = x1 + 1; - Q_ASSERT(x1 >= 0); - Q_ASSERT(x2 < count); - - int distx = (fx & 0x0000ffff) >> 8; - int idistx = 256 - distx; - int rb = ((intermediate_buffer[0][x1] * idistx + intermediate_buffer[0][x2] * distx) >> 8) & 0xff00ff; - int ag = (intermediate_buffer[1][x1] * idistx + intermediate_buffer[1][x2] * distx) & 0xff00ff00; - *b = rb | ag; - b++; - fx += fdx; - } + // Now interpolate the values from the intermediate.buffer to get the final result. + intermediate_adder(b, end, intermediate, offset, fx, fdx); } template<TextureBlendType blendType> @@ -2542,14 +2588,14 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper(uint static BilinearFastTransformHelper bilinearFastTransformHelperARGB32PM[2][NFastTransformTypes] = { { - fetchTransformedBilinearARGB32PM_simple_upscale_helper<BlendTransformedBilinear>, + fetchTransformedBilinearARGB32PM_simple_scale_helper<BlendTransformedBilinear>, fetchTransformedBilinearARGB32PM_upscale_helper<BlendTransformedBilinear>, fetchTransformedBilinearARGB32PM_downscale_helper<BlendTransformedBilinear>, fetchTransformedBilinearARGB32PM_rotate_helper<BlendTransformedBilinear>, fetchTransformedBilinearARGB32PM_fast_rotate_helper<BlendTransformedBilinear> }, { - fetchTransformedBilinearARGB32PM_simple_upscale_helper<BlendTransformedBilinearTiled>, + fetchTransformedBilinearARGB32PM_simple_scale_helper<BlendTransformedBilinearTiled>, fetchTransformedBilinearARGB32PM_upscale_helper<BlendTransformedBilinearTiled>, fetchTransformedBilinearARGB32PM_downscale_helper<BlendTransformedBilinearTiled>, fetchTransformedBilinearARGB32PM_rotate_helper<BlendTransformedBilinearTiled>, @@ -2584,7 +2630,13 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c if (fdy == 0) { // simple scale, no rotation or shear if (qAbs(fdx) <= fixed_scale) { // simple scale up on X - bilinearFastTransformHelperARGB32PM[tiled][SimpleUpscaleTransform](b, end, data->texture, fx, fy, fdx, fdy); + bilinearFastTransformHelperARGB32PM[tiled][SimpleScaleTransform](b, end, data->texture, fx, fy, fdx, fdy); + } else if (qAbs(fdx) <= 2 * fixed_scale) { + // simple scale down on X, less than 2x + const int mid = (length * 2 < BufferSize) ? length : ((length + 1) / 2); + bilinearFastTransformHelperARGB32PM[tiled][SimpleScaleTransform](buffer, buffer + mid, data->texture, fx, fy, fdx, fdy); + if (mid != length) + bilinearFastTransformHelperARGB32PM[tiled][SimpleScaleTransform](buffer + mid, buffer + length, data->texture, fx, fy, fdx, fdy); } else if (qAbs(data->m22) < qreal(1./8.)) { // scale up more than 8x (on Y) bilinearFastTransformHelperARGB32PM[tiled][UpscaleTransform](b, end, data->texture, fx, fy, fdx, fdy); @@ -2653,8 +2705,8 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c } template<TextureBlendType blendType, QPixelLayout::BPP bpp> -static void QT_FASTCALL fetchTransformedBilinear_simple_upscale_helper(uint *b, uint *end, const QTextureData &image, - int &fx, int &fy, int fdx, int /*fdy*/) +static void QT_FASTCALL fetchTransformedBilinear_simple_scale_helper(uint *b, uint *end, const QTextureData &image, + int &fx, int &fy, int fdx, int /*fdy*/) { const QPixelLayout *layout = &qPixelLayouts[image.format]; const QVector<QRgb> *clut = image.colorTable; @@ -2678,16 +2730,14 @@ static void QT_FASTCALL fetchTransformedBilinear_simple_upscale_helper(uint *b, const int offset = (fx + adjust) >> 16; int x = offset; - // The idea is first to do the interpolation between the row s1 and the row s2 - // into an intermediate buffer, then we interpolate between two pixel of this buffer. - // +1 for the last pixel to interpolate with, and +1 for rounding errors. - uint buf1[buffer_size + 2]; - uint buf2[buffer_size + 2]; + IntermediateBuffer intermediate; + uint *buf1 = intermediate.buffer_rb; + uint *buf2 = intermediate.buffer_ag; const uint *ptr1; const uint *ptr2; int count = (qint64(length) * qAbs(fdx) + fixed_scale - 1) / fixed_scale + 2; - Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case + Q_ASSERT(count <= BufferSize + 2); if (blendType == BlendTransformedBilinearTiled) { x %= image.width; @@ -2719,6 +2769,7 @@ static void QT_FASTCALL fetchTransformedBilinear_simple_upscale_helper(uint *b, buf2[i + len1] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff; } } + // Generate the rest by repeatedly repeating the previous set of pixels for (int i = image.width; i < count; ++i) { buf1[i] = buf1[i - image.width]; buf2[i] = buf2[i - image.width]; @@ -2751,22 +2802,8 @@ static void QT_FASTCALL fetchTransformedBilinear_simple_upscale_helper(uint *b, } } - // Now interpolate the values from the intermediate_buffer to get the final result. - fx -= offset * fixed_scale; // Switch to intermediate buffer coordinates - - while (b < end) { - int x1 = (fx >> 16); - int x2 = x1 + 1; - Q_ASSERT(x1 >= 0); - Q_ASSERT(x2 < count); - - int distx = (fx & 0x0000ffff) >> 8; - int idistx = 256 - distx; - int rb = ((buf1[x1] * idistx + buf1[x2] * distx) >> 8) & 0xff00ff; - int ag = (buf2[x1] * idistx + buf2[x2] * distx) & 0xff00ff00; - *b++ = rb | ag; - fx += fdx; - } + // Now interpolate the values from the intermediate.buffer to get the final result. + intermediate_adder(b, end, intermediate, offset, fx, fdx); } @@ -2916,15 +2953,20 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper if (fdy == 0) { // simple scale, no rotation or shear if (qAbs(fdx) <= fixed_scale) { // scale up on X - fetchTransformedBilinear_simple_upscale_helper<blendType, bpp>(buffer, buffer + length, data->texture, fx, fy, fdx, fdy); + fetchTransformedBilinear_simple_scale_helper<blendType, bpp>(buffer, buffer + length, data->texture, fx, fy, fdx, fdy); + } else if (qAbs(fdx) <= 2 * fixed_scale) { // scale down on X less than 2x + const int mid = (length * 2 < BufferSize) ? length : ((length + 1) / 2); + fetchTransformedBilinear_simple_scale_helper<blendType, bpp>(buffer, buffer + mid, data->texture, fx, fy, fdx, fdy); + if (mid != length) + fetchTransformedBilinear_simple_scale_helper<blendType, bpp>(buffer + mid, buffer + length, data->texture, fx, fy, fdx, fdy); } else { const BilinearFastTransformFetcher fetcher = fetchTransformedBilinear_fetcher<blendType,bpp>; - uint buf1[buffer_size]; - uint buf2[buffer_size]; + uint buf1[BufferSize]; + uint buf2[BufferSize]; uint *b = buffer; while (length) { - int len = qMin(length, buffer_size / 2); + int len = qMin(length, BufferSize / 2); fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, 0); layout->convertToARGB32PM(buf1, buf1, len * 2, clut, 0); layout->convertToARGB32PM(buf2, buf2, len * 2, clut, 0); @@ -2955,11 +2997,11 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper } else { // rotation or shear const BilinearFastTransformFetcher fetcher = fetchTransformedBilinear_fetcher<blendType,bpp>; - uint buf1[buffer_size]; - uint buf2[buffer_size]; + uint buf1[BufferSize]; + uint buf2[BufferSize]; uint *b = buffer; while (length) { - int len = qMin(length, buffer_size / 2); + int len = qMin(length, BufferSize / 2); fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, fdy); layout->convertToARGB32PM(buf1, buf1, len * 2, clut, 0); layout->convertToARGB32PM(buf2, buf2, len * 2, clut, 0); @@ -3009,15 +3051,15 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper qreal fy = data->m22 * cy + data->m12 * cx + data->dy; qreal fw = data->m23 * cy + data->m13 * cx + data->m33; - uint buf1[buffer_size]; - uint buf2[buffer_size]; + uint buf1[BufferSize]; + uint buf2[BufferSize]; uint *b = buffer; - int distxs[buffer_size / 2]; - int distys[buffer_size / 2]; + int distxs[BufferSize / 2]; + int distys[BufferSize / 2]; while (length) { - int len = qMin(length, buffer_size / 2); + int len = qMin(length, BufferSize / 2); for (int i = 0; i < len; ++i) { const qreal iw = fw == 0 ? 1 : 1 / fw; const qreal px = fx * iw - qreal(0.5); @@ -3094,13 +3136,13 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co if (fdy == 0) { //simple scale, no rotation - uint sbuf1[buffer_size]; - uint sbuf2[buffer_size]; - quint64 buf1[buffer_size]; - quint64 buf2[buffer_size]; + uint sbuf1[BufferSize]; + uint sbuf2[BufferSize]; + quint64 buf1[BufferSize]; + quint64 buf2[BufferSize]; QRgba64 *b = buffer; while (length) { - int len = qMin(length, buffer_size / 2); + int len = qMin(length, BufferSize / 2); int disty = (fy & 0x0000ffff); #if defined(__SSE2__) const __m128i vdy = _mm_set1_epi16(disty); @@ -3138,15 +3180,15 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co b += len; } } else { //rotation - uint sbuf1[buffer_size]; - uint sbuf2[buffer_size]; - quint64 buf1[buffer_size]; - quint64 buf2[buffer_size]; + uint sbuf1[BufferSize]; + uint sbuf2[BufferSize]; + quint64 buf1[BufferSize]; + quint64 buf2[BufferSize]; QRgba64 *end = buffer + length; QRgba64 *b = buffer; while (b < end) { - int len = qMin(length, buffer_size / 2); + int len = qMin(length, BufferSize / 2); fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy); @@ -3177,17 +3219,17 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co qreal fw = data->m23 * cy + data->m13 * cx + data->m33; FetchPixelFunc fetch = qFetchPixel[layout->bpp]; - uint sbuf1[buffer_size]; - uint sbuf2[buffer_size]; - quint64 buf1[buffer_size]; - quint64 buf2[buffer_size]; + uint sbuf1[BufferSize]; + uint sbuf2[BufferSize]; + quint64 buf1[BufferSize]; + quint64 buf2[BufferSize]; QRgba64 *b = buffer; - int distxs[buffer_size / 2]; - int distys[buffer_size / 2]; + int distxs[BufferSize / 2]; + int distys[BufferSize / 2]; while (length) { - int len = qMin(length, buffer_size / 2); + int len = qMin(length, BufferSize / 2); for (int i = 0; i < len; ++i) { const qreal iw = fw == 0 ? 1 : 1 / fw; const qreal px = fx * iw - qreal(0.5); @@ -3292,6 +3334,15 @@ static SourceFetchProc sourceFetchARGB32PM[NBlendTypes] = { fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled> // BilinearTiled }; +static SourceFetchProc sourceFetchAny16[NBlendTypes] = { + fetchUntransformed, // Untransformed + fetchUntransformed, // Tiled + fetchTransformed<BlendTransformed, QPixelLayout::BPP16>, // Transformed + fetchTransformed<BlendTransformedTiled, QPixelLayout::BPP16>, // TransformedTiled + fetchTransformedBilinear<BlendTransformedBilinear, QPixelLayout::BPP16>, // TransformedBilinear + fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPP16> // TransformedBilinearTiled +}; + static SourceFetchProc sourceFetchAny32[NBlendTypes] = { fetchUntransformed, // Untransformed fetchUntransformed, // Tiled @@ -3316,6 +3367,8 @@ static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage: return sourceFetchARGB32PM[blendType]; if (blendType == BlendUntransformed || blendType == BlendTiled) return sourceFetchUntransformed[format]; + if (qPixelLayouts[format].bpp == QPixelLayout::BPP16) + return sourceFetchAny16[blendType]; if (qPixelLayouts[format].bpp == QPixelLayout::BPP32) return sourceFetchAny32[blendType]; return sourceFetchGeneric[blendType]; @@ -3717,7 +3770,7 @@ static void blend_color_generic(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); - uint buffer[buffer_size]; + uint buffer[BufferSize]; Operator op = getOperator(data, spans, count); const uint color = data->solid.color.toArgb32(); @@ -3725,7 +3778,7 @@ void blend_color_generic(int count, const QSpan *spans, void *userData) int x = spans->x; int length = spans->len; while (length) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); uint *dest = op.destFetch ? op.destFetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer; op.funcSolid(dest, l, color, spans->coverage); if (op.destStore) @@ -3777,14 +3830,27 @@ void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData) return blend_color_generic(count, spans, userData); } - quint64 buffer[buffer_size]; + quint64 buffer[BufferSize]; const QRgba64 color = data->solid.color; + bool solidFill = data->rasterBuffer->compositionMode == QPainter::CompositionMode_Source + || (data->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver && color.isOpaque()); + bool isBpp32 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP32; while (count--) { int x = spans->x; int length = spans->len; + if (solidFill && isBpp32 && spans->coverage == 255) { + // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels + if (length > 0) { + op.destStore64(data->rasterBuffer, x, spans->y, &color, 1); + uint *dest = (uint*)data->rasterBuffer->scanLine(spans->y) + x; + qt_memfill32(dest + 1, dest[0], length - 1); + length = 0; + } + } + while (length) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); QRgba64 *dest = op.destFetch64((QRgba64 *)buffer, data->rasterBuffer, x, spans->y, l); op.funcSolid64(dest, l, color, spans->coverage); op.destStore64(data->rasterBuffer, x, spans->y, dest, l); @@ -3889,7 +3955,7 @@ void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handle int length = right - x; while (length) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); length -= l; int process_length = l; @@ -3936,8 +4002,8 @@ struct QBlendBase BlendType *dest; - BlendType buffer[buffer_size]; - BlendType src_buffer[buffer_size]; + BlendType buffer[BufferSize]; + BlendType src_buffer[BufferSize]; }; class BlendSrcGeneric : public QBlendBase<uint> @@ -4021,8 +4087,8 @@ static void blend_untransformed_generic(int count, const QSpan *spans, void *use { QSpanData *data = reinterpret_cast<QSpanData *>(userData); - uint buffer[buffer_size]; - uint src_buffer[buffer_size]; + uint buffer[BufferSize]; + uint src_buffer[BufferSize]; Operator op = getOperator(data, spans, count); const int image_width = data->texture.width; @@ -4046,7 +4112,7 @@ static void blend_untransformed_generic(int count, const QSpan *spans, void *use if (length > 0) { const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l); uint *dest = op.destFetch ? op.destFetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer; op.func(dest, src, l, coverage); @@ -4071,8 +4137,8 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi qCDebug(lcQtGuiDrawHelper, "blend_untransformed_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit"); return blend_untransformed_generic(count, spans, userData); } - quint64 buffer[buffer_size]; - quint64 src_buffer[buffer_size]; + quint64 buffer[BufferSize]; + quint64 src_buffer[BufferSize]; const int image_width = data->texture.width; const int image_height = data->texture.height; @@ -4095,7 +4161,7 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi if (length > 0) { const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); const QRgba64 *src = op.srcFetch64((QRgba64 *)src_buffer, &op, data, sy, sx, l); QRgba64 *dest = op.destFetch64((QRgba64 *)buffer, data->rasterBuffer, x, spans->y, l); op.func64(dest, src, l, coverage); @@ -4259,8 +4325,8 @@ static void blend_tiled_generic(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); - uint buffer[buffer_size]; - uint src_buffer[buffer_size]; + uint buffer[BufferSize]; + uint src_buffer[BufferSize]; Operator op = getOperator(data, spans, count); const int image_width = data->texture.width; @@ -4286,8 +4352,8 @@ static void blend_tiled_generic(int count, const QSpan *spans, void *userData) const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { int l = qMin(image_width - sx, length); - if (buffer_size < l) - l = buffer_size; + if (BufferSize < l) + l = BufferSize; const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l); uint *dest = op.destFetch ? op.destFetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer; op.func(dest, src, l, coverage); @@ -4312,8 +4378,8 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD qCDebug(lcQtGuiDrawHelper, "blend_tiled_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit"); return blend_tiled_generic(count, spans, userData); } - quint64 buffer[buffer_size]; - quint64 src_buffer[buffer_size]; + quint64 buffer[BufferSize]; + quint64 src_buffer[BufferSize]; const int image_width = data->texture.width; const int image_height = data->texture.height; @@ -4325,6 +4391,50 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD if (yoff < 0) yoff += image_height; + bool isBpp32 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP32; + if (op.destFetch64 == destFetch64Undefined && image_width <= BufferSize && isBpp32) { + // If destination isn't blended into the result, we can do the tiling directly on destination pixels. + while (count--) { + int x = spans->x; + int y = spans->y; + int length = spans->len; + int sx = (xoff + spans->x) % image_width; + int sy = (spans->y + yoff) % image_height; + if (sx < 0) + sx += image_width; + if (sy < 0) + sy += image_height; + + int sl = qMin(image_width, length); + if (sx > 0 && sl > 0) { + int l = qMin(image_width - sx, sl); + const QRgba64 *src = op.srcFetch64((QRgba64 *)src_buffer, &op, data, sy, sx, l); + op.destStore64(data->rasterBuffer, x, y, src, l); + x += l; + sx += l; + sl -= l; + if (sx >= image_width) + sx = 0; + } + if (sl > 0) { + Q_ASSERT(sx == 0); + const QRgba64 *src = op.srcFetch64((QRgba64 *)src_buffer, &op, data, sy, sx, sl); + op.destStore64(data->rasterBuffer, x, y, src, sl); + x += sl; + sx += sl; + sl -= sl; + if (sx >= image_width) + sx = 0; + } + uint *dest = (uint*)data->rasterBuffer->scanLine(y) + x - image_width; + for (int i = image_width; i < length; ++i) { + dest[i] = dest[i - image_width]; + } + ++spans; + } + return; + } + while (count--) { int x = spans->x; int length = spans->len; @@ -4338,8 +4448,8 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { int l = qMin(image_width - sx, length); - if (buffer_size < l) - l = buffer_size; + if (BufferSize < l) + l = BufferSize; const QRgba64 *src = op.srcFetch64((QRgba64 *)src_buffer, &op, data, sy, sx, l); QRgba64 *dest = op.destFetch64((QRgba64 *)buffer, data->rasterBuffer, x, spans->y, l); op.func64(dest, src, l, coverage); @@ -4388,8 +4498,8 @@ static void blend_tiled_argb(int count, const QSpan *spans, void *userData) const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { int l = qMin(image_width - sx, length); - if (buffer_size < l) - l = buffer_size; + if (BufferSize < l) + l = BufferSize; const uint *src = (const uint *)data->texture.scanLine(sy) + sx; uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x; op.func(dest, src, l, coverage); @@ -4448,8 +4558,8 @@ static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData) int tx = x; while (length) { int l = qMin(image_width - sx, length); - if (buffer_size < l) - l = buffer_size; + if (BufferSize < l) + l = BufferSize; quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + tx; const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx; memcpy(dest, src, l * sizeof(quint16)); @@ -4484,8 +4594,8 @@ static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData) if (alpha > 0) { while (length) { int l = qMin(image_width - sx, length); - if (buffer_size < l) - l = buffer_size; + if (BufferSize < l) + l = BufferSize; quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + x; const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx; blend_sourceOver_rgb16_rgb16(dest, src, l, alpha, ialpha); @@ -4501,199 +4611,6 @@ static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData) } } -static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans, void *userData) -{ - QSpanData *data = reinterpret_cast<QSpanData*>(userData); - QPainter::CompositionMode mode = data->rasterBuffer->compositionMode; - - if (data->texture.format != QImage::Format_RGB16 - || (mode != QPainter::CompositionMode_SourceOver - && mode != QPainter::CompositionMode_Source)) - { - blend_src_generic(count, spans, userData); - return; - } - - quint16 buffer[buffer_size]; - - const int src_minx = data->texture.x1; - const int src_miny = data->texture.y1; - const int src_maxx = data->texture.x2 - 1; - const int src_maxy = data->texture.y2 - 1; - - if (data->fast_matrix) { - // The increment pr x in the scanline - const int fdx = (int)(data->m11 * fixed_scale); - const int fdy = (int)(data->m12 * fixed_scale); - - while (count--) { - const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8; - const quint8 alpha = (coverage + 1) >> 3; - const quint8 ialpha = 0x20 - alpha; - if (alpha == 0) { - ++spans; - continue; - } - - quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x; - const qreal cx = spans->x + qreal(0.5); - const qreal cy = spans->y + qreal(0.5); - int x = int((data->m21 * cy - + data->m11 * cx + data->dx) * fixed_scale) - half_point; - int y = int((data->m22 * cy - + data->m12 * cx + data->dy) * fixed_scale) - half_point; - int length = spans->len; - - while (length) { - int l; - quint16 *b; - if (ialpha == 0) { - l = length; - b = dest; - } else { - l = qMin(length, buffer_size); - b = buffer; - } - const quint16 *end = b + l; - - while (b < end) { - int x1 = (x >> 16); - int x2; - int y1 = (y >> 16); - int y2; - - fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_minx, src_maxx, x1, x2); - fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_miny, src_maxy, y1, y2); - - const quint16 *src1 = (const quint16*)data->texture.scanLine(y1); - const quint16 *src2 = (const quint16*)data->texture.scanLine(y2); - quint16 tl = src1[x1]; - const quint16 tr = src1[x2]; - quint16 bl = src2[x1]; - const quint16 br = src2[x2]; - - const uint distxsl8 = x & 0xff00; - const uint distysl8 = y & 0xff00; - const uint distx = distxsl8 >> 8; - const uint disty = distysl8 >> 8; - const uint distxy = distx * disty; - - const uint tlw = 0x10000 - distxsl8 - distysl8 + distxy; // (256 - distx) * (256 - disty) - const uint trw = distxsl8 - distxy; // distx * (256 - disty) - const uint blw = distysl8 - distxy; // (256 - distx) * disty - const uint brw = distxy; // distx * disty - uint red = ((tl & 0xf800) * tlw + (tr & 0xf800) * trw - + (bl & 0xf800) * blw + (br & 0xf800) * brw) & 0xf8000000; - uint green = ((tl & 0x07e0) * tlw + (tr & 0x07e0) * trw - + (bl & 0x07e0) * blw + (br & 0x07e0) * brw) & 0x07e00000; - uint blue = ((tl & 0x001f) * tlw + (tr & 0x001f) * trw - + (bl & 0x001f) * blw + (br & 0x001f) * brw); - *b = quint16((red | green | blue) >> 16); - - ++b; - x += fdx; - y += fdy; - } - - if (ialpha != 0) - blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha); - - dest += l; - length -= l; - } - ++spans; - } - } else { - const qreal fdx = data->m11; - const qreal fdy = data->m12; - const qreal fdw = data->m13; - - while (count--) { - const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8; - const quint8 alpha = (coverage + 1) >> 3; - const quint8 ialpha = 0x20 - alpha; - if (alpha == 0) { - ++spans; - continue; - } - - quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x; - - const qreal cx = spans->x + qreal(0.5); - const qreal cy = spans->y + qreal(0.5); - - qreal x = data->m21 * cy + data->m11 * cx + data->dx; - qreal y = data->m22 * cy + data->m12 * cx + data->dy; - qreal w = data->m23 * cy + data->m13 * cx + data->m33; - - int length = spans->len; - while (length) { - int l; - quint16 *b; - if (ialpha == 0) { - l = length; - b = dest; - } else { - l = qMin(length, buffer_size); - b = buffer; - } - const quint16 *end = b + l; - - while (b < end) { - const qreal iw = w == 0 ? 1 : 1 / w; - const qreal px = x * iw - qreal(0.5); - const qreal py = y * iw - qreal(0.5); - - int x1 = int(px) - (px < 0); - int x2; - int y1 = int(py) - (py < 0); - int y2; - - fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_minx, src_maxx, x1, x2); - fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_miny, src_maxy, y1, y2); - - const quint16 *src1 = (const quint16 *)data->texture.scanLine(y1); - const quint16 *src2 = (const quint16 *)data->texture.scanLine(y2); - quint16 tl = src1[x1]; - const quint16 tr = src1[x2]; - quint16 bl = src2[x1]; - const quint16 br = src2[x2]; - - const uint distx = uint((px - x1) * 256); - const uint disty = uint((py - y1) * 256); - const uint distxsl8 = distx << 8; - const uint distysl8 = disty << 8; - const uint distxy = distx * disty; - - const uint tlw = 0x10000 - distxsl8 - distysl8 + distxy; // (256 - distx) * (256 - disty) - const uint trw = distxsl8 - distxy; // distx * (256 - disty) - const uint blw = distysl8 - distxy; // (256 - distx) * disty - const uint brw = distxy; // distx * disty - uint red = ((tl & 0xf800) * tlw + (tr & 0xf800) * trw - + (bl & 0xf800) * blw + (br & 0xf800) * brw) & 0xf8000000; - uint green = ((tl & 0x07e0) * tlw + (tr & 0x07e0) * trw - + (bl & 0x07e0) * blw + (br & 0x07e0) * brw) & 0x07e00000; - uint blue = ((tl & 0x001f) * tlw + (tr & 0x001f) * trw - + (bl & 0x001f) * blw + (br & 0x001f) * brw); - *b = quint16((red | green | blue) >> 16); - - ++b; - x += fdx; - y += fdy; - w += fdw; - } - - if (ialpha != 0) - blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha); - - dest += l; - length -= l; - } - ++spans; - } - } -} - static void blend_transformed_argb(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); @@ -4704,7 +4621,7 @@ static void blend_transformed_argb(int count, const QSpan *spans, void *userData } CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode]; - uint buffer[buffer_size]; + uint buffer[BufferSize]; quint32 mask = (data->texture.format == QImage::Format_RGB32) ? 0xff000000 : 0; const int image_x1 = data->texture.x1; @@ -4733,7 +4650,7 @@ static void blend_transformed_argb(int count, const QSpan *spans, void *userData int length = spans->len; const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { - int l = qMin(length, buffer_size); + int l = qMin(length, BufferSize); const uint *end = buffer + l; uint *b = buffer; while (b < end) { @@ -4770,7 +4687,7 @@ static void blend_transformed_argb(int count, const QSpan *spans, void *userData int length = spans->len; const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { - int l = qMin(length, buffer_size); + int l = qMin(length, BufferSize); const uint *end = buffer + l; uint *b = buffer; while (b < end) { @@ -4809,7 +4726,7 @@ static void blend_transformed_rgb565(int count, const QSpan *spans, void *userDa return; } - quint16 buffer[buffer_size]; + quint16 buffer[BufferSize]; const int image_x1 = data->texture.x1; const int image_y1 = data->texture.y1; const int image_x2 = data->texture.x2 - 1; @@ -4845,7 +4762,7 @@ static void blend_transformed_rgb565(int count, const QSpan *spans, void *userDa l = length; b = dest; } else { - l = qMin(length, buffer_size); + l = qMin(length, BufferSize); b = buffer; } const quint16 *end = b + l; @@ -4900,7 +4817,7 @@ static void blend_transformed_rgb565(int count, const QSpan *spans, void *userDa l = length; b = dest; } else { - l = qMin(length, buffer_size); + l = qMin(length, BufferSize); b = buffer; } const quint16 *end = b + l; @@ -4942,7 +4859,7 @@ static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *us } CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode]; - uint buffer[buffer_size]; + uint buffer[BufferSize]; int image_width = data->texture.width; int image_height = data->texture.height; @@ -4970,7 +4887,7 @@ static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *us const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; int length = spans->len; while (length) { - int l = qMin(length, buffer_size); + int l = qMin(length, BufferSize); const uint *end = buffer + l; uint *b = buffer; int px16 = x % (image_width << 16); @@ -5024,7 +4941,7 @@ static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *us const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; int length = spans->len; while (length) { - int l = qMin(length, buffer_size); + int l = qMin(length, BufferSize); const uint *end = buffer + l; uint *b = buffer; while (b < end) { @@ -5075,7 +4992,7 @@ static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void * return; } - quint16 buffer[buffer_size]; + quint16 buffer[BufferSize]; const int image_width = data->texture.width; const int image_height = data->texture.height; @@ -5109,7 +5026,7 @@ static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void * l = length; b = dest; } else { - l = qMin(length, buffer_size); + l = qMin(length, BufferSize); b = buffer; } const quint16 *end = b + l; @@ -5169,7 +5086,7 @@ static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void * l = length; b = dest; } else { - l = qMin(length, buffer_size); + l = qMin(length, BufferSize); b = buffer; } const quint16 *end = b + l; @@ -5227,7 +5144,7 @@ static const ProcessSpans processTextureSpansRGB16[NBlendTypes] = { blend_tiled_rgb565, // Tiled blend_transformed_rgb565, // Transformed blend_transformed_tiled_rgb565, // TransformedTiled - blend_transformed_bilinear_rgb565, // TransformedBilinear + blend_src_generic, // TransformedBilinear blend_src_generic // TransformedBilinearTiled }; @@ -5523,7 +5440,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); } - quint64 buffer[buffer_size]; + quint64 buffer[BufferSize]; const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format]; const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format]; @@ -5532,7 +5449,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, int i = x; int length = mapWidth; while (length > 0) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, i, y + ly, l); for (int j=0; j < l; ++j) { const int coverage = map[j + (i - x)]; @@ -5561,7 +5478,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, int end = qMin<int>(x + mapWidth, clip.x + clip.len); if (end <= start) continue; - Q_ASSERT(end - start <= buffer_size); + Q_ASSERT(end - start <= BufferSize); QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start); for (int xp=start; xp<end; ++xp) { @@ -5800,7 +5717,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); } - quint64 buffer[buffer_size]; + quint64 buffer[BufferSize]; const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format]; const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format]; @@ -5809,7 +5726,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, int i = x; int length = mapWidth; while (length > 0) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, i, y + ly, l); for (int j=0; j < l; ++j) { const uint coverage = src[j + (i - x)]; @@ -5838,7 +5755,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, int end = qMin<int>(x + mapWidth, clip.x + clip.len); if (end <= start) continue; - Q_ASSERT(end - start <= buffer_size); + Q_ASSERT(end - start <= BufferSize); QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start); for (int xp=start; xp<end; ++xp) { @@ -5928,8 +5845,26 @@ static void qt_rectfill_quint16(QRasterBuffer *rasterBuffer, int x, int y, int width, int height, const QRgba64 &color) { + const QPixelLayout &layout = qPixelLayouts[rasterBuffer->format]; + quint32 c32 = color.toArgb32(); + layout.convertFromARGB32PM(&c32, &c32, 1, nullptr, nullptr); + quint16 c16; + storePixel<QPixelLayout::BPP16>(reinterpret_cast<uchar *>(&c16), 0, c32); qt_rectfill<quint16>(reinterpret_cast<quint16 *>(rasterBuffer->buffer()), - color.toRgb16(), x, y, width, height, rasterBuffer->bytesPerLine()); + c16, x, y, width, height, rasterBuffer->bytesPerLine()); +} + +static void qt_rectfill_quint24(QRasterBuffer *rasterBuffer, + int x, int y, int width, int height, + const QRgba64 &color) +{ + const QPixelLayout &layout = qPixelLayouts[rasterBuffer->format]; + quint32 c32 = color.toArgb32(); + layout.convertFromARGB32PM(&c32, &c32, 1, nullptr, nullptr); + quint24 c24; + storePixel<QPixelLayout::BPP24>(reinterpret_cast<uchar *>(&c24), 0, c32); + qt_rectfill<quint24>(reinterpret_cast<quint24 *>(rasterBuffer->buffer()), + c24, x, y, width, height, rasterBuffer->bytesPerLine()); } static void qt_rectfill_nonpremul_argb32(QRasterBuffer *rasterBuffer, @@ -6049,7 +5984,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint24 }, // Format_RGB666 { @@ -6058,7 +5993,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint24 }, // Format_ARGB6666_Premultiplied { @@ -6067,7 +6002,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint24 }, // Format_RGB555 { @@ -6076,7 +6011,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint16 }, // Format_ARGB8555_Premultiplied { @@ -6085,7 +6020,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint24 }, // Format_RGB888 { @@ -6094,7 +6029,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint24 }, // Format_RGB444 { @@ -6103,7 +6038,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint16 }, // Format_ARGB4444_Premultiplied { @@ -6112,7 +6047,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint16 }, // Format_RGBX8888 { @@ -6401,14 +6336,14 @@ static void qInitDrawhelperFunctions() qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_avx2; qt_functionForModeSolid64_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_rgb64_avx2; - extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uint *b, uint *end, const QTextureData &image, - int &fx, int &fy, int fdx, int /*fdy*/); + extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2(uint *b, uint *end, const QTextureData &image, + int &fx, int &fy, int fdx, int /*fdy*/); extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_downscale_helper_avx2(uint *b, uint *end, const QTextureData &image, int &fx, int &fy, int fdx, int /*fdy*/); extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2(uint *b, uint *end, const QTextureData &image, int &fx, int &fy, int fdx, int fdy); - bilinearFastTransformHelperARGB32PM[0][SimpleUpscaleTransform] = fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2; + bilinearFastTransformHelperARGB32PM[0][SimpleScaleTransform] = fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2; bilinearFastTransformHelperARGB32PM[0][DownscaleTransform] = fetchTransformedBilinearARGB32PM_downscale_helper_avx2; bilinearFastTransformHelperARGB32PM[0][FastRotateTransform] = fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2; } diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp index 3a70524a9d..1c225b4568 100644 --- a/src/gui/painting/qdrawhelper_avx2.cpp +++ b/src/gui/painting/qdrawhelper_avx2.cpp @@ -45,8 +45,6 @@ QT_BEGIN_NAMESPACE -static Q_CONSTEXPR int BufferSize = 2048; - enum { FixedScale = 1 << 16, HalfPoint = 1 << 15 @@ -576,8 +574,10 @@ inline void fetchTransformedBilinear_pixelBounds(int, int l1, int l2, int &v1, i Q_ASSERT(v2 >= l1 && v2 <= l2); } -void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uint *b, uint *end, const QTextureData &image, - int &fx, int &fy, int fdx, int /*fdy*/) +void QT_FASTCALL intermediate_adder_avx2(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx); + +void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2(uint *b, uint *end, const QTextureData &image, + int &fx, int &fy, int fdx, int /*fdy*/) { int y1 = (fy >> 16); int y2; @@ -594,16 +594,12 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin const int offset = (fx + adjust) >> 16; int x = offset; - // The idea is first to do the interpolation between the row s1 and the row s2 - // into an intermediate buffer, then we interpolate between two pixel of this buffer. - - // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB - // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG - // +1 for the last pixel to interpolate with, and +1 for rounding errors. - quint32 intermediate_buffer[2][BufferSize + 2]; + IntermediateBuffer intermediate; // count is the size used in the intermediate_buffer. int count = (qint64(length) * qAbs(fdx) + FixedScale - 1) / FixedScale + 2; - Q_ASSERT(count <= BufferSize + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case + // length is supposed to be <= BufferSize either because data->m11 < 1 or + // data->m11 < 2, and any larger buffers split + Q_ASSERT(count <= BufferSize + 2); int f = 0; int lim = qMin(count, image.x2 - x); if (x < image.x1) { @@ -613,8 +609,8 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff; quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff; do { - intermediate_buffer[0][f] = rb; - intermediate_buffer[1][f] = ag; + intermediate.buffer_rb[f] = rb; + intermediate.buffer_ag[f] = ag; f++; x++; } while (x < image.x1 && f < lim); @@ -644,10 +640,10 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin // Add the values, and shift to only keep 8 significant bits per colors __m256i rAG =_mm256_add_epi16(topAG, bottomAG); rAG = _mm256_srli_epi16(rAG, 8); - _mm256_storeu_si256((__m256i*)(&intermediate_buffer[1][f]), rAG); + _mm256_storeu_si256((__m256i*)(&intermediate.buffer_ag[f]), rAG); __m256i rRB =_mm256_add_epi16(topRB, bottomRB); rRB = _mm256_srli_epi16(rRB, 8); - _mm256_storeu_si256((__m256i*)(&intermediate_buffer[0][f]), rRB); + _mm256_storeu_si256((__m256i*)(&intermediate.buffer_rb[f]), rRB); } for (; f < count; f++) { // Same as above but without simd @@ -656,11 +652,17 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin uint t = s1[x]; uint b = s2[x]; - intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff; - intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff; + intermediate.buffer_rb[f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff; + intermediate.buffer_ag[f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff; x++; } + // Now interpolate the values from the intermediate_buffer to get the final result. + intermediate_adder_avx2(b, end, intermediate, offset, fx, fdx); +} + +void QT_FASTCALL intermediate_adder_avx2(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx) +{ fx -= offset * FixedScale; const __m128i v_fdx = _mm_set1_epi32(fdx * 4); @@ -669,8 +671,8 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin while (b < end - 3) { const __m128i offset = _mm_srli_epi32(v_fx, 16); - __m256i vrb = _mm256_i32gather_epi64((const long long *)intermediate_buffer[0], offset, 4); - __m256i vag = _mm256_i32gather_epi64((const long long *)intermediate_buffer[1], offset, 4); + __m256i vrb = _mm256_i32gather_epi64((const long long *)intermediate.buffer_rb, offset, 4); + __m256i vag = _mm256_i32gather_epi64((const long long *)intermediate.buffer_ag, offset, 4); __m128i vdx = _mm_and_si128(v_fx, _mm_set1_epi32(0x0000ffff)); vdx = _mm_srli_epi16(vdx, 8); @@ -695,17 +697,17 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin v_fx = _mm_add_epi32(v_fx, v_fdx); } while (b < end) { - int x = (fx >> 16); - - uint distx = (fx & 0x0000ffff) >> 8; - uint idistx = 256 - distx; + const int x = (fx >> 16); - uint rb = ((intermediate_buffer[0][x] * idistx + intermediate_buffer[0][x + 1] * distx) >> 8) & 0xff00ff; - uint ag = (intermediate_buffer[1][x] * idistx + intermediate_buffer[1][x + 1] * distx) & 0xff00ff00; - *b = rb | ag; + const uint distx = (fx & 0x0000ffff) >> 8; + const uint idistx = 256 - distx; + const uint rb = (intermediate.buffer_rb[x] * idistx + intermediate.buffer_rb[x + 1] * distx) & 0xff00ff00; + const uint ag = (intermediate.buffer_ag[x] * idistx + intermediate.buffer_ag[x + 1] * distx) & 0xff00ff00; + *b = (rb >> 8) | ag; b++; fx += fdx; } + fx += offset * FixedScale; } void QT_FASTCALL fetchTransformedBilinearARGB32PM_downscale_helper_avx2(uint *b, uint *end, const QTextureData &image, diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index b94fd34b51..c0214e9c11 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -793,6 +793,7 @@ static Q_ALWAYS_INLINE uint qAlphaRgb30(uint c) } struct quint24 { + quint24() = default; quint24(uint value); operator uint() const; uchar data[3]; @@ -1200,6 +1201,22 @@ inline uint comp_func_Plus_one_pixel(uint d, const uint s) #undef MIX #undef AMIX +// must be multiple of 4 for easier SIMD implementations +static Q_CONSTEXPR int BufferSize = 2048; + +// A buffer of intermediate results used by simple bilinear scaling. +struct IntermediateBuffer +{ + // The idea is first to do the interpolation between the row s1 and the row s2 + // into this intermediate buffer, then later interpolate between two pixel of this buffer. + // + // buffer_rb is a buffer of red-blue component of the pixel, in the form 0x00RR00BB + // buffer_ag is the alpha-green component of the pixel, in the form 0x00AA00GG + // +1 for the last pixel to interpolate with, and +1 for rounding errors. + quint32 buffer_rb[BufferSize+2]; + quint32 buffer_ag[BufferSize+2]; +}; + struct QDitherInfo { int x; int y; @@ -1209,6 +1226,8 @@ typedef const uint *(QT_FASTCALL *ConvertFunc)(uint *buffer, const uint *src, in const QVector<QRgb> *clut, QDitherInfo *dither); typedef const QRgba64 *(QT_FASTCALL *ConvertFunc64)(QRgba64 *buffer, const uint *src, int count, const QVector<QRgb> *clut, QDitherInfo *dither); +typedef const uint *(QT_FASTCALL *RbSwapFunc)(uint *buffer, const uint *src, int count); + struct QPixelLayout { @@ -1224,17 +1243,10 @@ struct QPixelLayout BPPCount }; - // All numbers in bits. - uchar redWidth; - uchar redShift; - uchar greenWidth; - uchar greenShift; - uchar blueWidth; - uchar blueShift; - uchar alphaWidth; - uchar alphaShift; + bool hasAlphaChannel; bool premultiplied; BPP bpp; + RbSwapFunc rbSwap; ConvertFunc convertToARGB32PM; ConvertFunc convertFromARGB32PM; ConvertFunc convertFromRGB32; diff --git a/src/gui/painting/qpagedpaintdevice.cpp b/src/gui/painting/qpagedpaintdevice.cpp index 1c7d6471b6..613a686848 100644 --- a/src/gui/painting/qpagedpaintdevice.cpp +++ b/src/gui/painting/qpagedpaintdevice.cpp @@ -42,6 +42,41 @@ QT_BEGIN_NAMESPACE +class QDummyPagedPaintDevicePrivate : public QPagedPaintDevicePrivate +{ + bool setPageLayout(const QPageLayout &newPageLayout) override + { + m_pageLayout = newPageLayout; + return m_pageLayout.isEquivalentTo(newPageLayout); + } + + bool setPageSize(const QPageSize &pageSize) override + { + m_pageLayout.setPageSize(pageSize); + return m_pageLayout.pageSize().isEquivalentTo(pageSize); + } + + bool setPageOrientation(QPageLayout::Orientation orientation) override + { + m_pageLayout.setOrientation(orientation); + return m_pageLayout.orientation() == orientation; + } + + bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) override + { + m_pageLayout.setUnits(units); + m_pageLayout.setMargins(margins); + return m_pageLayout.margins() == margins && m_pageLayout.units() == units; + } + + QPageLayout pageLayout() const override + { + return m_pageLayout; + } + + QPageLayout m_pageLayout; +}; + QPagedPaintDevicePrivate::~QPagedPaintDevicePrivate() { } @@ -61,9 +96,11 @@ QPagedPaintDevicePrivate::~QPagedPaintDevicePrivate() /*! Constructs a new paged paint device. + + \deprecated */ QPagedPaintDevice::QPagedPaintDevice() - : d(new QPagedPaintDevicePrivate) + : d(new QDummyPagedPaintDevicePrivate) { } @@ -263,7 +300,7 @@ QPagedPaintDevicePrivate *QPagedPaintDevice::dd() */ void QPagedPaintDevice::setPageSize(PageSize size) { - d->m_pageLayout.setPageSize(QPageSize(QPageSize::PageSizeId(size))); + d->setPageSize(QPageSize(QPageSize::PageSizeId(size))); } /*! @@ -271,7 +308,7 @@ void QPagedPaintDevice::setPageSize(PageSize size) */ QPagedPaintDevice::PageSize QPagedPaintDevice::pageSize() const { - return PageSize(d->m_pageLayout.pageSize().id()); + return PageSize(d->pageLayout().pageSize().id()); } /*! @@ -282,7 +319,7 @@ QPagedPaintDevice::PageSize QPagedPaintDevice::pageSize() const */ void QPagedPaintDevice::setPageSizeMM(const QSizeF &size) { - d->m_pageLayout.setPageSize(QPageSize(size, QPageSize::Millimeter)); + d->setPageSize(QPageSize(size, QPageSize::Millimeter)); } /*! @@ -290,7 +327,7 @@ void QPagedPaintDevice::setPageSizeMM(const QSizeF &size) */ QSizeF QPagedPaintDevice::pageSizeMM() const { - return d->m_pageLayout.pageSize().size(QPageSize::Millimeter); + return d->pageLayout().pageSize().size(QPageSize::Millimeter); } /*! @@ -305,8 +342,7 @@ QSizeF QPagedPaintDevice::pageSizeMM() const */ void QPagedPaintDevice::setMargins(const Margins &margins) { - d->m_pageLayout.setUnits(QPageLayout::Millimeter); - d->m_pageLayout.setMargins(QMarginsF(margins.left, margins.top, margins.right, margins.bottom)); + d->setPageMargins(QMarginsF(margins.left, margins.top, margins.right, margins.bottom), QPageLayout::Millimeter); } /*! @@ -318,7 +354,7 @@ void QPagedPaintDevice::setMargins(const Margins &margins) */ QPagedPaintDevice::Margins QPagedPaintDevice::margins() const { - QMarginsF margins = d->m_pageLayout.margins(QPageLayout::Millimeter); + QMarginsF margins = d->pageLayout().margins(QPageLayout::Millimeter); Margins result; result.left = margins.left(); result.top = margins.top(); @@ -413,7 +449,7 @@ bool QPagedPaintDevice::setPageOrientation(QPageLayout::Orientation orientation) bool QPagedPaintDevice::setPageMargins(const QMarginsF &margins) { - return d->setPageMargins(margins); + return setPageMargins(margins, pageLayout().units()); } /*! @@ -458,23 +494,30 @@ QPageLayout QPagedPaintDevice::pageLayout() const /*! \internal + \deprecated + Returns the internal device page layout. */ QPageLayout QPagedPaintDevice::devicePageLayout() const { - return d->m_pageLayout; + qWarning("QPagedPaintDevice::devicePageLayout() is deprecated, just use QPagedPaintDevice::pageLayout()"); + return d->pageLayout(); } /*! \internal + \deprecated + Returns the internal device page layout. */ QPageLayout &QPagedPaintDevice::devicePageLayout() { - return d->m_pageLayout; + qWarning("QPagedPaintDevice::devicePageLayout() is deprecated, you shouldn't be using this at all."); + static QPageLayout dummy; + return dummy; } QT_END_NAMESPACE diff --git a/src/gui/painting/qpagedpaintdevice.h b/src/gui/painting/qpagedpaintdevice.h index 66dd6fa8cf..c8957edab8 100644 --- a/src/gui/painting/qpagedpaintdevice.h +++ b/src/gui/painting/qpagedpaintdevice.h @@ -55,7 +55,7 @@ class QPagedPaintDevicePrivate; class Q_GUI_EXPORT QPagedPaintDevice : public QPaintDevice { public: - QPagedPaintDevice(); + QT_DEPRECATED QPagedPaintDevice(); ~QPagedPaintDevice(); virtual bool newPage() = 0; @@ -243,8 +243,8 @@ public: protected: QPagedPaintDevice(QPagedPaintDevicePrivate *dd); QPagedPaintDevicePrivate *dd(); - QPageLayout devicePageLayout() const; - QPageLayout &devicePageLayout(); + QT_DEPRECATED QPageLayout devicePageLayout() const; + QT_DEPRECATED QPageLayout &devicePageLayout(); friend class QPagedPaintDevicePrivate; QPagedPaintDevicePrivate *d; }; diff --git a/src/gui/painting/qpagedpaintdevice_p.h b/src/gui/painting/qpagedpaintdevice_p.h index a993ea4cac..3a43bd7828 100644 --- a/src/gui/painting/qpagedpaintdevice_p.h +++ b/src/gui/painting/qpagedpaintdevice_p.h @@ -60,8 +60,7 @@ class Q_GUI_EXPORT QPagedPaintDevicePrivate { public: QPagedPaintDevicePrivate() - : m_pageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0, 0, 0, 0)), - fromPage(0), + : fromPage(0), toPage(0), pageOrderAscending(true), printSelectionOnly(false) @@ -70,46 +69,19 @@ public: virtual ~QPagedPaintDevicePrivate(); - // ### Qt6 Remove these and make public class methods virtual - virtual bool setPageLayout(const QPageLayout &newPageLayout) - { - m_pageLayout = newPageLayout; - return m_pageLayout.isEquivalentTo(newPageLayout);; - } - virtual bool setPageSize(const QPageSize &pageSize) - { - m_pageLayout.setPageSize(pageSize); - return m_pageLayout.pageSize().isEquivalentTo(pageSize); - } + virtual bool setPageLayout(const QPageLayout &newPageLayout) = 0; - virtual bool setPageOrientation(QPageLayout::Orientation orientation) - { - m_pageLayout.setOrientation(orientation); - return m_pageLayout.orientation() == orientation; - } + virtual bool setPageSize(const QPageSize &pageSize) = 0; - virtual bool setPageMargins(const QMarginsF &margins) - { - return setPageMargins(margins, m_pageLayout.units()); - } + virtual bool setPageOrientation(QPageLayout::Orientation orientation) = 0; - virtual bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) - { - m_pageLayout.setUnits(units); - m_pageLayout.setMargins(margins); - return m_pageLayout.margins() == margins && m_pageLayout.units() == units; - } + virtual bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) = 0; - virtual QPageLayout pageLayout() const - { - return m_pageLayout; - } + virtual QPageLayout pageLayout() const = 0; static inline QPagedPaintDevicePrivate *get(QPagedPaintDevice *pd) { return pd->d; } - QPageLayout m_pageLayout; - // These are currently required to keep QPrinter functionality working in QTextDocument::print() int fromPage; int toPage; diff --git a/src/gui/painting/qpdfwriter.cpp b/src/gui/painting/qpdfwriter.cpp index 2f24c7efcb..e6c5cabd7f 100644 --- a/src/gui/painting/qpdfwriter.cpp +++ b/src/gui/painting/qpdfwriter.cpp @@ -83,41 +83,28 @@ public: { // Try to set the paint engine page layout pd->engine->setPageLayout(newPageLayout); - // Set QPagedPaintDevice layout to match the current paint engine layout - m_pageLayout = pd->engine->pageLayout(); - return m_pageLayout.isEquivalentTo(newPageLayout); + return pageLayout().isEquivalentTo(newPageLayout); } bool setPageSize(const QPageSize &pageSize) override { // Try to set the paint engine page size pd->engine->setPageSize(pageSize); - // Set QPagedPaintDevice layout to match the current paint engine layout - m_pageLayout = pd->engine->pageLayout(); - return m_pageLayout.pageSize().isEquivalentTo(pageSize); + return pageLayout().pageSize().isEquivalentTo(pageSize); } bool setPageOrientation(QPageLayout::Orientation orientation) override { // Set the print engine value pd->engine->setPageOrientation(orientation); - // Set QPagedPaintDevice layout to match the current paint engine layout - m_pageLayout = pd->engine->pageLayout(); - return m_pageLayout.orientation() == orientation; - } - - bool setPageMargins(const QMarginsF &margins) override - { - return setPageMargins(margins, pageLayout().units()); + return pageLayout().orientation() == orientation; } bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) override { // Try to set engine margins pd->engine->setPageMargins(margins, units); - // Set QPagedPaintDevice layout to match the current paint engine layout - m_pageLayout = pd->engine->pageLayout(); - return m_pageLayout.margins() == margins && m_pageLayout.units() == units; + return pageLayout().margins() == margins && pageLayout().units() == units; } QPageLayout pageLayout() const override @@ -150,9 +137,6 @@ QPdfWriter::QPdfWriter(const QString &filename) Q_D(QPdfWriter); d->engine->setOutputFilename(filename); - - // Set QPagedPaintDevice layout to match the current paint engine layout - devicePageLayout() = d->engine->pageLayout(); } /*! @@ -165,9 +149,6 @@ QPdfWriter::QPdfWriter(QIODevice *device) Q_D(QPdfWriter); d->engine->d_func()->outDevice = device; - - // Set QPagedPaintDevice layout to match the current paint engine layout - devicePageLayout() = d->engine->pageLayout(); } /*! diff --git a/src/gui/painting/qrgba64_p.h b/src/gui/painting/qrgba64_p.h index adceda2210..213ee58ef0 100644 --- a/src/gui/painting/qrgba64_p.h +++ b/src/gui/painting/qrgba64_p.h @@ -51,10 +51,11 @@ // We mean it. // +#include "qrgba64.h" +#include "qdrawhelper_p.h" + +#include <QtCore/private/qsimd_p.h> #include <QtGui/private/qtguiglobal_p.h> -#include <QtGui/qrgba64.h> -#include <QtGui/private/qdrawhelper_p.h> -#include <private/qsimd_p.h> QT_BEGIN_NAMESPACE @@ -159,7 +160,7 @@ Q_ALWAYS_INLINE __m128i interpolate65535(__m128i x, uint alpha1, __m128i y, uint { return _mm_add_epi32(multiplyAlpha65535(x, alpha1), multiplyAlpha65535(y, alpha2)); } -// alpha2 below is const-ref because otherwise MSVC2013 complains that it can't 16-byte align the argument. +// alpha2 below is const-ref because otherwise MSVC2015 complains that it can't 16-byte align the argument. Q_ALWAYS_INLINE __m128i interpolate65535(__m128i x, __m128i alpha1, __m128i y, const __m128i &alpha2) { return _mm_add_epi32(multiplyAlpha65535(x, alpha1), multiplyAlpha65535(y, alpha2)); @@ -239,20 +240,6 @@ inline uint toRgba8888(QRgba64 rgba64) #endif } -#if defined(__SSE2__) -Q_ALWAYS_INLINE __m128i addWithSaturation(__m128i a, __m128i b) -{ - return _mm_adds_epu16(a, b); -} -#endif - -#if defined(__ARM_NEON__) -Q_ALWAYS_INLINE uint16x4_t addWithSaturation(uint16x4_t a, uint16x4_t b) -{ - return vqmovn_u32(vaddl_u16(a, b)); -} -#endif - inline QRgba64 rgbBlend(QRgba64 d, QRgba64 s, uint rgbAlpha) { QRgba64 blend; |