diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-05-07 11:23:03 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-05-11 10:57:05 +0200 |
commit | 8a0f100e97a3d6078b3035d4f516e60e605cb9e6 (patch) | |
tree | e82165c689349ee231bfc44fd706142e1efaaf77 | |
parent | 2ed048fa8dd506a8e57292e49dadd37011354a83 (diff) |
Split PixelLayout to separate source file
Change-Id: I0beafa39d92550ea78e78a07b25ce1253cc6668d
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
-rw-r--r-- | src/gui/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/gui/image/qimage.cpp | 2 | ||||
-rw-r--r-- | src/gui/image/qimage_conversions.cpp | 3 | ||||
-rw-r--r-- | src/gui/painting/painting.pri | 2 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper.cpp | 1581 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_avx2.cpp | 1 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_neon.cpp | 1 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_p.h | 343 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_sse4.cpp | 1 | ||||
-rw-r--r-- | src/gui/painting/qmemrotate.cpp | 3 | ||||
-rw-r--r-- | src/gui/painting/qmemrotate_p.h | 2 | ||||
-rw-r--r-- | src/gui/painting/qpaintengine_raster.cpp | 6 | ||||
-rw-r--r-- | src/gui/painting/qpixellayout.cpp | 1545 | ||||
-rw-r--r-- | src/gui/painting/qpixellayout_p.h | 336 |
14 files changed, 1958 insertions, 1869 deletions
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 686574700a..f3ecdde170 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -183,6 +183,7 @@ qt_add_module(Gui painting/qpdf.cpp painting/qpdf_p.h painting/qpdfwriter.cpp painting/qpdfwriter.h painting/qpen.cpp painting/qpen.h + painting/qpixellayout.cpp painting/qpixellayout_p.h painting/qplatformbackingstore.cpp painting/qplatformbackingstore.h painting/qpolygon.cpp painting/qpolygon.h painting/qpolygonclipper_p.h diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 8175ef42c1..830ec6c4af 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -56,9 +56,9 @@ #include <limits.h> #include <qpa/qplatformpixmap.h> #include <private/qcolortransform_p.h> -#include <private/qdrawhelper_p.h> #include <private/qmemrotate_p.h> #include <private/qimagescale_p.h> +#include <private/qpixellayout_p.h> #include <private/qsimd_p.h> #include <qhash.h> diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 506ebc797f..ea9a95a6c3 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -37,10 +37,11 @@ ** ****************************************************************************/ -#include <private/qdrawhelper_p.h> #include <private/qguiapplication_p.h> #include <private/qcolortrclut_p.h> +#include <private/qdrawhelper_p.h> #include <private/qendian_p.h> +#include <private/qpixellayout_p.h> #include <private/qsimd_p.h> #include <private/qimage_p.h> diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 4d32c592d1..cd4060b41d 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -47,6 +47,7 @@ HEADERS += \ painting/qpdf_p.h \ painting/qpdfwriter.h \ painting/qpen.h \ + painting/qpixellayout_p.h \ painting/qpolygon.h \ painting/qpolygonclipper_p.h \ painting/qrangecollection.h \ @@ -100,6 +101,7 @@ SOURCES += \ painting/qpdf.cpp \ painting/qpdfwriter.cpp \ painting/qpen.cpp \ + painting/qpixellayout.cpp \ painting/qpolygon.cpp \ painting/qrangecollection.cpp \ painting/qrasterizer.cpp \ diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 4587a0698d..3b76635b7a 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -45,8 +45,6 @@ #include <qatomic.h> #include <private/qcolortrclut_p.h> #include <private/qdrawhelper_p.h> -#include <private/qpaintengine_raster_p.h> -#include <private/qpainter_p.h> #include <private/qdrawhelper_x86_p.h> #include <private/qdrawingprimitive_sse2_p.h> #include <private/qdrawhelper_neon_p.h> @@ -54,6 +52,9 @@ #include <private/qdrawhelper_mips_dsp_p.h> #endif #include <private/qguiapplication_p.h> +#include <private/qpaintengine_raster_p.h> +#include <private/qpainter_p.h> +#include <private/qpixellayout_p.h> #include <private/qrgba64_p.h> #include <qendian.h> #include <qloggingcategory.h> @@ -74,1057 +75,6 @@ enum { half_point = 1 << 15 }; -template<QImage::Format> Q_DECL_CONSTEXPR uint redWidth(); -template<QImage::Format> Q_DECL_CONSTEXPR uint redShift(); -template<QImage::Format> Q_DECL_CONSTEXPR uint greenWidth(); -template<QImage::Format> Q_DECL_CONSTEXPR uint greenShift(); -template<QImage::Format> Q_DECL_CONSTEXPR uint blueWidth(); -template<QImage::Format> Q_DECL_CONSTEXPR uint blueShift(); -template<QImage::Format> Q_DECL_CONSTEXPR uint alphaWidth(); -template<QImage::Format> Q_DECL_CONSTEXPR uint alphaShift(); - -template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB16>() { return 5; } -template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB444>() { return 4; } -template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB555>() { return 5; } -template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB666>() { return 6; } -template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_BGR888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; } -template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; } -template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; } -template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } -template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBX8888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBA8888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; } - -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB16>() { return 11; } -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB444>() { return 8; } -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB555>() { return 10; } -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB666>() { return 12; } -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB888>() { return 16; } -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_BGR888>() { return 0; } -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB4444_Premultiplied>() { return 8; } -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8555_Premultiplied>() { return 18; } -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8565_Premultiplied>() { return 19; } -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB6666_Premultiplied>() { return 12; } -#if Q_BYTE_ORDER == Q_BIG_ENDIAN -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBX8888>() { return 24; } -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888>() { return 24; } -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; } -#else -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBX8888>() { return 0; } -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888>() { return 0; } -template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; } -#endif -template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB16>() { return 6; } -template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB444>() { return 4; } -template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB555>() { return 5; } -template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB666>() { return 6; } -template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_BGR888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; } -template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; } -template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8565_Premultiplied>() { return 6; } -template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } -template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBX8888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBA8888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; } - -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB16>() { return 5; } -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB444>() { return 4; } -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB555>() { return 5; } -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB666>() { return 6; } -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_BGR888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB4444_Premultiplied>() { return 4; } -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8555_Premultiplied>() { return 13; } -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8565_Premultiplied>() { return 13; } -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB6666_Premultiplied>() { return 6; } -#if Q_BYTE_ORDER == Q_BIG_ENDIAN -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBX8888>() { return 16; } -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888>() { return 16; } -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; } -#else -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBX8888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; } -#endif -template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB16>() { return 5; } -template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB444>() { return 4; } -template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB555>() { return 5; } -template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB666>() { return 6; } -template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_BGR888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; } -template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; } -template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; } -template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } -template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBX8888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBA8888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; } - -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB16>() { return 0; } -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB444>() { return 0; } -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB555>() { return 0; } -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB666>() { return 0; } -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB888>() { return 0; } -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_BGR888>() { return 16; } -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB4444_Premultiplied>() { return 0; } -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8555_Premultiplied>() { return 8; } -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8565_Premultiplied>() { return 8; } -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB6666_Premultiplied>() { return 0; } -#if Q_BYTE_ORDER == Q_BIG_ENDIAN -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBX8888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; } -#else -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBX8888>() { return 16; } -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888>() { return 16; } -template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; } -#endif -template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB16>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB444>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB555>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB666>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB888>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_BGR888>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; } -template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8555_Premultiplied>() { return 8; } -template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8565_Premultiplied>() { return 8; } -template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } -template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBX8888>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBA8888>() { return 8; } -template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; } - -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB16>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB444>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB555>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB666>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB888>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_BGR888>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB4444_Premultiplied>() { return 12; } -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8555_Premultiplied>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8565_Premultiplied>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB6666_Premultiplied>() { return 18; } -#if Q_BYTE_ORDER == Q_BIG_ENDIAN -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBX8888>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888>() { return 0; } -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; } -#else -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBX8888>() { return 24; } -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888>() { return 24; } -template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; } -#endif - -template<QImage::Format> constexpr QPixelLayout::BPP bitsPerPixel(); -template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB16>() { return QPixelLayout::BPP16; } -template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB444>() { return QPixelLayout::BPP16; } -template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB555>() { return QPixelLayout::BPP16; } -template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB666>() { return QPixelLayout::BPP24; } -template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB888>() { return QPixelLayout::BPP24; } -template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_BGR888>() { return QPixelLayout::BPP24; } -template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB4444_Premultiplied>() { return QPixelLayout::BPP16; } -template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8555_Premultiplied>() { return QPixelLayout::BPP24; } -template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8565_Premultiplied>() { return QPixelLayout::BPP24; } -template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB6666_Premultiplied>() { return QPixelLayout::BPP24; } -template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBX8888>() { return QPixelLayout::BPP32; } -template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888>() { return QPixelLayout::BPP32; } -template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888_Premultiplied>() { return QPixelLayout::BPP32; } - - -typedef const uint *(QT_FASTCALL *FetchPixelsFunc)(uint *buffer, const uchar *src, int index, int count); - -template <QPixelLayout::BPP bpp> static -uint QT_FASTCALL fetchPixel(const uchar *, int) -{ - Q_UNREACHABLE(); - return 0; -} - -template <> -inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP1LSB>(const uchar *src, int index) -{ - return (src[index >> 3] >> (index & 7)) & 1; -} - -template <> -inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP1MSB>(const uchar *src, int index) -{ - return (src[index >> 3] >> (~index & 7)) & 1; -} - -template <> -inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP8>(const uchar *src, int index) -{ - return src[index]; -} - -template <> -inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP16>(const uchar *src, int index) -{ - return reinterpret_cast<const quint16 *>(src)[index]; -} - -template <> -inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP24>(const uchar *src, int index) -{ - return reinterpret_cast<const quint24 *>(src)[index]; -} - -template <> -inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP32>(const uchar *src, int index) -{ - return reinterpret_cast<const uint *>(src)[index]; -} - -template <> -inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP64>(const uchar *src, int index) -{ - // We have to do the conversion in fetch to fit into a 32bit uint - QRgba64 c = reinterpret_cast<const QRgba64 *>(src)[index]; - return c.toArgb32(); -} - -template <QPixelLayout::BPP bpp> -static quint64 QT_FASTCALL fetchPixel64(const uchar *src, int index) -{ - Q_STATIC_ASSERT(bpp != QPixelLayout::BPP64); - return fetchPixel<bpp>(src, index); -} - -template <QPixelLayout::BPP width> static -void QT_FASTCALL storePixel(uchar *dest, int index, uint pixel); - -template <> -inline void QT_FASTCALL storePixel<QPixelLayout::BPP16>(uchar *dest, int index, uint pixel) -{ - reinterpret_cast<quint16 *>(dest)[index] = quint16(pixel); -} - -template <> -inline void QT_FASTCALL storePixel<QPixelLayout::BPP24>(uchar *dest, int index, uint pixel) -{ - reinterpret_cast<quint24 *>(dest)[index] = quint24(pixel); -} - -typedef uint (QT_FASTCALL *FetchPixelFunc)(const uchar *src, int index); - -static const FetchPixelFunc qFetchPixel[QPixelLayout::BPPCount] = { - nullptr, // BPPNone - fetchPixel<QPixelLayout::BPP1MSB>, // BPP1MSB - fetchPixel<QPixelLayout::BPP1LSB>, // BPP1LSB - fetchPixel<QPixelLayout::BPP8>, // BPP8 - fetchPixel<QPixelLayout::BPP16>, // BPP16 - fetchPixel<QPixelLayout::BPP24>, // BPP24 - fetchPixel<QPixelLayout::BPP32>, // BPP32 - fetchPixel<QPixelLayout::BPP64> // BPP64 -}; - -template<QImage::Format Format> -static Q_ALWAYS_INLINE uint convertPixelToRGB32(uint s) -{ - Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); - Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); - Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); - - Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>(); - Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>(); - Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>(); - - Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8; - Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8; - Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8; - - uint red = (s >> redShift<Format>()) & redMask; - uint green = (s >> greenShift<Format>()) & greenMask; - uint blue = (s >> blueShift<Format>()) & blueMask; - - red = ((red << redLeftShift) | (red >> redRightShift)) << 16; - green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8; - blue = (blue << blueLeftShift) | (blue >> blueRightShift); - return 0xff000000 | red | green | blue; -} - -template<QImage::Format Format> -static void QT_FASTCALL convertToRGB32(uint *buffer, int count, const QVector<QRgb> *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = convertPixelToRGB32<Format>(buffer[i]); -} - -#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3 -extern const uint * QT_FASTCALL fetchPixelsBPP24_ssse3(uint *dest, const uchar*src, int index, int count); -#endif - -template<QImage::Format Format> -static const uint *QT_FASTCALL fetchRGBToRGB32(uint *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>(); -#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3 - if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) { - // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3 - // to vectorize the deforested version below. - fetchPixelsBPP24_ssse3(buffer, src, index, count); - convertToRGB32<Format>(buffer, count, nullptr); - return buffer; - } -#endif - for (int i = 0; i < count; ++i) - buffer[i] = convertPixelToRGB32<Format>(fetchPixel<BPP>(src, index + i)); - return buffer; -} - -template<QImage::Format Format> -static Q_ALWAYS_INLINE QRgba64 convertPixelToRGB64(uint s) -{ - return QRgba64::fromArgb32(convertPixelToRGB32<Format>(s)); -} - -template<QImage::Format Format> -static const QRgba64 *QT_FASTCALL convertToRGB64(QRgba64 *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = convertPixelToRGB64<Format>(src[i]); - return buffer; -} - -template<QImage::Format Format> -static const QRgba64 *QT_FASTCALL fetchRGBToRGB64(QRgba64 *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = convertPixelToRGB64<Format>(fetchPixel<bitsPerPixel<Format>()>(src, index + i)); - return buffer; -} - -template<QImage::Format Format> -static Q_ALWAYS_INLINE uint convertPixelToARGB32PM(uint s) -{ - Q_CONSTEXPR uint alphaMask = ((1 << alphaWidth<Format>()) - 1); - Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); - Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); - Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); - - Q_CONSTEXPR uchar alphaLeftShift = 8 - alphaWidth<Format>(); - Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>(); - Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>(); - Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>(); - - Q_CONSTEXPR uchar alphaRightShift = 2 * alphaWidth<Format>() - 8; - Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8; - Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8; - Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8; - - Q_CONSTEXPR bool mustMin = (alphaWidth<Format>() != redWidth<Format>()) || - (alphaWidth<Format>() != greenWidth<Format>()) || - (alphaWidth<Format>() != blueWidth<Format>()); - - uint alpha = (s >> alphaShift<Format>()) & alphaMask; - uint red = (s >> redShift<Format>()) & redMask; - uint green = (s >> greenShift<Format>()) & greenMask; - uint blue = (s >> blueShift<Format>()) & blueMask; - - alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift); - red = (red << redLeftShift) | (red >> redRightShift); - green = (green << greenLeftShift) | (green >> greenRightShift); - blue = (blue << blueLeftShift) | (blue >> blueRightShift); - - if (mustMin) { - red = qMin(alpha, red); - green = qMin(alpha, green); - blue = qMin(alpha, blue); - } - - return (alpha << 24) | (red << 16) | (green << 8) | blue; -} - -template<QImage::Format Format> -static void QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, int count, const QVector<QRgb> *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = convertPixelToARGB32PM<Format>(buffer[i]); -} - -template<QImage::Format Format> -static const uint *QT_FASTCALL fetchARGBPMToARGB32PM(uint *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>(); -#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3 - if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) { - // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3 - // to vectorize the deforested version below. - fetchPixelsBPP24_ssse3(buffer, src, index, count); - convertARGBPMToARGB32PM<Format>(buffer, count, nullptr); - return buffer; - } -#endif - for (int i = 0; i < count; ++i) - buffer[i] = convertPixelToARGB32PM<Format>(fetchPixel<BPP>(src, index + i)); - return buffer; -} - -template<QImage::Format Format> -static Q_ALWAYS_INLINE QRgba64 convertPixelToRGBA64PM(uint s) -{ - return QRgba64::fromArgb32(convertPixelToARGB32PM<Format>(s)); -} - -template<QImage::Format Format> -static const QRgba64 *QT_FASTCALL convertARGBPMToRGBA64PM(QRgba64 *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = convertPixelToRGB64<Format>(src[i]); - return buffer; -} - -template<QImage::Format Format> -static const QRgba64 *QT_FASTCALL fetchARGBPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>(); - for (int i = 0; i < count; ++i) - buffer[i] = convertPixelToRGBA64PM<Format>(fetchPixel<bpp>(src, index + i)); - return buffer; -} - -template<QImage::Format Format, bool fromRGB> -static void QT_FASTCALL storeRGBFromARGB32PM(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *dither) -{ - Q_CONSTEXPR uchar rWidth = redWidth<Format>(); - Q_CONSTEXPR uchar gWidth = greenWidth<Format>(); - Q_CONSTEXPR uchar bWidth = blueWidth<Format>(); - constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>(); - - // RGB32 -> RGB888 is not a precision loss. - if (!dither || (rWidth == 8 && gWidth == 8 && bWidth == 8)) { - Q_CONSTEXPR uint rMask = (1 << redWidth<Format>()) - 1; - Q_CONSTEXPR uint gMask = (1 << greenWidth<Format>()) - 1; - Q_CONSTEXPR uint bMask = (1 << blueWidth<Format>()) - 1; - Q_CONSTEXPR uchar rRightShift = 24 - redWidth<Format>(); - Q_CONSTEXPR uchar gRightShift = 16 - greenWidth<Format>(); - Q_CONSTEXPR uchar bRightShift = 8 - blueWidth<Format>(); - - for (int i = 0; i < count; ++i) { - const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]); - const uint r = ((c >> rRightShift) & rMask) << redShift<Format>(); - const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>(); - const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>(); - storePixel<BPP>(dest, index + i, r | g | b); - }; - } else { - // We do ordered dither by using a rounding conversion, but instead of - // adding half of input precision, we add the adjusted result from the - // bayer matrix before narrowing. - // Note: Rounding conversion in itself is different from the naive - // conversion we do above for non-dithering. - const uint *bayer_line = qt_bayer_matrix[dither->y & 15]; - for (int i = 0; i < count; ++i) { - const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]); - const int d = bayer_line[(dither->x + i) & 15]; - const int dr = d - ((d + 1) >> rWidth); - const int dg = d - ((d + 1) >> gWidth); - const int db = d - ((d + 1) >> bWidth); - int r = qRed(c); - int g = qGreen(c); - int b = qBlue(c); - r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth); - g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth); - b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth); - const uint s = (r << redShift<Format>()) - | (g << greenShift<Format>()) - | (b << blueShift<Format>()); - storePixel<BPP>(dest, index + i, s); - } - } -} - -template<QImage::Format Format, bool fromRGB> -static void QT_FASTCALL storeARGBPMFromARGB32PM(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *dither) -{ - constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>(); - if (!dither) { - Q_CONSTEXPR uint aMask = (1 << alphaWidth<Format>()) - 1; - Q_CONSTEXPR uint rMask = (1 << redWidth<Format>()) - 1; - Q_CONSTEXPR uint gMask = (1 << greenWidth<Format>()) - 1; - Q_CONSTEXPR uint bMask = (1 << blueWidth<Format>()) - 1; - - Q_CONSTEXPR uchar aRightShift = 32 - alphaWidth<Format>(); - Q_CONSTEXPR uchar rRightShift = 24 - redWidth<Format>(); - Q_CONSTEXPR uchar gRightShift = 16 - greenWidth<Format>(); - Q_CONSTEXPR uchar bRightShift = 8 - blueWidth<Format>(); - - Q_CONSTEXPR uint aOpaque = aMask << alphaShift<Format>(); - for (int i = 0; i < count; ++i) { - const uint c = src[i]; - const uint a = fromRGB ? aOpaque : (((c >> aRightShift) & aMask) << alphaShift<Format>()); - const uint r = ((c >> rRightShift) & rMask) << redShift<Format>(); - const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>(); - const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>(); - storePixel<BPP>(dest, index + i, a | r | g | b); - }; - } else { - Q_CONSTEXPR uchar aWidth = alphaWidth<Format>(); - Q_CONSTEXPR uchar rWidth = redWidth<Format>(); - Q_CONSTEXPR uchar gWidth = greenWidth<Format>(); - Q_CONSTEXPR uchar bWidth = blueWidth<Format>(); - - const uint *bayer_line = qt_bayer_matrix[dither->y & 15]; - for (int i = 0; i < count; ++i) { - const uint c = src[i]; - const int d = bayer_line[(dither->x + i) & 15]; - const int da = d - ((d + 1) >> aWidth); - const int dr = d - ((d + 1) >> rWidth); - const int dg = d - ((d + 1) >> gWidth); - const int db = d - ((d + 1) >> bWidth); - int a = qAlpha(c); - int r = qRed(c); - int g = qGreen(c); - int b = qBlue(c); - if (fromRGB) - a = (1 << aWidth) - 1; - else - a = (a + ((da - a) >> aWidth) + 1) >> (8 - aWidth); - r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth); - g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth); - b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth); - uint s = (a << alphaShift<Format>()) - | (r << redShift<Format>()) - | (g << greenShift<Format>()) - | (b << blueShift<Format>()); - storePixel<BPP>(dest, index + i, s); - } - } -} - -template<QImage::Format Format> -static void QT_FASTCALL rbSwap(uchar *dst, const uchar *src, int count) -{ - Q_CONSTEXPR uchar aWidth = alphaWidth<Format>(); - Q_CONSTEXPR uchar aShift = alphaShift<Format>(); - Q_CONSTEXPR uchar rWidth = redWidth<Format>(); - Q_CONSTEXPR uchar rShift = redShift<Format>(); - Q_CONSTEXPR uchar gWidth = greenWidth<Format>(); - Q_CONSTEXPR uchar gShift = greenShift<Format>(); - Q_CONSTEXPR uchar bWidth = blueWidth<Format>(); - Q_CONSTEXPR uchar bShift = blueShift<Format>(); -#ifdef Q_COMPILER_CONSTEXPR - Q_STATIC_ASSERT(rWidth == bWidth); -#endif - Q_CONSTEXPR uint redBlueMask = (1 << rWidth) - 1; - Q_CONSTEXPR uint alphaGreenMask = (((1 << aWidth) - 1) << aShift) - | (((1 << gWidth) - 1) << gShift); - constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>(); - - for (int i = 0; i < count; ++i) { - const uint c = fetchPixel<bpp>(src, i); - const uint r = (c >> rShift) & redBlueMask; - const uint b = (c >> bShift) & redBlueMask; - const uint t = (c & alphaGreenMask) - | (r << bShift) - | (b << rShift); - storePixel<bpp>(dst, i, t); - } -} - -static void QT_FASTCALL rbSwap_rgb32(uchar *d, const uchar *s, int count) -{ - const uint *src = reinterpret_cast<const uint *>(s); - uint *dest = reinterpret_cast<uint *>(d); - for (int i = 0; i < count; ++i) { - const uint c = src[i]; - const uint ag = c & 0xff00ff00; - const uint rb = c & 0x00ff00ff; - dest[i] = ag | (rb << 16) | (rb >> 16); - } -} - -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -template<> -void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count) -{ - return rbSwap_rgb32(d, s, count); -} -#else -template<> -void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count) -{ - const uint *src = reinterpret_cast<const uint *>(s); - uint *dest = reinterpret_cast<uint *>(d); - for (int i = 0; i < count; ++i) { - const uint c = src[i]; - const uint rb = c & 0xff00ff00; - const uint ga = c & 0x00ff00ff; - dest[i] = ga | (rb << 16) | (rb >> 16); - } -} -#endif - -static void QT_FASTCALL rbSwap_rgb30(uchar *d, const uchar *s, int count) -{ - const uint *src = reinterpret_cast<const uint *>(s); - uint *dest = reinterpret_cast<uint *>(d); - UNALIASED_CONVERSION_LOOP(dest, src, count, qRgbSwapRgb30); -} - -template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutRGB() -{ - return QPixelLayout{ - false, - false, - bitsPerPixel<Format>(), - rbSwap<Format>, - convertToRGB32<Format>, - convertToRGB64<Format>, - fetchRGBToRGB32<Format>, - fetchRGBToRGB64<Format>, - storeRGBFromARGB32PM<Format, false>, - storeRGBFromARGB32PM<Format, true> - }; -} - -template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutARGBPM() -{ - return QPixelLayout{ - true, - true, - bitsPerPixel<Format>(), - rbSwap<Format>, - convertARGBPMToARGB32PM<Format>, - convertARGBPMToRGBA64PM<Format>, - fetchARGBPMToARGB32PM<Format>, - fetchARGBPMToRGBA64PM<Format>, - storeARGBPMFromARGB32PM<Format, false>, - storeARGBPMFromARGB32PM<Format, true> - }; -} - -static void QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, int count, const QVector<QRgb> *clut) -{ - for (int i = 0; i < count; ++i) - buffer[i] = qPremultiply(clut->at(buffer[i])); -} - -template<QPixelLayout::BPP BPP> -static const uint *QT_FASTCALL fetchIndexedToARGB32PM(uint *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *clut, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) { - const uint s = fetchPixel<BPP>(src, index + i); - buffer[i] = qPremultiply(clut->at(s)); - } - return buffer; -} - -template<QPixelLayout::BPP BPP> -static const QRgba64 *QT_FASTCALL fetchIndexedToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *clut, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) { - const uint s = fetchPixel<BPP>(src, index + i); - buffer[i] = QRgba64::fromArgb32(clut->at(s)).premultiplied(); - } - return buffer; -} - -static const QRgba64 *QT_FASTCALL convertIndexedToRGBA64PM(QRgba64 *buffer, const uint *src, int count, - const QVector<QRgb> *clut, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = QRgba64::fromArgb32(clut->at(src[i])).premultiplied(); - return buffer; -} - -static void QT_FASTCALL convertPassThrough(uint *, int, const QVector<QRgb> *) -{ -} - -static const uint *QT_FASTCALL fetchPassThrough(uint *, const uchar *src, int index, int, - const QVector<QRgb> *, QDitherInfo *) -{ - return reinterpret_cast<const uint *>(src) + index; -} - -static const QRgba64 *QT_FASTCALL fetchPassThrough64(QRgba64 *, const uchar *src, int index, int, - const QVector<QRgb> *, QDitherInfo *) -{ - return reinterpret_cast<const QRgba64 *>(src) + index; -} - -static void QT_FASTCALL storePassThrough(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - uint *d = reinterpret_cast<uint *>(dest) + index; - if (d != src) - memcpy(d, src, count * sizeof(uint)); -} - -static void QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, int count, const QVector<QRgb> *) -{ - qt_convertARGB32ToARGB32PM(buffer, buffer, count); -} - -static const uint *QT_FASTCALL fetchARGB32ToARGB32PM(uint *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - return qt_convertARGB32ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count); -} - -static void QT_FASTCALL convertRGBA8888PMToARGB32PM(uint *buffer, int count, const QVector<QRgb> *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = RGBA2ARGB(buffer[i]); -} - -static const uint *QT_FASTCALL fetchRGBA8888PMToARGB32PM(uint *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - const uint *s = reinterpret_cast<const uint *>(src) + index; - UNALIASED_CONVERSION_LOOP(buffer, s, count, RGBA2ARGB); - return buffer; -} - -static void QT_FASTCALL convertRGBA8888ToARGB32PM(uint *buffer, int count, const QVector<QRgb> *) -{ - qt_convertRGBA8888ToARGB32PM(buffer, buffer, count); -} - -static const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM(uint *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - return qt_convertRGBA8888ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count); -} - -static void QT_FASTCALL convertAlpha8ToRGB32(uint *buffer, int count, const QVector<QRgb> *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = qRgba(0, 0, 0, buffer[i]); -} - -static const uint *QT_FASTCALL fetchAlpha8ToRGB32(uint *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = qRgba(0, 0, 0, src[index + i]); - return buffer; -} - -static const QRgba64 *QT_FASTCALL convertAlpha8ToRGB64(QRgba64 *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = QRgba64::fromRgba(0, 0, 0, src[i]); - return buffer; -} -static const QRgba64 *QT_FASTCALL fetchAlpha8ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = QRgba64::fromRgba(0, 0, 0, src[index + i]); - return buffer; -} - -static void QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, int count, const QVector<QRgb> *) -{ - for (int i = 0; i < count; ++i) { - const uint s = buffer[i]; - buffer[i] = qRgb(s, s, s); - } -} - -static const uint *QT_FASTCALL fetchGrayscale8ToRGB32(uint *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) { - const uint s = src[index + i]; - buffer[i] = qRgb(s, s, s); - } - return buffer; -} - -static const QRgba64 *QT_FASTCALL convertGrayscale8ToRGB64(QRgba64 *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = QRgba64::fromRgba(src[i], src[i], src[i], 255); - return buffer; -} - -static const QRgba64 *QT_FASTCALL fetchGrayscale8ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) { - const uint s = src[index + i]; - buffer[i] = QRgba64::fromRgba(s, s, s, 255); - } - 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 *) -{ - uint *d = reinterpret_cast<uint *>(dest) + index; - UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return qUnpremultiply(c); }); -} - -static void QT_FASTCALL storeRGBA8888PMFromARGB32PM(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - uint *d = reinterpret_cast<uint *>(dest) + index; - UNALIASED_CONVERSION_LOOP(d, src, count, ARGB2RGBA); -} - -#ifdef __SSE2__ -template<bool RGBA, bool maskAlpha> -static inline void qConvertARGB32PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count) -{ - if (count <= 0) - return; - - const __m128i amask = _mm_set1_epi32(0xff000000); - int i = 0; - for (; ((uintptr_t)buffer & 0xf) && i < count; ++i) { - uint s = *src++; - if (maskAlpha) - s = s | 0xff000000; - if (RGBA) - s = RGBA2ARGB(s); - *buffer++ = QRgba64::fromArgb32(s); - } - for (; i < count-3; i += 4) { - __m128i vs = _mm_loadu_si128((const __m128i*)src); - if (maskAlpha) - vs = _mm_or_si128(vs, amask); - src += 4; - __m128i v1 = _mm_unpacklo_epi8(vs, vs); - __m128i v2 = _mm_unpackhi_epi8(vs, vs); - if (!RGBA) { - v1 = _mm_shufflelo_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2)); - v2 = _mm_shufflelo_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2)); - v1 = _mm_shufflehi_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2)); - v2 = _mm_shufflehi_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2)); - } - _mm_store_si128((__m128i*)(buffer), v1); - buffer += 2; - _mm_store_si128((__m128i*)(buffer), v2); - buffer += 2; - } - - SIMD_EPILOGUE(i, count, 3) { - uint s = *src++; - if (maskAlpha) - s = s | 0xff000000; - if (RGBA) - s = RGBA2ARGB(s); - *buffer++ = QRgba64::fromArgb32(s); - } -} - -template<QtPixelOrder PixelOrder> -static inline void qConvertRGBA64PMToA2RGB30PM_sse2(uint *dest, const QRgba64 *buffer, int count) -{ - const __m128i gmask = _mm_set1_epi32(0x000ffc00); - const __m128i cmask = _mm_set1_epi32(0x000003ff); - int i = 0; - __m128i vr, vg, vb, va; - for (; i < count && uintptr_t(buffer) & 0xF; ++i) { - *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++); - } - - for (; i < count-15; i += 16) { - // Repremultiplying is really expensive and hard to do in SIMD without AVX2, - // so we try to avoid it by checking if it is needed 16 samples at a time. - __m128i vOr = _mm_set1_epi32(0); - __m128i vAnd = _mm_set1_epi32(0xffffffff); - for (int j = 0; j < 16; j += 2) { - __m128i vs = _mm_load_si128((const __m128i*)(buffer + j)); - vOr = _mm_or_si128(vOr, vs); - vAnd = _mm_and_si128(vAnd, vs); - } - const quint16 orAlpha = ((uint)_mm_extract_epi16(vOr, 3)) | ((uint)_mm_extract_epi16(vOr, 7)); - const quint16 andAlpha = ((uint)_mm_extract_epi16(vAnd, 3)) & ((uint)_mm_extract_epi16(vAnd, 7)); - - if (andAlpha == 0xffff) { - for (int j = 0; j < 16; j += 2) { - __m128i vs = _mm_load_si128((const __m128i*)buffer); - buffer += 2; - vr = _mm_srli_epi64(vs, 6); - vg = _mm_srli_epi64(vs, 16 + 6 - 10); - vb = _mm_srli_epi64(vs, 32 + 6); - vr = _mm_and_si128(vr, cmask); - vg = _mm_and_si128(vg, gmask); - vb = _mm_and_si128(vb, cmask); - va = _mm_srli_epi64(vs, 48 + 14); - if (PixelOrder == PixelOrderRGB) - vr = _mm_slli_epi32(vr, 20); - else - vb = _mm_slli_epi32(vb, 20); - va = _mm_slli_epi32(va, 30); - __m128i vd = _mm_or_si128(_mm_or_si128(vr, vg), _mm_or_si128(vb, va)); - vd = _mm_shuffle_epi32(vd, _MM_SHUFFLE(3, 1, 2, 0)); - _mm_storel_epi64((__m128i*)dest, vd); - dest += 2; - } - } else if (orAlpha == 0) { - for (int j = 0; j < 16; ++j) { - *dest++ = 0; - buffer++; - } - } else { - for (int j = 0; j < 16; ++j) - *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++); - } - } - - SIMD_EPILOGUE(i, count, 15) - *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++); -} -#elif defined(__ARM_NEON__) -template<bool RGBA, bool maskAlpha> -static inline void qConvertARGB32PMToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count) -{ - if (count <= 0) - return; - - const uint32x4_t amask = vdupq_n_u32(0xff000000); -#if defined(Q_PROCESSOR_ARM_64) - const uint8x16_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15}; -#else - const uint8x8_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7 }; -#endif - int i = 0; - for (; i < count-3; i += 4) { - uint32x4_t vs32 = vld1q_u32(src); - src += 4; - if (maskAlpha) - vs32 = vorrq_u32(vs32, amask); - uint8x16_t vs8 = vreinterpretq_u8_u32(vs32); - if (!RGBA) { -#if defined(Q_PROCESSOR_ARM_64) - vs8 = vqtbl1q_u8(vs8, rgbaMask); -#else - // no vqtbl1q_u8 - const uint8x8_t vlo = vtbl1_u8(vget_low_u8(vs8), rgbaMask); - const uint8x8_t vhi = vtbl1_u8(vget_high_u8(vs8), rgbaMask); - vs8 = vcombine_u8(vlo, vhi); -#endif - } - uint8x16x2_t v = vzipq_u8(vs8, vs8); - - vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[0])); - buffer += 2; - vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[1])); - buffer += 2; - } - - SIMD_EPILOGUE(i, count, 3) { - uint s = *src++; - if (maskAlpha) - s = s | 0xff000000; - if (RGBA) - s = RGBA2ARGB(s); - *buffer++ = QRgba64::fromArgb32(s); - } -} -#endif - -static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) -{ -#ifdef __SSE2__ - qConvertARGB32PMToRGBA64PM_sse2<false, true>(buffer, src, count); -#elif defined(__ARM_NEON__) - qConvertARGB32PMToRGBA64PM_neon<false, true>(buffer, src, count); -#else - for (int i = 0; i < count; ++i) - buffer[i] = QRgba64::fromArgb32(0xff000000 | src[i]); -#endif - return buffer; -} - -static const QRgba64 *QT_FASTCALL fetchRGB32ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - return convertRGB32ToRGB64(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); -} - -static const QRgba64 *QT_FASTCALL convertARGB32ToRGBA64PM(QRgba64 *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied(); - return buffer; -} - -static const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - return convertARGB32ToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); -} - -static const QRgba64 *QT_FASTCALL convertARGB32PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) -{ -#ifdef __SSE2__ - qConvertARGB32PMToRGBA64PM_sse2<false, false>(buffer, src, count); -#elif defined(__ARM_NEON__) - qConvertARGB32PMToRGBA64PM_neon<false, false>(buffer, src, count); -#else - for (int i = 0; i < count; ++i) - buffer[i] = QRgba64::fromArgb32(src[i]); -#endif - return buffer; -} - -static const QRgba64 *QT_FASTCALL fetchARGB32PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - return convertARGB32PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); -} - #if QT_CONFIG(raster_64bit) static void convertRGBA64ToRGBA64PM(QRgba64 *buffer, int count) { @@ -1137,525 +87,6 @@ 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 *) -{ - const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index; - for (int i = 0; i < count; ++i) - buffer[i] = QRgba64::fromRgba64(s[i]).premultiplied(); - return buffer; -} - -static const QRgba64 *QT_FASTCALL convertRGBA8888ToRGBA64PM(QRgba64 *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied(); - return buffer; -} - -static const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - return convertRGBA8888ToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); -} - -static const QRgba64 *QT_FASTCALL convertRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) -{ -#ifdef __SSE2__ - qConvertARGB32PMToRGBA64PM_sse2<true, false>(buffer, src, count); -#elif defined(__ARM_NEON__) - qConvertARGB32PMToRGBA64PM_neon<true, false>(buffer, src, count); -#else - for (int i = 0; i < count; ++i) - buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])); -#endif - return buffer; -} - -static const QRgba64 *QT_FASTCALL fetchRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - return convertRGBA8888PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); -} - -static void QT_FASTCALL storeRGBA8888FromARGB32PM(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - uint *d = reinterpret_cast<uint *>(dest) + index; - UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(qUnpremultiply(c)); }); -} - -static void QT_FASTCALL storeRGBXFromRGB32(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - uint *d = reinterpret_cast<uint *>(dest) + index; - UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | c); }); -} - -static void QT_FASTCALL storeRGBXFromARGB32PM(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - uint *d = reinterpret_cast<uint *>(dest) + index; - UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | qUnpremultiply(c)); }); -} - -template<QtPixelOrder PixelOrder> -static void QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, int count, const QVector<QRgb> *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = qConvertA2rgb30ToArgb32<PixelOrder>(buffer[i]); -} - -template<QtPixelOrder PixelOrder> -static const uint *QT_FASTCALL fetchA2RGB30PMToARGB32PM(uint *buffer, const uchar *s, int index, int count, - const QVector<QRgb> *, QDitherInfo *dither) -{ - const uint *src = reinterpret_cast<const uint *>(s) + index; - if (!dither) { - UNALIASED_CONVERSION_LOOP(buffer, src, count, qConvertA2rgb30ToArgb32<PixelOrder>); - } else { - for (int i = 0; i < count; ++i) { - const uint c = src[i]; - short d10 = (qt_bayer_matrix[dither->y & 15][(dither->x + i) & 15] << 2); - short a10 = (c >> 30) * 0x155; - short r10 = ((c >> 20) & 0x3ff); - short g10 = ((c >> 10) & 0x3ff); - short b10 = (c & 0x3ff); - if (PixelOrder == PixelOrderBGR) - std::swap(r10, b10); - short a8 = (a10 + ((d10 - a10) >> 8)) >> 2; - short r8 = (r10 + ((d10 - r10) >> 8)) >> 2; - short g8 = (g10 + ((d10 - g10) >> 8)) >> 2; - short b8 = (b10 + ((d10 - b10) >> 8)) >> 2; - buffer[i] = qRgba(r8, g8, b8, a8); - } - } - return buffer; -} - -#ifdef __SSE2__ -template<QtPixelOrder PixelOrder> -static inline void qConvertA2RGB30PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count) -{ - if (count <= 0) - return; - - const __m128i rmask = _mm_set1_epi32(0x3ff00000); - const __m128i gmask = _mm_set1_epi32(0x000ffc00); - const __m128i bmask = _mm_set1_epi32(0x000003ff); - const __m128i afactor = _mm_set1_epi16(0x5555); - int i = 0; - - for (; ((uintptr_t)buffer & 0xf) && i < count; ++i) - *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++); - - for (; i < count-3; i += 4) { - __m128i vs = _mm_loadu_si128((const __m128i*)src); - src += 4; - __m128i va = _mm_srli_epi32(vs, 30); - __m128i vr = _mm_and_si128(vs, rmask); - __m128i vb = _mm_and_si128(vs, bmask); - __m128i vg = _mm_and_si128(vs, gmask); - va = _mm_mullo_epi16(va, afactor); - vr = _mm_or_si128(_mm_srli_epi32(vr, 14), _mm_srli_epi32(vr, 24)); - vg = _mm_or_si128(_mm_srli_epi32(vg, 4), _mm_srli_epi32(vg, 14)); - vb = _mm_or_si128(_mm_slli_epi32(vb, 6), _mm_srli_epi32(vb, 4)); - __m128i vrb; - if (PixelOrder == PixelOrderRGB) - vrb = _mm_or_si128(vr, _mm_slli_si128(vb, 2)); - else - vrb = _mm_or_si128(vb, _mm_slli_si128(vr, 2)); - __m128i vga = _mm_or_si128(vg, _mm_slli_si128(va, 2)); - _mm_store_si128((__m128i*)(buffer), _mm_unpacklo_epi16(vrb, vga)); - buffer += 2; - _mm_store_si128((__m128i*)(buffer), _mm_unpackhi_epi16(vrb, vga)); - buffer += 2; - } - - SIMD_EPILOGUE(i, count, 3) - *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++); -} -#endif - -template<QtPixelOrder PixelOrder> -static const QRgba64 *QT_FASTCALL convertA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) -{ -#ifdef __SSE2__ - qConvertA2RGB30PMToRGBA64PM_sse2<PixelOrder>(buffer, src, count); -#else - for (int i = 0; i < count; ++i) - buffer[i] = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]); -#endif - return buffer; -} - -template<QtPixelOrder PixelOrder> -static const QRgba64 *QT_FASTCALL fetchA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - return convertA2RGB30PMToRGBA64PM<PixelOrder>(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); -} - -template<QtPixelOrder PixelOrder> -static void QT_FASTCALL storeA2RGB30PMFromARGB32PM(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - uint *d = reinterpret_cast<uint *>(dest) + index; - UNALIASED_CONVERSION_LOOP(d, src, count, qConvertArgb32ToA2rgb30<PixelOrder>); -} - -template<QtPixelOrder PixelOrder> -static void QT_FASTCALL storeRGB30FromRGB32(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - uint *d = reinterpret_cast<uint *>(dest) + index; - UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>); -} - -template<QtPixelOrder PixelOrder> -static void QT_FASTCALL storeRGB30FromARGB32PM(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - uint *d = reinterpret_cast<uint *>(dest) + index; - UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>); -} - -template<bool RGBA> -void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count) -{ - int i = 0; -#ifdef __SSE2__ - if (((uintptr_t)dst & 0x7) && count > 0) { - uint s = (*src++).toArgb32(); - if (RGBA) - s = ARGB2RGBA(s); - *dst++ = s; - i++; - } - const __m128i vhalf = _mm_set1_epi32(0x80); - const __m128i vzero = _mm_setzero_si128(); - for (; i < count-1; i += 2) { - __m128i vs = _mm_loadu_si128((const __m128i*)src); - src += 2; - if (!RGBA) { - vs = _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2)); - vs = _mm_shufflehi_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2)); - } - __m128i v1 = _mm_unpacklo_epi16(vs, vzero); - __m128i v2 = _mm_unpackhi_epi16(vs, vzero); - v1 = _mm_add_epi32(v1, vhalf); - v2 = _mm_add_epi32(v2, vhalf); - v1 = _mm_sub_epi32(v1, _mm_srli_epi32(v1, 8)); - v2 = _mm_sub_epi32(v2, _mm_srli_epi32(v2, 8)); - v1 = _mm_srli_epi32(v1, 8); - v2 = _mm_srli_epi32(v2, 8); - v1 = _mm_packs_epi32(v1, v2); - v1 = _mm_packus_epi16(v1, vzero); - _mm_storel_epi64((__m128i*)(dst), v1); - dst += 2; - } -#endif - for (; i < count; i++) { - uint s = (*src++).toArgb32(); - if (RGBA) - s = ARGB2RGBA(s); - *dst++ = s; - } -} -template void qt_convertRGBA64ToARGB32<false>(uint *dst, const QRgba64 *src, int count); -template void qt_convertRGBA64ToARGB32<true>(uint *dst, const QRgba64 *src, int count); - - -static void QT_FASTCALL storeAlpha8FromARGB32PM(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) - dest[index + i] = qAlpha(src[i]); -} - -static void QT_FASTCALL storeGrayscale8FromRGB32(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) - dest[index + i] = qGray(src[i]); -} - -static void QT_FASTCALL storeGrayscale8FromARGB32PM(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - for (int i = 0; i < count; ++i) - 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 *) -{ - const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index; - for (int i = 0; i < count; ++i) - buffer[i] = toArgb32(s[i]); - return buffer; -} - -static void QT_FASTCALL storeRGB64FromRGB32(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index; - for (int i = 0; i < count; ++i) - d[i] = QRgba64::fromArgb32(src[i]); -} - -static const uint *QT_FASTCALL fetchRGBA64ToARGB32PM(uint *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index; - for (int i = 0; i < count; ++i) - buffer[i] = toArgb32(s[i].premultiplied()); - return buffer; -} - -static void QT_FASTCALL storeRGBA64FromARGB32PM(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index; - for (int i = 0; i < count; ++i) - d[i] = QRgba64::fromArgb32(src[i]).unpremultiplied(); -} - -// Note: -// convertToArgb32() assumes that no color channel is less than 4 bits. -// storeRGBFromARGB32PM() assumes that no color channel is more than 8 bits. -// QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits. -QPixelLayout qPixelLayouts[QImage::NImageFormats] = { - { false, false, QPixelLayout::BPPNone, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }, // Format_Invalid - { false, false, QPixelLayout::BPP1MSB, nullptr, - convertIndexedToARGB32PM, convertIndexedToRGBA64PM, - fetchIndexedToARGB32PM<QPixelLayout::BPP1MSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1MSB>, - nullptr, nullptr }, // Format_Mono - { false, false, QPixelLayout::BPP1LSB, nullptr, - convertIndexedToARGB32PM, convertIndexedToRGBA64PM, - fetchIndexedToARGB32PM<QPixelLayout::BPP1LSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1LSB>, - nullptr, nullptr }, // Format_MonoLSB - { false, false, QPixelLayout::BPP8, nullptr, - convertIndexedToARGB32PM, convertIndexedToRGBA64PM, - fetchIndexedToARGB32PM<QPixelLayout::BPP8>, fetchIndexedToRGBA64PM<QPixelLayout::BPP8>, - nullptr, nullptr }, // Format_Indexed8 - // Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong, - // but everywhere this generic conversion would be wrong is currently overloaded. - { false, false, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough, - convertRGB32ToRGB64, fetchPassThrough, fetchRGB32ToRGB64, storePassThrough, storePassThrough }, // Format_RGB32 - { true, false, QPixelLayout::BPP32, rbSwap_rgb32, convertARGB32ToARGB32PM, - convertARGB32ToRGBA64PM, fetchARGB32ToARGB32PM, fetchARGB32ToRGBA64PM, storeARGB32FromARGB32PM, storePassThrough }, // Format_ARGB32 - { true, true, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough, - convertARGB32PMToRGBA64PM, fetchPassThrough, fetchARGB32PMToRGBA64PM, storePassThrough, storePassThrough }, // Format_ARGB32_Premultiplied - pixelLayoutRGB<QImage::Format_RGB16>(), - pixelLayoutARGBPM<QImage::Format_ARGB8565_Premultiplied>(), - pixelLayoutRGB<QImage::Format_RGB666>(), - pixelLayoutARGBPM<QImage::Format_ARGB6666_Premultiplied>(), - pixelLayoutRGB<QImage::Format_RGB555>(), - pixelLayoutARGBPM<QImage::Format_ARGB8555_Premultiplied>(), - pixelLayoutRGB<QImage::Format_RGB888>(), - pixelLayoutRGB<QImage::Format_RGB444>(), - pixelLayoutARGBPM<QImage::Format_ARGB4444_Premultiplied>(), - { false, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM, - convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBXFromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBX8888 - { true, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888ToARGB32PM, - convertRGBA8888ToRGBA64PM, fetchRGBA8888ToARGB32PM, fetchRGBA8888ToRGBA64PM, storeRGBA8888FromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBA8888 - { true, true, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM, - convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBA8888PMFromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBA8888_Premultiplied - { false, false, QPixelLayout::BPP32, rbSwap_rgb30, - convertA2RGB30PMToARGB32PM<PixelOrderBGR>, - convertA2RGB30PMToRGBA64PM<PixelOrderBGR>, - fetchA2RGB30PMToARGB32PM<PixelOrderBGR>, - fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>, - storeRGB30FromARGB32PM<PixelOrderBGR>, - storeRGB30FromRGB32<PixelOrderBGR> - }, // Format_BGR30 - { true, true, QPixelLayout::BPP32, rbSwap_rgb30, - convertA2RGB30PMToARGB32PM<PixelOrderBGR>, - convertA2RGB30PMToRGBA64PM<PixelOrderBGR>, - fetchA2RGB30PMToARGB32PM<PixelOrderBGR>, - fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>, - storeA2RGB30PMFromARGB32PM<PixelOrderBGR>, - storeRGB30FromRGB32<PixelOrderBGR> - }, // Format_A2BGR30_Premultiplied - { false, false, QPixelLayout::BPP32, rbSwap_rgb30, - convertA2RGB30PMToARGB32PM<PixelOrderRGB>, - convertA2RGB30PMToRGBA64PM<PixelOrderRGB>, - fetchA2RGB30PMToARGB32PM<PixelOrderRGB>, - fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>, - storeRGB30FromARGB32PM<PixelOrderRGB>, - storeRGB30FromRGB32<PixelOrderRGB> - }, // Format_RGB30 - { true, true, QPixelLayout::BPP32, rbSwap_rgb30, - convertA2RGB30PMToARGB32PM<PixelOrderRGB>, - convertA2RGB30PMToRGBA64PM<PixelOrderRGB>, - fetchA2RGB30PMToARGB32PM<PixelOrderRGB>, - fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>, - storeA2RGB30PMFromARGB32PM<PixelOrderRGB>, - storeRGB30FromRGB32<PixelOrderRGB> - }, // Format_A2RGB30_Premultiplied - { true, true, QPixelLayout::BPP8, nullptr, - convertAlpha8ToRGB32, convertAlpha8ToRGB64, - fetchAlpha8ToRGB32, fetchAlpha8ToRGB64, - storeAlpha8FromARGB32PM, nullptr }, // Format_Alpha8 - { false, false, QPixelLayout::BPP8, nullptr, - convertGrayscale8ToRGB32, convertGrayscale8ToRGB64, - fetchGrayscale8ToRGB32, fetchGrayscale8ToRGB64, - storeGrayscale8FromARGB32PM, storeGrayscale8FromRGB32 }, // Format_Grayscale8 - { false, false, QPixelLayout::BPP64, nullptr, - convertPassThrough, nullptr, - fetchRGB64ToRGB32, fetchPassThrough64, - storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBX64 - { true, false, QPixelLayout::BPP64, nullptr, - convertARGB32ToARGB32PM, nullptr, - fetchRGBA64ToARGB32PM, fetchRGBA64ToRGBA64PM, - storeRGBA64FromARGB32PM, storeRGB64FromRGB32 }, // Format_RGBA64 - { true, true, QPixelLayout::BPP64, nullptr, - convertPassThrough, nullptr, - fetchRGB64ToRGB32, fetchPassThrough64, - storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied - { false, false, QPixelLayout::BPP16, nullptr, - convertGrayscale16ToRGB32, convertGrayscale16ToRGBA64, - fetchGrayscale16ToRGB32, fetchGrayscale16ToRGBA64, - storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 }, // Format_Grayscale16 - pixelLayoutRGB<QImage::Format_BGR888>(), -}; - -Q_STATIC_ASSERT(sizeof(qPixelLayouts) / sizeof(*qPixelLayouts) == QImage::NImageFormats); - -static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int length) -{ - for (int i = 0; i < length; ++i) { - dest[i] = toArgb32(src[i]); - } -} - -template<QImage::Format format> -static void QT_FASTCALL storeGenericFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, - const QVector<QRgb> *clut, QDitherInfo *dither) -{ - uint buffer[BufferSize]; - convertFromRgb64(buffer, src, count); - qPixelLayouts[format].storeFromARGB32PM(dest, buffer, index, count, clut, dither); -} - -static void QT_FASTCALL storeARGB32FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - uint *d = (uint*)dest + index; - for (int i = 0; i < count; ++i) - d[i] = toArgb32(src[i].unpremultiplied()); -} - -static void QT_FASTCALL storeRGBA8888FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - uint *d = (uint*)dest + index; - for (int i = 0; i < count; ++i) - d[i] = toRgba8888(src[i].unpremultiplied()); -} - -template<QtPixelOrder PixelOrder> -static void QT_FASTCALL storeRGB30FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - uint *d = (uint*)dest + index; -#ifdef __SSE2__ - qConvertRGBA64PMToA2RGB30PM_sse2<PixelOrder>(d, src, count); -#else - for (int i = 0; i < count; ++i) - d[i] = qConvertRgb64ToRgb30<PixelOrder>(src[i]); -#endif -} - -static void QT_FASTCALL storeRGBX64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index; - for (int i = 0; i < count; ++i) { - d[i] = src[i].unpremultiplied(); - d[i].setAlpha(65535); - } -} - -static void QT_FASTCALL storeRGBA64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index; - for (int i = 0; i < count; ++i) - d[i] = src[i].unpremultiplied(); -} - -static void QT_FASTCALL storeRGBA64PMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, - const QVector<QRgb> *, QDitherInfo *) -{ - QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index; - if (d != src) - 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, - nullptr, - nullptr, - storeGenericFromRGBA64PM<QImage::Format_RGB32>, - storeARGB32FromRGBA64PM, - storeGenericFromRGBA64PM<QImage::Format_ARGB32_Premultiplied>, - storeGenericFromRGBA64PM<QImage::Format_RGB16>, - storeGenericFromRGBA64PM<QImage::Format_ARGB8565_Premultiplied>, - storeGenericFromRGBA64PM<QImage::Format_RGB666>, - storeGenericFromRGBA64PM<QImage::Format_ARGB6666_Premultiplied>, - storeGenericFromRGBA64PM<QImage::Format_RGB555>, - storeGenericFromRGBA64PM<QImage::Format_ARGB8555_Premultiplied>, - storeGenericFromRGBA64PM<QImage::Format_RGB888>, - storeGenericFromRGBA64PM<QImage::Format_RGB444>, - storeGenericFromRGBA64PM<QImage::Format_ARGB4444_Premultiplied>, - storeGenericFromRGBA64PM<QImage::Format_RGBX8888>, - storeRGBA8888FromRGBA64PM, - storeGenericFromRGBA64PM<QImage::Format_RGBA8888_Premultiplied>, - storeRGB30FromRGBA64PM<PixelOrderBGR>, - storeRGB30FromRGBA64PM<PixelOrderBGR>, - storeRGB30FromRGBA64PM<PixelOrderRGB>, - storeRGB30FromRGBA64PM<PixelOrderRGB>, - storeGenericFromRGBA64PM<QImage::Format_Alpha8>, - storeGenericFromRGBA64PM<QImage::Format_Grayscale8>, - storeRGBX64FromRGBA64PM, - storeRGBA64FromRGBA64PM, - storeRGBA64PMFromRGBA64PM, - storeGray16FromRGBA64PM, - storeGenericFromRGBA64PM<QImage::Format_BGR888>, -}; - /* Destination fetch. This is simple as we don't have to do bounds checks or transformations @@ -2099,7 +530,7 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat if (!useFetch) Q_ASSERT(layout->bpp == bpp); // When templated 'fetch' should be inlined at compile time: - const FetchPixelFunc fetch = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout->bpp] : FetchPixelFunc(fetchPixel<bpp>); + const FetchPixelFunc fetch = (bpp == QPixelLayout::BPPNone) ? qFetchPixelTable[layout->bpp] : FetchPixelFunc(qFetchPixel<bpp>); if (canUseFastMatrixPath(cx, cy, length, data)) { // The increment pr x in the scanline @@ -3251,7 +1682,7 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const Q_ASSERT(sizeof(T) == sizeof(uint)); else Q_ASSERT(layout.bpp == bpp); - const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout.bpp] : fetchPixel<bpp>; + const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixelTable[layout.bpp] : qFetchPixel<bpp>; if (fdy == 0) { int y1 = (fy >> 16); int y2; @@ -3415,7 +1846,7 @@ static void QT_FASTCALL fetchTransformedBilinear_slow_fetcher(T *buf1, T *buf2, else Q_ASSERT(layout.bpp == bpp); - const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout.bpp] : fetchPixel<bpp>; + const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixelTable[layout.bpp] : qFetchPixel<bpp>; for (int i = 0; i < len; ++i) { const qreal iw = fw == 0 ? 16384 : 1 / fw; diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp index fb50cb6a50..1f6be21f50 100644 --- a/src/gui/painting/qdrawhelper_avx2.cpp +++ b/src/gui/painting/qdrawhelper_avx2.cpp @@ -41,6 +41,7 @@ #include "qdrawhelper_p.h" #include "qdrawhelper_x86_p.h" #include "qdrawingprimitive_sse2_p.h" +#include "qpixellayout_p.h" #include "qrgba64_p.h" #if defined(QT_COMPILER_SUPPORTS_AVX2) diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index 8196a87b24..3cb01ba5ac 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -40,6 +40,7 @@ #include <private/qdrawhelper_neon_p.h> #include <private/qblendfunctions_p.h> #include <private/qmath_p.h> +#include <private/qpixellayout_p.h> #ifdef __ARM_NEON__ diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index f1ad369906..387481a915 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -61,6 +61,7 @@ #define QT_FT_BEGIN_HEADER #define QT_FT_END_HEADER #endif +#include "private/qpixellayout_p.h" #include "private/qrasterdefs_p.h" #include <private/qsimd_p.h> @@ -149,8 +150,6 @@ typedef void (*SrcOverTransformFunc)(uchar *destPixels, int dbpl, const QTransform &targetRectTransform, int const_alpha); -typedef void (*MemRotateFunc)(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl); - struct DrawHelper { ProcessSpans blendColor; BitmapBlitFunc bitmapBlit; @@ -845,31 +844,6 @@ static inline QRgba64 interpolate_4_pixels_rgb64(const QRgba64 t[], const QRgba6 } #endif // __SSE2__ -#if Q_BYTE_ORDER == Q_BIG_ENDIAN -static Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) { - quint32 rgb = x >> 8; - quint32 a = x << 24; - return a | rgb; -} - -static Q_ALWAYS_INLINE quint32 ARGB2RGBA(quint32 x) { - quint32 rgb = x << 8; - quint32 a = x >> 24; - return a | rgb; -} -#else -static Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) { - // RGBA8888 is ABGR32 on little endian. - quint32 ag = x & 0xff00ff00; - quint32 rg = x & 0x00ff00ff; - return ag | (rg << 16) | (rg >> 16); -} - -static Q_ALWAYS_INLINE quint32 ARGB2RGBA(quint32 x) { - return RGBA2ARGB(x); -} -#endif - static Q_ALWAYS_INLINE uint BYTE_MUL_RGB16(uint x, uint a) { a += 1; uint t = (((x & 0x07e0)*a) >> 8) & 0x07e0; @@ -889,14 +863,6 @@ static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_div_257_floor(uint x) { return static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_div_257(uint x) { return qt_div_257_floor(x + 128); } static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_div_65535(uint x) { return (x + (x>>16) + 0x8000U) >> 16; } -static Q_ALWAYS_INLINE uint qAlphaRgb30(uint c) -{ - uint a = c >> 30; - a |= a << 2; - a |= a << 4; - return a; -} - template <class T> inline void qt_memfill_template(T *dest, T color, qsizetype count) { if (!count) @@ -978,214 +944,6 @@ inline QRgb qConvertRgb16To32(uint c) | ((((c) << 8) & 0xf80000) | (((c) << 3) & 0x70000)); } -enum QtPixelOrder { - PixelOrderRGB, - PixelOrderBGR -}; - -template<enum QtPixelOrder> inline uint qConvertArgb32ToA2rgb30(QRgb); - -template<enum QtPixelOrder> inline uint qConvertRgb32ToRgb30(QRgb); - -template<enum QtPixelOrder> inline QRgb qConvertA2rgb30ToArgb32(uint c); - -// A combined unpremultiply and premultiply with new simplified alpha. -// Needed when alpha loses precision relative to other colors during conversion (ARGB32 -> A2RGB30). -template<unsigned int Shift> -inline QRgb qRepremultiply(QRgb p) -{ - const uint alpha = qAlpha(p); - if (alpha == 255 || alpha == 0) - return p; - p = qUnpremultiply(p); - Q_CONSTEXPR uint mult = 255 / (255 >> Shift); - const uint newAlpha = mult * (alpha >> Shift); - p = (p & ~0xff000000) | (newAlpha<<24); - return qPremultiply(p); -} - -template<unsigned int Shift> -inline QRgba64 qRepremultiply(QRgba64 p) -{ - const uint alpha = p.alpha(); - if (alpha == 65535 || alpha == 0) - return p; - p = p.unpremultiplied(); - Q_CONSTEXPR uint mult = 65535 / (65535 >> Shift); - p.setAlpha(mult * (alpha >> Shift)); - return p.premultiplied(); -} - -template<> -inline uint qConvertArgb32ToA2rgb30<PixelOrderBGR>(QRgb c) -{ - c = qRepremultiply<6>(c); - return (c & 0xc0000000) - | (((c << 22) & 0x3fc00000) | ((c << 14) & 0x00300000)) - | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00)) - | (((c >> 14) & 0x000003fc) | ((c >> 22) & 0x00000003)); -} - -template<> -inline uint qConvertArgb32ToA2rgb30<PixelOrderRGB>(QRgb c) -{ - c = qRepremultiply<6>(c); - return (c & 0xc0000000) - | (((c << 6) & 0x3fc00000) | ((c >> 2) & 0x00300000)) - | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00)) - | (((c << 2) & 0x000003fc) | ((c >> 6) & 0x00000003)); -} - -template<> -inline uint qConvertRgb32ToRgb30<PixelOrderBGR>(QRgb c) -{ - return 0xc0000000 - | (((c << 22) & 0x3fc00000) | ((c << 14) & 0x00300000)) - | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00)) - | (((c >> 14) & 0x000003fc) | ((c >> 22) & 0x00000003)); -} - -template<> -inline uint qConvertRgb32ToRgb30<PixelOrderRGB>(QRgb c) -{ - return 0xc0000000 - | (((c << 6) & 0x3fc00000) | ((c >> 2) & 0x00300000)) - | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00)) - | (((c << 2) & 0x000003fc) | ((c >> 6) & 0x00000003)); -} - -template<> -inline QRgb qConvertA2rgb30ToArgb32<PixelOrderBGR>(uint c) -{ - uint a = c >> 30; - a |= a << 2; - a |= a << 4; - return (a << 24) - | ((c << 14) & 0x00ff0000) - | ((c >> 4) & 0x0000ff00) - | ((c >> 22) & 0x000000ff); -} - -template<> -inline QRgb qConvertA2rgb30ToArgb32<PixelOrderRGB>(uint c) -{ - uint a = c >> 30; - a |= a << 2; - a |= a << 4; - return (a << 24) - | ((c >> 6) & 0x00ff0000) - | ((c >> 4) & 0x0000ff00) - | ((c >> 2) & 0x000000ff); -} - -template<enum QtPixelOrder> inline QRgba64 qConvertA2rgb30ToRgb64(uint rgb); - -template<> -inline QRgba64 qConvertA2rgb30ToRgb64<PixelOrderBGR>(uint rgb) -{ - quint16 alpha = rgb >> 30; - quint16 blue = (rgb >> 20) & 0x3ff; - quint16 green = (rgb >> 10) & 0x3ff; - quint16 red = rgb & 0x3ff; - // Expand the range. - alpha |= (alpha << 2); - alpha |= (alpha << 4); - alpha |= (alpha << 8); - red = (red << 6) | (red >> 4); - green = (green << 6) | (green >> 4); - blue = (blue << 6) | (blue >> 4); - return qRgba64(red, green, blue, alpha); -} - -template<> -inline QRgba64 qConvertA2rgb30ToRgb64<PixelOrderRGB>(uint rgb) -{ - quint16 alpha = rgb >> 30; - quint16 red = (rgb >> 20) & 0x3ff; - quint16 green = (rgb >> 10) & 0x3ff; - quint16 blue = rgb & 0x3ff; - // Expand the range. - alpha |= (alpha << 2); - alpha |= (alpha << 4); - alpha |= (alpha << 8); - red = (red << 6) | (red >> 4); - green = (green << 6) | (green >> 4); - blue = (blue << 6) | (blue >> 4); - return qRgba64(red, green, blue, alpha); -} - -template<enum QtPixelOrder> inline unsigned int qConvertRgb64ToRgb30(QRgba64); - -template<> -inline unsigned int qConvertRgb64ToRgb30<PixelOrderBGR>(QRgba64 c) -{ - c = qRepremultiply<14>(c); - const uint a = c.alpha() >> 14; - const uint r = c.red() >> 6; - const uint g = c.green() >> 6; - const uint b = c.blue() >> 6; - return (a << 30) | (b << 20) | (g << 10) | r; -} - -template<> -inline unsigned int qConvertRgb64ToRgb30<PixelOrderRGB>(QRgba64 c) -{ - c = qRepremultiply<14>(c); - const uint a = c.alpha() >> 14; - const uint r = c.red() >> 6; - const uint g = c.green() >> 6; - const uint b = c.blue() >> 6; - return (a << 30) | (r << 20) | (g << 10) | b; -} - -inline uint qRgbSwapRgb30(uint c) -{ - const uint ag = c & 0xc00ffc00; - const uint rb = c & 0x3ff003ff; - return ag | (rb << 20) | (rb >> 20); -} - -inline int qRed565(quint16 rgb) { - const int r = (rgb & 0xf800); - return (r >> 8) | (r >> 13); -} - -inline int qGreen565(quint16 rgb) { - const int g = (rgb & 0x07e0); - return (g >> 3) | (g >> 9); -} - -inline int qBlue565(quint16 rgb) { - const int b = (rgb & 0x001f); - return (b << 3) | (b >> 2); -} - -// We manually unalias the variables to make sure the compiler -// fully optimizes both aliased and unaliased cases. -#define UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion) \ - if (src == buffer) { \ - for (int i = 0; i < count; ++i) \ - buffer[i] = conversion(buffer[i]); \ - } else { \ - for (int i = 0; i < count; ++i) \ - buffer[i] = conversion(src[i]); \ - } - - -static Q_ALWAYS_INLINE const uint *qt_convertARGB32ToARGB32PM(uint *buffer, const uint *src, int count) -{ - UNALIASED_CONVERSION_LOOP(buffer, src, count, qPremultiply); - return buffer; -} - -static Q_ALWAYS_INLINE const uint *qt_convertRGBA8888ToARGB32PM(uint *buffer, const uint *src, int count) -{ - UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint s) { return qPremultiply(RGBA2ARGB(s));}); - return buffer; -} - -template<bool RGBA> void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count); - const uint qt_bayer_matrix[16][16] = { { 0x1, 0xc0, 0x30, 0xf0, 0xc, 0xcc, 0x3c, 0xfc, 0x3, 0xc3, 0x33, 0xf3, 0xf, 0xcf, 0x3f, 0xff}, @@ -1265,60 +1023,69 @@ struct IntermediateBuffer quint32 buffer_ag[BufferSize+2]; }; -struct QDitherInfo { - int x; - int y; -}; - -typedef const uint *(QT_FASTCALL *FetchAndConvertPixelsFunc)(uint *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *clut, QDitherInfo *dither); -typedef void (QT_FASTCALL *ConvertAndStorePixelsFunc)(uchar *dest, const uint *src, int index, int count, - const QVector<QRgb> *clut, QDitherInfo *dither); +template <QPixelLayout::BPP bpp> +inline uint QT_FASTCALL qFetchPixel(const uchar *, int) +{ + Q_UNREACHABLE(); + return 0; +} -typedef const QRgba64 *(QT_FASTCALL *FetchAndConvertPixelsFunc64)(QRgba64 *buffer, const uchar *src, int index, int count, - const QVector<QRgb> *clut, QDitherInfo *dither); -typedef void (QT_FASTCALL *ConvertAndStorePixelsFunc64)(uchar *dest, const QRgba64 *src, int index, int count, - const QVector<QRgb> *clut, QDitherInfo *dither); +template <> +inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP1LSB>(const uchar *src, int index) +{ + return (src[index >> 3] >> (index & 7)) & 1; +} -typedef void (QT_FASTCALL *ConvertFunc)(uint *buffer, int count, const QVector<QRgb> *clut); -typedef void (QT_FASTCALL *Convert64Func)(quint64 *buffer, int count, const QVector<QRgb> *clut); -typedef const QRgba64 *(QT_FASTCALL *ConvertTo64Func)(QRgba64 *buffer, const uint *src, int count, - const QVector<QRgb> *clut, QDitherInfo *dither); -typedef void (QT_FASTCALL *RbSwapFunc)(uchar *dst, const uchar *src, int count); +template <> +inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP1MSB>(const uchar *src, int index) +{ + return (src[index >> 3] >> (~index & 7)) & 1; +} +template <> +inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP8>(const uchar *src, int index) +{ + return src[index]; +} -struct QPixelLayout +template <> +inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP16>(const uchar *src, int index) { - // Bits per pixel - enum BPP { - BPPNone, - BPP1MSB, - BPP1LSB, - BPP8, - BPP16, - BPP24, - BPP32, - BPP64, - BPPCount - }; + return reinterpret_cast<const quint16 *>(src)[index]; +} - bool hasAlphaChannel; - bool premultiplied; - BPP bpp; - RbSwapFunc rbSwap; - ConvertFunc convertToARGB32PM; - ConvertTo64Func convertToRGBA64PM; - FetchAndConvertPixelsFunc fetchToARGB32PM; - FetchAndConvertPixelsFunc64 fetchToRGBA64PM; - ConvertAndStorePixelsFunc storeFromARGB32PM; - ConvertAndStorePixelsFunc storeFromRGB32; -}; +template <> +inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP24>(const uchar *src, int index) +{ + return reinterpret_cast<const quint24 *>(src)[index]; +} -extern ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats]; +template <> +inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP32>(const uchar *src, int index) +{ + return reinterpret_cast<const uint *>(src)[index]; +} -extern QPixelLayout qPixelLayouts[QImage::NImageFormats]; +template <> +inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP64>(const uchar *src, int index) +{ + // We have to do the conversion in fetch to fit into a 32bit uint + QRgba64 c = reinterpret_cast<const QRgba64 *>(src)[index]; + return c.toArgb32(); +} -extern MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3]; +typedef uint (QT_FASTCALL *FetchPixelFunc)(const uchar *src, int index); + +constexpr FetchPixelFunc qFetchPixelTable[QPixelLayout::BPPCount] = { + nullptr, // BPPNone + qFetchPixel<QPixelLayout::BPP1MSB>, + qFetchPixel<QPixelLayout::BPP1LSB>, + qFetchPixel<QPixelLayout::BPP8>, + qFetchPixel<QPixelLayout::BPP16>, + qFetchPixel<QPixelLayout::BPP24>, + qFetchPixel<QPixelLayout::BPP32>, + qFetchPixel<QPixelLayout::BPP64>, +}; QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper_sse4.cpp b/src/gui/painting/qdrawhelper_sse4.cpp index 68d887ae6d..5b71d33043 100644 --- a/src/gui/painting/qdrawhelper_sse4.cpp +++ b/src/gui/painting/qdrawhelper_sse4.cpp @@ -40,6 +40,7 @@ #include <private/qdrawhelper_p.h> #include <private/qdrawingprimitive_sse2_p.h> #include <private/qpaintengine_raster_p.h> +#include <private/qpixellayout_p.h> #if defined(QT_COMPILER_SUPPORTS_SSE4_1) diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp index 685fbbb37a..5c04bcb795 100644 --- a/src/gui/painting/qmemrotate.cpp +++ b/src/gui/painting/qmemrotate.cpp @@ -37,7 +37,8 @@ ** ****************************************************************************/ -#include "private/qmemrotate_p.h" +#include "qmemrotate_p.h" +#include "qpixellayout_p.h" QT_BEGIN_NAMESPACE diff --git a/src/gui/painting/qmemrotate_p.h b/src/gui/painting/qmemrotate_p.h index 677fd57af9..1b25655b68 100644 --- a/src/gui/painting/qmemrotate_p.h +++ b/src/gui/painting/qmemrotate_p.h @@ -52,7 +52,7 @@ // #include <QtGui/private/qtguiglobal_p.h> -#include "private/qdrawhelper_p.h" +#include <QtGui/private/qdrawhelper_p.h> QT_BEGIN_NAMESPACE diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 6360f32682..13a6f5c16a 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -62,8 +62,10 @@ #include <private/qimage_p.h> #include <private/qstatictext_p.h> #include <private/qcosmeticstroker_p.h> -#include "qmemrotate_p.h" -#include "qrgba64_p.h" +#include <private/qdrawhelper_p.h> +#include <private/qmemrotate_p.h> +#include <private/qpixellayout_p.h> +#include <private/qrgba64_p.h> #include "qpaintengine_raster_p.h" // #include "qbezier_p.h" diff --git a/src/gui/painting/qpixellayout.cpp b/src/gui/painting/qpixellayout.cpp new file mode 100644 index 0000000000..d0fb8f0bb4 --- /dev/null +++ b/src/gui/painting/qpixellayout.cpp @@ -0,0 +1,1545 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qglobal.h> + +#include "qdrawhelper_p.h" +#include "qpixellayout_p.h" +#include "qrgba64_p.h" +#include <QtCore/private/qsimd_p.h> + +QT_BEGIN_NAMESPACE + +template<QImage::Format> Q_DECL_CONSTEXPR uint redWidth(); +template<QImage::Format> Q_DECL_CONSTEXPR uint redShift(); +template<QImage::Format> Q_DECL_CONSTEXPR uint greenWidth(); +template<QImage::Format> Q_DECL_CONSTEXPR uint greenShift(); +template<QImage::Format> Q_DECL_CONSTEXPR uint blueWidth(); +template<QImage::Format> Q_DECL_CONSTEXPR uint blueShift(); +template<QImage::Format> Q_DECL_CONSTEXPR uint alphaWidth(); +template<QImage::Format> Q_DECL_CONSTEXPR uint alphaShift(); + +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB16>() { return 5; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB444>() { return 4; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB555>() { return 5; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB666>() { return 6; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_BGR888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBX8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBA8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; } + +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB16>() { return 11; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB444>() { return 8; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB555>() { return 10; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB666>() { return 12; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB888>() { return 16; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_BGR888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB4444_Premultiplied>() { return 8; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8555_Premultiplied>() { return 18; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8565_Premultiplied>() { return 19; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB6666_Premultiplied>() { return 12; } +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBX8888>() { return 24; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888>() { return 24; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; } +#else +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBX8888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; } +#endif +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB16>() { return 6; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB444>() { return 4; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB555>() { return 5; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB666>() { return 6; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_BGR888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8565_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBX8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBA8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; } + +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB16>() { return 5; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB444>() { return 4; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB555>() { return 5; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB666>() { return 6; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_BGR888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB4444_Premultiplied>() { return 4; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8555_Premultiplied>() { return 13; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8565_Premultiplied>() { return 13; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBX8888>() { return 16; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888>() { return 16; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; } +#else +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBX8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; } +#endif +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB16>() { return 5; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB444>() { return 4; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB555>() { return 5; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB666>() { return 6; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_BGR888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBX8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBA8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; } + +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB16>() { return 0; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB444>() { return 0; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB555>() { return 0; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB666>() { return 0; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_BGR888>() { return 16; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB4444_Premultiplied>() { return 0; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8555_Premultiplied>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8565_Premultiplied>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB6666_Premultiplied>() { return 0; } +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBX8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; } +#else +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBX8888>() { return 16; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888>() { return 16; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; } +#endif +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB16>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB444>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB555>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB666>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_BGR888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8555_Premultiplied>() { return 8; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8565_Premultiplied>() { return 8; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBX8888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBA8888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; } + +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB16>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB444>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB555>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB666>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_BGR888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB4444_Premultiplied>() { return 12; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8555_Premultiplied>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8565_Premultiplied>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB6666_Premultiplied>() { return 18; } +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBX8888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; } +#else +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBX8888>() { return 24; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888>() { return 24; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; } +#endif + +template<QImage::Format> constexpr QPixelLayout::BPP bitsPerPixel(); +template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB16>() { return QPixelLayout::BPP16; } +template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB444>() { return QPixelLayout::BPP16; } +template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB555>() { return QPixelLayout::BPP16; } +template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB666>() { return QPixelLayout::BPP24; } +template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB888>() { return QPixelLayout::BPP24; } +template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_BGR888>() { return QPixelLayout::BPP24; } +template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB4444_Premultiplied>() { return QPixelLayout::BPP16; } +template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8555_Premultiplied>() { return QPixelLayout::BPP24; } +template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8565_Premultiplied>() { return QPixelLayout::BPP24; } +template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB6666_Premultiplied>() { return QPixelLayout::BPP24; } +template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBX8888>() { return QPixelLayout::BPP32; } +template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888>() { return QPixelLayout::BPP32; } +template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888_Premultiplied>() { return QPixelLayout::BPP32; } + +template <QPixelLayout::BPP width> static +void QT_FASTCALL storePixel(uchar *dest, int index, uint pixel); + +template <> +inline void QT_FASTCALL storePixel<QPixelLayout::BPP16>(uchar *dest, int index, uint pixel) +{ + reinterpret_cast<quint16 *>(dest)[index] = quint16(pixel); +} + +template <> +inline void QT_FASTCALL storePixel<QPixelLayout::BPP24>(uchar *dest, int index, uint pixel) +{ + reinterpret_cast<quint24 *>(dest)[index] = quint24(pixel); +} + +template<QImage::Format Format> +static Q_ALWAYS_INLINE uint convertPixelToRGB32(uint s) +{ + Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); + + Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>(); + Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>(); + Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>(); + + Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8; + Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8; + Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8; + + uint red = (s >> redShift<Format>()) & redMask; + uint green = (s >> greenShift<Format>()) & greenMask; + uint blue = (s >> blueShift<Format>()) & blueMask; + + red = ((red << redLeftShift) | (red >> redRightShift)) << 16; + green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8; + blue = (blue << blueLeftShift) | (blue >> blueRightShift); + return 0xff000000 | red | green | blue; +} + +template<QImage::Format Format> +static void QT_FASTCALL convertToRGB32(uint *buffer, int count, const QVector<QRgb> *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = convertPixelToRGB32<Format>(buffer[i]); +} + +#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3 +extern const uint * QT_FASTCALL fetchPixelsBPP24_ssse3(uint *dest, const uchar*src, int index, int count); +#endif + +template<QImage::Format Format> +static const uint *QT_FASTCALL fetchRGBToRGB32(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>(); +#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3 + if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) { + // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3 + // to vectorize the deforested version below. + fetchPixelsBPP24_ssse3(buffer, src, index, count); + convertToRGB32<Format>(buffer, count, nullptr); + return buffer; + } +#endif + for (int i = 0; i < count; ++i) + buffer[i] = convertPixelToRGB32<Format>(qFetchPixel<BPP>(src, index + i)); + return buffer; +} + +template<QImage::Format Format> +static Q_ALWAYS_INLINE QRgba64 convertPixelToRGB64(uint s) +{ + return QRgba64::fromArgb32(convertPixelToRGB32<Format>(s)); +} + +template<QImage::Format Format> +static const QRgba64 *QT_FASTCALL convertToRGB64(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = convertPixelToRGB64<Format>(src[i]); + return buffer; +} + +template<QImage::Format Format> +static const QRgba64 *QT_FASTCALL fetchRGBToRGB64(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = convertPixelToRGB64<Format>(qFetchPixel<bitsPerPixel<Format>()>(src, index + i)); + return buffer; +} + +template<QImage::Format Format> +static Q_ALWAYS_INLINE uint convertPixelToARGB32PM(uint s) +{ + Q_CONSTEXPR uint alphaMask = ((1 << alphaWidth<Format>()) - 1); + Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); + + Q_CONSTEXPR uchar alphaLeftShift = 8 - alphaWidth<Format>(); + Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>(); + Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>(); + Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>(); + + Q_CONSTEXPR uchar alphaRightShift = 2 * alphaWidth<Format>() - 8; + Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8; + Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8; + Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8; + + Q_CONSTEXPR bool mustMin = (alphaWidth<Format>() != redWidth<Format>()) || + (alphaWidth<Format>() != greenWidth<Format>()) || + (alphaWidth<Format>() != blueWidth<Format>()); + + uint alpha = (s >> alphaShift<Format>()) & alphaMask; + uint red = (s >> redShift<Format>()) & redMask; + uint green = (s >> greenShift<Format>()) & greenMask; + uint blue = (s >> blueShift<Format>()) & blueMask; + + alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift); + red = (red << redLeftShift) | (red >> redRightShift); + green = (green << greenLeftShift) | (green >> greenRightShift); + blue = (blue << blueLeftShift) | (blue >> blueRightShift); + + if (mustMin) { + red = qMin(alpha, red); + green = qMin(alpha, green); + blue = qMin(alpha, blue); + } + + return (alpha << 24) | (red << 16) | (green << 8) | blue; +} + +template<QImage::Format Format> +static void QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, int count, const QVector<QRgb> *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = convertPixelToARGB32PM<Format>(buffer[i]); +} + +template<QImage::Format Format> +static const uint *QT_FASTCALL fetchARGBPMToARGB32PM(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>(); +#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3 + if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) { + // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3 + // to vectorize the deforested version below. + fetchPixelsBPP24_ssse3(buffer, src, index, count); + convertARGBPMToARGB32PM<Format>(buffer, count, nullptr); + return buffer; + } +#endif + for (int i = 0; i < count; ++i) + buffer[i] = convertPixelToARGB32PM<Format>(qFetchPixel<BPP>(src, index + i)); + return buffer; +} + +template<QImage::Format Format> +static Q_ALWAYS_INLINE QRgba64 convertPixelToRGBA64PM(uint s) +{ + return QRgba64::fromArgb32(convertPixelToARGB32PM<Format>(s)); +} + +template<QImage::Format Format> +static const QRgba64 *QT_FASTCALL convertARGBPMToRGBA64PM(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = convertPixelToRGB64<Format>(src[i]); + return buffer; +} + +template<QImage::Format Format> +static const QRgba64 *QT_FASTCALL fetchARGBPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>(); + for (int i = 0; i < count; ++i) + buffer[i] = convertPixelToRGBA64PM<Format>(qFetchPixel<bpp>(src, index + i)); + return buffer; +} + +template<QImage::Format Format, bool fromRGB> +static void QT_FASTCALL storeRGBFromARGB32PM(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *dither) +{ + Q_CONSTEXPR uchar rWidth = redWidth<Format>(); + Q_CONSTEXPR uchar gWidth = greenWidth<Format>(); + Q_CONSTEXPR uchar bWidth = blueWidth<Format>(); + constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>(); + + // RGB32 -> RGB888 is not a precision loss. + if (!dither || (rWidth == 8 && gWidth == 8 && bWidth == 8)) { + Q_CONSTEXPR uint rMask = (1 << redWidth<Format>()) - 1; + Q_CONSTEXPR uint gMask = (1 << greenWidth<Format>()) - 1; + Q_CONSTEXPR uint bMask = (1 << blueWidth<Format>()) - 1; + Q_CONSTEXPR uchar rRightShift = 24 - redWidth<Format>(); + Q_CONSTEXPR uchar gRightShift = 16 - greenWidth<Format>(); + Q_CONSTEXPR uchar bRightShift = 8 - blueWidth<Format>(); + + for (int i = 0; i < count; ++i) { + const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]); + const uint r = ((c >> rRightShift) & rMask) << redShift<Format>(); + const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>(); + const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>(); + storePixel<BPP>(dest, index + i, r | g | b); + }; + } else { + // We do ordered dither by using a rounding conversion, but instead of + // adding half of input precision, we add the adjusted result from the + // bayer matrix before narrowing. + // Note: Rounding conversion in itself is different from the naive + // conversion we do above for non-dithering. + const uint *bayer_line = qt_bayer_matrix[dither->y & 15]; + for (int i = 0; i < count; ++i) { + const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]); + const int d = bayer_line[(dither->x + i) & 15]; + const int dr = d - ((d + 1) >> rWidth); + const int dg = d - ((d + 1) >> gWidth); + const int db = d - ((d + 1) >> bWidth); + int r = qRed(c); + int g = qGreen(c); + int b = qBlue(c); + r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth); + g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth); + b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth); + const uint s = (r << redShift<Format>()) + | (g << greenShift<Format>()) + | (b << blueShift<Format>()); + storePixel<BPP>(dest, index + i, s); + } + } +} + +template<QImage::Format Format, bool fromRGB> +static void QT_FASTCALL storeARGBPMFromARGB32PM(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *dither) +{ + constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>(); + if (!dither) { + Q_CONSTEXPR uint aMask = (1 << alphaWidth<Format>()) - 1; + Q_CONSTEXPR uint rMask = (1 << redWidth<Format>()) - 1; + Q_CONSTEXPR uint gMask = (1 << greenWidth<Format>()) - 1; + Q_CONSTEXPR uint bMask = (1 << blueWidth<Format>()) - 1; + + Q_CONSTEXPR uchar aRightShift = 32 - alphaWidth<Format>(); + Q_CONSTEXPR uchar rRightShift = 24 - redWidth<Format>(); + Q_CONSTEXPR uchar gRightShift = 16 - greenWidth<Format>(); + Q_CONSTEXPR uchar bRightShift = 8 - blueWidth<Format>(); + + Q_CONSTEXPR uint aOpaque = aMask << alphaShift<Format>(); + for (int i = 0; i < count; ++i) { + const uint c = src[i]; + const uint a = fromRGB ? aOpaque : (((c >> aRightShift) & aMask) << alphaShift<Format>()); + const uint r = ((c >> rRightShift) & rMask) << redShift<Format>(); + const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>(); + const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>(); + storePixel<BPP>(dest, index + i, a | r | g | b); + }; + } else { + Q_CONSTEXPR uchar aWidth = alphaWidth<Format>(); + Q_CONSTEXPR uchar rWidth = redWidth<Format>(); + Q_CONSTEXPR uchar gWidth = greenWidth<Format>(); + Q_CONSTEXPR uchar bWidth = blueWidth<Format>(); + + const uint *bayer_line = qt_bayer_matrix[dither->y & 15]; + for (int i = 0; i < count; ++i) { + const uint c = src[i]; + const int d = bayer_line[(dither->x + i) & 15]; + const int da = d - ((d + 1) >> aWidth); + const int dr = d - ((d + 1) >> rWidth); + const int dg = d - ((d + 1) >> gWidth); + const int db = d - ((d + 1) >> bWidth); + int a = qAlpha(c); + int r = qRed(c); + int g = qGreen(c); + int b = qBlue(c); + if (fromRGB) + a = (1 << aWidth) - 1; + else + a = (a + ((da - a) >> aWidth) + 1) >> (8 - aWidth); + r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth); + g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth); + b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth); + uint s = (a << alphaShift<Format>()) + | (r << redShift<Format>()) + | (g << greenShift<Format>()) + | (b << blueShift<Format>()); + storePixel<BPP>(dest, index + i, s); + } + } +} + +template<QImage::Format Format> +static void QT_FASTCALL rbSwap(uchar *dst, const uchar *src, int count) +{ + Q_CONSTEXPR uchar aWidth = alphaWidth<Format>(); + Q_CONSTEXPR uchar aShift = alphaShift<Format>(); + Q_CONSTEXPR uchar rWidth = redWidth<Format>(); + Q_CONSTEXPR uchar rShift = redShift<Format>(); + Q_CONSTEXPR uchar gWidth = greenWidth<Format>(); + Q_CONSTEXPR uchar gShift = greenShift<Format>(); + Q_CONSTEXPR uchar bWidth = blueWidth<Format>(); + Q_CONSTEXPR uchar bShift = blueShift<Format>(); +#ifdef Q_COMPILER_CONSTEXPR + Q_STATIC_ASSERT(rWidth == bWidth); +#endif + Q_CONSTEXPR uint redBlueMask = (1 << rWidth) - 1; + Q_CONSTEXPR uint alphaGreenMask = (((1 << aWidth) - 1) << aShift) + | (((1 << gWidth) - 1) << gShift); + constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>(); + + for (int i = 0; i < count; ++i) { + const uint c = qFetchPixel<bpp>(src, i); + const uint r = (c >> rShift) & redBlueMask; + const uint b = (c >> bShift) & redBlueMask; + const uint t = (c & alphaGreenMask) + | (r << bShift) + | (b << rShift); + storePixel<bpp>(dst, i, t); + } +} + +static void QT_FASTCALL rbSwap_rgb32(uchar *d, const uchar *s, int count) +{ + const uint *src = reinterpret_cast<const uint *>(s); + uint *dest = reinterpret_cast<uint *>(d); + for (int i = 0; i < count; ++i) { + const uint c = src[i]; + const uint ag = c & 0xff00ff00; + const uint rb = c & 0x00ff00ff; + dest[i] = ag | (rb << 16) | (rb >> 16); + } +} + +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN +template<> +void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count) +{ + return rbSwap_rgb32(d, s, count); +} +#else +template<> +void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count) +{ + const uint *src = reinterpret_cast<const uint *>(s); + uint *dest = reinterpret_cast<uint *>(d); + for (int i = 0; i < count; ++i) { + const uint c = src[i]; + const uint rb = c & 0xff00ff00; + const uint ga = c & 0x00ff00ff; + dest[i] = ga | (rb << 16) | (rb >> 16); + } +} +#endif + +static void QT_FASTCALL rbSwap_rgb30(uchar *d, const uchar *s, int count) +{ + const uint *src = reinterpret_cast<const uint *>(s); + uint *dest = reinterpret_cast<uint *>(d); + UNALIASED_CONVERSION_LOOP(dest, src, count, qRgbSwapRgb30); +} + +template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutRGB() +{ + return QPixelLayout{ + false, + false, + bitsPerPixel<Format>(), + rbSwap<Format>, + convertToRGB32<Format>, + convertToRGB64<Format>, + fetchRGBToRGB32<Format>, + fetchRGBToRGB64<Format>, + storeRGBFromARGB32PM<Format, false>, + storeRGBFromARGB32PM<Format, true> + }; +} + +template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutARGBPM() +{ + return QPixelLayout{ + true, + true, + bitsPerPixel<Format>(), + rbSwap<Format>, + convertARGBPMToARGB32PM<Format>, + convertARGBPMToRGBA64PM<Format>, + fetchARGBPMToARGB32PM<Format>, + fetchARGBPMToRGBA64PM<Format>, + storeARGBPMFromARGB32PM<Format, false>, + storeARGBPMFromARGB32PM<Format, true> + }; +} + +static void QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, int count, const QVector<QRgb> *clut) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qPremultiply(clut->at(buffer[i])); +} + +template<QPixelLayout::BPP BPP> +static const uint *QT_FASTCALL fetchIndexedToARGB32PM(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *clut, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) { + const uint s = qFetchPixel<BPP>(src, index + i); + buffer[i] = qPremultiply(clut->at(s)); + } + return buffer; +} + +template<QPixelLayout::BPP BPP> +static const QRgba64 *QT_FASTCALL fetchIndexedToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *clut, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) { + const uint s = qFetchPixel<BPP>(src, index + i); + buffer[i] = QRgba64::fromArgb32(clut->at(s)).premultiplied(); + } + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertIndexedToRGBA64PM(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *clut, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(clut->at(src[i])).premultiplied(); + return buffer; +} + +static void QT_FASTCALL convertPassThrough(uint *, int, const QVector<QRgb> *) +{ +} + +static const uint *QT_FASTCALL fetchPassThrough(uint *, const uchar *src, int index, int, + const QVector<QRgb> *, QDitherInfo *) +{ + return reinterpret_cast<const uint *>(src) + index; +} + +static const QRgba64 *QT_FASTCALL fetchPassThrough64(QRgba64 *, const uchar *src, int index, int, + const QVector<QRgb> *, QDitherInfo *) +{ + return reinterpret_cast<const QRgba64 *>(src) + index; +} + +static void QT_FASTCALL storePassThrough(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + if (d != src) + memcpy(d, src, count * sizeof(uint)); +} + +static void QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, int count, const QVector<QRgb> *) +{ + qt_convertARGB32ToARGB32PM(buffer, buffer, count); +} + +static const uint *QT_FASTCALL fetchARGB32ToARGB32PM(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + return qt_convertARGB32ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count); +} + +static void QT_FASTCALL convertRGBA8888PMToARGB32PM(uint *buffer, int count, const QVector<QRgb> *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = RGBA2ARGB(buffer[i]); +} + +static const uint *QT_FASTCALL fetchRGBA8888PMToARGB32PM(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + const uint *s = reinterpret_cast<const uint *>(src) + index; + UNALIASED_CONVERSION_LOOP(buffer, s, count, RGBA2ARGB); + return buffer; +} + +static void QT_FASTCALL convertRGBA8888ToARGB32PM(uint *buffer, int count, const QVector<QRgb> *) +{ + qt_convertRGBA8888ToARGB32PM(buffer, buffer, count); +} + +static const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + return qt_convertRGBA8888ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count); +} + +static void QT_FASTCALL convertAlpha8ToRGB32(uint *buffer, int count, const QVector<QRgb> *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qRgba(0, 0, 0, buffer[i]); +} + +static const uint *QT_FASTCALL fetchAlpha8ToRGB32(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qRgba(0, 0, 0, src[index + i]); + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertAlpha8ToRGB64(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromRgba(0, 0, 0, src[i]); + return buffer; +} +static const QRgba64 *QT_FASTCALL fetchAlpha8ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromRgba(0, 0, 0, src[index + i]); + return buffer; +} + +static void QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, int count, const QVector<QRgb> *) +{ + for (int i = 0; i < count; ++i) { + const uint s = buffer[i]; + buffer[i] = qRgb(s, s, s); + } +} + +static const uint *QT_FASTCALL fetchGrayscale8ToRGB32(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) { + const uint s = src[index + i]; + buffer[i] = qRgb(s, s, s); + } + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertGrayscale8ToRGB64(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromRgba(src[i], src[i], src[i], 255); + return buffer; +} + +static const QRgba64 *QT_FASTCALL fetchGrayscale8ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) { + const uint s = src[index + i]; + buffer[i] = QRgba64::fromRgba(s, s, s, 255); + } + 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 *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return qUnpremultiply(c); }); +} + +static void QT_FASTCALL storeRGBA8888PMFromARGB32PM(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + UNALIASED_CONVERSION_LOOP(d, src, count, ARGB2RGBA); +} + +#ifdef __SSE2__ +template<bool RGBA, bool maskAlpha> +static inline void qConvertARGB32PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count) +{ + if (count <= 0) + return; + + const __m128i amask = _mm_set1_epi32(0xff000000); + int i = 0; + for (; ((uintptr_t)buffer & 0xf) && i < count; ++i) { + uint s = *src++; + if (maskAlpha) + s = s | 0xff000000; + if (RGBA) + s = RGBA2ARGB(s); + *buffer++ = QRgba64::fromArgb32(s); + } + for (; i < count-3; i += 4) { + __m128i vs = _mm_loadu_si128((const __m128i*)src); + if (maskAlpha) + vs = _mm_or_si128(vs, amask); + src += 4; + __m128i v1 = _mm_unpacklo_epi8(vs, vs); + __m128i v2 = _mm_unpackhi_epi8(vs, vs); + if (!RGBA) { + v1 = _mm_shufflelo_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2)); + v2 = _mm_shufflelo_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2)); + v1 = _mm_shufflehi_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2)); + v2 = _mm_shufflehi_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2)); + } + _mm_store_si128((__m128i*)(buffer), v1); + buffer += 2; + _mm_store_si128((__m128i*)(buffer), v2); + buffer += 2; + } + + SIMD_EPILOGUE(i, count, 3) { + uint s = *src++; + if (maskAlpha) + s = s | 0xff000000; + if (RGBA) + s = RGBA2ARGB(s); + *buffer++ = QRgba64::fromArgb32(s); + } +} + +template<QtPixelOrder PixelOrder> +static inline void qConvertRGBA64PMToA2RGB30PM_sse2(uint *dest, const QRgba64 *buffer, int count) +{ + const __m128i gmask = _mm_set1_epi32(0x000ffc00); + const __m128i cmask = _mm_set1_epi32(0x000003ff); + int i = 0; + __m128i vr, vg, vb, va; + for (; i < count && uintptr_t(buffer) & 0xF; ++i) { + *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++); + } + + for (; i < count-15; i += 16) { + // Repremultiplying is really expensive and hard to do in SIMD without AVX2, + // so we try to avoid it by checking if it is needed 16 samples at a time. + __m128i vOr = _mm_set1_epi32(0); + __m128i vAnd = _mm_set1_epi32(0xffffffff); + for (int j = 0; j < 16; j += 2) { + __m128i vs = _mm_load_si128((const __m128i*)(buffer + j)); + vOr = _mm_or_si128(vOr, vs); + vAnd = _mm_and_si128(vAnd, vs); + } + const quint16 orAlpha = ((uint)_mm_extract_epi16(vOr, 3)) | ((uint)_mm_extract_epi16(vOr, 7)); + const quint16 andAlpha = ((uint)_mm_extract_epi16(vAnd, 3)) & ((uint)_mm_extract_epi16(vAnd, 7)); + + if (andAlpha == 0xffff) { + for (int j = 0; j < 16; j += 2) { + __m128i vs = _mm_load_si128((const __m128i*)buffer); + buffer += 2; + vr = _mm_srli_epi64(vs, 6); + vg = _mm_srli_epi64(vs, 16 + 6 - 10); + vb = _mm_srli_epi64(vs, 32 + 6); + vr = _mm_and_si128(vr, cmask); + vg = _mm_and_si128(vg, gmask); + vb = _mm_and_si128(vb, cmask); + va = _mm_srli_epi64(vs, 48 + 14); + if (PixelOrder == PixelOrderRGB) + vr = _mm_slli_epi32(vr, 20); + else + vb = _mm_slli_epi32(vb, 20); + va = _mm_slli_epi32(va, 30); + __m128i vd = _mm_or_si128(_mm_or_si128(vr, vg), _mm_or_si128(vb, va)); + vd = _mm_shuffle_epi32(vd, _MM_SHUFFLE(3, 1, 2, 0)); + _mm_storel_epi64((__m128i*)dest, vd); + dest += 2; + } + } else if (orAlpha == 0) { + for (int j = 0; j < 16; ++j) { + *dest++ = 0; + buffer++; + } + } else { + for (int j = 0; j < 16; ++j) + *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++); + } + } + + SIMD_EPILOGUE(i, count, 15) + *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++); +} +#elif defined(__ARM_NEON__) +template<bool RGBA, bool maskAlpha> +static inline void qConvertARGB32PMToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count) +{ + if (count <= 0) + return; + + const uint32x4_t amask = vdupq_n_u32(0xff000000); +#if defined(Q_PROCESSOR_ARM_64) + const uint8x16_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15}; +#else + const uint8x8_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7 }; +#endif + int i = 0; + for (; i < count-3; i += 4) { + uint32x4_t vs32 = vld1q_u32(src); + src += 4; + if (maskAlpha) + vs32 = vorrq_u32(vs32, amask); + uint8x16_t vs8 = vreinterpretq_u8_u32(vs32); + if (!RGBA) { +#if defined(Q_PROCESSOR_ARM_64) + vs8 = vqtbl1q_u8(vs8, rgbaMask); +#else + // no vqtbl1q_u8 + const uint8x8_t vlo = vtbl1_u8(vget_low_u8(vs8), rgbaMask); + const uint8x8_t vhi = vtbl1_u8(vget_high_u8(vs8), rgbaMask); + vs8 = vcombine_u8(vlo, vhi); +#endif + } + uint8x16x2_t v = vzipq_u8(vs8, vs8); + + vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[0])); + buffer += 2; + vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[1])); + buffer += 2; + } + + SIMD_EPILOGUE(i, count, 3) { + uint s = *src++; + if (maskAlpha) + s = s | 0xff000000; + if (RGBA) + s = RGBA2ARGB(s); + *buffer++ = QRgba64::fromArgb32(s); + } +} +#endif + +static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToRGBA64PM_sse2<false, true>(buffer, src, count); +#elif defined(__ARM_NEON__) + qConvertARGB32PMToRGBA64PM_neon<false, true>(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(0xff000000 | src[i]); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL fetchRGB32ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + return convertRGB32ToRGB64(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); +} + +static const QRgba64 *QT_FASTCALL convertARGB32ToRGBA64PM(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied(); + return buffer; +} + +static const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + return convertARGB32ToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); +} + +static const QRgba64 *QT_FASTCALL convertARGB32PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToRGBA64PM_sse2<false, false>(buffer, src, count); +#elif defined(__ARM_NEON__) + qConvertARGB32PMToRGBA64PM_neon<false, false>(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(src[i]); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL fetchARGB32PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + return convertARGB32PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); +} + +static const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index; + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromRgba64(s[i]).premultiplied(); + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertRGBA8888ToRGBA64PM(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied(); + return buffer; +} + +static const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + return convertRGBA8888ToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); +} + +static const QRgba64 *QT_FASTCALL convertRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToRGBA64PM_sse2<true, false>(buffer, src, count); +#elif defined(__ARM_NEON__) + qConvertARGB32PMToRGBA64PM_neon<true, false>(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL fetchRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + return convertRGBA8888PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); +} + +static void QT_FASTCALL storeRGBA8888FromARGB32PM(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(qUnpremultiply(c)); }); +} + +static void QT_FASTCALL storeRGBXFromRGB32(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | c); }); +} + +static void QT_FASTCALL storeRGBXFromARGB32PM(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | qUnpremultiply(c)); }); +} + +template<QtPixelOrder PixelOrder> +static void QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, int count, const QVector<QRgb> *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qConvertA2rgb30ToArgb32<PixelOrder>(buffer[i]); +} + +template<QtPixelOrder PixelOrder> +static const uint *QT_FASTCALL fetchA2RGB30PMToARGB32PM(uint *buffer, const uchar *s, int index, int count, + const QVector<QRgb> *, QDitherInfo *dither) +{ + const uint *src = reinterpret_cast<const uint *>(s) + index; + if (!dither) { + UNALIASED_CONVERSION_LOOP(buffer, src, count, qConvertA2rgb30ToArgb32<PixelOrder>); + } else { + for (int i = 0; i < count; ++i) { + const uint c = src[i]; + short d10 = (qt_bayer_matrix[dither->y & 15][(dither->x + i) & 15] << 2); + short a10 = (c >> 30) * 0x155; + short r10 = ((c >> 20) & 0x3ff); + short g10 = ((c >> 10) & 0x3ff); + short b10 = (c & 0x3ff); + if (PixelOrder == PixelOrderBGR) + std::swap(r10, b10); + short a8 = (a10 + ((d10 - a10) >> 8)) >> 2; + short r8 = (r10 + ((d10 - r10) >> 8)) >> 2; + short g8 = (g10 + ((d10 - g10) >> 8)) >> 2; + short b8 = (b10 + ((d10 - b10) >> 8)) >> 2; + buffer[i] = qRgba(r8, g8, b8, a8); + } + } + return buffer; +} + +#ifdef __SSE2__ +template<QtPixelOrder PixelOrder> +static inline void qConvertA2RGB30PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count) +{ + if (count <= 0) + return; + + const __m128i rmask = _mm_set1_epi32(0x3ff00000); + const __m128i gmask = _mm_set1_epi32(0x000ffc00); + const __m128i bmask = _mm_set1_epi32(0x000003ff); + const __m128i afactor = _mm_set1_epi16(0x5555); + int i = 0; + + for (; ((uintptr_t)buffer & 0xf) && i < count; ++i) + *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++); + + for (; i < count-3; i += 4) { + __m128i vs = _mm_loadu_si128((const __m128i*)src); + src += 4; + __m128i va = _mm_srli_epi32(vs, 30); + __m128i vr = _mm_and_si128(vs, rmask); + __m128i vb = _mm_and_si128(vs, bmask); + __m128i vg = _mm_and_si128(vs, gmask); + va = _mm_mullo_epi16(va, afactor); + vr = _mm_or_si128(_mm_srli_epi32(vr, 14), _mm_srli_epi32(vr, 24)); + vg = _mm_or_si128(_mm_srli_epi32(vg, 4), _mm_srli_epi32(vg, 14)); + vb = _mm_or_si128(_mm_slli_epi32(vb, 6), _mm_srli_epi32(vb, 4)); + __m128i vrb; + if (PixelOrder == PixelOrderRGB) + vrb = _mm_or_si128(vr, _mm_slli_si128(vb, 2)); + else + vrb = _mm_or_si128(vb, _mm_slli_si128(vr, 2)); + __m128i vga = _mm_or_si128(vg, _mm_slli_si128(va, 2)); + _mm_store_si128((__m128i*)(buffer), _mm_unpacklo_epi16(vrb, vga)); + buffer += 2; + _mm_store_si128((__m128i*)(buffer), _mm_unpackhi_epi16(vrb, vga)); + buffer += 2; + } + + SIMD_EPILOGUE(i, count, 3) + *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++); +} +#endif + +template<QtPixelOrder PixelOrder> +static const QRgba64 *QT_FASTCALL convertA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *) +{ +#ifdef __SSE2__ + qConvertA2RGB30PMToRGBA64PM_sse2<PixelOrder>(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]); +#endif + return buffer; +} + +template<QtPixelOrder PixelOrder> +static const QRgba64 *QT_FASTCALL fetchA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + return convertA2RGB30PMToRGBA64PM<PixelOrder>(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); +} + +template<QtPixelOrder PixelOrder> +static void QT_FASTCALL storeA2RGB30PMFromARGB32PM(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + UNALIASED_CONVERSION_LOOP(d, src, count, qConvertArgb32ToA2rgb30<PixelOrder>); +} + +template<QtPixelOrder PixelOrder> +static void QT_FASTCALL storeRGB30FromRGB32(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>); +} + +template<QtPixelOrder PixelOrder> +static void QT_FASTCALL storeRGB30FromARGB32PM(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>); +} + +template<bool RGBA> +void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count) +{ + int i = 0; +#ifdef __SSE2__ + if (((uintptr_t)dst & 0x7) && count > 0) { + uint s = (*src++).toArgb32(); + if (RGBA) + s = ARGB2RGBA(s); + *dst++ = s; + i++; + } + const __m128i vhalf = _mm_set1_epi32(0x80); + const __m128i vzero = _mm_setzero_si128(); + for (; i < count-1; i += 2) { + __m128i vs = _mm_loadu_si128((const __m128i*)src); + src += 2; + if (!RGBA) { + vs = _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2)); + vs = _mm_shufflehi_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2)); + } + __m128i v1 = _mm_unpacklo_epi16(vs, vzero); + __m128i v2 = _mm_unpackhi_epi16(vs, vzero); + v1 = _mm_add_epi32(v1, vhalf); + v2 = _mm_add_epi32(v2, vhalf); + v1 = _mm_sub_epi32(v1, _mm_srli_epi32(v1, 8)); + v2 = _mm_sub_epi32(v2, _mm_srli_epi32(v2, 8)); + v1 = _mm_srli_epi32(v1, 8); + v2 = _mm_srli_epi32(v2, 8); + v1 = _mm_packs_epi32(v1, v2); + v1 = _mm_packus_epi16(v1, vzero); + _mm_storel_epi64((__m128i*)(dst), v1); + dst += 2; + } +#endif + for (; i < count; i++) { + uint s = (*src++).toArgb32(); + if (RGBA) + s = ARGB2RGBA(s); + *dst++ = s; + } +} +template void qt_convertRGBA64ToARGB32<false>(uint *dst, const QRgba64 *src, int count); +template void qt_convertRGBA64ToARGB32<true>(uint *dst, const QRgba64 *src, int count); + + +static void QT_FASTCALL storeAlpha8FromARGB32PM(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + dest[index + i] = qAlpha(src[i]); +} + +static void QT_FASTCALL storeGrayscale8FromRGB32(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + dest[index + i] = qGray(src[i]); +} + +static void QT_FASTCALL storeGrayscale8FromARGB32PM(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + for (int i = 0; i < count; ++i) + 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 *) +{ + const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index; + for (int i = 0; i < count; ++i) + buffer[i] = toArgb32(s[i]); + return buffer; +} + +static void QT_FASTCALL storeRGB64FromRGB32(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index; + for (int i = 0; i < count; ++i) + d[i] = QRgba64::fromArgb32(src[i]); +} + +static const uint *QT_FASTCALL fetchRGBA64ToARGB32PM(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index; + for (int i = 0; i < count; ++i) + buffer[i] = toArgb32(s[i].premultiplied()); + return buffer; +} + +static void QT_FASTCALL storeRGBA64FromARGB32PM(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index; + for (int i = 0; i < count; ++i) + d[i] = QRgba64::fromArgb32(src[i]).unpremultiplied(); +} + +// Note: +// convertToArgb32() assumes that no color channel is less than 4 bits. +// storeRGBFromARGB32PM() assumes that no color channel is more than 8 bits. +// QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits. +QPixelLayout qPixelLayouts[QImage::NImageFormats] = { + { false, false, QPixelLayout::BPPNone, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }, // Format_Invalid + { false, false, QPixelLayout::BPP1MSB, nullptr, + convertIndexedToARGB32PM, convertIndexedToRGBA64PM, + fetchIndexedToARGB32PM<QPixelLayout::BPP1MSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1MSB>, + nullptr, nullptr }, // Format_Mono + { false, false, QPixelLayout::BPP1LSB, nullptr, + convertIndexedToARGB32PM, convertIndexedToRGBA64PM, + fetchIndexedToARGB32PM<QPixelLayout::BPP1LSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1LSB>, + nullptr, nullptr }, // Format_MonoLSB + { false, false, QPixelLayout::BPP8, nullptr, + convertIndexedToARGB32PM, convertIndexedToRGBA64PM, + fetchIndexedToARGB32PM<QPixelLayout::BPP8>, fetchIndexedToRGBA64PM<QPixelLayout::BPP8>, + nullptr, nullptr }, // Format_Indexed8 + // Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong, + // but everywhere this generic conversion would be wrong is currently overloaded. + { false, false, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough, + convertRGB32ToRGB64, fetchPassThrough, fetchRGB32ToRGB64, storePassThrough, storePassThrough }, // Format_RGB32 + { true, false, QPixelLayout::BPP32, rbSwap_rgb32, convertARGB32ToARGB32PM, + convertARGB32ToRGBA64PM, fetchARGB32ToARGB32PM, fetchARGB32ToRGBA64PM, storeARGB32FromARGB32PM, storePassThrough }, // Format_ARGB32 + { true, true, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough, + convertARGB32PMToRGBA64PM, fetchPassThrough, fetchARGB32PMToRGBA64PM, storePassThrough, storePassThrough }, // Format_ARGB32_Premultiplied + pixelLayoutRGB<QImage::Format_RGB16>(), + pixelLayoutARGBPM<QImage::Format_ARGB8565_Premultiplied>(), + pixelLayoutRGB<QImage::Format_RGB666>(), + pixelLayoutARGBPM<QImage::Format_ARGB6666_Premultiplied>(), + pixelLayoutRGB<QImage::Format_RGB555>(), + pixelLayoutARGBPM<QImage::Format_ARGB8555_Premultiplied>(), + pixelLayoutRGB<QImage::Format_RGB888>(), + pixelLayoutRGB<QImage::Format_RGB444>(), + pixelLayoutARGBPM<QImage::Format_ARGB4444_Premultiplied>(), + { false, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM, + convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBXFromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBX8888 + { true, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888ToARGB32PM, + convertRGBA8888ToRGBA64PM, fetchRGBA8888ToARGB32PM, fetchRGBA8888ToRGBA64PM, storeRGBA8888FromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBA8888 + { true, true, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM, + convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBA8888PMFromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBA8888_Premultiplied + { false, false, QPixelLayout::BPP32, rbSwap_rgb30, + convertA2RGB30PMToARGB32PM<PixelOrderBGR>, + convertA2RGB30PMToRGBA64PM<PixelOrderBGR>, + fetchA2RGB30PMToARGB32PM<PixelOrderBGR>, + fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>, + storeRGB30FromARGB32PM<PixelOrderBGR>, + storeRGB30FromRGB32<PixelOrderBGR> + }, // Format_BGR30 + { true, true, QPixelLayout::BPP32, rbSwap_rgb30, + convertA2RGB30PMToARGB32PM<PixelOrderBGR>, + convertA2RGB30PMToRGBA64PM<PixelOrderBGR>, + fetchA2RGB30PMToARGB32PM<PixelOrderBGR>, + fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>, + storeA2RGB30PMFromARGB32PM<PixelOrderBGR>, + storeRGB30FromRGB32<PixelOrderBGR> + }, // Format_A2BGR30_Premultiplied + { false, false, QPixelLayout::BPP32, rbSwap_rgb30, + convertA2RGB30PMToARGB32PM<PixelOrderRGB>, + convertA2RGB30PMToRGBA64PM<PixelOrderRGB>, + fetchA2RGB30PMToARGB32PM<PixelOrderRGB>, + fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>, + storeRGB30FromARGB32PM<PixelOrderRGB>, + storeRGB30FromRGB32<PixelOrderRGB> + }, // Format_RGB30 + { true, true, QPixelLayout::BPP32, rbSwap_rgb30, + convertA2RGB30PMToARGB32PM<PixelOrderRGB>, + convertA2RGB30PMToRGBA64PM<PixelOrderRGB>, + fetchA2RGB30PMToARGB32PM<PixelOrderRGB>, + fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>, + storeA2RGB30PMFromARGB32PM<PixelOrderRGB>, + storeRGB30FromRGB32<PixelOrderRGB> + }, // Format_A2RGB30_Premultiplied + { true, true, QPixelLayout::BPP8, nullptr, + convertAlpha8ToRGB32, convertAlpha8ToRGB64, + fetchAlpha8ToRGB32, fetchAlpha8ToRGB64, + storeAlpha8FromARGB32PM, nullptr }, // Format_Alpha8 + { false, false, QPixelLayout::BPP8, nullptr, + convertGrayscale8ToRGB32, convertGrayscale8ToRGB64, + fetchGrayscale8ToRGB32, fetchGrayscale8ToRGB64, + storeGrayscale8FromARGB32PM, storeGrayscale8FromRGB32 }, // Format_Grayscale8 + { false, false, QPixelLayout::BPP64, nullptr, + convertPassThrough, nullptr, + fetchRGB64ToRGB32, fetchPassThrough64, + storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBX64 + { true, false, QPixelLayout::BPP64, nullptr, + convertARGB32ToARGB32PM, nullptr, + fetchRGBA64ToARGB32PM, fetchRGBA64ToRGBA64PM, + storeRGBA64FromARGB32PM, storeRGB64FromRGB32 }, // Format_RGBA64 + { true, true, QPixelLayout::BPP64, nullptr, + convertPassThrough, nullptr, + fetchRGB64ToRGB32, fetchPassThrough64, + storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied + { false, false, QPixelLayout::BPP16, nullptr, + convertGrayscale16ToRGB32, convertGrayscale16ToRGBA64, + fetchGrayscale16ToRGB32, fetchGrayscale16ToRGBA64, + storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 }, // Format_Grayscale16 + pixelLayoutRGB<QImage::Format_BGR888>(), +}; + +Q_STATIC_ASSERT(sizeof(qPixelLayouts) / sizeof(*qPixelLayouts) == QImage::NImageFormats); + +static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int length) +{ + for (int i = 0; i < length; ++i) { + dest[i] = toArgb32(src[i]); + } +} + +template<QImage::Format format> +static void QT_FASTCALL storeGenericFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, + const QVector<QRgb> *clut, QDitherInfo *dither) +{ + uint buffer[BufferSize]; + convertFromRgb64(buffer, src, count); + qPixelLayouts[format].storeFromARGB32PM(dest, buffer, index, count, clut, dither); +} + +static void QT_FASTCALL storeARGB32FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = (uint*)dest + index; + for (int i = 0; i < count; ++i) + d[i] = toArgb32(src[i].unpremultiplied()); +} + +static void QT_FASTCALL storeRGBA8888FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = (uint*)dest + index; + for (int i = 0; i < count; ++i) + d[i] = toRgba8888(src[i].unpremultiplied()); +} + +template<QtPixelOrder PixelOrder> +static void QT_FASTCALL storeRGB30FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = (uint*)dest + index; +#ifdef __SSE2__ + qConvertRGBA64PMToA2RGB30PM_sse2<PixelOrder>(d, src, count); +#else + for (int i = 0; i < count; ++i) + d[i] = qConvertRgb64ToRgb30<PixelOrder>(src[i]); +#endif +} + +static void QT_FASTCALL storeRGBX64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index; + for (int i = 0; i < count; ++i) { + d[i] = src[i].unpremultiplied(); + d[i].setAlpha(65535); + } +} + +static void QT_FASTCALL storeRGBA64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index; + for (int i = 0; i < count; ++i) + d[i] = src[i].unpremultiplied(); +} + +static void QT_FASTCALL storeRGBA64PMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index; + if (d != src) + 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, + nullptr, + nullptr, + storeGenericFromRGBA64PM<QImage::Format_RGB32>, + storeARGB32FromRGBA64PM, + storeGenericFromRGBA64PM<QImage::Format_ARGB32_Premultiplied>, + storeGenericFromRGBA64PM<QImage::Format_RGB16>, + storeGenericFromRGBA64PM<QImage::Format_ARGB8565_Premultiplied>, + storeGenericFromRGBA64PM<QImage::Format_RGB666>, + storeGenericFromRGBA64PM<QImage::Format_ARGB6666_Premultiplied>, + storeGenericFromRGBA64PM<QImage::Format_RGB555>, + storeGenericFromRGBA64PM<QImage::Format_ARGB8555_Premultiplied>, + storeGenericFromRGBA64PM<QImage::Format_RGB888>, + storeGenericFromRGBA64PM<QImage::Format_RGB444>, + storeGenericFromRGBA64PM<QImage::Format_ARGB4444_Premultiplied>, + storeGenericFromRGBA64PM<QImage::Format_RGBX8888>, + storeRGBA8888FromRGBA64PM, + storeGenericFromRGBA64PM<QImage::Format_RGBA8888_Premultiplied>, + storeRGB30FromRGBA64PM<PixelOrderBGR>, + storeRGB30FromRGBA64PM<PixelOrderBGR>, + storeRGB30FromRGBA64PM<PixelOrderRGB>, + storeRGB30FromRGBA64PM<PixelOrderRGB>, + storeGenericFromRGBA64PM<QImage::Format_Alpha8>, + storeGenericFromRGBA64PM<QImage::Format_Grayscale8>, + storeRGBX64FromRGBA64PM, + storeRGBA64FromRGBA64PM, + storeRGBA64PMFromRGBA64PM, + storeGray16FromRGBA64PM, + storeGenericFromRGBA64PM<QImage::Format_BGR888>, +}; + +QT_END_NAMESPACE diff --git a/src/gui/painting/qpixellayout_p.h b/src/gui/painting/qpixellayout_p.h new file mode 100644 index 0000000000..99a781b49b --- /dev/null +++ b/src/gui/painting/qpixellayout_p.h @@ -0,0 +1,336 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPIXELLAYOUT_P_H +#define QPIXELLAYOUT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qvector.h> +#include <QtGui/qimage.h> +#include <QtGui/qrgba64.h> + +QT_BEGIN_NAMESPACE + +enum QtPixelOrder { + PixelOrderRGB, + PixelOrderBGR +}; + +template<enum QtPixelOrder> inline uint qConvertArgb32ToA2rgb30(QRgb); + +template<enum QtPixelOrder> inline uint qConvertRgb32ToRgb30(QRgb); + +template<enum QtPixelOrder> inline QRgb qConvertA2rgb30ToArgb32(uint c); + +// A combined unpremultiply and premultiply with new simplified alpha. +// Needed when alpha loses precision relative to other colors during conversion (ARGB32 -> A2RGB30). +template<unsigned int Shift> +inline QRgb qRepremultiply(QRgb p) +{ + const uint alpha = qAlpha(p); + if (alpha == 255 || alpha == 0) + return p; + p = qUnpremultiply(p); + Q_CONSTEXPR uint mult = 255 / (255 >> Shift); + const uint newAlpha = mult * (alpha >> Shift); + p = (p & ~0xff000000) | (newAlpha<<24); + return qPremultiply(p); +} + +template<unsigned int Shift> +inline QRgba64 qRepremultiply(QRgba64 p) +{ + const uint alpha = p.alpha(); + if (alpha == 65535 || alpha == 0) + return p; + p = p.unpremultiplied(); + Q_CONSTEXPR uint mult = 65535 / (65535 >> Shift); + p.setAlpha(mult * (alpha >> Shift)); + return p.premultiplied(); +} + +template<> +inline uint qConvertArgb32ToA2rgb30<PixelOrderBGR>(QRgb c) +{ + c = qRepremultiply<6>(c); + return (c & 0xc0000000) + | (((c << 22) & 0x3fc00000) | ((c << 14) & 0x00300000)) + | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00)) + | (((c >> 14) & 0x000003fc) | ((c >> 22) & 0x00000003)); +} + +template<> +inline uint qConvertArgb32ToA2rgb30<PixelOrderRGB>(QRgb c) +{ + c = qRepremultiply<6>(c); + return (c & 0xc0000000) + | (((c << 6) & 0x3fc00000) | ((c >> 2) & 0x00300000)) + | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00)) + | (((c << 2) & 0x000003fc) | ((c >> 6) & 0x00000003)); +} + +template<> +inline uint qConvertRgb32ToRgb30<PixelOrderBGR>(QRgb c) +{ + return 0xc0000000 + | (((c << 22) & 0x3fc00000) | ((c << 14) & 0x00300000)) + | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00)) + | (((c >> 14) & 0x000003fc) | ((c >> 22) & 0x00000003)); +} + +template<> +inline uint qConvertRgb32ToRgb30<PixelOrderRGB>(QRgb c) +{ + return 0xc0000000 + | (((c << 6) & 0x3fc00000) | ((c >> 2) & 0x00300000)) + | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00)) + | (((c << 2) & 0x000003fc) | ((c >> 6) & 0x00000003)); +} + +template<> +inline QRgb qConvertA2rgb30ToArgb32<PixelOrderBGR>(uint c) +{ + uint a = c >> 30; + a |= a << 2; + a |= a << 4; + return (a << 24) + | ((c << 14) & 0x00ff0000) + | ((c >> 4) & 0x0000ff00) + | ((c >> 22) & 0x000000ff); +} + +template<> +inline QRgb qConvertA2rgb30ToArgb32<PixelOrderRGB>(uint c) +{ + uint a = c >> 30; + a |= a << 2; + a |= a << 4; + return (a << 24) + | ((c >> 6) & 0x00ff0000) + | ((c >> 4) & 0x0000ff00) + | ((c >> 2) & 0x000000ff); +} + +template<enum QtPixelOrder> inline QRgba64 qConvertA2rgb30ToRgb64(uint rgb); + +template<> +inline QRgba64 qConvertA2rgb30ToRgb64<PixelOrderBGR>(uint rgb) +{ + quint16 alpha = rgb >> 30; + quint16 blue = (rgb >> 20) & 0x3ff; + quint16 green = (rgb >> 10) & 0x3ff; + quint16 red = rgb & 0x3ff; + // Expand the range. + alpha |= (alpha << 2); + alpha |= (alpha << 4); + alpha |= (alpha << 8); + red = (red << 6) | (red >> 4); + green = (green << 6) | (green >> 4); + blue = (blue << 6) | (blue >> 4); + return qRgba64(red, green, blue, alpha); +} + +template<> +inline QRgba64 qConvertA2rgb30ToRgb64<PixelOrderRGB>(uint rgb) +{ + quint16 alpha = rgb >> 30; + quint16 red = (rgb >> 20) & 0x3ff; + quint16 green = (rgb >> 10) & 0x3ff; + quint16 blue = rgb & 0x3ff; + // Expand the range. + alpha |= (alpha << 2); + alpha |= (alpha << 4); + alpha |= (alpha << 8); + red = (red << 6) | (red >> 4); + green = (green << 6) | (green >> 4); + blue = (blue << 6) | (blue >> 4); + return qRgba64(red, green, blue, alpha); +} + +template<enum QtPixelOrder> inline unsigned int qConvertRgb64ToRgb30(QRgba64); + +template<> +inline unsigned int qConvertRgb64ToRgb30<PixelOrderBGR>(QRgba64 c) +{ + c = qRepremultiply<14>(c); + const uint a = c.alpha() >> 14; + const uint r = c.red() >> 6; + const uint g = c.green() >> 6; + const uint b = c.blue() >> 6; + return (a << 30) | (b << 20) | (g << 10) | r; +} + +template<> +inline unsigned int qConvertRgb64ToRgb30<PixelOrderRGB>(QRgba64 c) +{ + c = qRepremultiply<14>(c); + const uint a = c.alpha() >> 14; + const uint r = c.red() >> 6; + const uint g = c.green() >> 6; + const uint b = c.blue() >> 6; + return (a << 30) | (r << 20) | (g << 10) | b; +} + +inline uint qRgbSwapRgb30(uint c) +{ + const uint ag = c & 0xc00ffc00; + const uint rb = c & 0x3ff003ff; + return ag | (rb << 20) | (rb >> 20); +} + +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) { + quint32 rgb = x >> 8; + quint32 a = x << 24; + return a | rgb; +} + +Q_ALWAYS_INLINE quint32 ARGB2RGBA(quint32 x) { + quint32 rgb = x << 8; + quint32 a = x >> 24; + return a | rgb; +} +#else +Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) { + // RGBA8888 is ABGR32 on little endian. + quint32 ag = x & 0xff00ff00; + quint32 rg = x & 0x00ff00ff; + return ag | (rg << 16) | (rg >> 16); +} + +Q_ALWAYS_INLINE quint32 ARGB2RGBA(quint32 x) { + return RGBA2ARGB(x); +} +#endif + +// We manually unalias the variables to make sure the compiler +// fully optimizes both aliased and unaliased cases. +#define UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion) \ + if (src == buffer) { \ + for (int i = 0; i < count; ++i) \ + buffer[i] = conversion(buffer[i]); \ + } else { \ + for (int i = 0; i < count; ++i) \ + buffer[i] = conversion(src[i]); \ + } + + +inline const uint *qt_convertARGB32ToARGB32PM(uint *buffer, const uint *src, int count) +{ + UNALIASED_CONVERSION_LOOP(buffer, src, count, qPremultiply); + return buffer; +} + +inline const uint *qt_convertRGBA8888ToARGB32PM(uint *buffer, const uint *src, int count) +{ + UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint s) { return qPremultiply(RGBA2ARGB(s));}); + return buffer; +} + +template<bool RGBA> void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count); + +struct QDitherInfo { + int x; + int y; +}; + +typedef const uint *(QT_FASTCALL *FetchAndConvertPixelsFunc)(uint *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *clut, QDitherInfo *dither); +typedef void (QT_FASTCALL *ConvertAndStorePixelsFunc)(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *clut, QDitherInfo *dither); + +typedef const QRgba64 *(QT_FASTCALL *FetchAndConvertPixelsFunc64)(QRgba64 *buffer, const uchar *src, int index, int count, + const QVector<QRgb> *clut, QDitherInfo *dither); +typedef void (QT_FASTCALL *ConvertAndStorePixelsFunc64)(uchar *dest, const QRgba64 *src, int index, int count, + const QVector<QRgb> *clut, QDitherInfo *dither); + +typedef void (QT_FASTCALL *ConvertFunc)(uint *buffer, int count, const QVector<QRgb> *clut); +typedef void (QT_FASTCALL *Convert64Func)(quint64 *buffer, int count, const QVector<QRgb> *clut); +typedef const QRgba64 *(QT_FASTCALL *ConvertTo64Func)(QRgba64 *buffer, const uint *src, int count, + const QVector<QRgb> *clut, QDitherInfo *dither); +typedef void (QT_FASTCALL *RbSwapFunc)(uchar *dst, const uchar *src, int count); + +typedef void (*MemRotateFunc)(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl); + +struct QPixelLayout +{ + // Bits per pixel + enum BPP { + BPPNone, + BPP1MSB, + BPP1LSB, + BPP8, + BPP16, + BPP24, + BPP32, + BPP64, + BPPCount + }; + + bool hasAlphaChannel; + bool premultiplied; + BPP bpp; + RbSwapFunc rbSwap; + ConvertFunc convertToARGB32PM; + ConvertTo64Func convertToRGBA64PM; + FetchAndConvertPixelsFunc fetchToARGB32PM; + FetchAndConvertPixelsFunc64 fetchToRGBA64PM; + ConvertAndStorePixelsFunc storeFromARGB32PM; + ConvertAndStorePixelsFunc storeFromRGB32; +}; + +extern ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats]; + +extern QPixelLayout qPixelLayouts[QImage::NImageFormats]; + +extern MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3]; + +QT_END_NAMESPACE + +#endif // QPIXELLAYOUT_P_H |