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

source code of qtbase/src/gui/painting/qpixellayout.cpp