Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qpixellayout.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <qglobal.h>
5
8#include "qrgba64_p.h"
9#include <QtCore/private/qsimd_p.h>
10#include <QtGui/private/qcmyk_p.h>
11
13
14template<QImage::Format> constexpr uint redWidth();
15template<QImage::Format> constexpr uint redShift();
16template<QImage::Format> constexpr uint greenWidth();
17template<QImage::Format> constexpr uint greenShift();
18template<QImage::Format> constexpr uint blueWidth();
19template<QImage::Format> constexpr uint blueShift();
20template<QImage::Format> constexpr uint alphaWidth();
21template<QImage::Format> constexpr uint alphaShift();
22
23template<> constexpr uint redWidth<QImage::Format_RGB32>() { return 8; }
24template<> constexpr uint redWidth<QImage::Format_ARGB32>() { return 8; }
25template<> constexpr uint redWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
26template<> constexpr uint redWidth<QImage::Format_RGB16>() { return 5; }
27template<> constexpr uint redWidth<QImage::Format_RGB444>() { return 4; }
28template<> constexpr uint redWidth<QImage::Format_RGB555>() { return 5; }
29template<> constexpr uint redWidth<QImage::Format_RGB666>() { return 6; }
30template<> constexpr uint redWidth<QImage::Format_RGB888>() { return 8; }
31template<> constexpr uint redWidth<QImage::Format_BGR888>() { return 8; }
32template<> constexpr uint redWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
33template<> constexpr uint redWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
34template<> constexpr uint redWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
35template<> constexpr uint redWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
36template<> constexpr uint redWidth<QImage::Format_RGBX8888>() { return 8; }
37template<> constexpr uint redWidth<QImage::Format_RGBA8888>() { return 8; }
38template<> constexpr uint redWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
39
40template<> constexpr uint redShift<QImage::Format_RGB32>() { return 16; }
41template<> constexpr uint redShift<QImage::Format_ARGB32>() { return 16; }
42template<> constexpr uint redShift<QImage::Format_ARGB32_Premultiplied>() { return 16; }
43template<> constexpr uint redShift<QImage::Format_RGB16>() { return 11; }
44template<> constexpr uint redShift<QImage::Format_RGB444>() { return 8; }
45template<> constexpr uint redShift<QImage::Format_RGB555>() { return 10; }
46template<> constexpr uint redShift<QImage::Format_RGB666>() { return 12; }
47template<> constexpr uint redShift<QImage::Format_RGB888>() { return 16; }
48template<> constexpr uint redShift<QImage::Format_BGR888>() { return 0; }
49template<> constexpr uint redShift<QImage::Format_ARGB4444_Premultiplied>() { return 8; }
50template<> constexpr uint redShift<QImage::Format_ARGB8555_Premultiplied>() { return 18; }
51template<> constexpr uint redShift<QImage::Format_ARGB8565_Premultiplied>() { return 19; }
52template<> constexpr uint redShift<QImage::Format_ARGB6666_Premultiplied>() { return 12; }
53#if Q_BYTE_ORDER == Q_BIG_ENDIAN
54template<> constexpr uint redShift<QImage::Format_RGBX8888>() { return 24; }
55template<> constexpr uint redShift<QImage::Format_RGBA8888>() { return 24; }
56template<> constexpr uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; }
57#else
58template<> constexpr uint redShift<QImage::Format_RGBX8888>() { return 0; }
59template<> constexpr uint redShift<QImage::Format_RGBA8888>() { return 0; }
60template<> constexpr uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; }
61#endif
62template<> constexpr uint greenWidth<QImage::Format_RGB32>() { return 8; }
63template<> constexpr uint greenWidth<QImage::Format_ARGB32>() { return 8; }
64template<> constexpr uint greenWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
65template<> constexpr uint greenWidth<QImage::Format_RGB16>() { return 6; }
66template<> constexpr uint greenWidth<QImage::Format_RGB444>() { return 4; }
67template<> constexpr uint greenWidth<QImage::Format_RGB555>() { return 5; }
68template<> constexpr uint greenWidth<QImage::Format_RGB666>() { return 6; }
69template<> constexpr uint greenWidth<QImage::Format_RGB888>() { return 8; }
70template<> constexpr uint greenWidth<QImage::Format_BGR888>() { return 8; }
71template<> constexpr uint greenWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
72template<> constexpr uint greenWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
73template<> constexpr uint greenWidth<QImage::Format_ARGB8565_Premultiplied>() { return 6; }
74template<> constexpr uint greenWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
75template<> constexpr uint greenWidth<QImage::Format_RGBX8888>() { return 8; }
76template<> constexpr uint greenWidth<QImage::Format_RGBA8888>() { return 8; }
77template<> constexpr uint greenWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
78
79template<> constexpr uint greenShift<QImage::Format_RGB32>() { return 8; }
80template<> constexpr uint greenShift<QImage::Format_ARGB32>() { return 8; }
81template<> constexpr uint greenShift<QImage::Format_ARGB32_Premultiplied>() { return 8; }
82template<> constexpr uint greenShift<QImage::Format_RGB16>() { return 5; }
83template<> constexpr uint greenShift<QImage::Format_RGB444>() { return 4; }
84template<> constexpr uint greenShift<QImage::Format_RGB555>() { return 5; }
85template<> constexpr uint greenShift<QImage::Format_RGB666>() { return 6; }
86template<> constexpr uint greenShift<QImage::Format_RGB888>() { return 8; }
87template<> constexpr uint greenShift<QImage::Format_BGR888>() { return 8; }
88template<> constexpr uint greenShift<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
89template<> constexpr uint greenShift<QImage::Format_ARGB8555_Premultiplied>() { return 13; }
90template<> constexpr uint greenShift<QImage::Format_ARGB8565_Premultiplied>() { return 13; }
91template<> constexpr uint greenShift<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
92#if Q_BYTE_ORDER == Q_BIG_ENDIAN
93template<> constexpr uint greenShift<QImage::Format_RGBX8888>() { return 16; }
94template<> constexpr uint greenShift<QImage::Format_RGBA8888>() { return 16; }
95template<> constexpr uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; }
96#else
97template<> constexpr uint greenShift<QImage::Format_RGBX8888>() { return 8; }
98template<> constexpr uint greenShift<QImage::Format_RGBA8888>() { return 8; }
99template<> constexpr uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
100#endif
101template<> constexpr uint blueWidth<QImage::Format_RGB32>() { return 8; }
102template<> constexpr uint blueWidth<QImage::Format_ARGB32>() { return 8; }
103template<> constexpr uint blueWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
104template<> constexpr uint blueWidth<QImage::Format_RGB16>() { return 5; }
105template<> constexpr uint blueWidth<QImage::Format_RGB444>() { return 4; }
106template<> constexpr uint blueWidth<QImage::Format_RGB555>() { return 5; }
107template<> constexpr uint blueWidth<QImage::Format_RGB666>() { return 6; }
108template<> constexpr uint blueWidth<QImage::Format_RGB888>() { return 8; }
109template<> constexpr uint blueWidth<QImage::Format_BGR888>() { return 8; }
110template<> constexpr uint blueWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
111template<> constexpr uint blueWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
112template<> constexpr uint blueWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
113template<> constexpr uint blueWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
114template<> constexpr uint blueWidth<QImage::Format_RGBX8888>() { return 8; }
115template<> constexpr uint blueWidth<QImage::Format_RGBA8888>() { return 8; }
116template<> constexpr uint blueWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
117
118template<> constexpr uint blueShift<QImage::Format_RGB32>() { return 0; }
119template<> constexpr uint blueShift<QImage::Format_ARGB32>() { return 0; }
120template<> constexpr uint blueShift<QImage::Format_ARGB32_Premultiplied>() { return 0; }
121template<> constexpr uint blueShift<QImage::Format_RGB16>() { return 0; }
122template<> constexpr uint blueShift<QImage::Format_RGB444>() { return 0; }
123template<> constexpr uint blueShift<QImage::Format_RGB555>() { return 0; }
124template<> constexpr uint blueShift<QImage::Format_RGB666>() { return 0; }
125template<> constexpr uint blueShift<QImage::Format_RGB888>() { return 0; }
126template<> constexpr uint blueShift<QImage::Format_BGR888>() { return 16; }
127template<> constexpr uint blueShift<QImage::Format_ARGB4444_Premultiplied>() { return 0; }
128template<> constexpr uint blueShift<QImage::Format_ARGB8555_Premultiplied>() { return 8; }
129template<> constexpr uint blueShift<QImage::Format_ARGB8565_Premultiplied>() { return 8; }
130template<> constexpr uint blueShift<QImage::Format_ARGB6666_Premultiplied>() { return 0; }
131#if Q_BYTE_ORDER == Q_BIG_ENDIAN
132template<> constexpr uint blueShift<QImage::Format_RGBX8888>() { return 8; }
133template<> constexpr uint blueShift<QImage::Format_RGBA8888>() { return 8; }
134template<> constexpr uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
135#else
136template<> constexpr uint blueShift<QImage::Format_RGBX8888>() { return 16; }
137template<> constexpr uint blueShift<QImage::Format_RGBA8888>() { return 16; }
138template<> constexpr uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; }
139#endif
140template<> constexpr uint alphaWidth<QImage::Format_RGB32>() { return 0; }
141template<> constexpr uint alphaWidth<QImage::Format_ARGB32>() { return 8; }
142template<> constexpr uint alphaWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
143template<> constexpr uint alphaWidth<QImage::Format_RGB16>() { return 0; }
144template<> constexpr uint alphaWidth<QImage::Format_RGB444>() { return 0; }
145template<> constexpr uint alphaWidth<QImage::Format_RGB555>() { return 0; }
146template<> constexpr uint alphaWidth<QImage::Format_RGB666>() { return 0; }
147template<> constexpr uint alphaWidth<QImage::Format_RGB888>() { return 0; }
148template<> constexpr uint alphaWidth<QImage::Format_BGR888>() { return 0; }
149template<> constexpr uint alphaWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
150template<> constexpr uint alphaWidth<QImage::Format_ARGB8555_Premultiplied>() { return 8; }
151template<> constexpr uint alphaWidth<QImage::Format_ARGB8565_Premultiplied>() { return 8; }
152template<> constexpr uint alphaWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
153template<> constexpr uint alphaWidth<QImage::Format_RGBX8888>() { return 0; }
154template<> constexpr uint alphaWidth<QImage::Format_RGBA8888>() { return 8; }
155template<> constexpr uint alphaWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
156
157template<> constexpr uint alphaShift<QImage::Format_RGB32>() { return 24; }
158template<> constexpr uint alphaShift<QImage::Format_ARGB32>() { return 24; }
159template<> constexpr uint alphaShift<QImage::Format_ARGB32_Premultiplied>() { return 24; }
160template<> constexpr uint alphaShift<QImage::Format_RGB16>() { return 0; }
161template<> constexpr uint alphaShift<QImage::Format_RGB444>() { return 0; }
162template<> constexpr uint alphaShift<QImage::Format_RGB555>() { return 0; }
163template<> constexpr uint alphaShift<QImage::Format_RGB666>() { return 0; }
164template<> constexpr uint alphaShift<QImage::Format_RGB888>() { return 0; }
165template<> constexpr uint alphaShift<QImage::Format_BGR888>() { return 0; }
166template<> constexpr uint alphaShift<QImage::Format_ARGB4444_Premultiplied>() { return 12; }
167template<> constexpr uint alphaShift<QImage::Format_ARGB8555_Premultiplied>() { return 0; }
168template<> constexpr uint alphaShift<QImage::Format_ARGB8565_Premultiplied>() { return 0; }
169template<> constexpr uint alphaShift<QImage::Format_ARGB6666_Premultiplied>() { return 18; }
170#if Q_BYTE_ORDER == Q_BIG_ENDIAN
171template<> constexpr uint alphaShift<QImage::Format_RGBX8888>() { return 0; }
172template<> constexpr uint alphaShift<QImage::Format_RGBA8888>() { return 0; }
173template<> constexpr uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; }
174#else
175template<> constexpr uint alphaShift<QImage::Format_RGBX8888>() { return 24; }
176template<> constexpr uint alphaShift<QImage::Format_RGBA8888>() { return 24; }
177template<> constexpr uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; }
178#endif
179
180template<QImage::Format> constexpr QPixelLayout::BPP bitsPerPixel();
181template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB32>() { return QPixelLayout::BPP32; }
182template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB32>() { return QPixelLayout::BPP32; }
183template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB32_Premultiplied>() { return QPixelLayout::BPP32; }
184template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB16>() { return QPixelLayout::BPP16; }
185template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB444>() { return QPixelLayout::BPP16; }
186template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB555>() { return QPixelLayout::BPP16; }
187template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB666>() { return QPixelLayout::BPP24; }
188template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB888>() { return QPixelLayout::BPP24; }
189template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_BGR888>() { return QPixelLayout::BPP24; }
190template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB4444_Premultiplied>() { return QPixelLayout::BPP16; }
191template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8555_Premultiplied>() { return QPixelLayout::BPP24; }
192template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8565_Premultiplied>() { return QPixelLayout::BPP24; }
193template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB6666_Premultiplied>() { return QPixelLayout::BPP24; }
194template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBX8888>() { return QPixelLayout::BPP32; }
195template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888>() { return QPixelLayout::BPP32; }
196template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888_Premultiplied>() { return QPixelLayout::BPP32; }
197
198template <QPixelLayout::BPP width> static
199void QT_FASTCALL storePixel(uchar *dest, int index, uint pixel);
200
201template <>
202inline void QT_FASTCALL storePixel<QPixelLayout::BPP16>(uchar *dest, int index, uint pixel)
203{
204 reinterpret_cast<quint16 *>(dest)[index] = quint16(pixel);
205}
206
207template <>
208inline void QT_FASTCALL storePixel<QPixelLayout::BPP24>(uchar *dest, int index, uint pixel)
209{
210 reinterpret_cast<quint24 *>(dest)[index] = quint24(pixel);
211}
212
213template <QPixelLayout::BPP bpp> static
214inline uint QT_FASTCALL fetchPixel(const uchar *, int)
215{
216 Q_UNREACHABLE_RETURN(0);
217}
218
219template <>
220inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP1LSB>(const uchar *src, int index)
221{
222 return (src[index >> 3] >> (index & 7)) & 1;
223}
224
225template <>
226inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP1MSB>(const uchar *src, int index)
227{
228 return (src[index >> 3] >> (~index & 7)) & 1;
229}
230
231template <>
232inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP8>(const uchar *src, int index)
233{
234 return src[index];
235}
236
237template <>
238inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP16>(const uchar *src, int index)
239{
240 return reinterpret_cast<const quint16 *>(src)[index];
241}
242
243template <>
244inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP24>(const uchar *src, int index)
245{
246 return reinterpret_cast<const quint24 *>(src)[index];
247}
248
249template <>
250inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP32>(const uchar *src, int index)
251{
252 return reinterpret_cast<const uint *>(src)[index];
253}
254
255template <>
256[[maybe_unused]]
257inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP64>(const uchar *src, int index)
258{
259 // We have to do the conversion in fetch to fit into a 32bit uint
260 QRgba64 c = reinterpret_cast<const QRgba64 *>(src)[index];
261 return c.toArgb32();
262}
263
264template <>
265[[maybe_unused]]
266inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP16FPx4>(const uchar *src, int index)
267{
268 // We have to do the conversion in fetch to fit into a 32bit uint
269 QRgbaFloat16 c = reinterpret_cast<const QRgbaFloat16 *>(src)[index];
270 return c.toArgb32();
271}
272
273template <>
274[[maybe_unused]]
275inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP32FPx4>(const uchar *src, int index)
276{
277 // We have to do the conversion in fetch to fit into a 32bit uint
278 QRgbaFloat32 c = reinterpret_cast<const QRgbaFloat32 *>(src)[index];
279 return c.toArgb32();
280}
281
282template<QImage::Format Format>
283static inline uint convertPixelToRGB32(uint s)
284{
285 constexpr uint redMask = ((1 << redWidth<Format>()) - 1);
286 constexpr uint greenMask = ((1 << greenWidth<Format>()) - 1);
287 constexpr uint blueMask = ((1 << blueWidth<Format>()) - 1);
288
289 constexpr uchar redLeftShift = 8 - redWidth<Format>();
290 constexpr uchar greenLeftShift = 8 - greenWidth<Format>();
291 constexpr uchar blueLeftShift = 8 - blueWidth<Format>();
292
293 constexpr uchar redRightShift = 2 * redWidth<Format>() - 8;
294 constexpr uchar greenRightShift = 2 * greenWidth<Format>() - 8;
295 constexpr uchar blueRightShift = 2 * blueWidth<Format>() - 8;
296
297 uint red = (s >> redShift<Format>()) & redMask;
298 uint green = (s >> greenShift<Format>()) & greenMask;
299 uint blue = (s >> blueShift<Format>()) & blueMask;
300
301 red = ((red << redLeftShift) | (red >> redRightShift)) << 16;
302 green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8;
303 blue = (blue << blueLeftShift) | (blue >> blueRightShift);
304 return 0xff000000 | red | green | blue;
305}
306
307template<QImage::Format Format>
308static void QT_FASTCALL convertToRGB32(uint *buffer, int count, const QList<QRgb> *)
309{
310 for (int i = 0; i < count; ++i)
311 buffer[i] = convertPixelToRGB32<Format>(buffer[i]);
312}
313
314#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
315extern const uint * QT_FASTCALL fetchPixelsBPP24_ssse3(uint *dest, const uchar*src, int index, int count);
316#elif defined QT_COMPILER_SUPPORTS_LSX
317// from qdrawhelper_lsx.cpp
318extern const uint * QT_FASTCALL fetchPixelsBPP24_lsx(uint *dest, const uchar *src, int index, int count);
319#endif
320
321template<QImage::Format Format>
322static const uint *QT_FASTCALL fetchRGBToRGB32(uint *buffer, const uchar *src, int index, int count,
323 const QList<QRgb> *, QDitherInfo *)
324{
325 constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
326#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
327 if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) {
328 // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3
329 // to vectorize the deforested version below.
330 fetchPixelsBPP24_ssse3(buffer, src, index, count);
331 convertToRGB32<Format>(buffer, count, nullptr);
332 return buffer;
333 }
334#elif defined QT_COMPILER_SUPPORTS_LSX
335 if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(LSX)) {
336 fetchPixelsBPP24_lsx(buffer, src, index, count);
337 convertToRGB32<Format>(buffer, count, nullptr);
338 return buffer;
339 }
340#endif
341 for (int i = 0; i < count; ++i)
342 buffer[i] = convertPixelToRGB32<Format>(fetchPixel<BPP>(src, index + i));
343 return buffer;
344}
345
346template<QImage::Format Format>
347static inline QRgba64 convertPixelToRGB64(uint s)
348{
349 return QRgba64::fromArgb32(convertPixelToRGB32<Format>(s));
350}
351
352template<QImage::Format Format>
353static const QRgba64 *QT_FASTCALL convertToRGB64(QRgba64 *buffer, const uint *src, int count,
354 const QList<QRgb> *, QDitherInfo *)
355{
356 for (int i = 0; i < count; ++i)
357 buffer[i] = convertPixelToRGB64<Format>(src[i]);
358 return buffer;
359}
360
361template<QImage::Format Format>
362static const QRgba64 *QT_FASTCALL fetchRGBToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
363 const QList<QRgb> *, QDitherInfo *)
364{
365 for (int i = 0; i < count; ++i)
366 buffer[i] = convertPixelToRGB64<Format>(fetchPixel<bitsPerPixel<Format>()>(src, index + i));
367 return buffer;
368}
369
370template<QImage::Format Format>
371Q_ALWAYS_INLINE static QRgbaFloat32 convertPixelToRGB32F(uint s)
372{
373 return QRgbaFloat32::fromArgb32(convertPixelToRGB32<Format>(s));
374}
375
376template<QImage::Format Format>
377static const QRgbaFloat32 *QT_FASTCALL fetchRGBToRGB32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
378 const QList<QRgb> *, QDitherInfo *)
379{
380 for (int i = 0; i < count; ++i)
381 buffer[i] = convertPixelToRGB32F<Format>(fetchPixel<bitsPerPixel<Format>()>(src, index + i));
382 return buffer;
383}
384
385template<QImage::Format Format>
386static inline uint convertPixelToARGB32PM(uint s)
387{
388 constexpr uint alphaMask = ((1 << alphaWidth<Format>()) - 1);
389 constexpr uint redMask = ((1 << redWidth<Format>()) - 1);
390 constexpr uint greenMask = ((1 << greenWidth<Format>()) - 1);
391 constexpr uint blueMask = ((1 << blueWidth<Format>()) - 1);
392
393 constexpr uchar alphaLeftShift = 8 - alphaWidth<Format>();
394 constexpr uchar redLeftShift = 8 - redWidth<Format>();
395 constexpr uchar greenLeftShift = 8 - greenWidth<Format>();
396 constexpr uchar blueLeftShift = 8 - blueWidth<Format>();
397
398 constexpr uchar alphaRightShift = 2 * alphaWidth<Format>() - 8;
399 constexpr uchar redRightShift = 2 * redWidth<Format>() - 8;
400 constexpr uchar greenRightShift = 2 * greenWidth<Format>() - 8;
401 constexpr uchar blueRightShift = 2 * blueWidth<Format>() - 8;
402
403 constexpr bool mustMin = (alphaWidth<Format>() != redWidth<Format>()) ||
404 (alphaWidth<Format>() != greenWidth<Format>()) ||
405 (alphaWidth<Format>() != blueWidth<Format>());
406
407 uint alpha = (s >> alphaShift<Format>()) & alphaMask;
408 uint red = (s >> redShift<Format>()) & redMask;
409 uint green = (s >> greenShift<Format>()) & greenMask;
410 uint blue = (s >> blueShift<Format>()) & blueMask;
411
412 alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift);
413 red = (red << redLeftShift) | (red >> redRightShift);
414 green = (green << greenLeftShift) | (green >> greenRightShift);
415 blue = (blue << blueLeftShift) | (blue >> blueRightShift);
416
417 if (mustMin) {
418 red = qMin(alpha, red);
419 green = qMin(alpha, green);
420 blue = qMin(alpha, blue);
421 }
422
423 return (alpha << 24) | (red << 16) | (green << 8) | blue;
424}
425
426template<QImage::Format Format>
427static void QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
428{
429 for (int i = 0; i < count; ++i)
430 buffer[i] = convertPixelToARGB32PM<Format>(buffer[i]);
431}
432
433template<QImage::Format Format>
434static const uint *QT_FASTCALL fetchARGBPMToARGB32PM(uint *buffer, const uchar *src, int index, int count,
435 const QList<QRgb> *, QDitherInfo *)
436{
437 constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
438#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
439 if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) {
440 // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3
441 // to vectorize the deforested version below.
442 fetchPixelsBPP24_ssse3(buffer, src, index, count);
443 convertARGBPMToARGB32PM<Format>(buffer, count, nullptr);
444 return buffer;
445 }
446#elif defined QT_COMPILER_SUPPORTS_LSX
447 if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(LSX)) {
448 fetchPixelsBPP24_lsx(buffer, src, index, count);
449 convertARGBPMToARGB32PM<Format>(buffer, count, nullptr);
450 return buffer;
451 }
452#endif
453 for (int i = 0; i < count; ++i)
454 buffer[i] = convertPixelToARGB32PM<Format>(fetchPixel<BPP>(src, index + i));
455 return buffer;
456}
457
458template<QImage::Format Format>
459static inline QRgba64 convertPixelToRGBA64PM(uint s)
460{
461 return QRgba64::fromArgb32(convertPixelToARGB32PM<Format>(s));
462}
463
464template<QImage::Format Format>
465static const QRgba64 *QT_FASTCALL convertARGBPMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
466 const QList<QRgb> *, QDitherInfo *)
467{
468 for (int i = 0; i < count; ++i)
469 buffer[i] = convertPixelToRGB64<Format>(src[i]);
470 return buffer;
471}
472
473template<QImage::Format Format>
474static const QRgba64 *QT_FASTCALL fetchARGBPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
475 const QList<QRgb> *, QDitherInfo *)
476{
477 constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
478 for (int i = 0; i < count; ++i)
479 buffer[i] = convertPixelToRGBA64PM<Format>(fetchPixel<bpp>(src, index + i));
480 return buffer;
481}
482
483template<QImage::Format Format>
484Q_ALWAYS_INLINE static QRgbaFloat32 convertPixelToRGBA32F(uint s)
485{
486 return QRgbaFloat32::fromArgb32(convertPixelToARGB32PM<Format>(s));
487}
488
489template<QImage::Format Format>
490static const QRgbaFloat32 *QT_FASTCALL fetchARGBPMToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
491 const QList<QRgb> *, QDitherInfo *)
492{
493 constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
494 for (int i = 0; i < count; ++i)
495 buffer[i] = convertPixelToRGBA32F<Format>(fetchPixel<bpp>(src, index + i));
496 return buffer;
497}
498
499template<QImage::Format Format>
500static const QRgbaFloat32 *QT_FASTCALL fetchARGBToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
501 const QList<QRgb> *, QDitherInfo *)
502{
503 constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
504 for (int i = 0; i < count; ++i)
505 buffer[i] = convertPixelToRGBA32F<Format>(fetchPixel<bpp>(src, index + i)).premultiplied();
506 return buffer;
507}
508
509template<QImage::Format Format, bool fromRGB>
510static void QT_FASTCALL storeRGBFromARGB32PM(uchar *dest, const uint *src, int index, int count,
511 const QList<QRgb> *, QDitherInfo *dither)
512{
513 constexpr uchar rWidth = redWidth<Format>();
514 constexpr uchar gWidth = greenWidth<Format>();
515 constexpr uchar bWidth = blueWidth<Format>();
516 constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
517
518 // RGB32 -> RGB888 is not a precision loss.
519 if (!dither || (rWidth == 8 && gWidth == 8 && bWidth == 8)) {
520 constexpr uint rMask = (1 << redWidth<Format>()) - 1;
521 constexpr uint gMask = (1 << greenWidth<Format>()) - 1;
522 constexpr uint bMask = (1 << blueWidth<Format>()) - 1;
523 constexpr uchar rRightShift = 24 - redWidth<Format>();
524 constexpr uchar gRightShift = 16 - greenWidth<Format>();
525 constexpr uchar bRightShift = 8 - blueWidth<Format>();
526
527 for (int i = 0; i < count; ++i) {
528 const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]);
529 const uint r = ((c >> rRightShift) & rMask) << redShift<Format>();
530 const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>();
531 const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>();
532 storePixel<BPP>(dest, index + i, r | g | b);
533 };
534 } else {
535 // We do ordered dither by using a rounding conversion, but instead of
536 // adding half of input precision, we add the adjusted result from the
537 // bayer matrix before narrowing.
538 // Note: Rounding conversion in itself is different from the naive
539 // conversion we do above for non-dithering.
540 const uint *bayer_line = qt_bayer_matrix[dither->y & 15];
541 for (int i = 0; i < count; ++i) {
542 const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]);
543 const int d = bayer_line[(dither->x + i) & 15];
544 const int dr = d - ((d + 1) >> rWidth);
545 const int dg = d - ((d + 1) >> gWidth);
546 const int db = d - ((d + 1) >> bWidth);
547 int r = qRed(c);
548 int g = qGreen(c);
549 int b = qBlue(c);
550 r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth);
551 g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth);
552 b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth);
553 const uint s = (r << redShift<Format>())
554 | (g << greenShift<Format>())
555 | (b << blueShift<Format>());
556 storePixel<BPP>(dest, index + i, s);
557 }
558 }
559}
560
561template<QImage::Format Format, bool fromRGB>
562static void QT_FASTCALL storeARGBPMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
563 const QList<QRgb> *, QDitherInfo *dither)
564{
565 constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
566 if (!dither) {
567 constexpr uint aMask = (1 << alphaWidth<Format>()) - 1;
568 constexpr uint rMask = (1 << redWidth<Format>()) - 1;
569 constexpr uint gMask = (1 << greenWidth<Format>()) - 1;
570 constexpr uint bMask = (1 << blueWidth<Format>()) - 1;
571
572 constexpr uchar aRightShift = 32 - alphaWidth<Format>();
573 constexpr uchar rRightShift = 24 - redWidth<Format>();
574 constexpr uchar gRightShift = 16 - greenWidth<Format>();
575 constexpr uchar bRightShift = 8 - blueWidth<Format>();
576
577 constexpr uint aOpaque = aMask << alphaShift<Format>();
578 for (int i = 0; i < count; ++i) {
579 const uint c = src[i];
580 const uint a = fromRGB ? aOpaque : (((c >> aRightShift) & aMask) << alphaShift<Format>());
581 const uint r = ((c >> rRightShift) & rMask) << redShift<Format>();
582 const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>();
583 const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>();
584 storePixel<BPP>(dest, index + i, a | r | g | b);
585 };
586 } else {
587 constexpr uchar aWidth = alphaWidth<Format>();
588 constexpr uchar rWidth = redWidth<Format>();
589 constexpr uchar gWidth = greenWidth<Format>();
590 constexpr uchar bWidth = blueWidth<Format>();
591
592 const uint *bayer_line = qt_bayer_matrix[dither->y & 15];
593 for (int i = 0; i < count; ++i) {
594 const uint c = src[i];
595 const int d = bayer_line[(dither->x + i) & 15];
596 const int da = d - ((d + 1) >> aWidth);
597 const int dr = d - ((d + 1) >> rWidth);
598 const int dg = d - ((d + 1) >> gWidth);
599 const int db = d - ((d + 1) >> bWidth);
600 int a = qAlpha(c);
601 int r = qRed(c);
602 int g = qGreen(c);
603 int b = qBlue(c);
604 if (fromRGB)
605 a = (1 << aWidth) - 1;
606 else
607 a = (a + ((da - a) >> aWidth) + 1) >> (8 - aWidth);
608 r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth);
609 g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth);
610 b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth);
611 uint s = (a << alphaShift<Format>())
612 | (r << redShift<Format>())
613 | (g << greenShift<Format>())
614 | (b << blueShift<Format>());
615 storePixel<BPP>(dest, index + i, s);
616 }
617 }
618}
619
620template<QImage::Format Format>
621static void QT_FASTCALL rbSwap(uchar *dst, const uchar *src, int count)
622{
623 constexpr uchar aWidth = alphaWidth<Format>();
624 constexpr uchar aShift = alphaShift<Format>();
625 constexpr uchar rWidth = redWidth<Format>();
626 constexpr uchar rShift = redShift<Format>();
627 constexpr uchar gWidth = greenWidth<Format>();
628 constexpr uchar gShift = greenShift<Format>();
629 constexpr uchar bWidth = blueWidth<Format>();
630 constexpr uchar bShift = blueShift<Format>();
631 static_assert(rWidth == bWidth);
632 constexpr uint redBlueMask = (1 << rWidth) - 1;
633 constexpr uint alphaGreenMask = (((1 << aWidth) - 1) << aShift)
634 | (((1 << gWidth) - 1) << gShift);
635 constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
636
637 for (int i = 0; i < count; ++i) {
638 const uint c = fetchPixel<bpp>(src, i);
639 const uint r = (c >> rShift) & redBlueMask;
640 const uint b = (c >> bShift) & redBlueMask;
641 const uint t = (c & alphaGreenMask)
642 | (r << bShift)
643 | (b << rShift);
644 storePixel<bpp>(dst, i, t);
645 }
646}
647
648static void QT_FASTCALL rbSwap_rgb32(uchar *d, const uchar *s, int count)
649{
650 const uint *src = reinterpret_cast<const uint *>(s);
651 uint *dest = reinterpret_cast<uint *>(d);
652 for (int i = 0; i < count; ++i) {
653 const uint c = src[i];
654 const uint ag = c & 0xff00ff00;
655 const uint rb = c & 0x00ff00ff;
656 dest[i] = ag | (rb << 16) | (rb >> 16);
657 }
658}
659
660#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
661template<>
662void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count)
663{
664 return rbSwap_rgb32(d, s, count);
665}
666#else
667template<>
668void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count)
669{
670 const uint *src = reinterpret_cast<const uint *>(s);
671 uint *dest = reinterpret_cast<uint *>(d);
672 for (int i = 0; i < count; ++i) {
673 const uint c = src[i];
674 const uint rb = c & 0xff00ff00;
675 const uint ga = c & 0x00ff00ff;
676 dest[i] = ga | (rb << 16) | (rb >> 16);
677 }
678}
679#endif
680
681static void QT_FASTCALL rbSwap_rgb30(uchar *d, const uchar *s, int count)
682{
683 const uint *src = reinterpret_cast<const uint *>(s);
684 uint *dest = reinterpret_cast<uint *>(d);
685 UNALIASED_CONVERSION_LOOP(dest, src, count, qRgbSwapRgb30);
686}
687
688static void QT_FASTCALL rbSwap_4x16(uchar *d, const uchar *s, int count)
689{
690 const ushort *src = reinterpret_cast<const ushort *>(s);
691 ushort *dest = reinterpret_cast<ushort *>(d);
692 if (src != dest) {
693 for (int i = 0; i < count; ++i) {
694 dest[i * 4 + 0] = src[i * 4 + 2];
695 dest[i * 4 + 1] = src[i * 4 + 1];
696 dest[i * 4 + 2] = src[i * 4 + 0];
697 dest[i * 4 + 3] = src[i * 4 + 3];
698 }
699 } else {
700 for (int i = 0; i < count; ++i) {
701 const ushort r = src[i * 4 + 0];
702 const ushort b = src[i * 4 + 2];
703 dest[i * 4 + 0] = b;
704 dest[i * 4 + 2] = r;
705 }
706 }
707}
708
709static void QT_FASTCALL rbSwap_4x32(uchar *d, const uchar *s, int count)
710{
711 const uint *src = reinterpret_cast<const uint *>(s);
712 uint *dest = reinterpret_cast<uint *>(d);
713 if (src != dest) {
714 for (int i = 0; i < count; ++i) {
715 dest[i * 4 + 0] = src[i * 4 + 2];
716 dest[i * 4 + 1] = src[i * 4 + 1];
717 dest[i * 4 + 2] = src[i * 4 + 0];
718 dest[i * 4 + 3] = src[i * 4 + 3];
719 }
720 } else {
721 for (int i = 0; i < count; ++i) {
722 const uint r = src[i * 4 + 0];
723 const uint b = src[i * 4 + 2];
724 dest[i * 4 + 0] = b;
725 dest[i * 4 + 2] = r;
726 }
727 }
728}
729
730template<QImage::Format Format> constexpr static inline QPixelLayout pixelLayoutRGB()
731{
732 return QPixelLayout{
733 false,
734 false,
735 bitsPerPixel<Format>(),
736 rbSwap<Format>,
737 convertToRGB32<Format>,
738 convertToRGB64<Format>,
739 fetchRGBToRGB32<Format>,
740 fetchRGBToRGB64<Format>,
741 storeRGBFromARGB32PM<Format, false>,
742 storeRGBFromARGB32PM<Format, true>
743 };
744}
745
746template<QImage::Format Format> constexpr static inline QPixelLayout pixelLayoutARGBPM()
747{
748 return QPixelLayout{
749 true,
750 true,
751 bitsPerPixel<Format>(),
752 rbSwap<Format>,
753 convertARGBPMToARGB32PM<Format>,
754 convertARGBPMToRGBA64PM<Format>,
755 fetchARGBPMToARGB32PM<Format>,
756 fetchARGBPMToRGBA64PM<Format>,
757 storeARGBPMFromARGB32PM<Format, false>,
758 storeARGBPMFromARGB32PM<Format, true>
759 };
760}
761
762static void QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, int count, const QList<QRgb> *clut)
763{
764 for (int i = 0; i < count; ++i)
765 buffer[i] = qPremultiply(clut->at(buffer[i]));
766}
767
768template<QPixelLayout::BPP BPP>
769static const uint *QT_FASTCALL fetchIndexedToARGB32PM(uint *buffer, const uchar *src, int index, int count,
770 const QList<QRgb> *clut, QDitherInfo *)
771{
772 for (int i = 0; i < count; ++i) {
773 const uint s = fetchPixel<BPP>(src, index + i);
774 buffer[i] = qPremultiply(clut->at(s));
775 }
776 return buffer;
777}
778
779template<QPixelLayout::BPP BPP>
780static const QRgba64 *QT_FASTCALL fetchIndexedToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
781 const QList<QRgb> *clut, QDitherInfo *)
782{
783 for (int i = 0; i < count; ++i) {
784 const uint s = fetchPixel<BPP>(src, index + i);
785 buffer[i] = QRgba64::fromArgb32(clut->at(s)).premultiplied();
786 }
787 return buffer;
788}
789
790template<QPixelLayout::BPP BPP>
791static const QRgbaFloat32 *QT_FASTCALL fetchIndexedToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
792 const QList<QRgb> *clut, QDitherInfo *)
793{
794 for (int i = 0; i < count; ++i) {
795 const uint s = fetchPixel<BPP>(src, index + i);
796 buffer[i] = QRgbaFloat32::fromArgb32(clut->at(s)).premultiplied();
797 }
798 return buffer;
799}
800
801template<typename QRgba>
802static const QRgba *QT_FASTCALL convertIndexedTo(QRgba *buffer, const uint *src, int count,
803 const QList<QRgb> *clut, QDitherInfo *)
804{
805 for (int i = 0; i < count; ++i)
806 buffer[i] = QRgba::fromArgb32(clut->at(src[i])).premultiplied();
807 return buffer;
808}
809
810static void QT_FASTCALL convertPassThrough(uint *, int, const QList<QRgb> *)
811{
812}
813
814static const uint *QT_FASTCALL fetchPassThrough(uint *, const uchar *src, int index, int,
815 const QList<QRgb> *, QDitherInfo *)
816{
817 return reinterpret_cast<const uint *>(src) + index;
818}
819
820static const QRgba64 *QT_FASTCALL fetchPassThrough64(QRgba64 *, const uchar *src, int index, int,
821 const QList<QRgb> *, QDitherInfo *)
822{
823 return reinterpret_cast<const QRgba64 *>(src) + index;
824}
825
826static void QT_FASTCALL storePassThrough(uchar *dest, const uint *src, int index, int count,
827 const QList<QRgb> *, QDitherInfo *)
828{
829 uint *d = reinterpret_cast<uint *>(dest) + index;
830 if (d != src)
831 memcpy(d, src, count * sizeof(uint));
832}
833
834static void QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
835{
836 qt_convertARGB32ToARGB32PM(buffer, buffer, count);
837}
838
839static const uint *QT_FASTCALL fetchARGB32ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
840 const QList<QRgb> *, QDitherInfo *)
841{
842 return qt_convertARGB32ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count);
843}
844
845static void QT_FASTCALL convertRGBA8888PMToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
846{
847 for (int i = 0; i < count; ++i)
848 buffer[i] = RGBA2ARGB(buffer[i]);
849}
850
851static const uint *QT_FASTCALL fetchRGBA8888PMToARGB32PM(uint *buffer, const uchar *src, int index, int count,
852 const QList<QRgb> *, QDitherInfo *)
853{
854 const uint *s = reinterpret_cast<const uint *>(src) + index;
855 UNALIASED_CONVERSION_LOOP(buffer, s, count, RGBA2ARGB);
856 return buffer;
857}
858
859static void QT_FASTCALL convertRGBA8888ToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
860{
861 qt_convertRGBA8888ToARGB32PM(buffer, buffer, count);
862}
863
864static const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
865 const QList<QRgb> *, QDitherInfo *)
866{
867 return qt_convertRGBA8888ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count);
868}
869
870static void QT_FASTCALL convertAlpha8ToRGB32(uint *buffer, int count, const QList<QRgb> *)
871{
872 for (int i = 0; i < count; ++i)
873 buffer[i] = qRgba(0, 0, 0, buffer[i]);
874}
875
876static const uint *QT_FASTCALL fetchAlpha8ToRGB32(uint *buffer, const uchar *src, int index, int count,
877 const QList<QRgb> *, QDitherInfo *)
878{
879 for (int i = 0; i < count; ++i)
880 buffer[i] = qRgba(0, 0, 0, src[index + i]);
881 return buffer;
882}
883
884template<typename QRgba>
885static const QRgba *QT_FASTCALL convertAlpha8To(QRgba *buffer, const uint *src, int count,
886 const QList<QRgb> *, QDitherInfo *)
887{
888 for (int i = 0; i < count; ++i)
889 buffer[i] = QRgba::fromRgba(0, 0, 0, src[i]);
890 return buffer;
891}
892
893template<typename QRgba>
894static const QRgba *QT_FASTCALL fetchAlpha8To(QRgba *buffer, const uchar *src, int index, int count,
895 const QList<QRgb> *, QDitherInfo *)
896{
897 for (int i = 0; i < count; ++i)
898 buffer[i] = QRgba::fromRgba(0, 0, 0, src[index + i]);
899 return buffer;
900}
901
902static void QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, int count, const QList<QRgb> *)
903{
904 for (int i = 0; i < count; ++i) {
905 const uint s = buffer[i];
906 buffer[i] = qRgb(s, s, s);
907 }
908}
909
910static const uint *QT_FASTCALL fetchGrayscale8ToRGB32(uint *buffer, const uchar *src, int index, int count,
911 const QList<QRgb> *, QDitherInfo *)
912{
913 for (int i = 0; i < count; ++i) {
914 const uint s = src[index + i];
915 buffer[i] = qRgb(s, s, s);
916 }
917 return buffer;
918}
919
920template<typename QRgba>
921static const QRgba *QT_FASTCALL convertGrayscale8To(QRgba *buffer, const uint *src, int count,
922 const QList<QRgb> *, QDitherInfo *)
923{
924 for (int i = 0; i < count; ++i)
925 buffer[i] = QRgba::fromRgba(src[i], src[i], src[i], 255);
926 return buffer;
927}
928
929template<typename QRgba>
930static const QRgba *QT_FASTCALL fetchGrayscale8To(QRgba *buffer, const uchar *src, int index, int count,
931 const QList<QRgb> *, QDitherInfo *)
932{
933 for (int i = 0; i < count; ++i) {
934 const uint s = src[index + i];
935 buffer[i] = QRgba::fromRgba(s, s, s, 255);
936 }
937 return buffer;
938}
939
940static void QT_FASTCALL convertGrayscale16ToRGB32(uint *buffer, int count, const QList<QRgb> *)
941{
942 for (int i = 0; i < count; ++i) {
943 const uint x = qt_div_257(buffer[i]);
944 buffer[i] = qRgb(x, x, x);
945 }
946}
947static const uint *QT_FASTCALL fetchGrayscale16ToRGB32(uint *buffer, const uchar *src, int index, int count,
948 const QList<QRgb> *, QDitherInfo *)
949{
950 const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index;
951 for (int i = 0; i < count; ++i) {
952 const uint x = qt_div_257(s[i]);
953 buffer[i] = qRgb(x, x, x);
954 }
955 return buffer;
956}
957
958template<typename QRgba>
959static const QRgba *QT_FASTCALL convertGrayscale16To(QRgba *buffer, const uint *src, int count,
960 const QList<QRgb> *, QDitherInfo *)
961{
962 for (int i = 0; i < count; ++i)
963 buffer[i] = QRgba::fromRgba64(src[i], src[i], src[i], 65535);
964 return buffer;
965}
966
967template<typename QRgba>
968static const QRgba *QT_FASTCALL fetchGrayscale16To(QRgba *buffer, const uchar *src, int index, int count,
969 const QList<QRgb> *, QDitherInfo *)
970{
971 const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index;
972 for (int i = 0; i < count; ++i) {
973 buffer[i] = QRgba::fromRgba64(s[i], s[i], s[i], 65535);
974 }
975 return buffer;
976}
977
978static void QT_FASTCALL storeARGB32FromARGB32PM(uchar *dest, const uint *src, int index, int count,
979 const QList<QRgb> *, QDitherInfo *)
980{
981 uint *d = reinterpret_cast<uint *>(dest) + index;
982 UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return qUnpremultiply(c); });
983}
984
985static void QT_FASTCALL storeRGBA8888PMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
986 const QList<QRgb> *, QDitherInfo *)
987{
988 uint *d = reinterpret_cast<uint *>(dest) + index;
989 UNALIASED_CONVERSION_LOOP(d, src, count, ARGB2RGBA);
990}
991
992#ifdef __SSE2__
993template<bool RGBA, bool maskAlpha>
994static inline void qConvertARGB32PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count)
995{
996 if (count <= 0)
997 return;
998
999 const __m128i amask = _mm_set1_epi32(0xff000000);
1000 int i = 0;
1001 for (; ((uintptr_t)buffer & 0xf) && i < count; ++i) {
1002 uint s = *src++;
1003 if (maskAlpha)
1004 s = s | 0xff000000;
1005 if (RGBA)
1006 s = RGBA2ARGB(s);
1007 *buffer++ = QRgba64::fromArgb32(s);
1008 }
1009 for (; i < count-3; i += 4) {
1010 __m128i vs = _mm_loadu_si128((const __m128i*)src);
1011 if (maskAlpha)
1012 vs = _mm_or_si128(vs, amask);
1013 src += 4;
1014 __m128i v1 = _mm_unpacklo_epi8(vs, vs);
1015 __m128i v2 = _mm_unpackhi_epi8(vs, vs);
1016 if (!RGBA) {
1017 v1 = _mm_shufflelo_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2));
1018 v2 = _mm_shufflelo_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2));
1019 v1 = _mm_shufflehi_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2));
1020 v2 = _mm_shufflehi_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2));
1021 }
1022 _mm_store_si128((__m128i*)(buffer), v1);
1023 buffer += 2;
1024 _mm_store_si128((__m128i*)(buffer), v2);
1025 buffer += 2;
1026 }
1027
1028 SIMD_EPILOGUE(i, count, 3) {
1029 uint s = *src++;
1030 if (maskAlpha)
1031 s = s | 0xff000000;
1032 if (RGBA)
1033 s = RGBA2ARGB(s);
1034 *buffer++ = QRgba64::fromArgb32(s);
1035 }
1036}
1037
1038template<QtPixelOrder PixelOrder>
1039static inline void qConvertRGBA64PMToA2RGB30PM_sse2(uint *dest, const QRgba64 *buffer, int count)
1040{
1041 const __m128i gmask = _mm_set1_epi32(0x000ffc00);
1042 const __m128i cmask = _mm_set1_epi32(0x000003ff);
1043 int i = 0;
1044 __m128i vr, vg, vb, va;
1045 for (; i < count && uintptr_t(buffer) & 0xF; ++i) {
1046 *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
1047 }
1048
1049 for (; i < count-15; i += 16) {
1050 // Repremultiplying is really expensive and hard to do in SIMD without AVX2,
1051 // so we try to avoid it by checking if it is needed 16 samples at a time.
1052 __m128i vOr = _mm_set1_epi32(0);
1053 __m128i vAnd = _mm_set1_epi32(0xffffffff);
1054 for (int j = 0; j < 16; j += 2) {
1055 __m128i vs = _mm_load_si128((const __m128i*)(buffer + j));
1056 vOr = _mm_or_si128(vOr, vs);
1057 vAnd = _mm_and_si128(vAnd, vs);
1058 }
1059 const quint16 orAlpha = ((uint)_mm_extract_epi16(vOr, 3)) | ((uint)_mm_extract_epi16(vOr, 7));
1060 const quint16 andAlpha = ((uint)_mm_extract_epi16(vAnd, 3)) & ((uint)_mm_extract_epi16(vAnd, 7));
1061
1062 if (andAlpha == 0xffff) {
1063 for (int j = 0; j < 16; j += 2) {
1064 __m128i vs = _mm_load_si128((const __m128i*)buffer);
1065 buffer += 2;
1066 vr = _mm_srli_epi64(vs, 6);
1067 vg = _mm_srli_epi64(vs, 16 + 6 - 10);
1068 vb = _mm_srli_epi64(vs, 32 + 6);
1069 vr = _mm_and_si128(vr, cmask);
1070 vg = _mm_and_si128(vg, gmask);
1071 vb = _mm_and_si128(vb, cmask);
1072 va = _mm_srli_epi64(vs, 48 + 14);
1073 if (PixelOrder == PixelOrderRGB)
1074 vr = _mm_slli_epi32(vr, 20);
1075 else
1076 vb = _mm_slli_epi32(vb, 20);
1077 va = _mm_slli_epi32(va, 30);
1078 __m128i vd = _mm_or_si128(_mm_or_si128(vr, vg), _mm_or_si128(vb, va));
1079 vd = _mm_shuffle_epi32(vd, _MM_SHUFFLE(3, 1, 2, 0));
1080 _mm_storel_epi64((__m128i*)dest, vd);
1081 dest += 2;
1082 }
1083 } else if (orAlpha == 0) {
1084 for (int j = 0; j < 16; ++j) {
1085 *dest++ = 0;
1086 buffer++;
1087 }
1088 } else {
1089 for (int j = 0; j < 16; ++j)
1090 *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
1091 }
1092 }
1093
1094 SIMD_EPILOGUE(i, count, 15)
1095 *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
1096}
1097#elif defined(__ARM_NEON__)
1098template<bool RGBA, bool maskAlpha>
1099static inline void qConvertARGB32PMToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count)
1100{
1101 if (count <= 0)
1102 return;
1103
1104 const uint32x4_t amask = vdupq_n_u32(0xff000000);
1105#if defined(Q_PROCESSOR_ARM_64)
1106 const uint8x16_t rgbaMask = qvsetq_n_u8(2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15);
1107#else
1108 const uint8x8_t rgbaMask = qvset_n_u8(2, 1, 0, 3, 6, 5, 4, 7);
1109#endif
1110 int i = 0;
1111 for (; i < count-3; i += 4) {
1112 uint32x4_t vs32 = vld1q_u32(src);
1113 src += 4;
1114 if (maskAlpha)
1115 vs32 = vorrq_u32(vs32, amask);
1116 uint8x16_t vs8 = vreinterpretq_u8_u32(vs32);
1117 if (!RGBA) {
1118#if defined(Q_PROCESSOR_ARM_64)
1119 vs8 = vqtbl1q_u8(vs8, rgbaMask);
1120#else
1121 // no vqtbl1q_u8
1122 const uint8x8_t vlo = vtbl1_u8(vget_low_u8(vs8), rgbaMask);
1123 const uint8x8_t vhi = vtbl1_u8(vget_high_u8(vs8), rgbaMask);
1124 vs8 = vcombine_u8(vlo, vhi);
1125#endif
1126 }
1127 uint8x16x2_t v = vzipq_u8(vs8, vs8);
1128
1129 vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[0]));
1130 buffer += 2;
1131 vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[1]));
1132 buffer += 2;
1133 }
1134
1135 SIMD_EPILOGUE(i, count, 3) {
1136 uint s = *src++;
1137 if (maskAlpha)
1138 s = s | 0xff000000;
1139 if (RGBA)
1140 s = RGBA2ARGB(s);
1141 *buffer++ = QRgba64::fromArgb32(s);
1142 }
1143}
1144#elif defined __loongarch_sx
1145template<bool RGBA, bool maskAlpha>
1146static inline void qConvertARGB32PMToRGBA64PM_lsx(QRgba64 *buffer, const uint *src, int count)
1147{
1148 if (count <= 0)
1149 return;
1150
1151 const __m128i amask = __lsx_vreplgr2vr_w(0xff000000);
1152 const __m128i shuffleMask = (__m128i)(v8i16){2, 1, 0, 3, 6, 5, 4, 7};
1153 int i = 0;
1154 for (; ((uintptr_t)buffer & 0xf) && i < count; ++i) {
1155 uint s = *src++;
1156 if (maskAlpha)
1157 s = s | 0xff000000;
1158 if (RGBA)
1159 s = RGBA2ARGB(s);
1160 *buffer++ = QRgba64::fromArgb32(s);
1161 }
1162 for (; i < count-3; i += 4) {
1163 __m128i vs = __lsx_vld((const __m128i*)src, 0);
1164 if (maskAlpha)
1165 vs = __lsx_vor_v(vs, amask);
1166 src += 4;
1167 __m128i v1 = __lsx_vilvl_b(vs, vs);
1168 __m128i v2 = __lsx_vilvh_b(vs, vs);
1169 if (!RGBA) {
1170 v1 = __lsx_vshuf_h(shuffleMask, v1, v1);
1171 v2 = __lsx_vshuf_h(shuffleMask, v2, v2);
1172 }
1173 __lsx_vst(v1, buffer, 0);
1174 buffer += 2;
1175 __lsx_vst(v2, buffer, 0);
1176 buffer += 2;
1177 }
1178
1179 SIMD_EPILOGUE(i, count, 3) {
1180 uint s = *src++;
1181 if (maskAlpha)
1182 s = s | 0xff000000;
1183 if (RGBA)
1184 s = RGBA2ARGB(s);
1185 *buffer++ = QRgba64::fromArgb32(s);
1186 }
1187}
1188
1189template<QtPixelOrder PixelOrder>
1190static inline void qConvertRGBA64PMToA2RGB30PM_lsx(uint *dest, const QRgba64 *buffer, int count)
1191{
1192 const __m128i gmask = __lsx_vreplgr2vr_w(0x000ffc00);
1193 const __m128i cmask = __lsx_vreplgr2vr_w(0x000003ff);
1194 int i = 0;
1195 __m128i vr, vg, vb, va;
1196 for (; i < count && uintptr_t(buffer) & 0xF; ++i) {
1197 *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
1198 }
1199
1200 for (; i < count-15; i += 16) {
1201 __m128i vOr = __lsx_vreplgr2vr_w(0);
1202 __m128i vAnd = __lsx_vreplgr2vr_w(0xffffffff);
1203 for (int j = 0; j < 16; j += 2) {
1204 __m128i vs = __lsx_vld((const __m128i*)(buffer + j), 0);
1205 vOr = __lsx_vor_v(vOr, vs);
1206 vAnd = __lsx_vand_v(vAnd, vs);
1207 }
1208 const quint16 orAlpha = ((uint)__lsx_vpickve2gr_h(vOr, 3)) | ((uint)__lsx_vpickve2gr_h(vOr, 7));
1209 const quint16 andAlpha = ((uint)__lsx_vpickve2gr_h(vAnd, 3)) & ((uint)__lsx_vpickve2gr_h(vAnd, 7));
1210
1211 if (andAlpha == 0xffff) {
1212 for (int j = 0; j < 16; j += 2) {
1213 __m128i vs = __lsx_vld((const __m128i*)buffer, 0);
1214 buffer += 2;
1215 vr = __lsx_vsrli_d(vs, 6);
1216 vg = __lsx_vsrli_d(vs, 16 + 6 - 10);
1217 vb = __lsx_vsrli_d(vs, 32 + 6);
1218 vr = __lsx_vand_v(vr, cmask);
1219 vg = __lsx_vand_v(vg, gmask);
1220 vb = __lsx_vand_v(vb, cmask);
1221 va = __lsx_vsrli_d(vs, 48 + 14);
1222 if (PixelOrder == PixelOrderRGB)
1223 vr = __lsx_vslli_w(vr, 20);
1224 else
1225 vb = __lsx_vslli_w(vb, 20);
1226 va = __lsx_vslli_w(va, 30);
1227 __m128i vd = __lsx_vor_v(__lsx_vor_v(vr, vg), __lsx_vor_v(vb, va));
1228 vd = __lsx_vshuf4i_w(vd, 0b11011000);
1229 __lsx_vstelm_d(vd, dest, 0, 0);
1230 dest += 2;
1231 }
1232 } else if (orAlpha == 0) {
1233 for (int j = 0; j < 16; ++j) {
1234 *dest++ = 0;
1235 buffer++;
1236 }
1237 } else {
1238 for (int j = 0; j < 16; ++j)
1239 *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
1240 }
1241 }
1242
1243 SIMD_EPILOGUE(i, count, 15)
1244 *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
1245}
1246#endif
1247
1248static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count,
1249 const QList<QRgb> *, QDitherInfo *)
1250{
1251#ifdef __SSE2__
1252 qConvertARGB32PMToRGBA64PM_sse2<false, true>(buffer, src, count);
1253#elif defined(__ARM_NEON__)
1254 qConvertARGB32PMToRGBA64PM_neon<false, true>(buffer, src, count);
1255#elif defined(__loongarch_sx)
1256 qConvertARGB32PMToRGBA64PM_lsx<false, true>(buffer, src, count);
1257#else
1258 for (int i = 0; i < count; ++i)
1259 buffer[i] = QRgba64::fromArgb32(0xff000000 | src[i]);
1260#endif
1261 return buffer;
1262}
1263
1264static const QRgba64 *QT_FASTCALL fetchRGB32ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
1265 const QList<QRgb> *, QDitherInfo *)
1266{
1267 return convertRGB32ToRGB64(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1268}
1269
1270static const QRgba64 *QT_FASTCALL convertARGB32ToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1271 const QList<QRgb> *, QDitherInfo *)
1272{
1273 for (int i = 0; i < count; ++i)
1274 buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied();
1275 return buffer;
1276}
1277
1278static const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1279 const QList<QRgb> *, QDitherInfo *)
1280{
1281 return convertARGB32ToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1282}
1283
1284static const QRgba64 *QT_FASTCALL convertARGB32PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1285 const QList<QRgb> *, QDitherInfo *)
1286{
1287#ifdef __SSE2__
1288 qConvertARGB32PMToRGBA64PM_sse2<false, false>(buffer, src, count);
1289#elif defined(__ARM_NEON__)
1290 qConvertARGB32PMToRGBA64PM_neon<false, false>(buffer, src, count);
1291#elif defined(__loongarch_sx)
1292 qConvertARGB32PMToRGBA64PM_lsx<false, false>(buffer, src, count);
1293#else
1294 for (int i = 0; i < count; ++i)
1295 buffer[i] = QRgba64::fromArgb32(src[i]);
1296#endif
1297 return buffer;
1298}
1299
1300static const QRgba64 *QT_FASTCALL fetchARGB32PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1301 const QList<QRgb> *, QDitherInfo *)
1302{
1303 return convertARGB32PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1304}
1305
1306static const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1307 const QList<QRgb> *, QDitherInfo *)
1308{
1309 const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
1310#ifdef __SSE2__
1311 for (int i = 0; i < count; ++i) {
1312 const auto a = s[i].alpha();
1313 __m128i vs = _mm_loadl_epi64((const __m128i *)(s + i));
1314 __m128i va = _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 3, 3, 3));
1315 vs = multiplyAlpha65535(vs, va);
1316 _mm_storel_epi64((__m128i *)(buffer + i), vs);
1317 buffer[i].setAlpha(a);
1318 }
1319#else
1320 for (int i = 0; i < count; ++i)
1321 buffer[i] = QRgba64::fromRgba64(s[i]).premultiplied();
1322#endif
1323 return buffer;
1324}
1325
1326static const QRgba64 *QT_FASTCALL convertRGBA8888ToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1327 const QList<QRgb> *, QDitherInfo *)
1328{
1329 for (int i = 0; i < count; ++i)
1330 buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied();
1331 return buffer;
1332}
1333
1334static const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1335 const QList<QRgb> *, QDitherInfo *)
1336{
1337 return convertRGBA8888ToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1338}
1339
1340static const QRgba64 *QT_FASTCALL convertRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1341 const QList<QRgb> *, QDitherInfo *)
1342{
1343#ifdef __SSE2__
1344 qConvertARGB32PMToRGBA64PM_sse2<true, false>(buffer, src, count);
1345#elif defined(__ARM_NEON__)
1346 qConvertARGB32PMToRGBA64PM_neon<true, false>(buffer, src, count);
1347#elif defined(__loongarch_sx)
1348 qConvertARGB32PMToRGBA64PM_lsx<true, false>(buffer, src, count);
1349#else
1350 for (int i = 0; i < count; ++i)
1351 buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i]));
1352#endif
1353 return buffer;
1354}
1355
1356static const QRgba64 *QT_FASTCALL fetchRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1357 const QList<QRgb> *, QDitherInfo *)
1358{
1359 return convertRGBA8888PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1360}
1361
1362static void QT_FASTCALL storeRGBA8888FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1363 const QList<QRgb> *, QDitherInfo *)
1364{
1365 uint *d = reinterpret_cast<uint *>(dest) + index;
1366 UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(qUnpremultiply(c)); });
1367}
1368
1369static void QT_FASTCALL storeRGBXFromRGB32(uchar *dest, const uint *src, int index, int count,
1370 const QList<QRgb> *, QDitherInfo *)
1371{
1372 uint *d = reinterpret_cast<uint *>(dest) + index;
1373 UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | c); });
1374}
1375
1376static void QT_FASTCALL storeRGBXFromARGB32PM(uchar *dest, const uint *src, int index, int count,
1377 const QList<QRgb> *, QDitherInfo *)
1378{
1379 uint *d = reinterpret_cast<uint *>(dest) + index;
1380 UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | qUnpremultiply(c)); });
1381}
1382
1383template<QtPixelOrder PixelOrder>
1384static void QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
1385{
1386 for (int i = 0; i < count; ++i)
1387 buffer[i] = qConvertA2rgb30ToArgb32<PixelOrder>(buffer[i]);
1388}
1389
1390template<QtPixelOrder PixelOrder>
1391static const uint *QT_FASTCALL fetchA2RGB30PMToARGB32PM(uint *buffer, const uchar *s, int index, int count,
1392 const QList<QRgb> *, QDitherInfo *dither)
1393{
1394 const uint *src = reinterpret_cast<const uint *>(s) + index;
1395 if (!dither) {
1396 UNALIASED_CONVERSION_LOOP(buffer, src, count, qConvertA2rgb30ToArgb32<PixelOrder>);
1397 } else {
1398 for (int i = 0; i < count; ++i) {
1399 const uint c = src[i];
1400 short d10 = (qt_bayer_matrix[dither->y & 15][(dither->x + i) & 15] << 2);
1401 short a10 = (c >> 30) * 0x155;
1402 short r10 = ((c >> 20) & 0x3ff);
1403 short g10 = ((c >> 10) & 0x3ff);
1404 short b10 = (c & 0x3ff);
1405 if (PixelOrder == PixelOrderBGR)
1406 std::swap(r10, b10);
1407 short a8 = (a10 + ((d10 - a10) >> 8)) >> 2;
1408 short r8 = (r10 + ((d10 - r10) >> 8)) >> 2;
1409 short g8 = (g10 + ((d10 - g10) >> 8)) >> 2;
1410 short b8 = (b10 + ((d10 - b10) >> 8)) >> 2;
1411 buffer[i] = qRgba(r8, g8, b8, a8);
1412 }
1413 }
1414 return buffer;
1415}
1416
1417#ifdef __SSE2__
1418template<QtPixelOrder PixelOrder>
1419static inline void qConvertA2RGB30PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count)
1420{
1421 if (count <= 0)
1422 return;
1423
1424 const __m128i rmask = _mm_set1_epi32(0x3ff00000);
1425 const __m128i gmask = _mm_set1_epi32(0x000ffc00);
1426 const __m128i bmask = _mm_set1_epi32(0x000003ff);
1427 const __m128i afactor = _mm_set1_epi16(0x5555);
1428 int i = 0;
1429
1430 for (; ((uintptr_t)buffer & 0xf) && i < count; ++i)
1431 *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++);
1432
1433 for (; i < count-3; i += 4) {
1434 __m128i vs = _mm_loadu_si128((const __m128i*)src);
1435 src += 4;
1436 __m128i va = _mm_srli_epi32(vs, 30);
1437 __m128i vr = _mm_and_si128(vs, rmask);
1438 __m128i vb = _mm_and_si128(vs, bmask);
1439 __m128i vg = _mm_and_si128(vs, gmask);
1440 va = _mm_mullo_epi16(va, afactor);
1441 vr = _mm_or_si128(_mm_srli_epi32(vr, 14), _mm_srli_epi32(vr, 24));
1442 vg = _mm_or_si128(_mm_srli_epi32(vg, 4), _mm_srli_epi32(vg, 14));
1443 vb = _mm_or_si128(_mm_slli_epi32(vb, 6), _mm_srli_epi32(vb, 4));
1444 __m128i vrb;
1445 if (PixelOrder == PixelOrderRGB)
1446 vrb = _mm_or_si128(vr, _mm_slli_si128(vb, 2));
1447 else
1448 vrb = _mm_or_si128(vb, _mm_slli_si128(vr, 2));
1449 __m128i vga = _mm_or_si128(vg, _mm_slli_si128(va, 2));
1450 _mm_store_si128((__m128i*)(buffer), _mm_unpacklo_epi16(vrb, vga));
1451 buffer += 2;
1452 _mm_store_si128((__m128i*)(buffer), _mm_unpackhi_epi16(vrb, vga));
1453 buffer += 2;
1454 }
1455
1456 SIMD_EPILOGUE(i, count, 3)
1457 *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++);
1458}
1459#elif defined(__loongarch_sx)
1460template<QtPixelOrder PixelOrder>
1461static inline void qConvertA2RGB30PMToRGBA64PM_lsx(QRgba64 *buffer, const uint *src, int count)
1462{
1463 if (count <= 0)
1464 return;
1465
1466 const __m128i rmask = __lsx_vreplgr2vr_w(0x3ff00000);
1467 const __m128i gmask = __lsx_vreplgr2vr_w(0x000ffc00);
1468 const __m128i bmask = __lsx_vreplgr2vr_w(0x000003ff);
1469 const __m128i afactor = __lsx_vreplgr2vr_h(0x5555);
1470 int i = 0;
1471
1472 for (; ((uintptr_t)buffer & 0xf) && i < count; ++i)
1473 *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++);
1474
1475 for (; i < count-3; i += 4) {
1476 __m128i vs = __lsx_vld((const __m128i*)src, 0);
1477 src += 4;
1478 __m128i va = __lsx_vsrli_w(vs, 30);
1479 __m128i vr = __lsx_vand_v(vs, rmask);
1480 __m128i vb = __lsx_vand_v(vs, bmask);
1481 __m128i vg = __lsx_vand_v(vs, gmask);
1482 va = __lsx_vmul_h(va, afactor);
1483 vr = __lsx_vor_v(__lsx_vsrli_w(vr, 14), __lsx_vsrli_w(vr, 24));
1484 vg = __lsx_vor_v(__lsx_vsrli_w(vg, 4), __lsx_vsrli_w(vg, 14));
1485 vb = __lsx_vor_v(__lsx_vslli_w(vb, 6), __lsx_vsrli_w(vb, 4));
1486 __m128i vrb;
1487 if (PixelOrder == PixelOrderRGB)
1488 vrb = __lsx_vor_v(vr, __lsx_vbsll_v(vb, 2));
1489 else
1490 vrb = __lsx_vor_v(vb, __lsx_vbsll_v(vr, 2));
1491 __m128i vga = __lsx_vor_v(vg, __lsx_vbsll_v(va, 2));
1492 __lsx_vst(__lsx_vilvl_h(vga, vrb), buffer, 0);
1493 buffer += 2;
1494 __lsx_vst(__lsx_vilvh_h(vga, vrb), buffer, 0);
1495 buffer += 2;
1496 }
1497
1498 SIMD_EPILOGUE(i, count, 3)
1499 *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++);
1500}
1501#endif
1502
1503template<QtPixelOrder PixelOrder>
1504static const QRgba64 *QT_FASTCALL convertA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1505 const QList<QRgb> *, QDitherInfo *)
1506{
1507#ifdef __SSE2__
1508 qConvertA2RGB30PMToRGBA64PM_sse2<PixelOrder>(buffer, src, count);
1509#elif defined (__loongarch_sx)
1510 qConvertA2RGB30PMToRGBA64PM_lsx<PixelOrder>(buffer, src, count);
1511#else
1512 for (int i = 0; i < count; ++i)
1513 buffer[i] = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]);
1514#endif
1515 return buffer;
1516}
1517
1518template<QtPixelOrder PixelOrder>
1519static const QRgba64 *QT_FASTCALL fetchA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1520 const QList<QRgb> *, QDitherInfo *)
1521{
1522 return convertA2RGB30PMToRGBA64PM<PixelOrder>(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1523}
1524
1525template<enum QtPixelOrder> inline QRgbaFloat32 qConvertA2rgb30ToRgbaFP(uint rgb);
1526
1527template<>
1528inline QRgbaFloat32 qConvertA2rgb30ToRgbaFP<PixelOrderBGR>(uint rgb)
1529{
1530 float alpha = (rgb >> 30) * (1.f/3.f);
1531 float blue = ((rgb >> 20) & 0x3ff) * (1.f/1023.f);
1532 float green = ((rgb >> 10) & 0x3ff) * (1.f/1023.f);
1533 float red = (rgb & 0x3ff) * (1.f/1023.f);
1534 return QRgbaFloat32{ red, green, blue, alpha };
1535}
1536
1537template<>
1538inline QRgbaFloat32 qConvertA2rgb30ToRgbaFP<PixelOrderRGB>(uint rgb)
1539{
1540 float alpha = (rgb >> 30) * (1.f/3.f);
1541 float red = ((rgb >> 20) & 0x3ff) * (1.f/1023.f);
1542 float green = ((rgb >> 10) & 0x3ff) * (1.f/1023.f);
1543 float blue = (rgb & 0x3ff) * (1.f/1023.f);
1544 return QRgbaFloat32{ red, green, blue, alpha };
1545}
1546
1547template<QtPixelOrder PixelOrder>
1548static const QRgbaFloat32 *QT_FASTCALL convertA2RGB30PMToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
1549 const QList<QRgb> *, QDitherInfo *)
1550{
1551 for (int i = 0; i < count; ++i)
1552 buffer[i] = qConvertA2rgb30ToRgbaFP<PixelOrder>(src[i]);
1553 return buffer;
1554}
1555
1556template<QtPixelOrder PixelOrder>
1557static const QRgbaFloat32 *QT_FASTCALL fetchRGB30ToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
1558 const QList<QRgb> *, QDitherInfo *)
1559{
1560 return convertA2RGB30PMToRGBA32F<PixelOrder>(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1561}
1562
1563template<QtPixelOrder PixelOrder>
1564static void QT_FASTCALL storeA2RGB30PMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
1565 const QList<QRgb> *, QDitherInfo *)
1566{
1567 uint *d = reinterpret_cast<uint *>(dest) + index;
1568 UNALIASED_CONVERSION_LOOP(d, src, count, qConvertArgb32ToA2rgb30<PixelOrder>);
1569}
1570
1571template<QtPixelOrder PixelOrder>
1572static void QT_FASTCALL storeRGB30FromRGB32(uchar *dest, const uint *src, int index, int count,
1573 const QList<QRgb> *, QDitherInfo *)
1574{
1575 uint *d = reinterpret_cast<uint *>(dest) + index;
1576 UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>);
1577}
1578
1579template<QtPixelOrder PixelOrder>
1580static void QT_FASTCALL storeRGB30FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1581 const QList<QRgb> *, QDitherInfo *)
1582{
1583 uint *d = reinterpret_cast<uint *>(dest) + index;
1584 UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>);
1585}
1586
1587template<bool RGBA>
1588void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count)
1589{
1590 int i = 0;
1591#ifdef __SSE2__
1592 if (((uintptr_t)dst & 0x7) && count > 0) {
1593 uint s = (*src++).toArgb32();
1594 if (RGBA)
1595 s = ARGB2RGBA(s);
1596 *dst++ = s;
1597 i++;
1598 }
1599 const __m128i vhalf = _mm_set1_epi32(0x80);
1600 const __m128i vzero = _mm_setzero_si128();
1601 for (; i < count-1; i += 2) {
1602 __m128i vs = _mm_loadu_si128((const __m128i*)src);
1603 src += 2;
1604 if (!RGBA) {
1605 vs = _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2));
1606 vs = _mm_shufflehi_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2));
1607 }
1608 __m128i v1 = _mm_unpacklo_epi16(vs, vzero);
1609 __m128i v2 = _mm_unpackhi_epi16(vs, vzero);
1610 v1 = _mm_add_epi32(v1, vhalf);
1611 v2 = _mm_add_epi32(v2, vhalf);
1612 v1 = _mm_sub_epi32(v1, _mm_srli_epi32(v1, 8));
1613 v2 = _mm_sub_epi32(v2, _mm_srli_epi32(v2, 8));
1614 v1 = _mm_srli_epi32(v1, 8);
1615 v2 = _mm_srli_epi32(v2, 8);
1616 v1 = _mm_packs_epi32(v1, v2);
1617 v1 = _mm_packus_epi16(v1, vzero);
1618 _mm_storel_epi64((__m128i*)(dst), v1);
1619 dst += 2;
1620 }
1621#elif defined(__loongarch_sx)
1622 if (((uintptr_t)dst & 0x7) && count > 0) {
1623 uint s = (*src++).toArgb32();
1624 if (RGBA)
1625 s = ARGB2RGBA(s);
1626 *dst++ = s;
1627 i++;
1628 }
1629 const __m128i vhalf = __lsx_vreplgr2vr_w(0x80);
1630 const __m128i vzero = __lsx_vldi(0);
1631 const __m128i shuffleMask = (__m128i)(v8i16){2, 1, 0, 3, 6, 5, 4, 7};
1632 for (; i < count-1; i += 2) {
1633 __m128i vs = __lsx_vld((const __m128i*)src, 0);
1634 src += 2;
1635 if (!RGBA) {
1636 vs = __lsx_vshuf_h(shuffleMask, vzero, vs);
1637 }
1638 __m128i v1 = __lsx_vilvl_h(vzero, vs);
1639 __m128i v2 = __lsx_vilvh_h(vzero, vs);
1640 v1 = __lsx_vadd_w(v1, vhalf);
1641 v2 = __lsx_vadd_w(v2, vhalf);
1642 v1 = __lsx_vsub_w(v1, __lsx_vsrli_w(v1, 8));
1643 v2 = __lsx_vsub_w(v2, __lsx_vsrli_w(v2, 8));
1644 v1 = __lsx_vsrli_w(v1, 8);
1645 v2 = __lsx_vsrli_w(v2, 8);
1646 v1 = __lsx_vpickev_h(__lsx_vsat_w(v2, 15), __lsx_vsat_w(v1, 15));
1647 v1 = __lsx_vmaxi_h(v1, 0);
1648 v1 = __lsx_vpickev_b(vzero, __lsx_vsat_hu(v1, 7));
1649 __lsx_vstelm_d(v1, dst, 0, 0);
1650 dst += 2;
1651 }
1652#endif
1653 for (; i < count; i++) {
1654 uint s = (*src++).toArgb32();
1655 if (RGBA)
1656 s = ARGB2RGBA(s);
1657 *dst++ = s;
1658 }
1659}
1660template void qt_convertRGBA64ToARGB32<false>(uint *dst, const QRgba64 *src, int count);
1661template void qt_convertRGBA64ToARGB32<true>(uint *dst, const QRgba64 *src, int count);
1662
1663
1664static void QT_FASTCALL storeAlpha8FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1665 const QList<QRgb> *, QDitherInfo *)
1666{
1667 for (int i = 0; i < count; ++i)
1668 dest[index + i] = qAlpha(src[i]);
1669}
1670
1671static void QT_FASTCALL storeGrayscale8FromRGB32(uchar *dest, const uint *src, int index, int count,
1672 const QList<QRgb> *, QDitherInfo *)
1673{
1674 for (int i = 0; i < count; ++i)
1675 dest[index + i] = qGray(src[i]);
1676}
1677
1678static void QT_FASTCALL storeGrayscale8FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1679 const QList<QRgb> *, QDitherInfo *)
1680{
1681 for (int i = 0; i < count; ++i)
1682 dest[index + i] = qGray(qUnpremultiply(src[i]));
1683}
1684
1685static void QT_FASTCALL storeGrayscale16FromRGB32(uchar *dest, const uint *src, int index, int count,
1686 const QList<QRgb> *, QDitherInfo *)
1687{
1688 unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index;
1689 for (int i = 0; i < count; ++i)
1690 d[i] = qGray(src[i]) * 257;
1691}
1692
1693static void QT_FASTCALL storeGrayscale16FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1694 const QList<QRgb> *, QDitherInfo *)
1695{
1696 unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index;
1697 for (int i = 0; i < count; ++i)
1698 d[i] = qGray(qUnpremultiply(src[i])) * 257;
1699}
1700
1701static const uint *QT_FASTCALL fetchRGB64ToRGB32(uint *buffer, const uchar *src, int index, int count,
1702 const QList<QRgb> *, QDitherInfo *)
1703{
1704 const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
1705 for (int i = 0; i < count; ++i)
1706 buffer[i] = toArgb32(s[i]);
1707 return buffer;
1708}
1709
1710static void QT_FASTCALL storeRGB64FromRGB32(uchar *dest, const uint *src, int index, int count,
1711 const QList<QRgb> *, QDitherInfo *)
1712{
1713 QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
1714 for (int i = 0; i < count; ++i)
1715 d[i] = QRgba64::fromArgb32(src[i] | 0xff000000);
1716}
1717
1718static const uint *QT_FASTCALL fetchRGBA64ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
1719 const QList<QRgb> *, QDitherInfo *)
1720{
1721 const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
1722 for (int i = 0; i < count; ++i)
1723 buffer[i] = toArgb32(s[i].premultiplied());
1724 return buffer;
1725}
1726
1727template<bool Mask>
1728static void QT_FASTCALL storeRGBA64FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1729 const QList<QRgb> *, QDitherInfo *)
1730{
1731 QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
1732 for (int i = 0; i < count; ++i) {
1733 d[i] = QRgba64::fromArgb32(src[i]).unpremultiplied();
1734 if (Mask)
1735 d[i].setAlpha(65535);
1736 }
1737}
1738
1739static void QT_FASTCALL storeRGBA64FromARGB32(uchar *dest, const uint *src, int index, int count,
1740 const QList<QRgb> *, QDitherInfo *)
1741{
1742 QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
1743 for (int i = 0; i < count; ++i)
1744 d[i] = QRgba64::fromArgb32(src[i]);
1745}
1746
1747static const uint *QT_FASTCALL fetchRGB16FToRGB32(uint *buffer, const uchar *src, int index, int count,
1748 const QList<QRgb> *, QDitherInfo *)
1749{
1750 const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
1751 for (int i = 0; i < count; ++i)
1752 buffer[i] = s[i].toArgb32();
1753 return buffer;
1754}
1755
1756static void QT_FASTCALL storeRGB16FFromRGB32(uchar *dest, const uint *src, int index, int count,
1757 const QList<QRgb> *, QDitherInfo *)
1758{
1759 QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
1760 for (int i = 0; i < count; ++i)
1761 d[i] = QRgbaFloat16::fromArgb32(src[i] | 0xff000000);
1762}
1763
1764static const uint *QT_FASTCALL fetchRGBA16FToARGB32PM(uint *buffer, const uchar *src, int index, int count,
1765 const QList<QRgb> *, QDitherInfo *)
1766{
1767 const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
1768 for (int i = 0; i < count; ++i)
1769 buffer[i] = s[i].premultiplied().toArgb32();
1770 return buffer;
1771}
1772
1773static const QRgba64 *QT_FASTCALL fetchRGBA16FToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1774 const QList<QRgb> *, QDitherInfo *)
1775{
1776 const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
1777 for (int i = 0; i < count; ++i) {
1778 QRgbaFloat16 c = s[i].premultiplied();
1779 buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
1780 }
1781 return buffer;
1782}
1783
1784static void QT_FASTCALL storeRGBA16FFromARGB32PM(uchar *dest, const uint *src, int index, int count,
1785 const QList<QRgb> *, QDitherInfo *)
1786{
1787 QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
1788 for (int i = 0; i < count; ++i)
1789 d[i] = QRgbaFloat16::fromArgb32(src[i]).unpremultiplied();
1790}
1791
1792static const QRgba64 *QT_FASTCALL fetchRGBA16FPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1793 const QList<QRgb> *, QDitherInfo *)
1794{
1795 const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
1796 for (int i = 0; i < count; ++i) {
1797 QRgbaFloat16 c = s[i];
1798 buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
1799 }
1800 return buffer;
1801}
1802
1803static const uint *QT_FASTCALL fetchRGB32FToRGB32(uint *buffer, const uchar *src, int index, int count,
1804 const QList<QRgb> *, QDitherInfo *)
1805{
1806 const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
1807 for (int i = 0; i < count; ++i)
1808 buffer[i] = s[i].toArgb32();
1809 return buffer;
1810}
1811
1812static void QT_FASTCALL storeRGB32FFromRGB32(uchar *dest, const uint *src, int index, int count,
1813 const QList<QRgb> *, QDitherInfo *)
1814{
1815 QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
1816 for (int i = 0; i < count; ++i)
1817 d[i] = QRgbaFloat32::fromArgb32(src[i] | 0xff000000);
1818}
1819
1820static const uint *QT_FASTCALL fetchRGBA32FToARGB32PM(uint *buffer, const uchar *src, int index, int count,
1821 const QList<QRgb> *, QDitherInfo *)
1822{
1823 const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
1824 for (int i = 0; i < count; ++i)
1825 buffer[i] = s[i].premultiplied().toArgb32();
1826 return buffer;
1827}
1828
1829static const QRgba64 *QT_FASTCALL fetchRGBA32FToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1830 const QList<QRgb> *, QDitherInfo *)
1831{
1832 const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
1833 for (int i = 0; i < count; ++i) {
1834 QRgbaFloat32 c = s[i].premultiplied();
1835 buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
1836 }
1837 return buffer;
1838}
1839
1840static void QT_FASTCALL storeRGBA32FFromARGB32PM(uchar *dest, const uint *src, int index, int count,
1841 const QList<QRgb> *, QDitherInfo *)
1842{
1843 QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
1844 for (int i = 0; i < count; ++i)
1845 d[i] = QRgbaFloat32::fromArgb32(src[i]).unpremultiplied();
1846}
1847
1848static const QRgba64 *QT_FASTCALL fetchRGBA32FPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1849 const QList<QRgb> *, QDitherInfo *)
1850{
1851 const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
1852 for (int i = 0; i < count; ++i) {
1853 QRgbaFloat32 c = s[i];
1854 buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
1855 }
1856 return buffer;
1857}
1858
1859inline const uint *qt_convertCMYK8888ToARGB32PM(uint *buffer, const uint *src, int count)
1860{
1861 UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint s) {
1862 const QColor color = QCmyk32::fromCmyk32(s).toColor();
1863 return color.rgba();
1864 });
1865 return buffer;
1866}
1867
1868static void QT_FASTCALL convertCMYK8888ToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
1869{
1870 qt_convertCMYK8888ToARGB32PM(buffer, buffer, count);
1871}
1872
1873static const QRgba64 *QT_FASTCALL convertCMYK8888ToToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1874 const QList<QRgb> *, QDitherInfo *)
1875{
1876 for (int i = 0; i < count; ++i)
1877 buffer[i] = QCmyk32::fromCmyk32(src[i]).toColor().rgba64();
1878 return buffer;
1879}
1880
1881static const uint *QT_FASTCALL fetchCMYK8888ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
1882 const QList<QRgb> *, QDitherInfo *)
1883{
1884 const uint *s = reinterpret_cast<const uint *>(src) + index;
1885 for (int i = 0; i < count; ++i)
1886 buffer[i] = QCmyk32::fromCmyk32(s[i]).toColor().rgba();
1887 return buffer;
1888}
1889
1890static const QRgba64 *QT_FASTCALL fetchCMYK8888ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1891 const QList<QRgb> *, QDitherInfo *)
1892{
1893 const uint *s = reinterpret_cast<const uint *>(src) + index;
1894 for (int i = 0; i < count; ++i)
1895 buffer[i] = QCmyk32::fromCmyk32(s[i]).toColor().rgba64();
1896 return buffer;
1897}
1898
1899static void QT_FASTCALL storeCMYK8888FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1900 const QList<QRgb> *, QDitherInfo *)
1901{
1902 uint *d = reinterpret_cast<uint *>(dest) + index;
1903 for (int i = 0; i < count; ++i) {
1904 QColor c = qUnpremultiply(src[i]);
1905 d[i] = QCmyk32::fromColor(c).toUint();
1906 }
1907}
1908
1909static void QT_FASTCALL storeCMYK8888FromRGB32(uchar *dest, const uint *src, int index, int count,
1910 const QList<QRgb> *, QDitherInfo *)
1911{
1912 uint *d = reinterpret_cast<uint *>(dest) + index;
1913 for (int i = 0; i < count; ++i) {
1914 QColor c = src[i];
1915 d[i] = QCmyk32::fromColor(c).toUint();
1916 }
1917}
1918
1919// Note:
1920// convertToArgb32() assumes that no color channel is less than 4 bits.
1921// storeRGBFromARGB32PM() assumes that no color channel is more than 8 bits.
1922// QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits.
1924 { false, false, QPixelLayout::BPPNone, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }, // Format_Invalid
1925 { false, false, QPixelLayout::BPP1MSB, nullptr,
1926 convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
1927 fetchIndexedToARGB32PM<QPixelLayout::BPP1MSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1MSB>,
1928 nullptr, nullptr }, // Format_Mono
1929 { false, false, QPixelLayout::BPP1LSB, nullptr,
1930 convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
1931 fetchIndexedToARGB32PM<QPixelLayout::BPP1LSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1LSB>,
1932 nullptr, nullptr }, // Format_MonoLSB
1933 { false, false, QPixelLayout::BPP8, nullptr,
1934 convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
1935 fetchIndexedToARGB32PM<QPixelLayout::BPP8>, fetchIndexedToRGBA64PM<QPixelLayout::BPP8>,
1936 nullptr, nullptr }, // Format_Indexed8
1937 // Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong,
1938 // but everywhere this generic conversion would be wrong is currently overloaded.
1939 { false, false, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough,
1940 convertRGB32ToRGB64, fetchPassThrough, fetchRGB32ToRGB64, storePassThrough, storePassThrough }, // Format_RGB32
1941 { true, false, QPixelLayout::BPP32, rbSwap_rgb32, convertARGB32ToARGB32PM,
1942 convertARGB32ToRGBA64PM, fetchARGB32ToARGB32PM, fetchARGB32ToRGBA64PM, storeARGB32FromARGB32PM, storePassThrough }, // Format_ARGB32
1943 { true, true, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough,
1944 convertARGB32PMToRGBA64PM, fetchPassThrough, fetchARGB32PMToRGBA64PM, storePassThrough, storePassThrough }, // Format_ARGB32_Premultiplied
1945 pixelLayoutRGB<QImage::Format_RGB16>(),
1946 pixelLayoutARGBPM<QImage::Format_ARGB8565_Premultiplied>(),
1947 pixelLayoutRGB<QImage::Format_RGB666>(),
1948 pixelLayoutARGBPM<QImage::Format_ARGB6666_Premultiplied>(),
1949 pixelLayoutRGB<QImage::Format_RGB555>(),
1950 pixelLayoutARGBPM<QImage::Format_ARGB8555_Premultiplied>(),
1951 pixelLayoutRGB<QImage::Format_RGB888>(),
1952 pixelLayoutRGB<QImage::Format_RGB444>(),
1953 pixelLayoutARGBPM<QImage::Format_ARGB4444_Premultiplied>(),
1954 { false, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM,
1955 convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBXFromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBX8888
1956 { true, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888ToARGB32PM,
1957 convertRGBA8888ToRGBA64PM, fetchRGBA8888ToARGB32PM, fetchRGBA8888ToRGBA64PM, storeRGBA8888FromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBA8888
1958 { true, true, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM,
1959 convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBA8888PMFromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBA8888_Premultiplied
1960 { false, false, QPixelLayout::BPP32, rbSwap_rgb30,
1961 convertA2RGB30PMToARGB32PM<PixelOrderBGR>,
1962 convertA2RGB30PMToRGBA64PM<PixelOrderBGR>,
1963 fetchA2RGB30PMToARGB32PM<PixelOrderBGR>,
1964 fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>,
1965 storeRGB30FromARGB32PM<PixelOrderBGR>,
1966 storeRGB30FromRGB32<PixelOrderBGR>
1967 }, // Format_BGR30
1968 { true, true, QPixelLayout::BPP32, rbSwap_rgb30,
1969 convertA2RGB30PMToARGB32PM<PixelOrderBGR>,
1970 convertA2RGB30PMToRGBA64PM<PixelOrderBGR>,
1971 fetchA2RGB30PMToARGB32PM<PixelOrderBGR>,
1972 fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>,
1973 storeA2RGB30PMFromARGB32PM<PixelOrderBGR>,
1974 storeRGB30FromRGB32<PixelOrderBGR>
1975 }, // Format_A2BGR30_Premultiplied
1976 { false, false, QPixelLayout::BPP32, rbSwap_rgb30,
1977 convertA2RGB30PMToARGB32PM<PixelOrderRGB>,
1978 convertA2RGB30PMToRGBA64PM<PixelOrderRGB>,
1979 fetchA2RGB30PMToARGB32PM<PixelOrderRGB>,
1980 fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>,
1981 storeRGB30FromARGB32PM<PixelOrderRGB>,
1982 storeRGB30FromRGB32<PixelOrderRGB>
1983 }, // Format_RGB30
1984 { true, true, QPixelLayout::BPP32, rbSwap_rgb30,
1985 convertA2RGB30PMToARGB32PM<PixelOrderRGB>,
1986 convertA2RGB30PMToRGBA64PM<PixelOrderRGB>,
1987 fetchA2RGB30PMToARGB32PM<PixelOrderRGB>,
1988 fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>,
1989 storeA2RGB30PMFromARGB32PM<PixelOrderRGB>,
1990 storeRGB30FromRGB32<PixelOrderRGB>
1991 }, // Format_A2RGB30_Premultiplied
1992 { true, true, QPixelLayout::BPP8, nullptr,
1993 convertAlpha8ToRGB32, convertAlpha8To<QRgba64>,
1994 fetchAlpha8ToRGB32, fetchAlpha8To<QRgba64>,
1995 storeAlpha8FromARGB32PM, nullptr }, // Format_Alpha8
1996 { false, false, QPixelLayout::BPP8, nullptr,
1997 convertGrayscale8ToRGB32, convertGrayscale8To<QRgba64>,
1998 fetchGrayscale8ToRGB32, fetchGrayscale8To<QRgba64>,
1999 storeGrayscale8FromARGB32PM, storeGrayscale8FromRGB32 }, // Format_Grayscale8
2000 { false, false, QPixelLayout::BPP64, rbSwap_4x16,
2001 convertPassThrough, nullptr,
2002 fetchRGB64ToRGB32, fetchPassThrough64,
2003 storeRGBA64FromARGB32PM<true>, storeRGB64FromRGB32 }, // Format_RGBX64
2004 { true, false, QPixelLayout::BPP64, rbSwap_4x16,
2005 convertARGB32ToARGB32PM, nullptr,
2006 fetchRGBA64ToARGB32PM, fetchRGBA64ToRGBA64PM,
2007 storeRGBA64FromARGB32PM<false>, storeRGB64FromRGB32 }, // Format_RGBA64
2008 { true, true, QPixelLayout::BPP64, rbSwap_4x16,
2009 convertPassThrough, nullptr,
2010 fetchRGB64ToRGB32, fetchPassThrough64,
2011 storeRGBA64FromARGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied
2012 { false, false, QPixelLayout::BPP16, nullptr,
2013 convertGrayscale16ToRGB32, convertGrayscale16To<QRgba64>,
2014 fetchGrayscale16ToRGB32, fetchGrayscale16To<QRgba64>,
2015 storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 }, // Format_Grayscale16
2016 pixelLayoutRGB<QImage::Format_BGR888>(),
2017 { false, false, QPixelLayout::BPP16FPx4, rbSwap_4x16,
2018 convertPassThrough, nullptr,
2019 fetchRGB16FToRGB32, fetchRGBA16FPMToRGBA64PM,
2020 storeRGB16FFromRGB32, storeRGB16FFromRGB32 }, // Format_RGBX16FPx4
2021 { true, false, QPixelLayout::BPP16FPx4, rbSwap_4x16,
2022 convertARGB32ToARGB32PM, nullptr,
2023 fetchRGBA16FToARGB32PM, fetchRGBA16FToRGBA64PM,
2024 storeRGBA16FFromARGB32PM, storeRGB16FFromRGB32 }, // Format_RGBA16FPx4
2025 { true, true, QPixelLayout::BPP16FPx4, rbSwap_4x16,
2026 convertPassThrough, nullptr,
2027 fetchRGB16FToRGB32, fetchRGBA16FPMToRGBA64PM,
2028 storeRGB16FFromRGB32, storeRGB16FFromRGB32 }, // Format_RGBA16FPx4_Premultiplied
2029 { false, false, QPixelLayout::BPP32FPx4, rbSwap_4x32,
2030 convertPassThrough, nullptr,
2031 fetchRGB32FToRGB32, fetchRGBA32FPMToRGBA64PM,
2032 storeRGB32FFromRGB32, storeRGB32FFromRGB32 }, // Format_RGBX32FPx4
2033 { true, false, QPixelLayout::BPP32FPx4, rbSwap_4x32,
2034 convertARGB32ToARGB32PM, nullptr,
2035 fetchRGBA32FToARGB32PM, fetchRGBA32FToRGBA64PM,
2036 storeRGBA32FFromARGB32PM, storeRGB32FFromRGB32 }, // Format_RGBA32FPx4
2037 { true, true, QPixelLayout::BPP32FPx4, rbSwap_4x32,
2038 convertPassThrough, nullptr,
2039 fetchRGB32FToRGB32, fetchRGBA32FPMToRGBA64PM,
2040 storeRGB32FFromRGB32, storeRGB32FFromRGB32 }, // Format_RGBA32FPx4_Premultiplied
2041 { false, false, QPixelLayout::BPP32, nullptr,
2042 convertCMYK8888ToARGB32PM, convertCMYK8888ToToRGBA64PM,
2043 fetchCMYK8888ToARGB32PM, fetchCMYK8888ToRGBA64PM,
2044 storeCMYK8888FromARGB32PM, storeCMYK8888FromRGB32 }, // Format_CMYK8888
2045};
2046
2047static_assert(std::size(qPixelLayouts) == QImage::NImageFormats);
2048
2049static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int length)
2050{
2051 for (int i = 0; i < length; ++i) {
2052 dest[i] = toArgb32(src[i]);
2053 }
2054}
2055
2056template<QImage::Format format>
2057static void QT_FASTCALL storeGenericFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2058 const QList<QRgb> *clut, QDitherInfo *dither)
2059{
2060 Q_DECL_UNINITIALIZED uint buffer[BufferSize];
2061 convertFromRgb64(buffer, src, count);
2062 qPixelLayouts[format].storeFromARGB32PM(dest, buffer, index, count, clut, dither);
2063}
2064
2065static void QT_FASTCALL storeARGB32FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2066 const QList<QRgb> *, QDitherInfo *)
2067{
2068 uint *d = (uint*)dest + index;
2069 for (int i = 0; i < count; ++i)
2070 d[i] = toArgb32(src[i].unpremultiplied());
2071}
2072
2073static void QT_FASTCALL storeRGBA8888FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2074 const QList<QRgb> *, QDitherInfo *)
2075{
2076 uint *d = (uint*)dest + index;
2077 for (int i = 0; i < count; ++i)
2078 d[i] = toRgba8888(src[i].unpremultiplied());
2079}
2080
2081template<QtPixelOrder PixelOrder>
2082static void QT_FASTCALL storeRGB30FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2083 const QList<QRgb> *, QDitherInfo *)
2084{
2085 uint *d = (uint*)dest + index;
2086#ifdef __SSE2__
2087 qConvertRGBA64PMToA2RGB30PM_sse2<PixelOrder>(d, src, count);
2088#elif defined (__loongarch_sx)
2089 qConvertRGBA64PMToA2RGB30PM_lsx<PixelOrder>(d, src, count);
2090#else
2091 for (int i = 0; i < count; ++i)
2092 d[i] = qConvertRgb64ToRgb30<PixelOrder>(src[i]);
2093#endif
2094}
2095
2096static void QT_FASTCALL storeRGBX64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2097 const QList<QRgb> *, QDitherInfo *)
2098{
2099 QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
2100 for (int i = 0; i < count; ++i) {
2101 d[i] = src[i].unpremultiplied();
2102 d[i].setAlpha(65535);
2103 }
2104}
2105
2106static void QT_FASTCALL storeRGBA64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2107 const QList<QRgb> *, QDitherInfo *)
2108{
2109 QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
2110 for (int i = 0; i < count; ++i)
2111 d[i] = src[i].unpremultiplied();
2112}
2113
2114static void QT_FASTCALL storeRGBA64PMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2115 const QList<QRgb> *, QDitherInfo *)
2116{
2117 QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
2118 if (d != src)
2119 memcpy(d, src, count * sizeof(QRgba64));
2120}
2121
2122static void QT_FASTCALL storeGray16FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2123 const QList<QRgb> *, QDitherInfo *)
2124{
2125 quint16 *d = reinterpret_cast<quint16*>(dest) + index;
2126 for (int i = 0; i < count; ++i) {
2127 QRgba64 s = src[i].unpremultiplied();
2128 d[i] = qGray(s.red(), s.green(), s.blue());
2129 }
2130}
2131
2132static void QT_FASTCALL storeRGBX16FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2133 const QList<QRgb> *, QDitherInfo *)
2134{
2135 QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
2136 for (int i = 0; i < count; ++i) {
2137 d[i] = qConvertRgb64ToRgbaF16(src[i]).unpremultiplied();
2138 d[i].setAlpha(1.0);
2139 }
2140}
2141
2142static void QT_FASTCALL storeRGBA16FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2143 const QList<QRgb> *, QDitherInfo *)
2144{
2145 QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
2146 for (int i = 0; i < count; ++i)
2147 d[i] = qConvertRgb64ToRgbaF16(src[i]).unpremultiplied();
2148}
2149
2150static void QT_FASTCALL storeRGBA16FPMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2151 const QList<QRgb> *, QDitherInfo *)
2152{
2153 QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
2154 for (int i = 0; i < count; ++i)
2155 d[i] = qConvertRgb64ToRgbaF16(src[i]);
2156}
2157
2158static void QT_FASTCALL storeRGBX32FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2159 const QList<QRgb> *, QDitherInfo *)
2160{
2161 QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
2162 for (int i = 0; i < count; ++i) {
2163 d[i] = qConvertRgb64ToRgbaF32(src[i]).unpremultiplied();
2164 d[i].setAlpha(1.0);
2165 }
2166}
2167
2168static void QT_FASTCALL storeRGBA32FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2169 const QList<QRgb> *, QDitherInfo *)
2170{
2171 QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
2172 for (int i = 0; i < count; ++i)
2173 d[i] = qConvertRgb64ToRgbaF32(src[i]).unpremultiplied();
2174}
2175
2176static void QT_FASTCALL storeRGBA32FPMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2177 const QList<QRgb> *, QDitherInfo *)
2178{
2179 QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
2180 for (int i = 0; i < count; ++i)
2181 d[i] = qConvertRgb64ToRgbaF32(src[i]);
2182}
2183
2184static void QT_FASTCALL storeCMYKFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
2185 const QList<QRgb> *, QDitherInfo *)
2186{
2187 uint *d = reinterpret_cast<uint *>(dest) + index;
2188 for (int i = 0; i < count; ++i)
2189 d[i] = QCmyk32::fromColor(QColor(src[i])).toUint();
2190}
2191
2193 nullptr,
2194 nullptr,
2195 nullptr,
2196 nullptr,
2197 storeGenericFromRGBA64PM<QImage::Format_RGB32>,
2198 storeARGB32FromRGBA64PM,
2199 storeGenericFromRGBA64PM<QImage::Format_ARGB32_Premultiplied>,
2200 storeGenericFromRGBA64PM<QImage::Format_RGB16>,
2201 storeGenericFromRGBA64PM<QImage::Format_ARGB8565_Premultiplied>,
2202 storeGenericFromRGBA64PM<QImage::Format_RGB666>,
2203 storeGenericFromRGBA64PM<QImage::Format_ARGB6666_Premultiplied>,
2204 storeGenericFromRGBA64PM<QImage::Format_RGB555>,
2205 storeGenericFromRGBA64PM<QImage::Format_ARGB8555_Premultiplied>,
2206 storeGenericFromRGBA64PM<QImage::Format_RGB888>,
2207 storeGenericFromRGBA64PM<QImage::Format_RGB444>,
2208 storeGenericFromRGBA64PM<QImage::Format_ARGB4444_Premultiplied>,
2209 storeGenericFromRGBA64PM<QImage::Format_RGBX8888>,
2210 storeRGBA8888FromRGBA64PM,
2211 storeGenericFromRGBA64PM<QImage::Format_RGBA8888_Premultiplied>,
2212 storeRGB30FromRGBA64PM<PixelOrderBGR>,
2213 storeRGB30FromRGBA64PM<PixelOrderBGR>,
2214 storeRGB30FromRGBA64PM<PixelOrderRGB>,
2215 storeRGB30FromRGBA64PM<PixelOrderRGB>,
2216 storeGenericFromRGBA64PM<QImage::Format_Alpha8>,
2217 storeGenericFromRGBA64PM<QImage::Format_Grayscale8>,
2218 storeRGBX64FromRGBA64PM,
2219 storeRGBA64FromRGBA64PM,
2220 storeRGBA64PMFromRGBA64PM,
2221 storeGray16FromRGBA64PM,
2222 storeGenericFromRGBA64PM<QImage::Format_BGR888>,
2223 storeRGBX16FFromRGBA64PM,
2224 storeRGBA16FFromRGBA64PM,
2225 storeRGBA16FPMFromRGBA64PM,
2226 storeRGBX32FFromRGBA64PM,
2227 storeRGBA32FFromRGBA64PM,
2228 storeRGBA32FPMFromRGBA64PM,
2229 storeCMYKFromRGBA64PM,
2230};
2231
2232static_assert(std::size(qStoreFromRGBA64PM) == QImage::NImageFormats);
2233
2234#if QT_CONFIG(raster_fp)
2235static void QT_FASTCALL convertToRgbaF32(QRgbaFloat32 *dest, const uint *src, int length)
2236{
2237 for (int i = 0; i < length; ++i)
2238 dest[i] = QRgbaFloat32::fromArgb32(src[i]);
2239}
2240
2241template<QImage::Format format>
2242static const QRgbaFloat32 * QT_FASTCALL convertGenericToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
2243 const QList<QRgb> *clut, QDitherInfo *)
2244{
2245 Q_DECL_UNINITIALIZED uint buffer32[BufferSize];
2246 memcpy(buffer32, src, count * sizeof(uint));
2247 qPixelLayouts[format].convertToARGB32PM(buffer32, count, clut);
2248 convertToRgbaF32(buffer, buffer32, count);
2249 return buffer;
2250}
2251
2252static const QRgbaFloat32 * QT_FASTCALL convertARGB32ToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
2253 const QList<QRgb> *, QDitherInfo *)
2254{
2255 for (int i = 0; i < count; ++i)
2256 buffer[i] = QRgbaFloat32::fromArgb32(src[i]).premultiplied();
2257 return buffer;
2258}
2259
2260static const QRgbaFloat32 * QT_FASTCALL convertRGBA8888ToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
2261 const QList<QRgb> *, QDitherInfo *)
2262{
2263 for (int i = 0; i < count; ++i)
2264 buffer[i] = QRgbaFloat32::fromArgb32(RGBA2ARGB(src[i])).premultiplied();
2265 return buffer;
2266}
2267
2268template<QtPixelOrder PixelOrder>
2269static const QRgbaFloat32 * QT_FASTCALL convertRGB30ToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
2270 const QList<QRgb> *, QDitherInfo *)
2271{
2272 for (int i = 0; i < count; ++i) {
2273 QRgba64 s = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]);
2274 buffer[i] = QRgbaFloat32::fromRgba64(s.red(), s.green(), s.blue(), s.alpha());
2275 }
2276 return buffer;
2277}
2278
2279static const QRgbaFloat32 * QT_FASTCALL convertCMYKToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
2280 const QList<QRgb> *, QDitherInfo *)
2281{
2282 for (int i = 0; i < count; ++i)
2283 buffer[i] = QRgbaFloat32::fromArgb32(QCmyk32::fromCmyk32(src[i]).toColor().rgba());
2284
2285 return buffer;
2286}
2287
2288ConvertToFPFunc qConvertToRGBA32F[] = {
2289 nullptr,
2290 convertIndexedTo<QRgbaFloat32>,
2291 convertIndexedTo<QRgbaFloat32>,
2292 convertIndexedTo<QRgbaFloat32>,
2293 convertGenericToRGBA32F<QImage::Format_RGB32>,
2294 convertARGB32ToRGBA32F,
2295 convertGenericToRGBA32F<QImage::Format_ARGB32_Premultiplied>,
2296 convertGenericToRGBA32F<QImage::Format_RGB16>,
2297 convertGenericToRGBA32F<QImage::Format_ARGB8565_Premultiplied>,
2298 convertGenericToRGBA32F<QImage::Format_RGB666>,
2299 convertGenericToRGBA32F<QImage::Format_ARGB6666_Premultiplied>,
2300 convertGenericToRGBA32F<QImage::Format_RGB555>,
2301 convertGenericToRGBA32F<QImage::Format_ARGB8555_Premultiplied>,
2302 convertGenericToRGBA32F<QImage::Format_RGB888>,
2303 convertGenericToRGBA32F<QImage::Format_RGB444>,
2304 convertGenericToRGBA32F<QImage::Format_ARGB4444_Premultiplied>,
2305 convertGenericToRGBA32F<QImage::Format_RGBX8888>,
2306 convertRGBA8888ToRGBA32F,
2307 convertGenericToRGBA32F<QImage::Format_RGBA8888_Premultiplied>,
2308 convertRGB30ToRGBA32F<PixelOrderBGR>,
2309 convertRGB30ToRGBA32F<PixelOrderBGR>,
2310 convertRGB30ToRGBA32F<PixelOrderRGB>,
2311 convertRGB30ToRGBA32F<PixelOrderRGB>,
2312 convertAlpha8To<QRgbaFloat32>,
2313 convertGrayscale8To<QRgbaFloat32>,
2314 nullptr,
2315 nullptr,
2316 nullptr,
2317 convertGrayscale16To<QRgbaFloat32>,
2318 convertGenericToRGBA32F<QImage::Format_BGR888>,
2319 nullptr,
2320 nullptr,
2321 nullptr,
2322 nullptr,
2323 nullptr,
2324 nullptr,
2325 convertCMYKToRGBA32F,
2326};
2327
2328static_assert(std::size(qConvertToRGBA32F) == QImage::NImageFormats);
2329
2330static const QRgbaFloat32 *QT_FASTCALL fetchRGBX64ToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
2331 const QList<QRgb> *, QDitherInfo *)
2332{
2333 const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
2334 for (int i = 0; i < count; ++i) {
2335 QRgba64 c = s[i];
2336 buffer[i] = QRgbaFloat32::fromRgba64(c.red(), c.green(), c.blue(), 65535);
2337 }
2338 return buffer;
2339}
2340
2341static const QRgbaFloat32 *QT_FASTCALL fetchRGBA64ToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
2342 const QList<QRgb> *, QDitherInfo *)
2343{
2344 const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
2345 for (int i = 0; i < count; ++i)
2346 buffer[i] = qConvertRgb64ToRgbaF32(s[i]).premultiplied();
2347 return buffer;
2348}
2349
2350static const QRgbaFloat32 *QT_FASTCALL fetchRGBA64PMToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
2351 const QList<QRgb> *, QDitherInfo *)
2352{
2353 const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
2354 for (int i = 0; i < count; ++i)
2355 buffer[i] = qConvertRgb64ToRgbaF32(s[i]);
2356 return buffer;
2357}
2358
2359static const QRgbaFloat32 *QT_FASTCALL fetchRGBA16FToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
2360 const QList<QRgb> *, QDitherInfo *)
2361{
2362 const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
2363 for (int i = 0; i < count; ++i) {
2364 auto c = s[i].premultiplied();
2365 buffer[i] = QRgbaFloat32 { c.r, c.g, c.b, c.a};
2366 }
2367 return buffer;
2368}
2369
2370static const QRgbaFloat32 *QT_FASTCALL fetchRGBA16F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
2371 const QList<QRgb> *, QDitherInfo *)
2372{
2373 const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
2374 qFloatFromFloat16((float *)buffer, (const qfloat16 *)s, count * 4);
2375 return buffer;
2376}
2377
2378static const QRgbaFloat32 *QT_FASTCALL fetchRGBA32FToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
2379 const QList<QRgb> *, QDitherInfo *)
2380{
2381 const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
2382 for (int i = 0; i < count; ++i)
2383 buffer[i] = s[i].premultiplied();
2384 return buffer;
2385}
2386
2387static const QRgbaFloat32 *QT_FASTCALL fetchRGBA32F(QRgbaFloat32 *, const uchar *src, int index, int,
2388 const QList<QRgb> *, QDitherInfo *)
2389{
2390 const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
2391 return s;
2392}
2393
2394static const QRgbaFloat32 *QT_FASTCALL fetchCMYKToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
2395 const QList<QRgb> *, QDitherInfo *)
2396{
2397 const uint *s = reinterpret_cast<const uint *>(src) + index;
2398 for (int i = 0; i < count; ++i)
2399 buffer[i] = QRgbaFloat32::fromArgb32(QCmyk32::fromCmyk32(s[i]).toColor().rgba());
2400
2401 return buffer;
2402}
2403
2404FetchAndConvertPixelsFuncFP qFetchToRGBA32F[] = {
2405 nullptr,
2406 fetchIndexedToRGBA32F<QPixelLayout::BPP1MSB>,
2407 fetchIndexedToRGBA32F<QPixelLayout::BPP1LSB>,
2408 fetchIndexedToRGBA32F<QPixelLayout::BPP8>,
2409 fetchRGBToRGB32F<QImage::Format_RGB32>,
2410 fetchARGBToRGBA32F<QImage::Format_ARGB32>,
2411 fetchARGBPMToRGBA32F<QImage::Format_ARGB32_Premultiplied>,
2412 fetchRGBToRGB32F<QImage::Format_RGB16>,
2413 fetchARGBToRGBA32F<QImage::Format_ARGB8565_Premultiplied>,
2414 fetchRGBToRGB32F<QImage::Format_RGB666>,
2415 fetchARGBToRGBA32F<QImage::Format_ARGB6666_Premultiplied>,
2416 fetchRGBToRGB32F<QImage::Format_RGB555>,
2417 fetchARGBToRGBA32F<QImage::Format_ARGB8555_Premultiplied>,
2418 fetchRGBToRGB32F<QImage::Format_RGB888>,
2419 fetchRGBToRGB32F<QImage::Format_RGB444>,
2420 fetchARGBToRGBA32F<QImage::Format_ARGB4444_Premultiplied>,
2421 fetchRGBToRGB32F<QImage::Format_RGBX8888>,
2422 fetchARGBToRGBA32F<QImage::Format_RGBA8888>,
2423 fetchARGBPMToRGBA32F<QImage::Format_RGBA8888_Premultiplied>,
2424 fetchRGB30ToRGBA32F<PixelOrderBGR>,
2425 fetchRGB30ToRGBA32F<PixelOrderBGR>,
2426 fetchRGB30ToRGBA32F<PixelOrderRGB>,
2427 fetchRGB30ToRGBA32F<PixelOrderRGB>,
2428 fetchAlpha8To<QRgbaFloat32>,
2429 fetchGrayscale8To<QRgbaFloat32>,
2430 fetchRGBX64ToRGBA32F,
2431 fetchRGBA64ToRGBA32F,
2432 fetchRGBA64PMToRGBA32F,
2433 fetchGrayscale16To<QRgbaFloat32>,
2434 fetchRGBToRGB32F<QImage::Format_BGR888>,
2435 fetchRGBA16F,
2436 fetchRGBA16FToRGBA32F,
2437 fetchRGBA16F,
2438 fetchRGBA32F,
2439 fetchRGBA32FToRGBA32F,
2440 fetchRGBA32F,
2441 fetchCMYKToRGBA32F,
2442};
2443
2444static_assert(std::size(qFetchToRGBA32F) == QImage::NImageFormats);
2445
2446static void QT_FASTCALL convertFromRgba32f(uint *dest, const QRgbaFloat32 *src, int length)
2447{
2448 for (int i = 0; i < length; ++i)
2449 dest[i] = src[i].toArgb32();
2450}
2451
2452template<QImage::Format format>
2453static void QT_FASTCALL storeGenericFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2454 const QList<QRgb> *clut, QDitherInfo *dither)
2455{
2456 Q_DECL_UNINITIALIZED uint buffer[BufferSize];
2457 convertFromRgba32f(buffer, src, count);
2458 qPixelLayouts[format].storeFromARGB32PM(dest, buffer, index, count, clut, dither);
2459}
2460
2461static void QT_FASTCALL storeARGB32FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2462 const QList<QRgb> *, QDitherInfo *)
2463{
2464 uint *d = (uint*)dest + index;
2465 for (int i = 0; i < count; ++i)
2466 d[i] = src[i].unpremultiplied().toArgb32();
2467}
2468
2469static void QT_FASTCALL storeRGBA8888FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2470 const QList<QRgb> *, QDitherInfo *)
2471{
2472 uint *d = (uint*)dest + index;
2473 for (int i = 0; i < count; ++i)
2474 d[i] = ARGB2RGBA(src[i].unpremultiplied().toArgb32());
2475}
2476
2477template<QtPixelOrder PixelOrder>
2478static void QT_FASTCALL storeRGB30FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2479 const QList<QRgb> *, QDitherInfo *)
2480{
2481 uint *d = (uint*)dest + index;
2482 for (int i = 0; i < count; ++i) {
2483 const auto s = src[i];
2484 d[i] = qConvertRgb64ToRgb30<PixelOrder>(QRgba64::fromRgba64(s.red16(), s.green16(), s.blue16(), s.alpha16()));
2485 }
2486}
2487
2488static void QT_FASTCALL storeRGBX64FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2489 const QList<QRgb> *, QDitherInfo *)
2490{
2491 QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
2492 for (int i = 0; i < count; ++i) {
2493 const auto s = src[i].unpremultiplied();
2494 d[i] = QRgba64::fromRgba64(s.red16(), s.green16(), s.blue16(), 65535);
2495 }
2496}
2497
2498static void QT_FASTCALL storeRGBA64FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2499 const QList<QRgb> *, QDitherInfo *)
2500{
2501 QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
2502 for (int i = 0; i < count; ++i) {
2503 const auto s = src[i].unpremultiplied();
2504 d[i] = QRgba64::fromRgba64(s.red16(), s.green16(), s.blue16(), s.alpha16());
2505 }
2506}
2507
2508static void QT_FASTCALL storeRGBA64PMFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2509 const QList<QRgb> *, QDitherInfo *)
2510{
2511 QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
2512 for (int i = 0; i < count; ++i)
2513 d[i] = QRgba64::fromRgba64(src[i].red16(), src[i].green16(), src[i].blue16(), src[i].alpha16());
2514}
2515
2516static void QT_FASTCALL storeGray16FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2517 const QList<QRgb> *, QDitherInfo *)
2518{
2519 quint16 *d = reinterpret_cast<quint16 *>(dest) + index;
2520 for (int i = 0; i < count; ++i) {
2521 auto s = src[i].unpremultiplied();
2522 d[i] = qGray(s.red16(), s.green16(), s.blue16());
2523 }
2524}
2525
2526static void QT_FASTCALL storeRGBX16FFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2527 const QList<QRgb> *, QDitherInfo *)
2528{
2529 QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
2530 for (int i = 0; i < count; ++i) {
2531 auto s = src[i].unpremultiplied();
2532 d[i] = QRgbaFloat16{ qfloat16(s.r), qfloat16(s.g), qfloat16(s.b), qfloat16(1.0f) };
2533 }
2534}
2535
2536static void QT_FASTCALL storeRGBA16FFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2537 const QList<QRgb> *, QDitherInfo *)
2538{
2539 QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
2540 for (int i = 0; i < count; ++i) {
2541 auto s = src[i].unpremultiplied();
2542 d[i] = QRgbaFloat16{ qfloat16(s.r), qfloat16(s.g), qfloat16(s.b), qfloat16(s.a) };
2543 }
2544}
2545
2546static void QT_FASTCALL storeRGBA16FPMFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2547 const QList<QRgb> *, QDitherInfo *)
2548{
2549 QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
2550 qFloatToFloat16((qfloat16 *)d, (const float *)src, count * 4);
2551}
2552
2553static void QT_FASTCALL storeRGBX32FFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2554 const QList<QRgb> *, QDitherInfo *)
2555{
2556 QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
2557 for (int i = 0; i < count; ++i) {
2558 auto s = src[i].unpremultiplied();
2559 s.a = 1.0f;
2560 d[i] = s;
2561 }
2562}
2563
2564static void QT_FASTCALL storeRGBA32FFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2565 const QList<QRgb> *, QDitherInfo *)
2566{
2567 QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
2568 for (int i = 0; i < count; ++i)
2569 d[i] = src[i].unpremultiplied();
2570}
2571
2572static void QT_FASTCALL storeRGBA32FPMFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2573 const QList<QRgb> *, QDitherInfo *)
2574{
2575 QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
2576 if (d != src) {
2577 for (int i = 0; i < count; ++i)
2578 d[i] = src[i];
2579 }
2580}
2581
2582static void QT_FASTCALL storeCMYKFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
2583 const QList<QRgb> *, QDitherInfo *)
2584{
2585 uint *d = reinterpret_cast<uint *>(dest) + index;
2586 for (int i = 0; i < count; ++i) {
2587 // Yikes, this really needs enablers in QColor and friends
2588 d[i] = QCmyk32::fromColor(QColor(src[i].toArgb32())).toUint();
2589 }
2590}
2591
2592ConvertAndStorePixelsFuncFP qStoreFromRGBA32F[] = {
2593 nullptr,
2594 nullptr,
2595 nullptr,
2596 nullptr,
2597 storeGenericFromRGBA32F<QImage::Format_RGB32>,
2598 storeARGB32FromRGBA32F,
2599 storeGenericFromRGBA32F<QImage::Format_ARGB32_Premultiplied>,
2600 storeGenericFromRGBA32F<QImage::Format_RGB16>,
2601 storeGenericFromRGBA32F<QImage::Format_ARGB8565_Premultiplied>,
2602 storeGenericFromRGBA32F<QImage::Format_RGB666>,
2603 storeGenericFromRGBA32F<QImage::Format_ARGB6666_Premultiplied>,
2604 storeGenericFromRGBA32F<QImage::Format_RGB555>,
2605 storeGenericFromRGBA32F<QImage::Format_ARGB8555_Premultiplied>,
2606 storeGenericFromRGBA32F<QImage::Format_RGB888>,
2607 storeGenericFromRGBA32F<QImage::Format_RGB444>,
2608 storeGenericFromRGBA32F<QImage::Format_ARGB4444_Premultiplied>,
2609 storeGenericFromRGBA32F<QImage::Format_RGBX8888>,
2610 storeRGBA8888FromRGBA32F,
2611 storeGenericFromRGBA32F<QImage::Format_RGBA8888_Premultiplied>,
2612 storeRGB30FromRGBA32F<PixelOrderBGR>,
2613 storeRGB30FromRGBA32F<PixelOrderBGR>,
2614 storeRGB30FromRGBA32F<PixelOrderRGB>,
2615 storeRGB30FromRGBA32F<PixelOrderRGB>,
2616 storeGenericFromRGBA32F<QImage::Format_Alpha8>,
2617 storeGenericFromRGBA32F<QImage::Format_Grayscale8>,
2618 storeRGBX64FromRGBA32F,
2619 storeRGBA64FromRGBA32F,
2620 storeRGBA64PMFromRGBA32F,
2621 storeGray16FromRGBA32F,
2622 storeGenericFromRGBA32F<QImage::Format_BGR888>,
2623 storeRGBX16FFromRGBA32F,
2624 storeRGBA16FFromRGBA32F,
2625 storeRGBA16FPMFromRGBA32F,
2626 storeRGBX32FFromRGBA32F,
2627 storeRGBA32FFromRGBA32F,
2628 storeRGBA32FPMFromRGBA32F,
2629 storeCMYKFromRGBA32F,
2630};
2631
2632static_assert(std::size(qStoreFromRGBA32F) == QImage::NImageFormats);
2633
2634#endif // QT_CONFIG(raster_fp)
2635
2636QT_END_NAMESPACE
uint QT_FASTCALL fetch1Pixel< QPixelLayout::BPP1LSB >(const uchar *src, int index)
QRgbaFloat< float > QRgbaFloat32
constexpr uint alphaWidth()
static constexpr QPixelLayout pixelLayoutRGB()
constexpr uint greenShift()
constexpr uint greenWidth()
static uint convertPixelToRGB32(uint s)
static QRgba64 convertPixelToRGBA64PM(uint s)
constexpr uint blueShift()
constexpr uint alphaShift()
constexpr QPixelLayout::BPP bitsPerPixel()
constexpr uint redShift()
constexpr uint blueWidth()
static QRgba64 convertPixelToRGB64(uint s)
QRgbaFloat32 qConvertA2rgb30ToRgbaFP(uint rgb)
static uint convertPixelToARGB32PM(uint s)
static constexpr QPixelLayout pixelLayoutARGBPM()
const uint * qt_convertCMYK8888ToARGB32PM(uint *buffer, const uint *src, int count)
QPixelLayout qPixelLayouts[]
#define UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion)
ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats]
void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count)