diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-08 16:36:11 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-04-06 08:18:53 +0000 |
commit | 54dcbf49927954e913c1f65d2c67396f0bec14f9 (patch) | |
tree | b1cd4718a01cd0b51941a95836dac71b080bbdf6 /src/gui/painting/qcompositionfunctions.cpp | |
parent | 5a20a1d7807426f21cf553bb56215c1fae0df6ca (diff) |
Generalize composition functions
Change the composition functions upto and including comp_func_plus to
a templated structure sharing implementations.
Change-Id: I14bcb4b28870aacffce78f372589fdebbaf12ecf
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
Diffstat (limited to 'src/gui/painting/qcompositionfunctions.cpp')
-rw-r--r-- | src/gui/painting/qcompositionfunctions.cpp | 1094 |
1 files changed, 640 insertions, 454 deletions
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); } /* |