Revision control
Copy as Markdown
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include <qglobal.h>
#include "qdrawhelper_p.h"
#include "qpixellayout_p.h"
#include "qrgba64_p.h"
#include <QtCore/private/qsimd_p.h>
#include <QtGui/private/qcmyk_p.h>
QT_BEGIN_NAMESPACE
template<QImage::Format> constexpr uint redWidth();
template<QImage::Format> constexpr uint redShift();
template<QImage::Format> constexpr uint greenWidth();
template<QImage::Format> constexpr uint greenShift();
template<QImage::Format> constexpr uint blueWidth();
template<QImage::Format> constexpr uint blueShift();
template<QImage::Format> constexpr uint alphaWidth();
template<QImage::Format> constexpr uint alphaShift();
template<> constexpr uint redWidth<QImage::Format_RGB32>() { return 8; }
template<> constexpr uint redWidth<QImage::Format_ARGB32>() { return 8; }
template<> constexpr uint redWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
template<> constexpr uint redWidth<QImage::Format_RGB16>() { return 5; }
template<> constexpr uint redWidth<QImage::Format_RGB444>() { return 4; }
template<> constexpr uint redWidth<QImage::Format_RGB555>() { return 5; }
template<> constexpr uint redWidth<QImage::Format_RGB666>() { return 6; }
template<> constexpr uint redWidth<QImage::Format_RGB888>() { return 8; }
template<> constexpr uint redWidth<QImage::Format_BGR888>() { return 8; }
template<> constexpr uint redWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
template<> constexpr uint redWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
template<> constexpr uint redWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
template<> constexpr uint redWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
template<> constexpr uint redWidth<QImage::Format_RGBX8888>() { return 8; }
template<> constexpr uint redWidth<QImage::Format_RGBA8888>() { return 8; }
template<> constexpr uint redWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
template<> constexpr uint redShift<QImage::Format_RGB32>() { return 16; }
template<> constexpr uint redShift<QImage::Format_ARGB32>() { return 16; }
template<> constexpr uint redShift<QImage::Format_ARGB32_Premultiplied>() { return 16; }
template<> constexpr uint redShift<QImage::Format_RGB16>() { return 11; }
template<> constexpr uint redShift<QImage::Format_RGB444>() { return 8; }
template<> constexpr uint redShift<QImage::Format_RGB555>() { return 10; }
template<> constexpr uint redShift<QImage::Format_RGB666>() { return 12; }
template<> constexpr uint redShift<QImage::Format_RGB888>() { return 16; }
template<> constexpr uint redShift<QImage::Format_BGR888>() { return 0; }
template<> constexpr uint redShift<QImage::Format_ARGB4444_Premultiplied>() { return 8; }
template<> constexpr uint redShift<QImage::Format_ARGB8555_Premultiplied>() { return 18; }
template<> constexpr uint redShift<QImage::Format_ARGB8565_Premultiplied>() { return 19; }
template<> constexpr uint redShift<QImage::Format_ARGB6666_Premultiplied>() { return 12; }
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
template<> constexpr uint redShift<QImage::Format_RGBX8888>() { return 24; }
template<> constexpr uint redShift<QImage::Format_RGBA8888>() { return 24; }
template<> constexpr uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; }
#else
template<> constexpr uint redShift<QImage::Format_RGBX8888>() { return 0; }
template<> constexpr uint redShift<QImage::Format_RGBA8888>() { return 0; }
template<> constexpr uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; }
#endif
template<> constexpr uint greenWidth<QImage::Format_RGB32>() { return 8; }
template<> constexpr uint greenWidth<QImage::Format_ARGB32>() { return 8; }
template<> constexpr uint greenWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
template<> constexpr uint greenWidth<QImage::Format_RGB16>() { return 6; }
template<> constexpr uint greenWidth<QImage::Format_RGB444>() { return 4; }
template<> constexpr uint greenWidth<QImage::Format_RGB555>() { return 5; }
template<> constexpr uint greenWidth<QImage::Format_RGB666>() { return 6; }
template<> constexpr uint greenWidth<QImage::Format_RGB888>() { return 8; }
template<> constexpr uint greenWidth<QImage::Format_BGR888>() { return 8; }
template<> constexpr uint greenWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
template<> constexpr uint greenWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
template<> constexpr uint greenWidth<QImage::Format_ARGB8565_Premultiplied>() { return 6; }
template<> constexpr uint greenWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
template<> constexpr uint greenWidth<QImage::Format_RGBX8888>() { return 8; }
template<> constexpr uint greenWidth<QImage::Format_RGBA8888>() { return 8; }
template<> constexpr uint greenWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
template<> constexpr uint greenShift<QImage::Format_RGB32>() { return 8; }
template<> constexpr uint greenShift<QImage::Format_ARGB32>() { return 8; }
template<> constexpr uint greenShift<QImage::Format_ARGB32_Premultiplied>() { return 8; }
template<> constexpr uint greenShift<QImage::Format_RGB16>() { return 5; }
template<> constexpr uint greenShift<QImage::Format_RGB444>() { return 4; }
template<> constexpr uint greenShift<QImage::Format_RGB555>() { return 5; }
template<> constexpr uint greenShift<QImage::Format_RGB666>() { return 6; }
template<> constexpr uint greenShift<QImage::Format_RGB888>() { return 8; }
template<> constexpr uint greenShift<QImage::Format_BGR888>() { return 8; }
template<> constexpr uint greenShift<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
template<> constexpr uint greenShift<QImage::Format_ARGB8555_Premultiplied>() { return 13; }
template<> constexpr uint greenShift<QImage::Format_ARGB8565_Premultiplied>() { return 13; }
template<> constexpr uint greenShift<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
template<> constexpr uint greenShift<QImage::Format_RGBX8888>() { return 16; }
template<> constexpr uint greenShift<QImage::Format_RGBA8888>() { return 16; }
template<> constexpr uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; }
#else
template<> constexpr uint greenShift<QImage::Format_RGBX8888>() { return 8; }
template<> constexpr uint greenShift<QImage::Format_RGBA8888>() { return 8; }
template<> constexpr uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
#endif
template<> constexpr uint blueWidth<QImage::Format_RGB32>() { return 8; }
template<> constexpr uint blueWidth<QImage::Format_ARGB32>() { return 8; }
template<> constexpr uint blueWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
template<> constexpr uint blueWidth<QImage::Format_RGB16>() { return 5; }
template<> constexpr uint blueWidth<QImage::Format_RGB444>() { return 4; }
template<> constexpr uint blueWidth<QImage::Format_RGB555>() { return 5; }
template<> constexpr uint blueWidth<QImage::Format_RGB666>() { return 6; }
template<> constexpr uint blueWidth<QImage::Format_RGB888>() { return 8; }
template<> constexpr uint blueWidth<QImage::Format_BGR888>() { return 8; }
template<> constexpr uint blueWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
template<> constexpr uint blueWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
template<> constexpr uint blueWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
template<> constexpr uint blueWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
template<> constexpr uint blueWidth<QImage::Format_RGBX8888>() { return 8; }
template<> constexpr uint blueWidth<QImage::Format_RGBA8888>() { return 8; }
template<> constexpr uint blueWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
template<> constexpr uint blueShift<QImage::Format_RGB32>() { return 0; }
template<> constexpr uint blueShift<QImage::Format_ARGB32>() { return 0; }
template<> constexpr uint blueShift<QImage::Format_ARGB32_Premultiplied>() { return 0; }
template<> constexpr uint blueShift<QImage::Format_RGB16>() { return 0; }
template<> constexpr uint blueShift<QImage::Format_RGB444>() { return 0; }
template<> constexpr uint blueShift<QImage::Format_RGB555>() { return 0; }
template<> constexpr uint blueShift<QImage::Format_RGB666>() { return 0; }
template<> constexpr uint blueShift<QImage::Format_RGB888>() { return 0; }
template<> constexpr uint blueShift<QImage::Format_BGR888>() { return 16; }
template<> constexpr uint blueShift<QImage::Format_ARGB4444_Premultiplied>() { return 0; }
template<> constexpr uint blueShift<QImage::Format_ARGB8555_Premultiplied>() { return 8; }
template<> constexpr uint blueShift<QImage::Format_ARGB8565_Premultiplied>() { return 8; }
template<> constexpr uint blueShift<QImage::Format_ARGB6666_Premultiplied>() { return 0; }
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
template<> constexpr uint blueShift<QImage::Format_RGBX8888>() { return 8; }
template<> constexpr uint blueShift<QImage::Format_RGBA8888>() { return 8; }
template<> constexpr uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
#else
template<> constexpr uint blueShift<QImage::Format_RGBX8888>() { return 16; }
template<> constexpr uint blueShift<QImage::Format_RGBA8888>() { return 16; }
template<> constexpr uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; }
#endif
template<> constexpr uint alphaWidth<QImage::Format_RGB32>() { return 0; }
template<> constexpr uint alphaWidth<QImage::Format_ARGB32>() { return 8; }
template<> constexpr uint alphaWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
template<> constexpr uint alphaWidth<QImage::Format_RGB16>() { return 0; }
template<> constexpr uint alphaWidth<QImage::Format_RGB444>() { return 0; }
template<> constexpr uint alphaWidth<QImage::Format_RGB555>() { return 0; }
template<> constexpr uint alphaWidth<QImage::Format_RGB666>() { return 0; }
template<> constexpr uint alphaWidth<QImage::Format_RGB888>() { return 0; }
template<> constexpr uint alphaWidth<QImage::Format_BGR888>() { return 0; }
template<> constexpr uint alphaWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
template<> constexpr uint alphaWidth<QImage::Format_ARGB8555_Premultiplied>() { return 8; }
template<> constexpr uint alphaWidth<QImage::Format_ARGB8565_Premultiplied>() { return 8; }
template<> constexpr uint alphaWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
template<> constexpr uint alphaWidth<QImage::Format_RGBX8888>() { return 0; }
template<> constexpr uint alphaWidth<QImage::Format_RGBA8888>() { return 8; }
template<> constexpr uint alphaWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
template<> constexpr uint alphaShift<QImage::Format_RGB32>() { return 24; }
template<> constexpr uint alphaShift<QImage::Format_ARGB32>() { return 24; }
template<> constexpr uint alphaShift<QImage::Format_ARGB32_Premultiplied>() { return 24; }
template<> constexpr uint alphaShift<QImage::Format_RGB16>() { return 0; }
template<> constexpr uint alphaShift<QImage::Format_RGB444>() { return 0; }
template<> constexpr uint alphaShift<QImage::Format_RGB555>() { return 0; }
template<> constexpr uint alphaShift<QImage::Format_RGB666>() { return 0; }
template<> constexpr uint alphaShift<QImage::Format_RGB888>() { return 0; }
template<> constexpr uint alphaShift<QImage::Format_BGR888>() { return 0; }
template<> constexpr uint alphaShift<QImage::Format_ARGB4444_Premultiplied>() { return 12; }
template<> constexpr uint alphaShift<QImage::Format_ARGB8555_Premultiplied>() { return 0; }
template<> constexpr uint alphaShift<QImage::Format_ARGB8565_Premultiplied>() { return 0; }
template<> constexpr uint alphaShift<QImage::Format_ARGB6666_Premultiplied>() { return 18; }
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
template<> constexpr uint alphaShift<QImage::Format_RGBX8888>() { return 0; }
template<> constexpr uint alphaShift<QImage::Format_RGBA8888>() { return 0; }
template<> constexpr uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; }
#else
template<> constexpr uint alphaShift<QImage::Format_RGBX8888>() { return 24; }
template<> constexpr uint alphaShift<QImage::Format_RGBA8888>() { return 24; }
template<> constexpr uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; }
#endif
template<QImage::Format> constexpr QPixelLayout::BPP bitsPerPixel();
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB32>() { return QPixelLayout::BPP32; }
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB32>() { return QPixelLayout::BPP32; }
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB32_Premultiplied>() { return QPixelLayout::BPP32; }
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 <QPixelLayout::BPP bpp> static
inline 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 <>
[[maybe_unused]]
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 <>
[[maybe_unused]]
inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP16FPx4>(const uchar *src, int index)
{
// We have to do the conversion in fetch to fit into a 32bit uint
QRgbaFloat16 c = reinterpret_cast<const QRgbaFloat16 *>(src)[index];
return c.toArgb32();
}
template <>
[[maybe_unused]]
inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP32FPx4>(const uchar *src, int index)
{
// We have to do the conversion in fetch to fit into a 32bit uint
QRgbaFloat32 c = reinterpret_cast<const QRgbaFloat32 *>(src)[index];
return c.toArgb32();
}
template<QImage::Format Format>
static inline uint convertPixelToRGB32(uint s)
{
constexpr uint redMask = ((1 << redWidth<Format>()) - 1);
constexpr uint greenMask = ((1 << greenWidth<Format>()) - 1);
constexpr uint blueMask = ((1 << blueWidth<Format>()) - 1);
constexpr uchar redLeftShift = 8 - redWidth<Format>();
constexpr uchar greenLeftShift = 8 - greenWidth<Format>();
constexpr uchar blueLeftShift = 8 - blueWidth<Format>();
constexpr uchar redRightShift = 2 * redWidth<Format>() - 8;
constexpr uchar greenRightShift = 2 * greenWidth<Format>() - 8;
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 QList<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);
#elif defined QT_COMPILER_SUPPORTS_LSX
// from qdrawhelper_lsx.cpp
extern const uint * QT_FASTCALL fetchPixelsBPP24_lsx(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 QList<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;
}
#elif defined QT_COMPILER_SUPPORTS_LSX
if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(LSX)) {
fetchPixelsBPP24_lsx(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 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 QList<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 QList<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>
Q_ALWAYS_INLINE static QRgbaFloat32 convertPixelToRGB32F(uint s)
{
return QRgbaFloat32::fromArgb32(convertPixelToRGB32<Format>(s));
}
template<QImage::Format Format>
static const QRgbaFloat32 *QT_FASTCALL fetchRGBToRGB32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = convertPixelToRGB32F<Format>(fetchPixel<bitsPerPixel<Format>()>(src, index + i));
return buffer;
}
template<QImage::Format Format>
static inline uint convertPixelToARGB32PM(uint s)
{
constexpr uint alphaMask = ((1 << alphaWidth<Format>()) - 1);
constexpr uint redMask = ((1 << redWidth<Format>()) - 1);
constexpr uint greenMask = ((1 << greenWidth<Format>()) - 1);
constexpr uint blueMask = ((1 << blueWidth<Format>()) - 1);
constexpr uchar alphaLeftShift = 8 - alphaWidth<Format>();
constexpr uchar redLeftShift = 8 - redWidth<Format>();
constexpr uchar greenLeftShift = 8 - greenWidth<Format>();
constexpr uchar blueLeftShift = 8 - blueWidth<Format>();
constexpr uchar alphaRightShift = 2 * alphaWidth<Format>() - 8;
constexpr uchar redRightShift = 2 * redWidth<Format>() - 8;
constexpr uchar greenRightShift = 2 * greenWidth<Format>() - 8;
constexpr uchar blueRightShift = 2 * blueWidth<Format>() - 8;
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 QList<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 QList<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;
}
#elif defined QT_COMPILER_SUPPORTS_LSX
if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(LSX)) {
fetchPixelsBPP24_lsx(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 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 QList<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 QList<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>
Q_ALWAYS_INLINE static QRgbaFloat32 convertPixelToRGBA32F(uint s)
{
return QRgbaFloat32::fromArgb32(convertPixelToARGB32PM<Format>(s));
}
template<QImage::Format Format>
static const QRgbaFloat32 *QT_FASTCALL fetchARGBPMToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
for (int i = 0; i < count; ++i)
buffer[i] = convertPixelToRGBA32F<Format>(fetchPixel<bpp>(src, index + i));
return buffer;
}
template<QImage::Format Format>
static const QRgbaFloat32 *QT_FASTCALL fetchARGBToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
for (int i = 0; i < count; ++i)
buffer[i] = convertPixelToRGBA32F<Format>(fetchPixel<bpp>(src, index + i)).premultiplied();
return buffer;
}
template<QImage::Format Format, bool fromRGB>
static void QT_FASTCALL storeRGBFromARGB32PM(uchar *dest, const uint *src, int index, int count,
const QList<QRgb> *, QDitherInfo *dither)
{
constexpr uchar rWidth = redWidth<Format>();
constexpr uchar gWidth = greenWidth<Format>();
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)) {
constexpr uint rMask = (1 << redWidth<Format>()) - 1;
constexpr uint gMask = (1 << greenWidth<Format>()) - 1;
constexpr uint bMask = (1 << blueWidth<Format>()) - 1;
constexpr uchar rRightShift = 24 - redWidth<Format>();
constexpr uchar gRightShift = 16 - greenWidth<Format>();
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 QList<QRgb> *, QDitherInfo *dither)
{
constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
if (!dither) {
constexpr uint aMask = (1 << alphaWidth<Format>()) - 1;
constexpr uint rMask = (1 << redWidth<Format>()) - 1;
constexpr uint gMask = (1 << greenWidth<Format>()) - 1;
constexpr uint bMask = (1 << blueWidth<Format>()) - 1;
constexpr uchar aRightShift = 32 - alphaWidth<Format>();
constexpr uchar rRightShift = 24 - redWidth<Format>();
constexpr uchar gRightShift = 16 - greenWidth<Format>();
constexpr uchar bRightShift = 8 - blueWidth<Format>();
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 {
constexpr uchar aWidth = alphaWidth<Format>();
constexpr uchar rWidth = redWidth<Format>();
constexpr uchar gWidth = greenWidth<Format>();
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)
{
constexpr uchar aWidth = alphaWidth<Format>();
constexpr uchar aShift = alphaShift<Format>();
constexpr uchar rWidth = redWidth<Format>();
constexpr uchar rShift = redShift<Format>();
constexpr uchar gWidth = greenWidth<Format>();
constexpr uchar gShift = greenShift<Format>();
constexpr uchar bWidth = blueWidth<Format>();
constexpr uchar bShift = blueShift<Format>();
static_assert(rWidth == bWidth);
constexpr uint redBlueMask = (1 << rWidth) - 1;
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);
}
static void QT_FASTCALL rbSwap_4x16(uchar *d, const uchar *s, int count)
{
const ushort *src = reinterpret_cast<const ushort *>(s);
ushort *dest = reinterpret_cast<ushort *>(d);
if (src != dest) {
for (int i = 0; i < count; ++i) {
dest[i * 4 + 0] = src[i * 4 + 2];
dest[i * 4 + 1] = src[i * 4 + 1];
dest[i * 4 + 2] = src[i * 4 + 0];
dest[i * 4 + 3] = src[i * 4 + 3];
}
} else {
for (int i = 0; i < count; ++i) {
const ushort r = src[i * 4 + 0];
const ushort b = src[i * 4 + 2];
dest[i * 4 + 0] = b;
dest[i * 4 + 2] = r;
}
}
}
static void QT_FASTCALL rbSwap_4x32(uchar *d, const uchar *s, int count)
{
const uint *src = reinterpret_cast<const uint *>(s);
uint *dest = reinterpret_cast<uint *>(d);
if (src != dest) {
for (int i = 0; i < count; ++i) {
dest[i * 4 + 0] = src[i * 4 + 2];
dest[i * 4 + 1] = src[i * 4 + 1];
dest[i * 4 + 2] = src[i * 4 + 0];
dest[i * 4 + 3] = src[i * 4 + 3];
}
} else {
for (int i = 0; i < count; ++i) {
const uint r = src[i * 4 + 0];
const uint b = src[i * 4 + 2];
dest[i * 4 + 0] = b;
dest[i * 4 + 2] = r;
}
}
}
template<QImage::Format Format> 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> 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 QList<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 QList<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 QList<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;
}
template<QPixelLayout::BPP BPP>
static const QRgbaFloat32 *QT_FASTCALL fetchIndexedToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *clut, QDitherInfo *)
{
for (int i = 0; i < count; ++i) {
const uint s = fetchPixel<BPP>(src, index + i);
buffer[i] = QRgbaFloat32::fromArgb32(clut->at(s)).premultiplied();
}
return buffer;
}
template<typename QRgba>
static const QRgba *QT_FASTCALL convertIndexedTo(QRgba *buffer, const uint *src, int count,
const QList<QRgb> *clut, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = QRgba::fromArgb32(clut->at(src[i])).premultiplied();
return buffer;
}
static void QT_FASTCALL convertPassThrough(uint *, int, const QList<QRgb> *)
{
}
static const uint *QT_FASTCALL fetchPassThrough(uint *, const uchar *src, int index, int,
const QList<QRgb> *, QDitherInfo *)
{
return reinterpret_cast<const uint *>(src) + index;
}
static const QRgba64 *QT_FASTCALL fetchPassThrough64(QRgba64 *, const uchar *src, int index, int,
const QList<QRgb> *, QDitherInfo *)
{
return reinterpret_cast<const QRgba64 *>(src) + index;
}
static void QT_FASTCALL storePassThrough(uchar *dest, const uint *src, int index, int count,
const QList<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 QList<QRgb> *)
{
qt_convertARGB32ToARGB32PM(buffer, buffer, count);
}
static const uint *QT_FASTCALL fetchARGB32ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
return qt_convertARGB32ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count);
}
static void QT_FASTCALL convertRGBA8888PMToARGB32PM(uint *buffer, int count, const QList<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 QList<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 QList<QRgb> *)
{
qt_convertRGBA8888ToARGB32PM(buffer, buffer, count);
}
static const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
return qt_convertRGBA8888ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count);
}
static void QT_FASTCALL convertAlpha8ToRGB32(uint *buffer, int count, const QList<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 QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = qRgba(0, 0, 0, src[index + i]);
return buffer;
}
template<typename QRgba>
static const QRgba *QT_FASTCALL convertAlpha8To(QRgba *buffer, const uint *src, int count,
const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = QRgba::fromRgba(0, 0, 0, src[i]);
return buffer;
}
template<typename QRgba>
static const QRgba *QT_FASTCALL fetchAlpha8To(QRgba *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = QRgba::fromRgba(0, 0, 0, src[index + i]);
return buffer;
}
static void QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, int count, const QList<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 QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i) {
const uint s = src[index + i];
buffer[i] = qRgb(s, s, s);
}
return buffer;
}
template<typename QRgba>
static const QRgba *QT_FASTCALL convertGrayscale8To(QRgba *buffer, const uint *src, int count,
const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = QRgba::fromRgba(src[i], src[i], src[i], 255);
return buffer;
}
template<typename QRgba>
static const QRgba *QT_FASTCALL fetchGrayscale8To(QRgba *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i) {
const uint s = src[index + i];
buffer[i] = QRgba::fromRgba(s, s, s, 255);
}
return buffer;
}
static void QT_FASTCALL convertGrayscale16ToRGB32(uint *buffer, int count, const QList<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 QList<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;
}
template<typename QRgba>
static const QRgba *QT_FASTCALL convertGrayscale16To(QRgba *buffer, const uint *src, int count,
const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = QRgba::fromRgba64(src[i], src[i], src[i], 65535);
return buffer;
}
template<typename QRgba>
static const QRgba *QT_FASTCALL fetchGrayscale16To(QRgba *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index;
for (int i = 0; i < count; ++i) {
buffer[i] = QRgba::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 QList<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 QList<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 = qvsetq_n_u8(2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15);
#else
const uint8x8_t rgbaMask = qvset_n_u8(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);
}
}
#elif defined __loongarch_sx
template<bool RGBA, bool maskAlpha>
static inline void qConvertARGB32PMToRGBA64PM_lsx(QRgba64 *buffer, const uint *src, int count)
{
if (count <= 0)
return;
const __m128i amask = __lsx_vreplgr2vr_w(0xff000000);
const __m128i shuffleMask = (__m128i)(v8i16){2, 1, 0, 3, 6, 5, 4, 7};
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 = __lsx_vld((const __m128i*)src, 0);
if (maskAlpha)
vs = __lsx_vor_v(vs, amask);
src += 4;
__m128i v1 = __lsx_vilvl_b(vs, vs);
__m128i v2 = __lsx_vilvh_b(vs, vs);
if (!RGBA) {
v1 = __lsx_vshuf_h(shuffleMask, v1, v1);
v2 = __lsx_vshuf_h(shuffleMask, v2, v2);
}
__lsx_vst(v1, buffer, 0);
buffer += 2;
__lsx_vst(v2, buffer, 0);
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_lsx(uint *dest, const QRgba64 *buffer, int count)
{
const __m128i gmask = __lsx_vreplgr2vr_w(0x000ffc00);
const __m128i cmask = __lsx_vreplgr2vr_w(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) {
__m128i vOr = __lsx_vreplgr2vr_w(0);
__m128i vAnd = __lsx_vreplgr2vr_w(0xffffffff);
for (int j = 0; j < 16; j += 2) {
__m128i vs = __lsx_vld((const __m128i*)(buffer + j), 0);
vOr = __lsx_vor_v(vOr, vs);
vAnd = __lsx_vand_v(vAnd, vs);
}
const quint16 orAlpha = ((uint)__lsx_vpickve2gr_h(vOr, 3)) | ((uint)__lsx_vpickve2gr_h(vOr, 7));
const quint16 andAlpha = ((uint)__lsx_vpickve2gr_h(vAnd, 3)) & ((uint)__lsx_vpickve2gr_h(vAnd, 7));
if (andAlpha == 0xffff) {
for (int j = 0; j < 16; j += 2) {
__m128i vs = __lsx_vld((const __m128i*)buffer, 0);
buffer += 2;
vr = __lsx_vsrli_d(vs, 6);
vg = __lsx_vsrli_d(vs, 16 + 6 - 10);
vb = __lsx_vsrli_d(vs, 32 + 6);
vr = __lsx_vand_v(vr, cmask);
vg = __lsx_vand_v(vg, gmask);
vb = __lsx_vand_v(vb, cmask);
va = __lsx_vsrli_d(vs, 48 + 14);
if (PixelOrder == PixelOrderRGB)
vr = __lsx_vslli_w(vr, 20);
else
vb = __lsx_vslli_w(vb, 20);
va = __lsx_vslli_w(va, 30);
__m128i vd = __lsx_vor_v(__lsx_vor_v(vr, vg), __lsx_vor_v(vb, va));
vd = __lsx_vshuf4i_w(vd, 0b11011000);
__lsx_vstelm_d(vd, dest, 0, 0);
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++);
}
#endif
static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count,
const QList<QRgb> *, QDitherInfo *)
{
#ifdef __SSE2__
qConvertARGB32PMToRGBA64PM_sse2<false, true>(buffer, src, count);
#elif defined(__ARM_NEON__)
qConvertARGB32PMToRGBA64PM_neon<false, true>(buffer, src, count);
#elif defined(__loongarch_sx)
qConvertARGB32PMToRGBA64PM_lsx<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 QList<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 QList<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 QList<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 QList<QRgb> *, QDitherInfo *)
{
#ifdef __SSE2__
qConvertARGB32PMToRGBA64PM_sse2<false, false>(buffer, src, count);
#elif defined(__ARM_NEON__)
qConvertARGB32PMToRGBA64PM_neon<false, false>(buffer, src, count);
#elif defined(__loongarch_sx)
qConvertARGB32PMToRGBA64PM_lsx<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 QList<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 QList<QRgb> *, QDitherInfo *)
{
const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
#ifdef __SSE2__
for (int i = 0; i < count; ++i) {
const auto a = s[i].alpha();
__m128i vs = _mm_loadl_epi64((const __m128i *)(s + i));
__m128i va = _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 3, 3, 3));
vs = multiplyAlpha65535(vs, va);
_mm_storel_epi64((__m128i *)(buffer + i), vs);
buffer[i].setAlpha(a);
}
#else
for (int i = 0; i < count; ++i)
buffer[i] = QRgba64::fromRgba64(s[i]).premultiplied();
#endif
return buffer;
}
static const QRgba64 *QT_FASTCALL convertRGBA8888ToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
const QList<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 QList<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 QList<QRgb> *, QDitherInfo *)
{
#ifdef __SSE2__
qConvertARGB32PMToRGBA64PM_sse2<true, false>(buffer, src, count);
#elif defined(__ARM_NEON__)
qConvertARGB32PMToRGBA64PM_neon<true, false>(buffer, src, count);
#elif defined(__loongarch_sx)
qConvertARGB32PMToRGBA64PM_lsx<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 QList<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 QList<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 QList<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 QList<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 QList<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 QList<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++);
}
#elif defined(__loongarch_sx)
template<QtPixelOrder PixelOrder>
static inline void qConvertA2RGB30PMToRGBA64PM_lsx(QRgba64 *buffer, const uint *src, int count)
{
if (count <= 0)
return;
const __m128i rmask = __lsx_vreplgr2vr_w(0x3ff00000);
const __m128i gmask = __lsx_vreplgr2vr_w(0x000ffc00);
const __m128i bmask = __lsx_vreplgr2vr_w(0x000003ff);
const __m128i afactor = __lsx_vreplgr2vr_h(0x5555);
int i = 0;
for (; ((uintptr_t)buffer & 0xf) && i < count; ++i)
*buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++);
for (; i < count-3; i += 4) {
__m128i vs = __lsx_vld((const __m128i*)src, 0);
src += 4;
__m128i va = __lsx_vsrli_w(vs, 30);
__m128i vr = __lsx_vand_v(vs, rmask);
__m128i vb = __lsx_vand_v(vs, bmask);
__m128i vg = __lsx_vand_v(vs, gmask);
va = __lsx_vmul_h(va, afactor);
vr = __lsx_vor_v(__lsx_vsrli_w(vr, 14), __lsx_vsrli_w(vr, 24));
vg = __lsx_vor_v(__lsx_vsrli_w(vg, 4), __lsx_vsrli_w(vg, 14));
vb = __lsx_vor_v(__lsx_vslli_w(vb, 6), __lsx_vsrli_w(vb, 4));
__m128i vrb;
if (PixelOrder == PixelOrderRGB)
vrb = __lsx_vor_v(vr, __lsx_vbsll_v(vb, 2));
else
vrb = __lsx_vor_v(vb, __lsx_vbsll_v(vr, 2));
__m128i vga = __lsx_vor_v(vg, __lsx_vbsll_v(va, 2));
__lsx_vst(__lsx_vilvl_h(vga, vrb), buffer, 0);
buffer += 2;
__lsx_vst(__lsx_vilvh_h(vga, vrb), buffer, 0);
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 QList<QRgb> *, QDitherInfo *)
{
#ifdef __SSE2__
qConvertA2RGB30PMToRGBA64PM_sse2<PixelOrder>(buffer, src, count);
#elif defined (__loongarch_sx)
qConvertA2RGB30PMToRGBA64PM_lsx<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 QList<QRgb> *, QDitherInfo *)
{
return convertA2RGB30PMToRGBA64PM<PixelOrder>(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
}
template<enum QtPixelOrder> inline QRgbaFloat32 qConvertA2rgb30ToRgbaFP(uint rgb);
template<>
inline QRgbaFloat32 qConvertA2rgb30ToRgbaFP<PixelOrderBGR>(uint rgb)
{
float alpha = (rgb >> 30) * (1.f/3.f);
float blue = ((rgb >> 20) & 0x3ff) * (1.f/1023.f);
float green = ((rgb >> 10) & 0x3ff) * (1.f/1023.f);
float red = (rgb & 0x3ff) * (1.f/1023.f);
return QRgbaFloat32{ red, green, blue, alpha };
}
template<>
inline QRgbaFloat32 qConvertA2rgb30ToRgbaFP<PixelOrderRGB>(uint rgb)
{
float alpha = (rgb >> 30) * (1.f/3.f);
float red = ((rgb >> 20) & 0x3ff) * (1.f/1023.f);
float green = ((rgb >> 10) & 0x3ff) * (1.f/1023.f);
float blue = (rgb & 0x3ff) * (1.f/1023.f);
return QRgbaFloat32{ red, green, blue, alpha };
}
template<QtPixelOrder PixelOrder>
static const QRgbaFloat32 *QT_FASTCALL convertA2RGB30PMToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = qConvertA2rgb30ToRgbaFP<PixelOrder>(src[i]);
return buffer;
}
template<QtPixelOrder PixelOrder>
static const QRgbaFloat32 *QT_FASTCALL fetchRGB30ToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
return convertA2RGB30PMToRGBA32F<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 QList<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 QList<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 QList<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;
}
#elif defined(__loongarch_sx)
if (((uintptr_t)dst & 0x7) && count > 0) {
uint s = (*src++).toArgb32();
if (RGBA)
s = ARGB2RGBA(s);
*dst++ = s;
i++;
}
const __m128i vhalf = __lsx_vreplgr2vr_w(0x80);
const __m128i vzero = __lsx_vldi(0);
const __m128i shuffleMask = (__m128i)(v8i16){2, 1, 0, 3, 6, 5, 4, 7};
for (; i < count-1; i += 2) {
__m128i vs = __lsx_vld((const __m128i*)src, 0);
src += 2;
if (!RGBA) {
vs = __lsx_vshuf_h(shuffleMask, vzero, vs);
}
__m128i v1 = __lsx_vilvl_h(vzero, vs);
__m128i v2 = __lsx_vilvh_h(vzero, vs);
v1 = __lsx_vadd_w(v1, vhalf);
v2 = __lsx_vadd_w(v2, vhalf);
v1 = __lsx_vsub_w(v1, __lsx_vsrli_w(v1, 8));
v2 = __lsx_vsub_w(v2, __lsx_vsrli_w(v2, 8));
v1 = __lsx_vsrli_w(v1, 8);
v2 = __lsx_vsrli_w(v2, 8);
v1 = __lsx_vpickev_h(__lsx_vsat_w(v2, 15), __lsx_vsat_w(v1, 15));
v1 = __lsx_vmaxi_h(v1, 0);
v1 = __lsx_vpickev_b(vzero, __lsx_vsat_hu(v1, 7));
__lsx_vstelm_d(v1, dst, 0, 0);
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 QList<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 QList<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 QList<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 QList<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 QList<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 QList<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 QList<QRgb> *, QDitherInfo *)
{
QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
for (int i = 0; i < count; ++i)
d[i] = QRgba64::fromArgb32(src[i] | 0xff000000);
}
static const uint *QT_FASTCALL fetchRGBA64ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
const QList<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;
}
template<bool Mask>
static void QT_FASTCALL storeRGBA64FromARGB32PM(uchar *dest, const uint *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
for (int i = 0; i < count; ++i) {
d[i] = QRgba64::fromArgb32(src[i]).unpremultiplied();
if (Mask)
d[i].setAlpha(65535);
}
}
static void QT_FASTCALL storeRGBA64FromARGB32(uchar *dest, const uint *src, int index, int count,
const QList<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 fetchRGB16FToRGB32(uint *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
for (int i = 0; i < count; ++i)
buffer[i] = s[i].toArgb32();
return buffer;
}
static void QT_FASTCALL storeRGB16FFromRGB32(uchar *dest, const uint *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
for (int i = 0; i < count; ++i)
d[i] = QRgbaFloat16::fromArgb32(src[i] | 0xff000000);
}
static const uint *QT_FASTCALL fetchRGBA16FToARGB32PM(uint *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
for (int i = 0; i < count; ++i)
buffer[i] = s[i].premultiplied().toArgb32();
return buffer;
}
static const QRgba64 *QT_FASTCALL fetchRGBA16FToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
for (int i = 0; i < count; ++i) {
QRgbaFloat16 c = s[i].premultiplied();
buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
}
return buffer;
}
static void QT_FASTCALL storeRGBA16FFromARGB32PM(uchar *dest, const uint *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
for (int i = 0; i < count; ++i)
d[i] = QRgbaFloat16::fromArgb32(src[i]).unpremultiplied();
}
static const QRgba64 *QT_FASTCALL fetchRGBA16FPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
for (int i = 0; i < count; ++i) {
QRgbaFloat16 c = s[i];
buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
}
return buffer;
}
static const uint *QT_FASTCALL fetchRGB32FToRGB32(uint *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
for (int i = 0; i < count; ++i)
buffer[i] = s[i].toArgb32();
return buffer;
}
static void QT_FASTCALL storeRGB32FFromRGB32(uchar *dest, const uint *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
for (int i = 0; i < count; ++i)
d[i] = QRgbaFloat32::fromArgb32(src[i] | 0xff000000);
}
static const uint *QT_FASTCALL fetchRGBA32FToARGB32PM(uint *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
for (int i = 0; i < count; ++i)
buffer[i] = s[i].premultiplied().toArgb32();
return buffer;
}
static const QRgba64 *QT_FASTCALL fetchRGBA32FToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
for (int i = 0; i < count; ++i) {
QRgbaFloat32 c = s[i].premultiplied();
buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
}
return buffer;
}
static void QT_FASTCALL storeRGBA32FFromARGB32PM(uchar *dest, const uint *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
for (int i = 0; i < count; ++i)
d[i] = QRgbaFloat32::fromArgb32(src[i]).unpremultiplied();
}
static const QRgba64 *QT_FASTCALL fetchRGBA32FPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
for (int i = 0; i < count; ++i) {
QRgbaFloat32 c = s[i];
buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
}
return buffer;
}
inline const uint *qt_convertCMYK8888ToARGB32PM(uint *buffer, const uint *src, int count)
{
UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint s) {
const QColor color = QCmyk32::fromCmyk32(s).toColor();
return color.rgba();
});
return buffer;
}
static void QT_FASTCALL convertCMYK8888ToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
{
qt_convertCMYK8888ToARGB32PM(buffer, buffer, count);
}
static const QRgba64 *QT_FASTCALL convertCMYK8888ToToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = QCmyk32::fromCmyk32(src[i]).toColor().rgba64();
return buffer;
}
static const uint *QT_FASTCALL fetchCMYK8888ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const uint *s = reinterpret_cast<const uint *>(src) + index;
for (int i = 0; i < count; ++i)
buffer[i] = QCmyk32::fromCmyk32(s[i]).toColor().rgba();
return buffer;
}
static const QRgba64 *QT_FASTCALL fetchCMYK8888ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const uint *s = reinterpret_cast<const uint *>(src) + index;
for (int i = 0; i < count; ++i)
buffer[i] = QCmyk32::fromCmyk32(s[i]).toColor().rgba64();
return buffer;
}
static void QT_FASTCALL storeCMYK8888FromARGB32PM(uchar *dest, const uint *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
for (int i = 0; i < count; ++i) {
QColor c = qUnpremultiply(src[i]);
d[i] = QCmyk32::fromColor(c).toUint();
}
}
static void QT_FASTCALL storeCMYK8888FromRGB32(uchar *dest, const uint *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
for (int i = 0; i < count; ++i) {
QColor c = src[i];
d[i] = QCmyk32::fromColor(c).toUint();
}
}
// 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[] = {
{ false, false, QPixelLayout::BPPNone, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }, // Format_Invalid
{ false, false, QPixelLayout::BPP1MSB, nullptr,
convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
fetchIndexedToARGB32PM<QPixelLayout::BPP1MSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1MSB>,
nullptr, nullptr }, // Format_Mono
{ false, false, QPixelLayout::BPP1LSB, nullptr,
convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
fetchIndexedToARGB32PM<QPixelLayout::BPP1LSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1LSB>,
nullptr, nullptr }, // Format_MonoLSB
{ false, false, QPixelLayout::BPP8, nullptr,
convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
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, convertAlpha8To<QRgba64>,
fetchAlpha8ToRGB32, fetchAlpha8To<QRgba64>,
storeAlpha8FromARGB32PM, nullptr }, // Format_Alpha8
{ false, false, QPixelLayout::BPP8, nullptr,
convertGrayscale8ToRGB32, convertGrayscale8To<QRgba64>,
fetchGrayscale8ToRGB32, fetchGrayscale8To<QRgba64>,
storeGrayscale8FromARGB32PM, storeGrayscale8FromRGB32 }, // Format_Grayscale8
{ false, false, QPixelLayout::BPP64, rbSwap_4x16,
convertPassThrough, nullptr,
fetchRGB64ToRGB32, fetchPassThrough64,
storeRGBA64FromARGB32PM<true>, storeRGB64FromRGB32 }, // Format_RGBX64
{ true, false, QPixelLayout::BPP64, rbSwap_4x16,
convertARGB32ToARGB32PM, nullptr,
fetchRGBA64ToARGB32PM, fetchRGBA64ToRGBA64PM,
storeRGBA64FromARGB32PM<false>, storeRGB64FromRGB32 }, // Format_RGBA64
{ true, true, QPixelLayout::BPP64, rbSwap_4x16,
convertPassThrough, nullptr,
fetchRGB64ToRGB32, fetchPassThrough64,
storeRGBA64FromARGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied
{ false, false, QPixelLayout::BPP16, nullptr,
convertGrayscale16ToRGB32, convertGrayscale16To<QRgba64>,
fetchGrayscale16ToRGB32, fetchGrayscale16To<QRgba64>,
storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 }, // Format_Grayscale16
pixelLayoutRGB<QImage::Format_BGR888>(),
{ false, false, QPixelLayout::BPP16FPx4, rbSwap_4x16,
convertPassThrough, nullptr,
fetchRGB16FToRGB32, fetchRGBA16FPMToRGBA64PM,
storeRGB16FFromRGB32, storeRGB16FFromRGB32 }, // Format_RGBX16FPx4
{ true, false, QPixelLayout::BPP16FPx4, rbSwap_4x16,
convertARGB32ToARGB32PM, nullptr,
fetchRGBA16FToARGB32PM, fetchRGBA16FToRGBA64PM,
storeRGBA16FFromARGB32PM, storeRGB16FFromRGB32 }, // Format_RGBA16FPx4
{ true, true, QPixelLayout::BPP16FPx4, rbSwap_4x16,
convertPassThrough, nullptr,
fetchRGB16FToRGB32, fetchRGBA16FPMToRGBA64PM,
storeRGB16FFromRGB32, storeRGB16FFromRGB32 }, // Format_RGBA16FPx4_Premultiplied
{ false, false, QPixelLayout::BPP32FPx4, rbSwap_4x32,
convertPassThrough, nullptr,
fetchRGB32FToRGB32, fetchRGBA32FPMToRGBA64PM,
storeRGB32FFromRGB32, storeRGB32FFromRGB32 }, // Format_RGBX32FPx4
{ true, false, QPixelLayout::BPP32FPx4, rbSwap_4x32,
convertARGB32ToARGB32PM, nullptr,
fetchRGBA32FToARGB32PM, fetchRGBA32FToRGBA64PM,
storeRGBA32FFromARGB32PM, storeRGB32FFromRGB32 }, // Format_RGBA32FPx4
{ true, true, QPixelLayout::BPP32FPx4, rbSwap_4x32,
convertPassThrough, nullptr,
fetchRGB32FToRGB32, fetchRGBA32FPMToRGBA64PM,
storeRGB32FFromRGB32, storeRGB32FFromRGB32 }, // Format_RGBA32FPx4_Premultiplied
{ false, false, QPixelLayout::BPP32, nullptr,
convertCMYK8888ToARGB32PM, convertCMYK8888ToToRGBA64PM,
fetchCMYK8888ToARGB32PM, fetchCMYK8888ToRGBA64PM,
storeCMYK8888FromARGB32PM, storeCMYK8888FromRGB32 }, // Format_CMYK8888
};
static_assert(std::size(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 QList<QRgb> *clut, QDitherInfo *dither)
{
Q_DECL_UNINITIALIZED 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 QList<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 QList<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 QList<QRgb> *, QDitherInfo *)
{
uint *d = (uint*)dest + index;
#ifdef __SSE2__
qConvertRGBA64PMToA2RGB30PM_sse2<PixelOrder>(d, src, count);
#elif defined (__loongarch_sx)
qConvertRGBA64PMToA2RGB30PM_lsx<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 QList<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 QList<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 QList<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 QList<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());
}
}
static void QT_FASTCALL storeRGBX16FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
for (int i = 0; i < count; ++i) {
d[i] = qConvertRgb64ToRgbaF16(src[i]).unpremultiplied();
d[i].setAlpha(1.0);
}
}
static void QT_FASTCALL storeRGBA16FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
for (int i = 0; i < count; ++i)
d[i] = qConvertRgb64ToRgbaF16(src[i]).unpremultiplied();
}
static void QT_FASTCALL storeRGBA16FPMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
for (int i = 0; i < count; ++i)
d[i] = qConvertRgb64ToRgbaF16(src[i]);
}
static void QT_FASTCALL storeRGBX32FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
for (int i = 0; i < count; ++i) {
d[i] = qConvertRgb64ToRgbaF32(src[i]).unpremultiplied();
d[i].setAlpha(1.0);
}
}
static void QT_FASTCALL storeRGBA32FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
for (int i = 0; i < count; ++i)
d[i] = qConvertRgb64ToRgbaF32(src[i]).unpremultiplied();
}
static void QT_FASTCALL storeRGBA32FPMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
for (int i = 0; i < count; ++i)
d[i] = qConvertRgb64ToRgbaF32(src[i]);
}
static void QT_FASTCALL storeCMYKFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
for (int i = 0; i < count; ++i)
d[i] = QCmyk32::fromColor(QColor(src[i])).toUint();
}
ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[] = {
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>,
storeRGBX16FFromRGBA64PM,
storeRGBA16FFromRGBA64PM,
storeRGBA16FPMFromRGBA64PM,
storeRGBX32FFromRGBA64PM,
storeRGBA32FFromRGBA64PM,
storeRGBA32FPMFromRGBA64PM,
storeCMYKFromRGBA64PM,
};
static_assert(std::size(qStoreFromRGBA64PM) == QImage::NImageFormats);
#if QT_CONFIG(raster_fp)
static void QT_FASTCALL convertToRgbaF32(QRgbaFloat32 *dest, const uint *src, int length)
{
for (int i = 0; i < length; ++i)
dest[i] = QRgbaFloat32::fromArgb32(src[i]);
}
template<QImage::Format format>
static const QRgbaFloat32 * QT_FASTCALL convertGenericToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
const QList<QRgb> *clut, QDitherInfo *)
{
Q_DECL_UNINITIALIZED uint buffer32[BufferSize];
memcpy(buffer32, src, count * sizeof(uint));
qPixelLayouts[format].convertToARGB32PM(buffer32, count, clut);
convertToRgbaF32(buffer, buffer32, count);
return buffer;
}
static const QRgbaFloat32 * QT_FASTCALL convertARGB32ToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = QRgbaFloat32::fromArgb32(src[i]).premultiplied();
return buffer;
}
static const QRgbaFloat32 * QT_FASTCALL convertRGBA8888ToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = QRgbaFloat32::fromArgb32(RGBA2ARGB(src[i])).premultiplied();
return buffer;
}
template<QtPixelOrder PixelOrder>
static const QRgbaFloat32 * QT_FASTCALL convertRGB30ToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i) {
QRgba64 s = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]);
buffer[i] = QRgbaFloat32::fromRgba64(s.red(), s.green(), s.blue(), s.alpha());
}
return buffer;
}
static const QRgbaFloat32 * QT_FASTCALL convertCMYKToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = QRgbaFloat32::fromArgb32(QCmyk32::fromCmyk32(src[i]).toColor().rgba());
return buffer;
}
ConvertToFPFunc qConvertToRGBA32F[] = {
nullptr,
convertIndexedTo<QRgbaFloat32>,
convertIndexedTo<QRgbaFloat32>,
convertIndexedTo<QRgbaFloat32>,
convertGenericToRGBA32F<QImage::Format_RGB32>,
convertARGB32ToRGBA32F,
convertGenericToRGBA32F<QImage::Format_ARGB32_Premultiplied>,
convertGenericToRGBA32F<QImage::Format_RGB16>,
convertGenericToRGBA32F<QImage::Format_ARGB8565_Premultiplied>,
convertGenericToRGBA32F<QImage::Format_RGB666>,
convertGenericToRGBA32F<QImage::Format_ARGB6666_Premultiplied>,
convertGenericToRGBA32F<QImage::Format_RGB555>,
convertGenericToRGBA32F<QImage::Format_ARGB8555_Premultiplied>,
convertGenericToRGBA32F<QImage::Format_RGB888>,
convertGenericToRGBA32F<QImage::Format_RGB444>,
convertGenericToRGBA32F<QImage::Format_ARGB4444_Premultiplied>,
convertGenericToRGBA32F<QImage::Format_RGBX8888>,
convertRGBA8888ToRGBA32F,
convertGenericToRGBA32F<QImage::Format_RGBA8888_Premultiplied>,
convertRGB30ToRGBA32F<PixelOrderBGR>,
convertRGB30ToRGBA32F<PixelOrderBGR>,
convertRGB30ToRGBA32F<PixelOrderRGB>,
convertRGB30ToRGBA32F<PixelOrderRGB>,
convertAlpha8To<QRgbaFloat32>,
convertGrayscale8To<QRgbaFloat32>,
nullptr,
nullptr,
nullptr,
convertGrayscale16To<QRgbaFloat32>,
convertGenericToRGBA32F<QImage::Format_BGR888>,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
convertCMYKToRGBA32F,
};
static_assert(std::size(qConvertToRGBA32F) == QImage::NImageFormats);
static const QRgbaFloat32 *QT_FASTCALL fetchRGBX64ToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
for (int i = 0; i < count; ++i) {
QRgba64 c = s[i];
buffer[i] = QRgbaFloat32::fromRgba64(c.red(), c.green(), c.blue(), 65535);
}
return buffer;
}
static const QRgbaFloat32 *QT_FASTCALL fetchRGBA64ToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
for (int i = 0; i < count; ++i)
buffer[i] = qConvertRgb64ToRgbaF32(s[i]).premultiplied();
return buffer;
}
static const QRgbaFloat32 *QT_FASTCALL fetchRGBA64PMToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
for (int i = 0; i < count; ++i)
buffer[i] = qConvertRgb64ToRgbaF32(s[i]);
return buffer;
}
static const QRgbaFloat32 *QT_FASTCALL fetchRGBA16FToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
for (int i = 0; i < count; ++i) {
auto c = s[i].premultiplied();
buffer[i] = QRgbaFloat32 { c.r, c.g, c.b, c.a};
}
return buffer;
}
static const QRgbaFloat32 *QT_FASTCALL fetchRGBA16F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
qFloatFromFloat16((float *)buffer, (const qfloat16 *)s, count * 4);
return buffer;
}
static const QRgbaFloat32 *QT_FASTCALL fetchRGBA32FToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
for (int i = 0; i < count; ++i)
buffer[i] = s[i].premultiplied();
return buffer;
}
static const QRgbaFloat32 *QT_FASTCALL fetchRGBA32F(QRgbaFloat32 *, const uchar *src, int index, int,
const QList<QRgb> *, QDitherInfo *)
{
const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
return s;
}
static const QRgbaFloat32 *QT_FASTCALL fetchCMYKToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
const uint *s = reinterpret_cast<const uint *>(src) + index;
for (int i = 0; i < count; ++i)
buffer[i] = QRgbaFloat32::fromArgb32(QCmyk32::fromCmyk32(s[i]).toColor().rgba());
return buffer;
}
FetchAndConvertPixelsFuncFP qFetchToRGBA32F[] = {
nullptr,
fetchIndexedToRGBA32F<QPixelLayout::BPP1MSB>,
fetchIndexedToRGBA32F<QPixelLayout::BPP1LSB>,
fetchIndexedToRGBA32F<QPixelLayout::BPP8>,
fetchRGBToRGB32F<QImage::Format_RGB32>,
fetchARGBToRGBA32F<QImage::Format_ARGB32>,
fetchARGBPMToRGBA32F<QImage::Format_ARGB32_Premultiplied>,
fetchRGBToRGB32F<QImage::Format_RGB16>,
fetchARGBToRGBA32F<QImage::Format_ARGB8565_Premultiplied>,
fetchRGBToRGB32F<QImage::Format_RGB666>,
fetchARGBToRGBA32F<QImage::Format_ARGB6666_Premultiplied>,
fetchRGBToRGB32F<QImage::Format_RGB555>,
fetchARGBToRGBA32F<QImage::Format_ARGB8555_Premultiplied>,
fetchRGBToRGB32F<QImage::Format_RGB888>,
fetchRGBToRGB32F<QImage::Format_RGB444>,
fetchARGBToRGBA32F<QImage::Format_ARGB4444_Premultiplied>,
fetchRGBToRGB32F<QImage::Format_RGBX8888>,
fetchARGBToRGBA32F<QImage::Format_RGBA8888>,
fetchARGBPMToRGBA32F<QImage::Format_RGBA8888_Premultiplied>,
fetchRGB30ToRGBA32F<PixelOrderBGR>,
fetchRGB30ToRGBA32F<PixelOrderBGR>,
fetchRGB30ToRGBA32F<PixelOrderRGB>,
fetchRGB30ToRGBA32F<PixelOrderRGB>,
fetchAlpha8To<QRgbaFloat32>,
fetchGrayscale8To<QRgbaFloat32>,
fetchRGBX64ToRGBA32F,
fetchRGBA64ToRGBA32F,
fetchRGBA64PMToRGBA32F,
fetchGrayscale16To<QRgbaFloat32>,
fetchRGBToRGB32F<QImage::Format_BGR888>,
fetchRGBA16F,
fetchRGBA16FToRGBA32F,
fetchRGBA16F,
fetchRGBA32F,
fetchRGBA32FToRGBA32F,
fetchRGBA32F,
fetchCMYKToRGBA32F,
};
static_assert(std::size(qFetchToRGBA32F) == QImage::NImageFormats);
static void QT_FASTCALL convertFromRgba32f(uint *dest, const QRgbaFloat32 *src, int length)
{
for (int i = 0; i < length; ++i)
dest[i] = src[i].toArgb32();
}
template<QImage::Format format>
static void QT_FASTCALL storeGenericFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *clut, QDitherInfo *dither)
{
Q_DECL_UNINITIALIZED uint buffer[BufferSize];
convertFromRgba32f(buffer, src, count);
qPixelLayouts[format].storeFromARGB32PM(dest, buffer, index, count, clut, dither);
}
static void QT_FASTCALL storeARGB32FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
uint *d = (uint*)dest + index;
for (int i = 0; i < count; ++i)
d[i] = src[i].unpremultiplied().toArgb32();
}
static void QT_FASTCALL storeRGBA8888FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
uint *d = (uint*)dest + index;
for (int i = 0; i < count; ++i)
d[i] = ARGB2RGBA(src[i].unpremultiplied().toArgb32());
}
template<QtPixelOrder PixelOrder>
static void QT_FASTCALL storeRGB30FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
uint *d = (uint*)dest + index;
for (int i = 0; i < count; ++i) {
const auto s = src[i];
d[i] = qConvertRgb64ToRgb30<PixelOrder>(QRgba64::fromRgba64(s.red16(), s.green16(), s.blue16(), s.alpha16()));
}
}
static void QT_FASTCALL storeRGBX64FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
for (int i = 0; i < count; ++i) {
const auto s = src[i].unpremultiplied();
d[i] = QRgba64::fromRgba64(s.red16(), s.green16(), s.blue16(), 65535);
}
}
static void QT_FASTCALL storeRGBA64FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
for (int i = 0; i < count; ++i) {
const auto s = src[i].unpremultiplied();
d[i] = QRgba64::fromRgba64(s.red16(), s.green16(), s.blue16(), s.alpha16());
}
}
static void QT_FASTCALL storeRGBA64PMFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
for (int i = 0; i < count; ++i)
d[i] = QRgba64::fromRgba64(src[i].red16(), src[i].green16(), src[i].blue16(), src[i].alpha16());
}
static void QT_FASTCALL storeGray16FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
quint16 *d = reinterpret_cast<quint16 *>(dest) + index;
for (int i = 0; i < count; ++i) {
auto s = src[i].unpremultiplied();
d[i] = qGray(s.red16(), s.green16(), s.blue16());
}
}
static void QT_FASTCALL storeRGBX16FFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
for (int i = 0; i < count; ++i) {
auto s = src[i].unpremultiplied();
d[i] = QRgbaFloat16{ qfloat16(s.r), qfloat16(s.g), qfloat16(s.b), qfloat16(1.0f) };
}
}
static void QT_FASTCALL storeRGBA16FFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
for (int i = 0; i < count; ++i) {
auto s = src[i].unpremultiplied();
d[i] = QRgbaFloat16{ qfloat16(s.r), qfloat16(s.g), qfloat16(s.b), qfloat16(s.a) };
}
}
static void QT_FASTCALL storeRGBA16FPMFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
qFloatToFloat16((qfloat16 *)d, (const float *)src, count * 4);
}
static void QT_FASTCALL storeRGBX32FFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
for (int i = 0; i < count; ++i) {
auto s = src[i].unpremultiplied();
s.a = 1.0f;
d[i] = s;
}
}
static void QT_FASTCALL storeRGBA32FFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
for (int i = 0; i < count; ++i)
d[i] = src[i].unpremultiplied();
}
static void QT_FASTCALL storeRGBA32FPMFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
if (d != src) {
for (int i = 0; i < count; ++i)
d[i] = src[i];
}
}
static void QT_FASTCALL storeCMYKFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
for (int i = 0; i < count; ++i) {
// Yikes, this really needs enablers in QColor and friends
d[i] = QCmyk32::fromColor(QColor(src[i].toArgb32())).toUint();
}
}
ConvertAndStorePixelsFuncFP qStoreFromRGBA32F[] = {
nullptr,
nullptr,
nullptr,
nullptr,
storeGenericFromRGBA32F<QImage::Format_RGB32>,
storeARGB32FromRGBA32F,
storeGenericFromRGBA32F<QImage::Format_ARGB32_Premultiplied>,
storeGenericFromRGBA32F<QImage::Format_RGB16>,
storeGenericFromRGBA32F<QImage::Format_ARGB8565_Premultiplied>,
storeGenericFromRGBA32F<QImage::Format_RGB666>,
storeGenericFromRGBA32F<QImage::Format_ARGB6666_Premultiplied>,
storeGenericFromRGBA32F<QImage::Format_RGB555>,
storeGenericFromRGBA32F<QImage::Format_ARGB8555_Premultiplied>,
storeGenericFromRGBA32F<QImage::Format_RGB888>,
storeGenericFromRGBA32F<QImage::Format_RGB444>,
storeGenericFromRGBA32F<QImage::Format_ARGB4444_Premultiplied>,
storeGenericFromRGBA32F<QImage::Format_RGBX8888>,
storeRGBA8888FromRGBA32F,
storeGenericFromRGBA32F<QImage::Format_RGBA8888_Premultiplied>,
storeRGB30FromRGBA32F<PixelOrderBGR>,
storeRGB30FromRGBA32F<PixelOrderBGR>,
storeRGB30FromRGBA32F<PixelOrderRGB>,
storeRGB30FromRGBA32F<PixelOrderRGB>,
storeGenericFromRGBA32F<QImage::Format_Alpha8>,
storeGenericFromRGBA32F<QImage::Format_Grayscale8>,
storeRGBX64FromRGBA32F,
storeRGBA64FromRGBA32F,
storeRGBA64PMFromRGBA32F,
storeGray16FromRGBA32F,
storeGenericFromRGBA32F<QImage::Format_BGR888>,
storeRGBX16FFromRGBA32F,
storeRGBA16FFromRGBA32F,
storeRGBA16FPMFromRGBA32F,
storeRGBX32FFromRGBA32F,
storeRGBA32FFromRGBA32F,
storeRGBA32FPMFromRGBA32F,
storeCMYKFromRGBA32F,
};
static_assert(std::size(qStoreFromRGBA32F) == QImage::NImageFormats);
#endif // QT_CONFIG(raster_fp)
QT_END_NAMESPACE