diff options
Diffstat (limited to 'src/gui/painting/qdrawhelper.cpp')
-rw-r--r-- | src/gui/painting/qdrawhelper.cpp | 1093 |
1 files changed, 739 insertions, 354 deletions
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index bbeb9fd9ea..ac15d8f4f4 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2018 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtGui module of the Qt Toolkit. @@ -43,7 +43,7 @@ #include <qstylehints.h> #include <qguiapplication.h> #include <qatomic.h> -#include <private/qcolorprofile_p.h> +#include <private/qcolortrclut_p.h> #include <private/qdrawhelper_p.h> #include <private/qpaintengine_raster_p.h> #include <private/qpainter_p.h> @@ -55,6 +55,7 @@ #endif #include <private/qguiapplication_p.h> #include <private/qrgba64_p.h> +#include <qendian.h> #include <qloggingcategory.h> #include <qmath.h> @@ -856,6 +857,44 @@ static const QRgba64 *QT_FASTCALL fetchGrayscale8ToRGB64(QRgba64 *buffer, const return buffer; } +static void QT_FASTCALL convertGrayscale16ToRGB32(uint *buffer, int count, const QVector<QRgb> *) +{ + for (int i = 0; i < count; ++i) { + const uint x = qt_div_257(buffer[i]); + buffer[i] = qRgb(x, x, x); + } +} + +static const uint *QT_FASTCALL fetchGrayscale16ToRGB32(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index; + for (int i = 0; i < count; ++i) { + const uint x = qt_div_257(s[i]); + buffer[i] = qRgb(x, x, x); + } + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertGrayscale16ToRGBA64(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + const unsigned short *s = reinterpret_cast<const unsigned short *>(src); + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromRgba64(s[i], s[i], s[i], 65535); + return buffer; +} + +static const QRgba64 *QT_FASTCALL fetchGrayscale16ToRGBA64(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index; + for (int i = 0; i < count; ++i) { + buffer[i] = QRgba64::fromRgba64(s[i], s[i], s[i], 65535); + } + return buffer; +} + static void QT_FASTCALL storeARGB32FromARGB32PM(uchar *dest, const uint *src, int index, int count, const QVector<QRgb> *, QDitherInfo *) { @@ -1047,18 +1086,8 @@ static const QRgba64 *QT_FASTCALL fetchRGB32ToRGB64(QRgba64 *buffer, const uchar static const QRgba64 *QT_FASTCALL convertARGB32ToRGBA64PM(QRgba64 *buffer, const uint *src, int count, const QVector<QRgb> *, QDitherInfo *) { -#ifdef __SSE2__ - qConvertARGB32PMToRGBA64PM_sse2<false, false>(buffer, src, count); - for (int i = 0; i < count; ++i) - buffer[i] = buffer[i].premultiplied(); -#elif defined(__ARM_NEON__) - qConvertARGB32PMToRGBA64PM_neon<false, false>(buffer, src, count); - for (int i = 0; i < count; ++i) - buffer[i] = buffer[i].premultiplied(); -#else for (int i = 0; i < count; ++i) buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied(); -#endif return buffer; } @@ -1088,6 +1117,7 @@ static const QRgba64 *QT_FASTCALL fetchARGB32PMToRGBA64PM(QRgba64 *buffer, const return convertARGB32PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); } +#if QT_CONFIG(raster_64bit) static void convertRGBA64ToRGBA64PM(QRgba64 *buffer, int count) { for (int i = 0; i < count; ++i) @@ -1097,6 +1127,7 @@ static void convertRGBA64ToRGBA64PM(QRgba64 *buffer, int count) static void convertRGBA64PMToRGBA64PM(QRgba64 *, int) { } +#endif static const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, const QVector<QRgb> *, QDitherInfo *) @@ -1110,18 +1141,8 @@ static const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM(QRgba64 *buffer, const u static const QRgba64 *QT_FASTCALL convertRGBA8888ToRGBA64PM(QRgba64 *buffer, const uint *src, int count, const QVector<QRgb> *, QDitherInfo *) { -#ifdef __SSE2__ - qConvertARGB32PMToRGBA64PM_sse2<true, false>(buffer, src, count); - for (int i = 0; i < count; ++i) - buffer[i] = buffer[i].premultiplied(); -#elif defined(__ARM_NEON__) - qConvertARGB32PMToRGBA64PM_neon<true, false>(buffer, src, count); - for (int i = 0; i < count; ++i) - buffer[i] = buffer[i].premultiplied(); -#else for (int i = 0; i < count; ++i) buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied(); -#endif return buffer; } @@ -1361,6 +1382,22 @@ static void QT_FASTCALL storeGrayscale8FromARGB32PM(uchar *dest, const uint *src dest[index + i] = qGray(qUnpremultiply(src[i])); } +static void QT_FASTCALL storeGrayscale16FromRGB32(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index; + for (int i = 0; i < count; ++i) + d[i] = qGray(src[i]) * 257; +} + +static void QT_FASTCALL storeGrayscale16FromARGB32PM(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index; + for (int i = 0; i < count; ++i) + d[i] = qGray(qUnpremultiply(src[i])) * 257; +} + static const uint *QT_FASTCALL fetchRGB64ToRGB32(uint *buffer, const uchar *src, int index, int count, const QVector<QRgb> *, QDitherInfo *) { @@ -1487,7 +1524,11 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = { { true, true, QPixelLayout::BPP64, nullptr, convertPassThrough, nullptr, fetchRGB64ToRGB32, fetchPassThrough64, - storeRGB64FromRGB32, storeRGB64FromRGB32 } // Format_RGBA64_Premultiplied + storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied + { false, false, QPixelLayout::BPP16, nullptr, + convertGrayscale16ToRGB32, convertGrayscale16ToRGBA64, + fetchGrayscale16ToRGB32, fetchGrayscale16ToRGBA64, + storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 } // Format_Grayscale16 }; Q_STATIC_ASSERT(sizeof(qPixelLayouts) / sizeof(*qPixelLayouts) == QImage::NImageFormats); @@ -1563,6 +1604,16 @@ static void QT_FASTCALL storeRGBA64PMFromRGBA64PM(uchar *dest, const QRgba64 *sr memcpy(d, src, count * sizeof(QRgba64)); } +static void QT_FASTCALL storeGray16FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + quint16 *d = reinterpret_cast<quint16*>(dest) + index; + for (int i = 0; i < count; ++i) { + QRgba64 s = src[i].unpremultiplied(); + d[i] = qGray(s.red(), s.green(), s.blue()); + } +} + ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats] = { nullptr, nullptr, @@ -1591,7 +1642,8 @@ ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats] = { storeGenericFromRGBA64PM<QImage::Format_Grayscale8>, storeRGBX64FromRGBA64PM, storeRGBA64FromRGBA64PM, - storeRGBA64PMFromRGBA64PM + storeRGBA64PMFromRGBA64PM, + storeGray16FromRGBA64PM }; /* @@ -1649,22 +1701,6 @@ static uint *QT_FASTCALL destFetchUndefined(uint *buffer, QRasterBuffer *, int, return buffer; } -static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) -{ - const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; - return const_cast<QRgba64 *>(layout->fetchToRGBA64PM(buffer, rasterBuffer->scanLine(y), x, length, nullptr, nullptr)); -} - -static QRgba64 * QT_FASTCALL destFetchRGB64(QRgba64 *, QRasterBuffer *rasterBuffer, int x, int y, int) -{ - return (QRgba64 *)rasterBuffer->scanLine(y) + x; -} - -static QRgba64 * QT_FASTCALL destFetch64Undefined(QRgba64 *buffer, QRasterBuffer *, int, int, int) -{ - return buffer; -} - static DestFetchProc destFetchProc[QImage::NImageFormats] = { 0, // Format_Invalid @@ -1695,8 +1731,26 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] = destFetch, // Format_RGBX64 destFetch, // Format_RGBA64 destFetch, // Format_RGBA64_Premultiplied + destFetch, // Format_Grayscale16 }; +#if QT_CONFIG(raster_64bit) +static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) +{ + const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; + return const_cast<QRgba64 *>(layout->fetchToRGBA64PM(buffer, rasterBuffer->scanLine(y), x, length, nullptr, nullptr)); +} + +static QRgba64 * QT_FASTCALL destFetchRGB64(QRgba64 *, QRasterBuffer *rasterBuffer, int x, int y, int) +{ + return (QRgba64 *)rasterBuffer->scanLine(y) + x; +} + +static QRgba64 * QT_FASTCALL destFetch64Undefined(QRgba64 *buffer, QRasterBuffer *, int, int, int) +{ + return buffer; +} + static DestFetchProc64 destFetchProc64[QImage::NImageFormats] = { 0, // Format_Invalid @@ -1727,7 +1781,9 @@ static DestFetchProc64 destFetchProc64[QImage::NImageFormats] = destFetchRGB64, // Format_RGBX64 destFetch64, // Format_RGBA64 destFetchRGB64, // Format_RGBA64_Premultiplied + destFetch64, // Format_Grayscale16 }; +#endif /* Returns the color in the mono destination color table @@ -1835,21 +1891,6 @@ static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, con store(dest, buffer, x, length, nullptr, nullptr); } -static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) -{ - auto store = qStoreFromRGBA64PM[rasterBuffer->format]; - uchar *dest = rasterBuffer->scanLine(y); - store(dest, buffer, x, length, nullptr, nullptr); -} - -static void QT_FASTCALL destStore64RGBA64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) -{ - QRgba64 *dest = reinterpret_cast<QRgba64*>(rasterBuffer->scanLine(y)) + x; - for (int i = 0; i < length; ++i) { - dest[i] = buffer[i].unpremultiplied(); - } -} - static DestStoreProc destStoreProc[QImage::NImageFormats] = { 0, // Format_Invalid @@ -1880,8 +1921,25 @@ static DestStoreProc destStoreProc[QImage::NImageFormats] = destStore, // Format_RGBX64 destStore, // Format_RGBA64 destStore, // Format_RGBA64_Premultiplied + destStore, // Format_Grayscale16 }; +#if QT_CONFIG(raster_64bit) +static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) +{ + auto store = qStoreFromRGBA64PM[rasterBuffer->format]; + uchar *dest = rasterBuffer->scanLine(y); + store(dest, buffer, x, length, nullptr, nullptr); +} + +static void QT_FASTCALL destStore64RGBA64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) +{ + QRgba64 *dest = reinterpret_cast<QRgba64*>(rasterBuffer->scanLine(y)) + x; + for (int i = 0; i < length; ++i) { + dest[i] = buffer[i].unpremultiplied(); + } +} + static DestStoreProc64 destStoreProc64[QImage::NImageFormats] = { 0, // Format_Invalid @@ -1911,8 +1969,10 @@ static DestStoreProc64 destStoreProc64[QImage::NImageFormats] = destStore64, // Format_Grayscale8 0, // Format_RGBX64 destStore64RGBA64, // Format_RGBA64 - 0 // Format_RGBA64_Premultiplied + 0, // Format_RGBA64_Premultiplied + destStore64, // Format_Grayscale16 }; +#endif /* Source fetches @@ -1963,6 +2023,7 @@ static const uint *QT_FASTCALL fetchUntransformedRGB16(uint *buffer, const Opera return buffer; } +#if QT_CONFIG(raster_64bit) static const QRgba64 *QT_FASTCALL fetchUntransformed64(QRgba64 *buffer, const Operator *, const QSpanData *data, int y, int x, int length) { @@ -1976,6 +2037,7 @@ static const QRgba64 *QT_FASTCALL fetchUntransformedRGBA64PM(QRgba64 *, const Op const uchar *scanLine = data->texture.scanLine(y); return reinterpret_cast<const QRgba64 *>(scanLine) + x; } +#endif template<TextureBlendType blendType> inline void fetchTransformed_pixelBounds(int max, int l1, int l2, int &v) @@ -2166,6 +2228,7 @@ static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, return buffer; } +#if QT_CONFIG(raster_64bit) template<TextureBlendType blendType> /* either BlendTransformed or BlendTransformedTiled */ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Operator *, const QSpanData *data, int y, int x, int length) @@ -2186,6 +2249,7 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper convertRGBA64ToRGBA64PM(buffer, length); return buffer; } +#endif /** \internal interpolate 4 argb pixels with the distx and disty factor. @@ -3487,6 +3551,7 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper return buffer; } +#if QT_CONFIG(raster_64bit) template<TextureBlendType blendType> static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buffer, const QSpanData *data, int y, int x, int length) @@ -3500,8 +3565,8 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf uint sbuf1[BufferSize]; uint sbuf2[BufferSize]; - QRgba64 buf1[BufferSize]; - QRgba64 buf2[BufferSize]; + alignas(8) QRgba64 buf1[BufferSize]; + alignas(8) QRgba64 buf2[BufferSize]; QRgba64 *end = buffer + length; QRgba64 *b = buffer; @@ -3658,8 +3723,8 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint64(QRgba64 *buf const qreal cx = x + qreal(0.5); const qreal cy = y + qreal(0.5); - QRgba64 buf1[BufferSize]; - QRgba64 buf2[BufferSize]; + alignas(8) QRgba64 buf1[BufferSize]; + alignas(8) QRgba64 buf2[BufferSize]; QRgba64 *end = buffer + length; QRgba64 *b = buffer; @@ -3807,6 +3872,7 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co return fetchTransformedBilinear64_uint64<blendType>(buffer, data, y, x, length); return fetchTransformedBilinear64_uint32<blendType>(buffer, data, y, x, length); } +#endif // FetchUntransformed can have more specialized methods added depending on SIMD features. static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = { @@ -3838,6 +3904,7 @@ static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = { fetchUntransformed, // RGBX64 fetchUntransformed, // RGBA64 fetchUntransformed, // RGBA64_Premultiplied + fetchUntransformed, // Grayscale16 }; static const SourceFetchProc sourceFetchGeneric[NBlendTypes] = { @@ -3876,6 +3943,20 @@ static SourceFetchProc sourceFetchAny32[NBlendTypes] = { fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPP32> // TransformedBilinearTiled }; +static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage::Format format) +{ + if (format == QImage::Format_RGB32 || format == QImage::Format_ARGB32_Premultiplied) + 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]; +} + +#if QT_CONFIG(raster_64bit) static const SourceFetchProc64 sourceFetchGeneric64[NBlendTypes] = { fetchUntransformed64, // Untransformed fetchUntransformed64, // Tiled @@ -3894,25 +3975,13 @@ static const SourceFetchProc64 sourceFetchRGBA64PM[NBlendTypes] = { fetchTransformedBilinear64<BlendTransformedBilinearTiled> // BilinearTiled }; -static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage::Format format) -{ - if (format == QImage::Format_RGB32 || format == QImage::Format_ARGB32_Premultiplied) - 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]; -} - static inline SourceFetchProc64 getSourceFetch64(TextureBlendType blendType, QImage::Format format) { if (format == QImage::Format_RGBX64 || format == QImage::Format_RGBA64_Premultiplied) return sourceFetchRGBA64PM[blendType]; return sourceFetchGeneric64[blendType]; } +#endif #define FIXPT_BITS 8 @@ -3924,11 +3993,13 @@ static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos) return data->colorTable32[qt_gradient_clamp(data, ipos)]; } +#if QT_CONFIG(raster_64bit) static const QRgba64& qt_gradient_pixel64_fixed(const QGradientData *data, int fixed_pos) { int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS; return data->colorTable64[qt_gradient_clamp(data, ipos)]; } +#endif static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data) { @@ -3962,6 +4033,7 @@ public: } }; +#if QT_CONFIG(raster_64bit) class GradientBase64 { public: @@ -3980,6 +4052,7 @@ public: qt_memfill64((quint64*)buffer, fill, length); } }; +#endif template<class GradientBase, typename BlendType> static inline const BlendType * QT_FASTCALL qt_fetch_linear_gradient_template( @@ -4057,11 +4130,13 @@ static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Ope return qt_fetch_linear_gradient_template<GradientBase32, uint>(buffer, op, data, y, x, length); } +#if QT_CONFIG(raster_64bit) static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { return qt_fetch_linear_gradient_template<GradientBase64, QRgba64>(buffer, op, data, y, x, length); } +#endif static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data) { @@ -4123,11 +4198,13 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Oper static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain; +#if QT_CONFIG(raster_64bit) const QRgba64 * QT_FASTCALL qt_fetch_radial_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { return qt_fetch_radial_gradient_template<RadialFetchPlain<GradientBase64>, QRgba64>(buffer, op, data, y, x, length); } +#endif template <class GradientBase, typename BlendType> static inline const BlendType * QT_FASTCALL qt_fetch_conical_gradient_template( @@ -4186,23 +4263,29 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op return qt_fetch_conical_gradient_template<GradientBase32, uint>(buffer, data, y, x, length); } +#if QT_CONFIG(raster_64bit) static const QRgba64 * QT_FASTCALL qt_fetch_conical_gradient_rgb64(QRgba64 *buffer, const Operator *, const QSpanData *data, int y, int x, int length) { return qt_fetch_conical_gradient_template<GradientBase64, QRgba64>(buffer, data, y, x, length); } +#endif extern CompositionFunctionSolid qt_functionForModeSolid_C[]; extern CompositionFunctionSolid64 qt_functionForModeSolid64_C[]; static const CompositionFunctionSolid *functionForModeSolid = qt_functionForModeSolid_C; +#if QT_CONFIG(raster_64bit) static const CompositionFunctionSolid64 *functionForModeSolid64 = qt_functionForModeSolid64_C; +#endif extern CompositionFunction qt_functionForMode_C[]; extern CompositionFunction64 qt_functionForMode64_C[]; static const CompositionFunction *functionForMode = qt_functionForMode_C; +#if QT_CONFIG(raster_64bit) static const CompositionFunction64 *functionForMode64 = qt_functionForMode64_C; +#endif static TextureBlendType getBlendType(const QSpanData *data) { @@ -4232,43 +4315,60 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in switch(data->type) { case QSpanData::Solid: - solidSource = data->solid.color.isOpaque(); + solidSource = data->solidColor.isOpaque(); op.srcFetch = 0; +#if QT_CONFIG(raster_64bit) op.srcFetch64 = 0; +#endif break; case QSpanData::LinearGradient: solidSource = !data->gradient.alphaColor; getLinearGradientValues(&op.linear, data); op.srcFetch = qt_fetch_linear_gradient; +#if QT_CONFIG(raster_64bit) op.srcFetch64 = qt_fetch_linear_gradient_rgb64; +#endif break; case QSpanData::RadialGradient: solidSource = !data->gradient.alphaColor; getRadialGradientValues(&op.radial, data); op.srcFetch = qt_fetch_radial_gradient; +#if QT_CONFIG(raster_64bit) op.srcFetch64 = qt_fetch_radial_gradient_rgb64; +#endif break; case QSpanData::ConicalGradient: solidSource = !data->gradient.alphaColor; op.srcFetch = qt_fetch_conical_gradient; +#if QT_CONFIG(raster_64bit) op.srcFetch64 = qt_fetch_conical_gradient_rgb64; +#endif break; case QSpanData::Texture: solidSource = !data->texture.hasAlpha; op.srcFetch = getSourceFetch(getBlendType(data), data->texture.format); +#if QT_CONFIG(raster_64bit) op.srcFetch64 = getSourceFetch64(getBlendType(data), data->texture.format);; +#endif break; default: Q_UNREACHABLE(); break; } +#if !QT_CONFIG(raster_64bit) + op.srcFetch64 = 0; +#endif op.mode = data->rasterBuffer->compositionMode; if (op.mode == QPainter::CompositionMode_SourceOver && solidSource) op.mode = QPainter::CompositionMode_Source; op.destFetch = destFetchProc[data->rasterBuffer->format]; +#if QT_CONFIG(raster_64bit) op.destFetch64 = destFetchProc64[data->rasterBuffer->format]; +#else + op.destFetch64 = 0; +#endif if (op.mode == QPainter::CompositionMode_Source && (data->type != QSpanData::Texture || data->texture.const_alpha == 256)) { const QSpan *lastSpan = spans + spanCount; @@ -4280,44 +4380,90 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in } ++spans; } - if (!alphaSpans) { + if (!alphaSpans && spanCount > 0) { // If all spans are opaque we do not need to fetch dest. // But don't clear passthrough destFetch as they are just as fast and save destStore. if (op.destFetch != destFetchARGB32P) op.destFetch = destFetchUndefined; +#if QT_CONFIG(raster_64bit) if (op.destFetch64 != destFetchRGB64) op.destFetch64 = destFetch64Undefined; +#endif } } op.destStore = destStoreProc[data->rasterBuffer->format]; - op.destStore64 = destStoreProc64[data->rasterBuffer->format]; - op.funcSolid = functionForModeSolid[op.mode]; - op.funcSolid64 = functionForModeSolid64[op.mode]; op.func = functionForMode[op.mode]; +#if QT_CONFIG(raster_64bit) + op.destStore64 = destStoreProc64[data->rasterBuffer->format]; + op.funcSolid64 = functionForModeSolid64[op.mode]; op.func64 = functionForMode64[op.mode]; +#else + op.destStore64 = 0; + op.funcSolid64 = 0; + op.func64 = 0; +#endif return op; } +static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP bpp, int x, int y, int length) +{ + switch (bpp) { + case QPixelLayout::BPP64: { + quint64 *dest = reinterpret_cast<quint64 *>(rasterBuffer->scanLine(y)) + x; + qt_memfill_template(dest + 1, dest[0], length - 1); + break; + } + case QPixelLayout::BPP32: { + quint32 *dest = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(y)) + x; + qt_memfill_template(dest + 1, dest[0], length - 1); + break; + } + case QPixelLayout::BPP24: { + quint24 *dest = reinterpret_cast<quint24 *>(rasterBuffer->scanLine(y)) + x; + qt_memfill_template(dest + 1, dest[0], length - 1); + break; + } + case QPixelLayout::BPP16: { + quint16 *dest = reinterpret_cast<quint16 *>(rasterBuffer->scanLine(y)) + x; + qt_memfill_template(dest + 1, dest[0], length - 1); + break; + } + case QPixelLayout::BPP8: { + uchar *dest = rasterBuffer->scanLine(y) + x; + memset(dest + 1, dest[0], length - 1); + break; + } + default: + Q_UNREACHABLE(); + } +} // -------------------- blend methods --------------------- -#if !defined(Q_CC_SUN) -static -#endif -void blend_color_generic(int count, const QSpan *spans, void *userData) +static void blend_color_generic(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); uint buffer[BufferSize]; - Operator op = getOperator(data, spans, count); - const uint color = data->solid.color.toArgb32(); + Operator op = getOperator(data, nullptr, 0); + const uint color = data->solidColor.toArgb32(); + bool solidFill = data->rasterBuffer->compositionMode == QPainter::CompositionMode_Source + || (data->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver && qAlpha(color) == 255); + QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp; while (count--) { int x = spans->x; int length = spans->len; + if (solidFill && bpp >= QPixelLayout::BPP8 && spans->coverage == 255 && length) { + // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels + op.destStore(data->rasterBuffer, x, spans->y, &color, 1); + spanfill_from_first(data->rasterBuffer, bpp, x, spans->y, length); + length = 0; + } + while (length) { int l = qMin(BufferSize, length); uint *dest = op.destFetch(buffer, data->rasterBuffer, x, spans->y, l); @@ -4335,15 +4481,15 @@ static void blend_color_argb(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); - const Operator op = getOperator(data, spans, count); - const uint color = data->solid.color.toArgb32(); + const Operator op = getOperator(data, nullptr, 0); + const uint color = data->solidColor.toArgb32(); if (op.mode == QPainter::CompositionMode_Source) { // inline for performance while (count--) { uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x; if (spans->coverage == 255) { - QT_MEMFILL_UINT(target, spans->len, color); + qt_memfill(target, color, spans->len); } else { uint c = BYTE_MUL(color, spans->coverage); int ialpha = 255 - spans->coverage; @@ -4364,35 +4510,33 @@ static void blend_color_argb(int count, const QSpan *spans, void *userData) void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData) { +#if QT_CONFIG(raster_64bit) QSpanData *data = reinterpret_cast<QSpanData *>(userData); - Operator op = getOperator(data, spans, count); + Operator op = getOperator(data, nullptr, 0); if (!op.funcSolid64) { qCDebug(lcQtGuiDrawHelper, "blend_color_generic_rgb64: unsupported 64bit blend attempted, falling back to 32-bit"); return blend_color_generic(count, spans, userData); } - quint64 buffer[BufferSize]; - const QRgba64 color = data->solid.color; + alignas(8) QRgba64 buffer[BufferSize]; + const QRgba64 color = data->solidColor; 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; + QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp; while (count--) { int x = spans->x; int length = spans->len; - if (solidFill && isBpp32 && spans->coverage == 255) { + if (solidFill && bpp >= QPixelLayout::BPP8 && spans->coverage == 255 && length) { // 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; - } + op.destStore64(data->rasterBuffer, x, spans->y, &color, 1); + spanfill_from_first(data->rasterBuffer, bpp, x, spans->y, length); + length = 0; } while (length) { int l = qMin(BufferSize, length); - QRgba64 *dest = op.destFetch64((QRgba64 *)buffer, data->rasterBuffer, x, spans->y, l); + QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l); op.funcSolid64(dest, l, color, spans->coverage); if (op.destStore64) op.destStore64(data->rasterBuffer, x, spans->y, dest, l); @@ -4401,6 +4545,9 @@ void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData) } ++spans; } +#else + blend_color_generic(count, spans, userData); +#endif } static void blend_color_rgb16(int count, const QSpan *spans, void *userData) @@ -4413,16 +4560,16 @@ static void blend_color_rgb16(int count, const QSpan *spans, void *userData) from qt_gradient_quint16 with minimal overhead. */ QPainter::CompositionMode mode = data->rasterBuffer->compositionMode; - if (mode == QPainter::CompositionMode_SourceOver && data->solid.color.isOpaque()) + if (mode == QPainter::CompositionMode_SourceOver && data->solidColor.isOpaque()) mode = QPainter::CompositionMode_Source; if (mode == QPainter::CompositionMode_Source) { // inline for performance - ushort c = data->solid.color.toRgb16(); + ushort c = data->solidColor.toRgb16(); while (count--) { ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x; if (spans->coverage == 255) { - QT_MEMFILL_USHORT(target, spans->len, c); + qt_memfill(target, c, spans->len); } else { ushort color = BYTE_MUL_RGB16(c, spans->coverage); int ialpha = 255 - spans->coverage; @@ -4439,7 +4586,7 @@ static void blend_color_rgb16(int count, const QSpan *spans, void *userData) if (mode == QPainter::CompositionMode_SourceOver) { while (count--) { - uint color = BYTE_MUL(data->solid.color.toArgb32(), spans->coverage); + uint color = BYTE_MUL(data->solidColor.toArgb32(), spans->coverage); int ialpha = qAlpha(~color); ushort c = qConvertRgb32To16(color); ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x; @@ -4544,8 +4691,8 @@ struct QBlendBase BlendType *dest; - BlendType buffer[BufferSize]; - BlendType src_buffer[BufferSize]; + alignas(8) BlendType buffer[BufferSize]; + alignas(8) BlendType src_buffer[BufferSize]; }; class BlendSrcGeneric : public QBlendBase<uint> @@ -4574,11 +4721,12 @@ public: } }; -class BlendSrcGenericRGB64 : public QBlendBase<quint64> +#if QT_CONFIG(raster_64bit) +class BlendSrcGenericRGB64 : public QBlendBase<QRgba64> { public: BlendSrcGenericRGB64(QSpanData *d, const Operator &o) - : QBlendBase<quint64>(d, o) + : QBlendBase<QRgba64>(d, o) { } @@ -4587,23 +4735,24 @@ public: return op.func64 && op.destFetch64; } - const quint64 *fetch(int x, int y, int len) + const QRgba64 *fetch(int x, int y, int len) { - dest = (quint64 *)op.destFetch64((QRgba64 *)buffer, data->rasterBuffer, x, y, len); - return (const quint64 *)op.srcFetch64((QRgba64 *)src_buffer, &op, data, y, x, len); + dest = op.destFetch64(buffer, data->rasterBuffer, x, y, len); + return op.srcFetch64(src_buffer, &op, data, y, x, len); } - void process(int, int, int len, int coverage, const quint64 *src, int offset) + void process(int, int, int len, int coverage, const QRgba64 *src, int offset) { - op.func64((QRgba64 *)dest + offset, (const QRgba64 *)src + offset, len, coverage); + op.func64(dest + offset, src + offset, len, coverage); } void store(int x, int y, int len) { if (op.destStore64) - op.destStore64(data->rasterBuffer, x, y, (QRgba64 *)dest, len); + op.destStore64(data->rasterBuffer, x, y, dest, len); } }; +#endif static void blend_src_generic(int count, const QSpan *spans, void *userData) { @@ -4612,6 +4761,7 @@ static void blend_src_generic(int count, const QSpan *spans, void *userData) handleSpans(count, spans, data, blend); } +#if QT_CONFIG(raster_64bit) static void blend_src_generic_rgb64(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); @@ -4625,6 +4775,7 @@ static void blend_src_generic_rgb64(int count, const QSpan *spans, void *userDat handleSpans(count, spans, data, blend32); } } +#endif static void blend_untransformed_generic(int count, const QSpan *spans, void *userData) { @@ -4671,6 +4822,7 @@ static void blend_untransformed_generic(int count, const QSpan *spans, void *use } } +#if QT_CONFIG(raster_64bit) static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); @@ -4680,8 +4832,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[BufferSize]; - quint64 src_buffer[BufferSize]; + alignas(8) QRgba64 buffer[BufferSize]; + alignas(8) QRgba64 src_buffer[BufferSize]; const int image_width = data->texture.width; const int image_height = data->texture.height; @@ -4705,8 +4857,8 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (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); + const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l); + QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l); op.func64(dest, src, l, coverage); if (op.destStore64) op.destStore64(data->rasterBuffer, x, spans->y, dest, l); @@ -4719,6 +4871,7 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi ++spans; } } +#endif static void blend_untransformed_argb(int count, const QSpan *spans, void *userData) { @@ -4913,6 +5066,7 @@ static void blend_tiled_generic(int count, const QSpan *spans, void *userData) } } +#if QT_CONFIG(raster_64bit) static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); @@ -4922,8 +5076,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[BufferSize]; - quint64 src_buffer[BufferSize]; + alignas(8) QRgba64 buffer[BufferSize]; + alignas(8) QRgba64 src_buffer[BufferSize]; const int image_width = data->texture.width; const int image_height = data->texture.height; @@ -4952,7 +5106,7 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD 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); + const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l); op.destStore64(data->rasterBuffer, x, y, src, l); x += l; sx += l; @@ -4962,7 +5116,7 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD } if (sl > 0) { Q_ASSERT(sx == 0); - const QRgba64 *src = op.srcFetch64((QRgba64 *)src_buffer, &op, data, sy, sx, sl); + const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, sl); op.destStore64(data->rasterBuffer, x, y, src, sl); x += sl; sx += sl; @@ -4994,8 +5148,8 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD int l = qMin(image_width - sx, length); 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); + const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l); + QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l); op.func64(dest, src, l, coverage); if (op.destStore64) op.destStore64(data->rasterBuffer, x, spans->y, dest, l); @@ -5008,6 +5162,7 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD ++spans; } } +#endif static void blend_tiled_argb(int count, const QSpan *spans, void *userData) { @@ -5184,6 +5339,7 @@ static const ProcessSpans processTextureSpansGeneric[NBlendTypes] = { blend_src_generic // TransformedBilinearTiled }; +#if QT_CONFIG(raster_64bit) static const ProcessSpans processTextureSpansGeneric64[NBlendTypes] = { blend_untransformed_generic_rgb64, // Untransformed blend_tiled_generic_rgb64, // Tiled @@ -5192,6 +5348,7 @@ static const ProcessSpans processTextureSpansGeneric64[NBlendTypes] = { blend_src_generic_rgb64, // TransformedBilinear blend_src_generic_rgb64 // TransformedBilinearTiled }; +#endif void qBlendTexture(int count, const QSpan *spans, void *userData) { @@ -5205,6 +5362,7 @@ void qBlendTexture(int count, const QSpan *spans, void *userData) case QImage::Format_RGB16: proc = processTextureSpansRGB16[blendType]; break; +#if QT_CONFIG(raster_64bit) #if defined(__SSE2__) || defined(__ARM_NEON__) || (Q_PROCESSOR_WORDSIZE == 8) case QImage::Format_ARGB32: case QImage::Format_RGBA8888: @@ -5216,8 +5374,10 @@ void qBlendTexture(int count, const QSpan *spans, void *userData) case QImage::Format_RGBX64: case QImage::Format_RGBA64: case QImage::Format_RGBA64_Premultiplied: + case QImage::Format_Grayscale16: proc = processTextureSpansGeneric64[blendType]; break; +#endif // QT_CONFIG(raster_64bit) case QImage::Format_Invalid: Q_UNREACHABLE(); return; @@ -5228,7 +5388,117 @@ void qBlendTexture(int count, const QSpan *spans, void *userData) proc(count, spans, userData); } -template <class DST> Q_STATIC_TEMPLATE_FUNCTION +static void blend_vertical_gradient_argb(int count, const QSpan *spans, void *userData) +{ + QSpanData *data = reinterpret_cast<QSpanData *>(userData); + + LinearGradientValues linear; + getLinearGradientValues(&linear, data); + + CompositionFunctionSolid funcSolid = + functionForModeSolid[data->rasterBuffer->compositionMode]; + + /* + The logic for vertical gradient calculations is a mathematically + reduced copy of that in fetchLinearGradient() - which is basically: + + qreal ry = data->m22 * (y + 0.5) + data->dy; + qreal t = linear.dy*ry + linear.off; + t *= (GRADIENT_STOPTABLE_SIZE - 1); + quint32 color = + qt_gradient_pixel_fixed(&data->gradient, + int(t * FIXPT_SIZE)); + + This has then been converted to fixed point to improve performance. + */ + const int gss = GRADIENT_STOPTABLE_SIZE - 1; + int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE); + int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE)); + + while (count--) { + int y = spans->y; + int x = spans->x; + + quint32 *dst = (quint32 *)(data->rasterBuffer->scanLine(y)) + x; + quint32 color = + qt_gradient_pixel_fixed(&data->gradient, yinc * y + off); + + funcSolid(dst, spans->len, color, spans->coverage); + ++spans; + } +} + +template<ProcessSpans blend_color> +static void blend_vertical_gradient(int count, const QSpan *spans, void *userData) +{ + QSpanData *data = reinterpret_cast<QSpanData *>(userData); + + LinearGradientValues linear; + getLinearGradientValues(&linear, data); + + // Based on the same logic as blend_vertical_gradient_argb. + + const int gss = GRADIENT_STOPTABLE_SIZE - 1; + int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE); + int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE)); + + while (count--) { + int y = spans->y; + +#if QT_CONFIG(raster_64bit) + data->solidColor = qt_gradient_pixel64_fixed(&data->gradient, yinc * y + off); +#else + data->solidColor = QRgba64::fromArgb32(qt_gradient_pixel_fixed(&data->gradient, yinc * y + off)); +#endif + blend_color(1, spans, userData); + ++spans; + } +} + +void qBlendGradient(int count, const QSpan *spans, void *userData) +{ + QSpanData *data = reinterpret_cast<QSpanData *>(userData); + bool isVerticalGradient = + data->txop <= QTransform::TxScale && + data->type == QSpanData::LinearGradient && + data->gradient.linear.end.x == data->gradient.linear.origin.x; + switch (data->rasterBuffer->format) { + case QImage::Format_RGB16: + if (isVerticalGradient) + return blend_vertical_gradient<blend_color_rgb16>(count, spans, userData); + return blend_src_generic(count, spans, userData); + case QImage::Format_RGB32: + case QImage::Format_ARGB32_Premultiplied: + if (isVerticalGradient) + return blend_vertical_gradient_argb(count, spans, userData); + return blend_src_generic(count, spans, userData); +#if QT_CONFIG(raster_64bit) +#if defined(__SSE2__) || defined(__ARM_NEON__) || (Q_PROCESSOR_WORDSIZE == 8) + case QImage::Format_ARGB32: + case QImage::Format_RGBA8888: +#endif + case QImage::Format_BGR30: + case QImage::Format_A2BGR30_Premultiplied: + case QImage::Format_RGB30: + case QImage::Format_A2RGB30_Premultiplied: + case QImage::Format_RGBX64: + case QImage::Format_RGBA64: + case QImage::Format_RGBA64_Premultiplied: + if (isVerticalGradient) + return blend_vertical_gradient<blend_color_generic_rgb64>(count, spans, userData); + return blend_src_generic_rgb64(count, spans, userData); +#endif // QT_CONFIG(raster_64bit) + case QImage::Format_Invalid: + break; + default: + if (isVerticalGradient) + return blend_vertical_gradient<blend_color_generic>(count, spans, userData); + return blend_src_generic(count, spans, userData); + } + Q_UNREACHABLE(); +} + +template <class DST> static inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer, int x, int y, DST color, const uchar *map, @@ -5290,103 +5560,6 @@ inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer, } } -static void qt_gradient_argb32(int count, const QSpan *spans, void *userData) -{ - QSpanData *data = reinterpret_cast<QSpanData *>(userData); - - bool isVerticalGradient = - data->txop <= QTransform::TxScale && - data->type == QSpanData::LinearGradient && - data->gradient.linear.end.x == data->gradient.linear.origin.x; - - if (isVerticalGradient) { - LinearGradientValues linear; - getLinearGradientValues(&linear, data); - - CompositionFunctionSolid funcSolid = - functionForModeSolid[data->rasterBuffer->compositionMode]; - - /* - The logic for vertical gradient calculations is a mathematically - reduced copy of that in fetchLinearGradient() - which is basically: - - qreal ry = data->m22 * (y + 0.5) + data->dy; - qreal t = linear.dy*ry + linear.off; - t *= (GRADIENT_STOPTABLE_SIZE - 1); - quint32 color = - qt_gradient_pixel_fixed(&data->gradient, - int(t * FIXPT_SIZE)); - - This has then been converted to fixed point to improve performance. - */ - const int gss = GRADIENT_STOPTABLE_SIZE - 1; - int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE); - int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE)); - - while (count--) { - int y = spans->y; - int x = spans->x; - - quint32 *dst = (quint32 *)(data->rasterBuffer->scanLine(y)) + x; - quint32 color = - qt_gradient_pixel_fixed(&data->gradient, yinc * y + off); - - funcSolid(dst, spans->len, color, spans->coverage); - ++spans; - } - - } else { - blend_src_generic(count, spans, userData); - } -} - -static void qt_gradient_quint16(int count, const QSpan *spans, void *userData) -{ - QSpanData *data = reinterpret_cast<QSpanData *>(userData); - - bool isVerticalGradient = - data->txop <= QTransform::TxScale && - data->type == QSpanData::LinearGradient && - data->gradient.linear.end.x == data->gradient.linear.origin.x; - - if (isVerticalGradient) { - - LinearGradientValues linear; - getLinearGradientValues(&linear, data); - - /* - The logic for vertical gradient calculations is a mathematically - reduced copy of that in fetchLinearGradient() - which is basically: - - qreal ry = data->m22 * (y + 0.5) + data->dy; - qreal t = linear.dy*ry + linear.off; - t *= (GRADIENT_STOPTABLE_SIZE - 1); - quint32 color = - qt_gradient_pixel_fixed(&data->gradient, - int(t * FIXPT_SIZE)); - - This has then been converted to fixed point to improve performance. - */ - const int gss = GRADIENT_STOPTABLE_SIZE - 1; - int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE); - int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE)); - - // Save the fillData since we overwrite it when setting solid.color. - QGradientData gradient = data->gradient; - while (count--) { - int y = spans->y; - - data->solid.color = QRgba64::fromArgb32(qt_gradient_pixel_fixed(&gradient, yinc * y + off)); - blend_color_rgb16(1, spans, userData); - ++spans; - } - data->gradient = gradient; - - } else { - blend_src_generic(count, spans, userData); - } -} - inline static void qt_bitmapblit_argb32(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 &color, const uchar *map, @@ -5424,7 +5597,36 @@ inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer, map, mapWidth, mapHeight, mapStride); } -static inline void alphamapblend_generic(int coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorProfile *colorProfile) +static inline void grayBlendPixel(quint32 *dst, int coverage, QRgba64 srcLinear, const QColorTrcLut *colorProfile) +{ + // Do a gammacorrected gray alphablend... + const QRgba64 dstLinear = colorProfile ? colorProfile->toLinear64(*dst) : QRgba64::fromArgb32(*dst); + + QRgba64 blend = interpolate255(srcLinear, coverage, dstLinear, 255 - coverage); + + *dst = colorProfile ? colorProfile->fromLinear64(blend) : toArgb32(blend); +} + +static inline void alphamapblend_argb32(quint32 *dst, int coverage, QRgba64 srcLinear, quint32 src, const QColorTrcLut *colorProfile) +{ + if (coverage == 0) { + // nothing + } else if (coverage == 255) { + *dst = src; + } else if (!colorProfile) { + *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage); + } else { + if (*dst >= 0xff000000) { + grayBlendPixel(dst, coverage, srcLinear, colorProfile); + } else { + // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571 + *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage); + } + } +} + +#if QT_CONFIG(raster_64bit) +static inline void alphamapblend_generic(int coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile) { if (coverage == 0) { // nothing @@ -5459,7 +5661,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, if (color.isTransparent()) return; - const QColorProfile *colorProfile = nullptr; + const QColorTrcLut *colorProfile = nullptr; if (useGammaCorrection) colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text(); @@ -5472,7 +5674,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); } - quint64 buffer[BufferSize]; + alignas(8) QRgba64 buffer[BufferSize]; const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format]; const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format]; @@ -5482,7 +5684,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, int length = mapWidth; while (length > 0) { int l = qMin(BufferSize, length); - QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, i, y + ly, l); + QRgba64 *dest = destFetch64(buffer, rasterBuffer, i, y + ly, l); for (int j=0; j < l; ++j) { const int coverage = map[j + (i - x)]; alphamapblend_generic(coverage, dest, j, srcColor, color, colorProfile); @@ -5512,7 +5714,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, if (end <= start) continue; Q_ASSERT(end - start <= BufferSize); - QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start); + QRgba64 *dest = destFetch64(buffer, rasterBuffer, start, clip.y, end - start); for (int xp=start; xp<end; ++xp) { const int coverage = map[xp - x]; @@ -5525,6 +5727,85 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, } // for (yp -> bottom) } } +#else +static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, + int x, int y, const QRgba64 &color, + const uchar *map, + int mapWidth, int mapHeight, int mapStride, + const QClipData *clip, bool useGammaCorrection) +{ + if (color.isTransparent()) + return; + + const quint32 c = color.toArgb32(); + + const QColorTrcLut *colorProfile = nullptr; + + if (useGammaCorrection) + colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text(); + + QRgba64 srcColor = color; + if (colorProfile) { + if (color.isOpaque()) + srcColor = colorProfile->toLinear(srcColor); + else + srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); + } + + quint32 buffer[BufferSize]; + const DestFetchProc destFetch = destFetchProc[rasterBuffer->format]; + const DestStoreProc destStore = destStoreProc[rasterBuffer->format]; + + if (!clip) { + for (int ly = 0; ly < mapHeight; ++ly) { + int i = x; + int length = mapWidth; + while (length > 0) { + int l = qMin(BufferSize, length); + quint32 *dest = destFetch(buffer, rasterBuffer, i, y + ly, l); + for (int j=0; j < l; ++j) { + const int coverage = map[j + (i - x)]; + alphamapblend_argb32(dest + j, coverage, srcColor, c, colorProfile); + } + if (destStore) + destStore(rasterBuffer, i, y + ly, dest, l); + length -= l; + i += l; + } + map += mapStride; + } + } else { + int bottom = qMin(y + mapHeight, rasterBuffer->height()); + + int top = qMax(y, 0); + map += (top - y) * mapStride; + + const_cast<QClipData *>(clip)->initialize(); + for (int yp = top; yp<bottom; ++yp) { + const QClipData::ClipLine &line = clip->m_clipLines[yp]; + + for (int i=0; i<line.count; ++i) { + const QSpan &clip = line.spans[i]; + + int start = qMax<int>(x, clip.x); + int end = qMin<int>(x + mapWidth, clip.x + clip.len); + if (end <= start) + continue; + Q_ASSERT(end - start <= BufferSize); + quint32 *dest = destFetch(buffer, rasterBuffer, start, clip.y, end - start); + + for (int xp=start; xp<end; ++xp) { + const int coverage = map[xp - x]; + alphamapblend_argb32(dest + xp - x, coverage, srcColor, color, colorProfile); + } + if (destStore) + destStore(rasterBuffer, start, clip.y, dest, end - start); + } // for (i -> line.count) + map += mapStride; + } // for (yp -> bottom) + } +} +#endif static inline void alphamapblend_quint16(int coverage, quint16 *dest, int x, const quint16 srcColor) { @@ -5585,44 +5866,6 @@ void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer, } } -static inline void rgbBlendPixel(quint32 *dst, int coverage, QRgba64 slinear, const QColorProfile *colorProfile) -{ - // Do a gammacorrected RGB alphablend... - const QRgba64 dlinear = colorProfile ? colorProfile->toLinear64(*dst) : QRgba64::fromArgb32(*dst); - - QRgba64 blend = rgbBlend(dlinear, slinear, coverage); - - *dst = colorProfile ? colorProfile->fromLinear64(blend) : toArgb32(blend); -} - -static inline void grayBlendPixel(quint32 *dst, int coverage, QRgba64 srcLinear, const QColorProfile *colorProfile) -{ - // Do a gammacorrected gray alphablend... - const QRgba64 dstLinear = colorProfile ? colorProfile->toLinear64(*dst) : QRgba64::fromArgb32(*dst); - - QRgba64 blend = interpolate255(srcLinear, coverage, dstLinear, 255 - coverage); - - *dst = colorProfile ? colorProfile->fromLinear64(blend) : toArgb32(blend); -} - -static inline void alphamapblend_argb32(quint32 *dst, int coverage, QRgba64 srcLinear, quint32 src, const QColorProfile *colorProfile) -{ - if (coverage == 0) { - // nothing - } else if (coverage == 255) { - *dst = src; - } else if (!colorProfile) { - *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage); - } else { - if (*dst >= 0xff000000) { - grayBlendPixel(dst, coverage, srcLinear, colorProfile); - } else { - // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571 - *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage); - } - } -} - static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 &color, const uchar *map, @@ -5635,7 +5878,7 @@ static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer, if (color.isTransparent()) return; - const QColorProfile *colorProfile = nullptr; + const QColorTrcLut *colorProfile = nullptr; if (useGammaCorrection) colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text(); @@ -5691,6 +5934,16 @@ static inline int qRgbAvg(QRgb rgb) return (qRed(rgb) * 5 + qGreen(rgb) * 6 + qBlue(rgb) * 5) / 16; } +static inline void rgbBlendPixel(quint32 *dst, int coverage, QRgba64 slinear, const QColorTrcLut *colorProfile) +{ + // Do a gammacorrected RGB alphablend... + const QRgba64 dlinear = colorProfile ? colorProfile->toLinear64(*dst) : QRgba64::fromArgb32(*dst); + + QRgba64 blend = rgbBlend(dlinear, slinear, coverage); + + *dst = colorProfile ? colorProfile->fromLinear64(blend) : toArgb32(blend); +} + static inline QRgb rgbBlend(QRgb d, QRgb s, uint rgbAlpha) { #if defined(__SSE2__) @@ -5731,7 +5984,8 @@ static inline QRgb rgbBlend(QRgb d, QRgb s, uint rgbAlpha) #endif } -static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorProfile *colorProfile) +#if QT_CONFIG(raster_64bit) +static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile) { if (coverage == 0xff000000) { // nothing @@ -5752,8 +6006,9 @@ static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, co } } } +#endif -static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorProfile *colorProfile) +static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorTrcLut *colorProfile) { if (coverage == 0xff000000) { // nothing @@ -5770,6 +6025,7 @@ static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba } } +#if QT_CONFIG(raster_64bit) static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 &color, const uint *src, int mapWidth, int mapHeight, int srcStride, @@ -5778,7 +6034,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, if (color.isTransparent()) return; - const QColorProfile *colorProfile = nullptr; + const QColorTrcLut *colorProfile = nullptr; if (useGammaCorrection) colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text(); @@ -5791,7 +6047,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); } - quint64 buffer[BufferSize]; + alignas(8) QRgba64 buffer[BufferSize]; const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format]; const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format]; @@ -5801,7 +6057,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, int length = mapWidth; while (length > 0) { int l = qMin(BufferSize, length); - QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, i, y + ly, l); + QRgba64 *dest = destFetch64(buffer, rasterBuffer, i, y + ly, l); for (int j=0; j < l; ++j) { const uint coverage = src[j + (i - x)]; alphargbblend_generic(coverage, dest, j, srcColor, color, colorProfile); @@ -5831,7 +6087,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, if (end <= start) continue; Q_ASSERT(end - start <= BufferSize); - QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start); + QRgba64 *dest = destFetch64(buffer, rasterBuffer, start, clip.y, end - start); for (int xp=start; xp<end; ++xp) { const uint coverage = src[xp - x]; @@ -5844,6 +6100,84 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, } // for (yp -> bottom) } } +#else +static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, + int x, int y, const QRgba64 &color, + const uint *src, int mapWidth, int mapHeight, int srcStride, + const QClipData *clip, bool useGammaCorrection) +{ + if (color.isTransparent()) + return; + + const quint32 c = color.toArgb32(); + + const QColorTrcLut *colorProfile = nullptr; + + if (useGammaCorrection) + colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text(); + + QRgba64 srcColor = color; + if (colorProfile) { + if (color.isOpaque()) + srcColor = colorProfile->toLinear(srcColor); + else + srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); + } + + quint32 buffer[BufferSize]; + const DestFetchProc destFetch = destFetchProc[rasterBuffer->format]; + const DestStoreProc destStore = destStoreProc[rasterBuffer->format]; + + if (!clip) { + for (int ly = 0; ly < mapHeight; ++ly) { + int i = x; + int length = mapWidth; + while (length > 0) { + int l = qMin(BufferSize, length); + quint32 *dest = destFetch(buffer, rasterBuffer, i, y + ly, l); + for (int j=0; j < l; ++j) { + const uint coverage = src[j + (i - x)]; + alphargbblend_argb32(dest + j, coverage, srcColor, c, colorProfile); + } + if (destStore) + destStore(rasterBuffer, i, y + ly, dest, l); + length -= l; + i += l; + } + src += srcStride; + } + } else { + int bottom = qMin(y + mapHeight, rasterBuffer->height()); + + int top = qMax(y, 0); + src += (top - y) * srcStride; + + const_cast<QClipData *>(clip)->initialize(); + for (int yp = top; yp<bottom; ++yp) { + const QClipData::ClipLine &line = clip->m_clipLines[yp]; + + for (int i=0; i<line.count; ++i) { + const QSpan &clip = line.spans[i]; + + int start = qMax<int>(x, clip.x); + int end = qMin<int>(x + mapWidth, clip.x + clip.len); + if (end <= start) + continue; + Q_ASSERT(end - start <= BufferSize); + quint32 *dest = destFetch(buffer, rasterBuffer, start, clip.y, end - start); + + for (int xp=start; xp<end; ++xp) { + const uint coverage = src[xp - x]; + alphargbblend_argb32(dest + xp - start, coverage, srcColor, c, colorProfile); + } + if (destStore) + destStore(rasterBuffer, start, clip.y, dest, end - start); + } // for (i -> line.count) + src += srcStride; + } // for (yp -> bottom) + } +} +#endif static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 &color, @@ -5855,7 +6189,7 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer, const quint32 c = color.toArgb32(); - const QColorProfile *colorProfile = nullptr; + const QColorTrcLut *colorProfile = nullptr; if (useGammaCorrection) colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text(); @@ -6007,29 +6341,25 @@ static void qt_rectfill_quint64(QRasterBuffer *rasterBuffer, DrawHelper qDrawHelper[QImage::NImageFormats] = { // Format_Invalid, - { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, // Format_Mono, { blend_color_generic, - blend_src_generic, 0, 0, 0, 0 }, // Format_MonoLSB, { blend_color_generic, - blend_src_generic, 0, 0, 0, 0 }, // Format_Indexed8, { blend_color_generic, - blend_src_generic, 0, 0, 0, 0 }, // Format_RGB32, { blend_color_argb, - qt_gradient_argb32, qt_bitmapblit_argb32, qt_alphamapblit_argb32, qt_alphargbblit_argb32, @@ -6038,7 +6368,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_ARGB32, { blend_color_generic, - blend_src_generic, qt_bitmapblit_argb32, qt_alphamapblit_argb32, qt_alphargbblit_argb32, @@ -6047,7 +6376,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_ARGB32_Premultiplied { blend_color_argb, - qt_gradient_argb32, qt_bitmapblit_argb32, qt_alphamapblit_argb32, qt_alphargbblit_argb32, @@ -6056,7 +6384,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_RGB16 { blend_color_rgb16, - qt_gradient_quint16, qt_bitmapblit_quint16, qt_alphamapblit_quint16, qt_alphargbblit_generic, @@ -6065,7 +6392,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_ARGB8565_Premultiplied { blend_color_generic, - blend_src_generic, 0, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6074,7 +6400,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_RGB666 { blend_color_generic, - blend_src_generic, 0, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6083,7 +6408,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_ARGB6666_Premultiplied { blend_color_generic, - blend_src_generic, 0, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6092,7 +6416,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_RGB555 { blend_color_generic, - blend_src_generic, 0, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6101,7 +6424,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_ARGB8555_Premultiplied { blend_color_generic, - blend_src_generic, 0, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6110,7 +6432,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_RGB888 { blend_color_generic, - blend_src_generic, 0, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6119,7 +6440,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_RGB444 { blend_color_generic, - blend_src_generic, 0, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6128,7 +6448,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_ARGB4444_Premultiplied { blend_color_generic, - blend_src_generic, 0, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6137,7 +6456,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_RGBX8888 { blend_color_generic, - blend_src_generic, qt_bitmapblit_rgba8888, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6146,7 +6464,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_RGBA8888 { blend_color_generic, - blend_src_generic, qt_bitmapblit_rgba8888, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6155,7 +6472,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_RGB8888_Premultiplied { blend_color_generic, - blend_src_generic, qt_bitmapblit_rgba8888, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6164,7 +6480,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_BGR30 { blend_color_generic_rgb64, - blend_src_generic_rgb64, qt_bitmapblit_rgb30<PixelOrderBGR>, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6173,7 +6488,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_A2BGR30_Premultiplied { blend_color_generic_rgb64, - blend_src_generic_rgb64, qt_bitmapblit_rgb30<PixelOrderBGR>, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6182,7 +6496,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_RGB30 { blend_color_generic_rgb64, - blend_src_generic_rgb64, qt_bitmapblit_rgb30<PixelOrderRGB>, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6191,7 +6504,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_A2RGB30_Premultiplied { blend_color_generic_rgb64, - blend_src_generic_rgb64, qt_bitmapblit_rgb30<PixelOrderRGB>, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6200,7 +6512,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_Alpha8 { blend_color_generic, - blend_src_generic, 0, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6209,7 +6520,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_Grayscale8 { blend_color_generic, - blend_src_generic, 0, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6218,7 +6528,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_RGBX64 { blend_color_generic_rgb64, - blend_src_generic_rgb64, 0, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6227,7 +6536,6 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_RGBA64 { blend_color_generic_rgb64, - blend_src_generic_rgb64, 0, qt_alphamapblit_generic, qt_alphargbblit_generic, @@ -6236,82 +6544,98 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = // Format_RGBA64_Premultiplied { blend_color_generic_rgb64, - blend_src_generic_rgb64, 0, qt_alphamapblit_generic, qt_alphargbblit_generic, qt_rectfill_quint64 }, + // Format_Grayscale16 + { + blend_color_generic_rgb64, + 0, + qt_alphamapblit_generic, + qt_alphargbblit_generic, + qt_rectfill_quint16 + }, }; -#if defined(Q_CC_MSVC) && !defined(_MIPS_) -template <class T> -inline void qt_memfill_template(T *dest, T color, int count) +#if !defined(__SSE2__) +void qt_memfill64(quint64 *dest, quint64 color, qsizetype count) { - while (count--) - *dest++ = color; + qt_memfill_template<quint64>(dest, color, count); } +#endif -#else - -template <class T> -inline void qt_memfill_template(T *dest, T color, int count) +#if defined(QT_COMPILER_SUPPORTS_SSSE3) && defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG) +__attribute__((optimize("no-tree-vectorize"))) +#endif +void qt_memfill24(quint24 *dest, quint24 color, qsizetype count) { - int n = (count + 7) / 8; - switch (count & 0x07) - { - case 0: do { *dest++ = color; Q_FALLTHROUGH(); - case 7: *dest++ = color; Q_FALLTHROUGH(); - case 6: *dest++ = color; Q_FALLTHROUGH(); - case 5: *dest++ = color; Q_FALLTHROUGH(); - case 4: *dest++ = color; Q_FALLTHROUGH(); - case 3: *dest++ = color; Q_FALLTHROUGH(); - case 2: *dest++ = color; Q_FALLTHROUGH(); - case 1: *dest++ = color; - } while (--n > 0); - } -} +# ifdef QT_COMPILER_SUPPORTS_SSSE3 + extern void qt_memfill24_ssse3(quint24 *, quint24, qsizetype); + if (qCpuHasFeature(SSSE3)) + return qt_memfill24_ssse3(dest, color, count); +# endif -template <> -inline void qt_memfill_template(quint16 *dest, quint16 value, int count) -{ - if (count < 3) { - switch (count) { - case 2: *dest++ = value; Q_FALLTHROUGH(); - case 1: *dest = value; - } + const quint32 v = color; + quint24 *end = dest + count; + + // prolog: align dest to 32bit + while ((quintptr(dest) & 0x3) && dest < end) { + *dest++ = v; + } + if (dest >= end) return; + + const uint val1 = qFromBigEndian((v << 8) | (v >> 16)); + const uint val2 = qFromBigEndian((v << 16) | (v >> 8)); + const uint val3 = qFromBigEndian((v << 24) | (v >> 0)); + + for ( ; dest <= (end - 4); dest += 4) { + quint32 *dst = reinterpret_cast<quint32 *>(dest); + dst[0] = val1; + dst[1] = val2; + dst[2] = val3; } - const int align = (quintptr)(dest) & 0x3; - switch (align) { - case 2: *dest++ = value; --count; + // less than 4px left + switch (end - dest) { + case 3: + *dest++ = v; + Q_FALLTHROUGH(); + case 2: + *dest++ = v; + Q_FALLTHROUGH(); + case 1: + *dest++ = v; + } +} + +void qt_memfill16(quint16 *dest, quint16 value, qsizetype count) +{ + const int align = quintptr(dest) & 0x3; + if (align) { + *dest++ = value; + --count; } - const quint32 value32 = (value << 16) | value; - qt_memfill(reinterpret_cast<quint32*>(dest), value32, count / 2); if (count & 0x1) dest[count - 1] = value; -} -#endif -void qt_memfill64(quint64 *dest, quint64 color, int count) -{ - qt_memfill_template<quint64>(dest, color, count); + const quint32 value32 = (value << 16) | value; + qt_memfill32(reinterpret_cast<quint32*>(dest), value32, count / 2); } -#if !defined(__SSE2__) -void qt_memfill16(quint16 *dest, quint16 color, int count) -{ - qt_memfill_template<quint16>(dest, color, count); -} -#endif #if !defined(__SSE2__) && !defined(__ARM_NEON__) && !defined(__MIPS_DSP__) -void qt_memfill32(quint32 *dest, quint32 color, int count) +void qt_memfill32(quint32 *dest, quint32 color, qsizetype count) { qt_memfill_template<quint32>(dest, color, count); } #endif +#ifdef __SSE2__ +decltype(qt_memfill32_sse2) *qt_memfill32 = nullptr; +decltype(qt_memfill64_sse2) *qt_memfill64 = nullptr; +#endif #ifdef QT_COMPILER_SUPPORTS_SSE4_1 template<QtPixelOrder> void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, const QVector<QRgb> *, QDitherInfo *); @@ -6325,6 +6649,10 @@ static void qInitDrawhelperFunctions() qInitBlendFunctions(); #ifdef __SSE2__ +# ifndef __AVX2__ + qt_memfill32 = qt_memfill32_sse2; + qt_memfill64 = qt_memfill64_sse2; +# endif qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2; qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2; qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2; @@ -6401,6 +6729,14 @@ static void qInitDrawhelperFunctions() const QVector<QRgb> *, QDitherInfo *); extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_sse4(uint *buffer, const uchar *src, int index, int count, const QVector<QRgb> *, QDitherInfo *); + extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_sse4(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *); + extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_sse4(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *); + extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_sse4(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *); + extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_sse4(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *); extern void QT_FASTCALL storeARGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, const QVector<QRgb> *, QDitherInfo *); extern void QT_FASTCALL storeRGBA8888FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, @@ -6413,10 +6749,18 @@ static void qInitDrawhelperFunctions() const QVector<QRgb> *, QDitherInfo *); extern void QT_FASTCALL destStore64ARGB32_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length); extern void QT_FASTCALL destStore64RGBA8888_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length); +# ifndef __AVX2__ qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_sse4; qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4; qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_sse4; qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_sse4; + qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_sse4; + qPixelLayouts[QImage::Format_ARGB32].convertToRGBA64PM = convertARGB32ToRGBA64PM_sse4; + qPixelLayouts[QImage::Format_RGBA8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_sse4; + qPixelLayouts[QImage::Format_RGBA8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_sse4; + qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_sse4; + qPixelLayouts[QImage::Format_RGBX8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_sse4; +# endif qPixelLayouts[QImage::Format_ARGB32].storeFromARGB32PM = storeARGB32FromARGB32PM_sse4; qPixelLayouts[QImage::Format_RGBA8888].storeFromARGB32PM = storeRGBA8888FromARGB32PM_sse4; qPixelLayouts[QImage::Format_RGBX8888].storeFromARGB32PM = storeRGBXFromARGB32PM_sse4; @@ -6424,13 +6768,17 @@ static void qInitDrawhelperFunctions() qPixelLayouts[QImage::Format_A2RGB30_Premultiplied].storeFromARGB32PM = storeA2RGB30PMFromARGB32PM_sse4<PixelOrderRGB>; qStoreFromRGBA64PM[QImage::Format_ARGB32] = storeARGB32FromRGBA64PM_sse4; qStoreFromRGBA64PM[QImage::Format_RGBA8888] = storeRGBA8888FromRGBA64PM_sse4; +#if QT_CONFIG(raster_64bit) destStoreProc64[QImage::Format_ARGB32] = destStore64ARGB32_sse4; destStoreProc64[QImage::Format_RGBA8888] = destStore64RGBA8888_sse4; +#endif } #endif #if defined(QT_COMPILER_SUPPORTS_AVX2) if (qCpuHasFeature(ArchHaswell)) { + qt_memfill32 = qt_memfill32_avx2; + qt_memfill64 = qt_memfill64_avx2; extern void qt_blend_rgb32_on_rgb32_avx2(uchar *destPixels, int dbpl, const uchar *srcPixels, int sbpl, int w, int h, int const_alpha); @@ -6447,18 +6795,19 @@ static void qInitDrawhelperFunctions() qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_avx2; extern void QT_FASTCALL comp_func_Source_avx2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); - extern void QT_FASTCALL comp_func_Source_rgb64_avx2(QRgba64 *destPixels, const QRgba64 *srcPixels, int length, uint const_alpha); extern void QT_FASTCALL comp_func_SourceOver_avx2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); - extern void QT_FASTCALL comp_func_SourceOver_rgb64_avx2(QRgba64 *destPixels, const QRgba64 *srcPixels, int length, uint const_alpha); extern void QT_FASTCALL comp_func_solid_SourceOver_avx2(uint *destPixels, int length, uint color, uint const_alpha); - extern void QT_FASTCALL comp_func_solid_SourceOver_rgb64_avx2(QRgba64 *destPixels, int length, QRgba64 color, uint const_alpha); - qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_avx2; - qt_functionForMode64_C[QPainter::CompositionMode_Source] = comp_func_Source_rgb64_avx2; qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_avx2; - qt_functionForMode64_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_rgb64_avx2; qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_avx2; +#if QT_CONFIG(raster_64bit) + extern void QT_FASTCALL comp_func_Source_rgb64_avx2(QRgba64 *destPixels, const QRgba64 *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_SourceOver_rgb64_avx2(QRgba64 *destPixels, const QRgba64 *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_solid_SourceOver_rgb64_avx2(QRgba64 *destPixels, int length, QRgba64 color, uint const_alpha); + qt_functionForMode64_C[QPainter::CompositionMode_Source] = comp_func_Source_rgb64_avx2; + qt_functionForMode64_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_rgb64_avx2; qt_functionForModeSolid64_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_rgb64_avx2; +#endif extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2(uint *b, uint *end, const QTextureData &image, int &fx, int &fy, int fdx, int /*fdy*/); @@ -6470,6 +6819,28 @@ static void qInitDrawhelperFunctions() bilinearFastTransformHelperARGB32PM[0][SimpleScaleTransform] = fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2; bilinearFastTransformHelperARGB32PM[0][DownscaleTransform] = fetchTransformedBilinearARGB32PM_downscale_helper_avx2; bilinearFastTransformHelperARGB32PM[0][FastRotateTransform] = fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2; + + extern void QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, int count, const QVector<QRgb> *); + extern void QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, int count, const QVector<QRgb> *); + extern const uint *QT_FASTCALL fetchARGB32ToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *); + extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *); + qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_avx2; + qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_avx2; + qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_avx2; + qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_avx2; + +#if QT_CONFIG(raster_64bit) + extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_avx2(QRgba64 *, const uint *, int, const QVector<QRgb> *, QDitherInfo *); + extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_avx2(QRgba64 *, const uint *, int count, const QVector<QRgb> *, QDitherInfo *); + extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_avx2(QRgba64 *, const uchar *, int, int, const QVector<QRgb> *, QDitherInfo *); + extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_avx2(QRgba64 *, const uchar *, int, int, const QVector<QRgb> *, QDitherInfo *); + qPixelLayouts[QImage::Format_ARGB32].convertToRGBA64PM = convertARGB32ToRGBA64PM_avx2; + qPixelLayouts[QImage::Format_RGBX8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_avx2; + qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_avx2; + qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_avx2; +#endif } #endif @@ -6505,6 +6876,14 @@ static void qInitDrawhelperFunctions() const QVector<QRgb> *, QDitherInfo *); extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_neon(uint *buffer, const uchar *src, int index, int count, const QVector<QRgb> *, QDitherInfo *); + extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *); + extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *); + extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_neon(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *); + extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_neon(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *); extern void QT_FASTCALL storeARGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, const QVector<QRgb> *, QDitherInfo *); extern void QT_FASTCALL storeRGBA8888FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, @@ -6514,10 +6893,16 @@ static void qInitDrawhelperFunctions() qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_neon; qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_neon; qPixelLayouts[QImage::Format_ARGB32].storeFromARGB32PM = storeARGB32FromARGB32PM_neon; + qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_neon; + qPixelLayouts[QImage::Format_ARGB32].convertToRGBA64PM = convertARGB32ToRGBA64PM_neon; qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_neon; qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_neon; qPixelLayouts[QImage::Format_RGBA8888].storeFromARGB32PM = storeRGBA8888FromARGB32PM_neon; + qPixelLayouts[QImage::Format_RGBA8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_neon; + qPixelLayouts[QImage::Format_RGBA8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_neon; qPixelLayouts[QImage::Format_RGBX8888].storeFromARGB32PM = storeRGBXFromARGB32PM_neon; + qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_neon; + qPixelLayouts[QImage::Format_RGBX8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_neon; #endif #if defined(ENABLE_PIXMAN_DRAWHELPERS) |