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