1/****************************************************************************
2**
3** Copyright (C) 2020 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <qglobal.h>
41
42#include "qdrawhelper_p.h"
43#include "qpixellayout_p.h"
44#include "qrgba64_p.h"
45#include <QtCore/private/qsimd_p.h>
46
47QT_BEGIN_NAMESPACE
48
49template<QImage::Format> constexpr uint redWidth();
50template<QImage::Format> constexpr uint redShift();
51template<QImage::Format> constexpr uint greenWidth();
52template<QImage::Format> constexpr uint greenShift();
53template<QImage::Format> constexpr uint blueWidth();
54template<QImage::Format> constexpr uint blueShift();
55template<QImage::Format> constexpr uint alphaWidth();
56template<QImage::Format> constexpr uint alphaShift();
57
58template<> constexpr uint redWidth<QImage::Format_RGB16>() { return 5; }
59template<> constexpr uint redWidth<QImage::Format_RGB444>() { return 4; }
60template<> constexpr uint redWidth<QImage::Format_RGB555>() { return 5; }
61template<> constexpr uint redWidth<QImage::Format_RGB666>() { return 6; }
62template<> constexpr uint redWidth<QImage::Format_RGB888>() { return 8; }
63template<> constexpr uint redWidth<QImage::Format_BGR888>() { return 8; }
64template<> constexpr uint redWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
65template<> constexpr uint redWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
66template<> constexpr uint redWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
67template<> constexpr uint redWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
68template<> constexpr uint redWidth<QImage::Format_RGBX8888>() { return 8; }
69template<> constexpr uint redWidth<QImage::Format_RGBA8888>() { return 8; }
70template<> constexpr uint redWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
71
72template<> constexpr uint redShift<QImage::Format_RGB16>() { return 11; }
73template<> constexpr uint redShift<QImage::Format_RGB444>() { return 8; }
74template<> constexpr uint redShift<QImage::Format_RGB555>() { return 10; }
75template<> constexpr uint redShift<QImage::Format_RGB666>() { return 12; }
76template<> constexpr uint redShift<QImage::Format_RGB888>() { return 16; }
77template<> constexpr uint redShift<QImage::Format_BGR888>() { return 0; }
78template<> constexpr uint redShift<QImage::Format_ARGB4444_Premultiplied>() { return 8; }
79template<> constexpr uint redShift<QImage::Format_ARGB8555_Premultiplied>() { return 18; }
80template<> constexpr uint redShift<QImage::Format_ARGB8565_Premultiplied>() { return 19; }
81template<> constexpr uint redShift<QImage::Format_ARGB6666_Premultiplied>() { return 12; }
82#if Q_BYTE_ORDER == Q_BIG_ENDIAN
83template<> constexpr uint redShift<QImage::Format_RGBX8888>() { return 24; }
84template<> constexpr uint redShift<QImage::Format_RGBA8888>() { return 24; }
85template<> constexpr uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; }
86#else
87template<> constexpr uint redShift<QImage::Format_RGBX8888>() { return 0; }
88template<> constexpr uint redShift<QImage::Format_RGBA8888>() { return 0; }
89template<> constexpr uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; }
90#endif
91template<> constexpr uint greenWidth<QImage::Format_RGB16>() { return 6; }
92template<> constexpr uint greenWidth<QImage::Format_RGB444>() { return 4; }
93template<> constexpr uint greenWidth<QImage::Format_RGB555>() { return 5; }
94template<> constexpr uint greenWidth<QImage::Format_RGB666>() { return 6; }
95template<> constexpr uint greenWidth<QImage::Format_RGB888>() { return 8; }
96template<> constexpr uint greenWidth<QImage::Format_BGR888>() { return 8; }
97template<> constexpr uint greenWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
98template<> constexpr uint greenWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
99template<> constexpr uint greenWidth<QImage::Format_ARGB8565_Premultiplied>() { return 6; }
100template<> constexpr uint greenWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
101template<> constexpr uint greenWidth<QImage::Format_RGBX8888>() { return 8; }
102template<> constexpr uint greenWidth<QImage::Format_RGBA8888>() { return 8; }
103template<> constexpr uint greenWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
104
105template<> constexpr uint greenShift<QImage::Format_RGB16>() { return 5; }
106template<> constexpr uint greenShift<QImage::Format_RGB444>() { return 4; }
107template<> constexpr uint greenShift<QImage::Format_RGB555>() { return 5; }
108template<> constexpr uint greenShift<QImage::Format_RGB666>() { return 6; }
109template<> constexpr uint greenShift<QImage::Format_RGB888>() { return 8; }
110template<> constexpr uint greenShift<QImage::Format_BGR888>() { return 8; }
111template<> constexpr uint greenShift<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
112template<> constexpr uint greenShift<QImage::Format_ARGB8555_Premultiplied>() { return 13; }
113template<> constexpr uint greenShift<QImage::Format_ARGB8565_Premultiplied>() { return 13; }
114template<> constexpr uint greenShift<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
115#if Q_BYTE_ORDER == Q_BIG_ENDIAN
116template<> constexpr uint greenShift<QImage::Format_RGBX8888>() { return 16; }
117template<> constexpr uint greenShift<QImage::Format_RGBA8888>() { return 16; }
118template<> constexpr uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; }
119#else
120template<> constexpr uint greenShift<QImage::Format_RGBX8888>() { return 8; }
121template<> constexpr uint greenShift<QImage::Format_RGBA8888>() { return 8; }
122template<> constexpr uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
123#endif
124template<> constexpr uint blueWidth<QImage::Format_RGB16>() { return 5; }
125template<> constexpr uint blueWidth<QImage::Format_RGB444>() { return 4; }
126template<> constexpr uint blueWidth<QImage::Format_RGB555>() { return 5; }
127template<> constexpr uint blueWidth<QImage::Format_RGB666>() { return 6; }
128template<> constexpr uint blueWidth<QImage::Format_RGB888>() { return 8; }
129template<> constexpr uint blueWidth<QImage::Format_BGR888>() { return 8; }
130template<> constexpr uint blueWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
131template<> constexpr uint blueWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
132template<> constexpr uint blueWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
133template<> constexpr uint blueWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
134template<> constexpr uint blueWidth<QImage::Format_RGBX8888>() { return 8; }
135template<> constexpr uint blueWidth<QImage::Format_RGBA8888>() { return 8; }
136template<> constexpr uint blueWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
137
138template<> constexpr uint blueShift<QImage::Format_RGB16>() { return 0; }
139template<> constexpr uint blueShift<QImage::Format_RGB444>() { return 0; }
140template<> constexpr uint blueShift<QImage::Format_RGB555>() { return 0; }
141template<> constexpr uint blueShift<QImage::Format_RGB666>() { return 0; }
142template<> constexpr uint blueShift<QImage::Format_RGB888>() { return 0; }
143template<> constexpr uint blueShift<QImage::Format_BGR888>() { return 16; }
144template<> constexpr uint blueShift<QImage::Format_ARGB4444_Premultiplied>() { return 0; }
145template<> constexpr uint blueShift<QImage::Format_ARGB8555_Premultiplied>() { return 8; }
146template<> constexpr uint blueShift<QImage::Format_ARGB8565_Premultiplied>() { return 8; }
147template<> constexpr uint blueShift<QImage::Format_ARGB6666_Premultiplied>() { return 0; }
148#if Q_BYTE_ORDER == Q_BIG_ENDIAN
149template<> constexpr uint blueShift<QImage::Format_RGBX8888>() { return 8; }
150template<> constexpr uint blueShift<QImage::Format_RGBA8888>() { return 8; }
151template<> constexpr uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
152#else
153template<> constexpr uint blueShift<QImage::Format_RGBX8888>() { return 16; }
154template<> constexpr uint blueShift<QImage::Format_RGBA8888>() { return 16; }
155template<> constexpr uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; }
156#endif
157template<> constexpr uint alphaWidth<QImage::Format_RGB16>() { return 0; }
158template<> constexpr uint alphaWidth<QImage::Format_RGB444>() { return 0; }
159template<> constexpr uint alphaWidth<QImage::Format_RGB555>() { return 0; }
160template<> constexpr uint alphaWidth<QImage::Format_RGB666>() { return 0; }
161template<> constexpr uint alphaWidth<QImage::Format_RGB888>() { return 0; }
162template<> constexpr uint alphaWidth<QImage::Format_BGR888>() { return 0; }
163template<> constexpr uint alphaWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
164template<> constexpr uint alphaWidth<QImage::Format_ARGB8555_Premultiplied>() { return 8; }
165template<> constexpr uint alphaWidth<QImage::Format_ARGB8565_Premultiplied>() { return 8; }
166template<> constexpr uint alphaWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
167template<> constexpr uint alphaWidth<QImage::Format_RGBX8888>() { return 0; }
168template<> constexpr uint alphaWidth<QImage::Format_RGBA8888>() { return 8; }
169template<> constexpr uint alphaWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
170
171template<> constexpr uint alphaShift<QImage::Format_RGB16>() { return 0; }
172template<> constexpr uint alphaShift<QImage::Format_RGB444>() { return 0; }
173template<> constexpr uint alphaShift<QImage::Format_RGB555>() { return 0; }
174template<> constexpr uint alphaShift<QImage::Format_RGB666>() { return 0; }
175template<> constexpr uint alphaShift<QImage::Format_RGB888>() { return 0; }
176template<> constexpr uint alphaShift<QImage::Format_BGR888>() { return 0; }
177template<> constexpr uint alphaShift<QImage::Format_ARGB4444_Premultiplied>() { return 12; }
178template<> constexpr uint alphaShift<QImage::Format_ARGB8555_Premultiplied>() { return 0; }
179template<> constexpr uint alphaShift<QImage::Format_ARGB8565_Premultiplied>() { return 0; }
180template<> constexpr uint alphaShift<QImage::Format_ARGB6666_Premultiplied>() { return 18; }
181#if Q_BYTE_ORDER == Q_BIG_ENDIAN
182template<> constexpr uint alphaShift<QImage::Format_RGBX8888>() { return 0; }
183template<> constexpr uint alphaShift<QImage::Format_RGBA8888>() { return 0; }
184template<> constexpr uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; }
185#else
186template<> constexpr uint alphaShift<QImage::Format_RGBX8888>() { return 24; }
187template<> constexpr uint alphaShift<QImage::Format_RGBA8888>() { return 24; }
188template<> constexpr uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; }
189#endif
190
191template<QImage::Format> constexpr QPixelLayout::BPP bitsPerPixel();
192template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB16>() { return QPixelLayout::BPP16; }
193template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB444>() { return QPixelLayout::BPP16; }
194template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB555>() { return QPixelLayout::BPP16; }
195template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB666>() { return QPixelLayout::BPP24; }
196template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB888>() { return QPixelLayout::BPP24; }
197template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_BGR888>() { return QPixelLayout::BPP24; }
198template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB4444_Premultiplied>() { return QPixelLayout::BPP16; }
199template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8555_Premultiplied>() { return QPixelLayout::BPP24; }
200template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8565_Premultiplied>() { return QPixelLayout::BPP24; }
201template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB6666_Premultiplied>() { return QPixelLayout::BPP24; }
202template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBX8888>() { return QPixelLayout::BPP32; }
203template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888>() { return QPixelLayout::BPP32; }
204template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888_Premultiplied>() { return QPixelLayout::BPP32; }
205
206template <QPixelLayout::BPP width> static
207void QT_FASTCALL storePixel(uchar *dest, int index, uint pixel);
208
209template <>
210inline void QT_FASTCALL storePixel<QPixelLayout::BPP16>(uchar *dest, int index, uint pixel)
211{
212 reinterpret_cast<quint16 *>(dest)[index] = quint16(pixel);
213}
214
215template <>
216inline void QT_FASTCALL storePixel<QPixelLayout::BPP24>(uchar *dest, int index, uint pixel)
217{
218 reinterpret_cast<quint24 *>(dest)[index] = quint24(pixel);
219}
220
221template<QImage::Format Format>
222static inline uint convertPixelToRGB32(uint s)
223{
224 constexpr uint redMask = ((1 << redWidth<Format>()) - 1);
225 constexpr uint greenMask = ((1 << greenWidth<Format>()) - 1);
226 constexpr uint blueMask = ((1 << blueWidth<Format>()) - 1);
227
228 constexpr uchar redLeftShift = 8 - redWidth<Format>();
229 constexpr uchar greenLeftShift = 8 - greenWidth<Format>();
230 constexpr uchar blueLeftShift = 8 - blueWidth<Format>();
231
232 constexpr uchar redRightShift = 2 * redWidth<Format>() - 8;
233 constexpr uchar greenRightShift = 2 * greenWidth<Format>() - 8;
234 constexpr uchar blueRightShift = 2 * blueWidth<Format>() - 8;
235
236 uint red = (s >> redShift<Format>()) & redMask;
237 uint green = (s >> greenShift<Format>()) & greenMask;
238 uint blue = (s >> blueShift<Format>()) & blueMask;
239
240 red = ((red << redLeftShift) | (red >> redRightShift)) << 16;
241 green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8;
242 blue = (blue << blueLeftShift) | (blue >> blueRightShift);
243 return 0xff000000 | red | green | blue;
244}
245
246template<QImage::Format Format>
247static void QT_FASTCALL convertToRGB32(uint *buffer, int count, const QList<QRgb> *)
248{
249 for (int i = 0; i < count; ++i)
250 buffer[i] = convertPixelToRGB32<Format>(buffer[i]);
251}
252
253#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
254extern const uint * QT_FASTCALL fetchPixelsBPP24_ssse3(uint *dest, const uchar*src, int index, int count);
255#endif
256
257template<QImage::Format Format>
258static const uint *QT_FASTCALL fetchRGBToRGB32(uint *buffer, const uchar *src, int index, int count,
259 const QList<QRgb> *, QDitherInfo *)
260{
261 constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
262#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
263 if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) {
264 // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3
265 // to vectorize the deforested version below.
266 fetchPixelsBPP24_ssse3(buffer, src, index, count);
267 convertToRGB32<Format>(buffer, count, nullptr);
268 return buffer;
269 }
270#endif
271 for (int i = 0; i < count; ++i)
272 buffer[i] = convertPixelToRGB32<Format>(qFetchPixel<BPP>(src, index + i));
273 return buffer;
274}
275
276template<QImage::Format Format>
277static inline QRgba64 convertPixelToRGB64(uint s)
278{
279 return QRgba64::fromArgb32(convertPixelToRGB32<Format>(s));
280}
281
282template<QImage::Format Format>
283static const QRgba64 *QT_FASTCALL convertToRGB64(QRgba64 *buffer, const uint *src, int count,
284 const QList<QRgb> *, QDitherInfo *)
285{
286 for (int i = 0; i < count; ++i)
287 buffer[i] = convertPixelToRGB64<Format>(src[i]);
288 return buffer;
289}
290
291template<QImage::Format Format>
292static const QRgba64 *QT_FASTCALL fetchRGBToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
293 const QList<QRgb> *, QDitherInfo *)
294{
295 for (int i = 0; i < count; ++i)
296 buffer[i] = convertPixelToRGB64<Format>(qFetchPixel<bitsPerPixel<Format>()>(src, index + i));
297 return buffer;
298}
299
300template<QImage::Format Format>
301static inline uint convertPixelToARGB32PM(uint s)
302{
303 constexpr uint alphaMask = ((1 << alphaWidth<Format>()) - 1);
304 constexpr uint redMask = ((1 << redWidth<Format>()) - 1);
305 constexpr uint greenMask = ((1 << greenWidth<Format>()) - 1);
306 constexpr uint blueMask = ((1 << blueWidth<Format>()) - 1);
307
308 constexpr uchar alphaLeftShift = 8 - alphaWidth<Format>();
309 constexpr uchar redLeftShift = 8 - redWidth<Format>();
310 constexpr uchar greenLeftShift = 8 - greenWidth<Format>();
311 constexpr uchar blueLeftShift = 8 - blueWidth<Format>();
312
313 constexpr uchar alphaRightShift = 2 * alphaWidth<Format>() - 8;
314 constexpr uchar redRightShift = 2 * redWidth<Format>() - 8;
315 constexpr uchar greenRightShift = 2 * greenWidth<Format>() - 8;
316 constexpr uchar blueRightShift = 2 * blueWidth<Format>() - 8;
317
318 constexpr bool mustMin = (alphaWidth<Format>() != redWidth<Format>()) ||
319 (alphaWidth<Format>() != greenWidth<Format>()) ||
320 (alphaWidth<Format>() != blueWidth<Format>());
321
322 uint alpha = (s >> alphaShift<Format>()) & alphaMask;
323 uint red = (s >> redShift<Format>()) & redMask;
324 uint green = (s >> greenShift<Format>()) & greenMask;
325 uint blue = (s >> blueShift<Format>()) & blueMask;
326
327 alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift);
328 red = (red << redLeftShift) | (red >> redRightShift);
329 green = (green << greenLeftShift) | (green >> greenRightShift);
330 blue = (blue << blueLeftShift) | (blue >> blueRightShift);
331
332 if (mustMin) {
333 red = qMin(alpha, red);
334 green = qMin(alpha, green);
335 blue = qMin(alpha, blue);
336 }
337
338 return (alpha << 24) | (red << 16) | (green << 8) | blue;
339}
340
341template<QImage::Format Format>
342static void QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
343{
344 for (int i = 0; i < count; ++i)
345 buffer[i] = convertPixelToARGB32PM<Format>(buffer[i]);
346}
347
348template<QImage::Format Format>
349static const uint *QT_FASTCALL fetchARGBPMToARGB32PM(uint *buffer, const uchar *src, int index, int count,
350 const QList<QRgb> *, QDitherInfo *)
351{
352 constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
353#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
354 if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) {
355 // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3
356 // to vectorize the deforested version below.
357 fetchPixelsBPP24_ssse3(buffer, src, index, count);
358 convertARGBPMToARGB32PM<Format>(buffer, count, nullptr);
359 return buffer;
360 }
361#endif
362 for (int i = 0; i < count; ++i)
363 buffer[i] = convertPixelToARGB32PM<Format>(qFetchPixel<BPP>(src, index + i));
364 return buffer;
365}
366
367template<QImage::Format Format>
368static inline QRgba64 convertPixelToRGBA64PM(uint s)
369{
370 return QRgba64::fromArgb32(convertPixelToARGB32PM<Format>(s));
371}
372
373template<QImage::Format Format>
374static const QRgba64 *QT_FASTCALL convertARGBPMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
375 const QList<QRgb> *, QDitherInfo *)
376{
377 for (int i = 0; i < count; ++i)
378 buffer[i] = convertPixelToRGB64<Format>(src[i]);
379 return buffer;
380}
381
382template<QImage::Format Format>
383static const QRgba64 *QT_FASTCALL fetchARGBPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
384 const QList<QRgb> *, QDitherInfo *)
385{
386 constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
387 for (int i = 0; i < count; ++i)
388 buffer[i] = convertPixelToRGBA64PM<Format>(qFetchPixel<bpp>(src, index + i));
389 return buffer;
390}
391
392template<QImage::Format Format, bool fromRGB>
393static void QT_FASTCALL storeRGBFromARGB32PM(uchar *dest, const uint *src, int index, int count,
394 const QList<QRgb> *, QDitherInfo *dither)
395{
396 constexpr uchar rWidth = redWidth<Format>();
397 constexpr uchar gWidth = greenWidth<Format>();
398 constexpr uchar bWidth = blueWidth<Format>();
399 constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
400
401 // RGB32 -> RGB888 is not a precision loss.
402 if (!dither || (rWidth == 8 && gWidth == 8 && bWidth == 8)) {
403 constexpr uint rMask = (1 << redWidth<Format>()) - 1;
404 constexpr uint gMask = (1 << greenWidth<Format>()) - 1;
405 constexpr uint bMask = (1 << blueWidth<Format>()) - 1;
406 constexpr uchar rRightShift = 24 - redWidth<Format>();
407 constexpr uchar gRightShift = 16 - greenWidth<Format>();
408 constexpr uchar bRightShift = 8 - blueWidth<Format>();
409
410 for (int i = 0; i < count; ++i) {
411 const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]);
412 const uint r = ((c >> rRightShift) & rMask) << redShift<Format>();
413 const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>();
414 const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>();
415 storePixel<BPP>(dest, index + i, r | g | b);
416 };
417 } else {
418 // We do ordered dither by using a rounding conversion, but instead of
419 // adding half of input precision, we add the adjusted result from the
420 // bayer matrix before narrowing.
421 // Note: Rounding conversion in itself is different from the naive
422 // conversion we do above for non-dithering.
423 const uint *bayer_line = qt_bayer_matrix[dither->y & 15];
424 for (int i = 0; i < count; ++i) {
425 const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]);
426 const int d = bayer_line[(dither->x + i) & 15];
427 const int dr = d - ((d + 1) >> rWidth);
428 const int dg = d - ((d + 1) >> gWidth);
429 const int db = d - ((d + 1) >> bWidth);
430 int r = qRed(c);
431 int g = qGreen(c);
432 int b = qBlue(c);
433 r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth);
434 g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth);
435 b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth);
436 const uint s = (r << redShift<Format>())
437 | (g << greenShift<Format>())
438 | (b << blueShift<Format>());
439 storePixel<BPP>(dest, index + i, s);
440 }
441 }
442}
443
444template<QImage::Format Format, bool fromRGB>
445static void QT_FASTCALL storeARGBPMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
446 const QList<QRgb> *, QDitherInfo *dither)
447{
448 constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
449 if (!dither) {
450 constexpr uint aMask = (1 << alphaWidth<Format>()) - 1;
451 constexpr uint rMask = (1 << redWidth<Format>()) - 1;
452 constexpr uint gMask = (1 << greenWidth<Format>()) - 1;
453 constexpr uint bMask = (1 << blueWidth<Format>()) - 1;
454
455 constexpr uchar aRightShift = 32 - alphaWidth<Format>();
456 constexpr uchar rRightShift = 24 - redWidth<Format>();
457 constexpr uchar gRightShift = 16 - greenWidth<Format>();
458 constexpr uchar bRightShift = 8 - blueWidth<Format>();
459
460 constexpr uint aOpaque = aMask << alphaShift<Format>();
461 for (int i = 0; i < count; ++i) {
462 const uint c = src[i];
463 const uint a = fromRGB ? aOpaque : (((c >> aRightShift) & aMask) << alphaShift<Format>());
464 const uint r = ((c >> rRightShift) & rMask) << redShift<Format>();
465 const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>();
466 const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>();
467 storePixel<BPP>(dest, index + i, a | r | g | b);
468 };
469 } else {
470 constexpr uchar aWidth = alphaWidth<Format>();
471 constexpr uchar rWidth = redWidth<Format>();
472 constexpr uchar gWidth = greenWidth<Format>();
473 constexpr uchar bWidth = blueWidth<Format>();
474
475 const uint *bayer_line = qt_bayer_matrix[dither->y & 15];
476 for (int i = 0; i < count; ++i) {
477 const uint c = src[i];
478 const int d = bayer_line[(dither->x + i) & 15];
479 const int da = d - ((d + 1) >> aWidth);
480 const int dr = d - ((d + 1) >> rWidth);
481 const int dg = d - ((d + 1) >> gWidth);
482 const int db = d - ((d + 1) >> bWidth);
483 int a = qAlpha(c);
484 int r = qRed(c);
485 int g = qGreen(c);
486 int b = qBlue(c);
487 if (fromRGB)
488 a = (1 << aWidth) - 1;
489 else
490 a = (a + ((da - a) >> aWidth) + 1) >> (8 - aWidth);
491 r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth);
492 g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth);
493 b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth);
494 uint s = (a << alphaShift<Format>())
495 | (r << redShift<Format>())
496 | (g << greenShift<Format>())
497 | (b << blueShift<Format>());
498 storePixel<BPP>(dest, index + i, s);
499 }
500 }
501}
502
503template<QImage::Format Format>
504static void QT_FASTCALL rbSwap(uchar *dst, const uchar *src, int count)
505{
506 constexpr uchar aWidth = alphaWidth<Format>();
507 constexpr uchar aShift = alphaShift<Format>();
508 constexpr uchar rWidth = redWidth<Format>();
509 constexpr uchar rShift = redShift<Format>();
510 constexpr uchar gWidth = greenWidth<Format>();
511 constexpr uchar gShift = greenShift<Format>();
512 constexpr uchar bWidth = blueWidth<Format>();
513 constexpr uchar bShift = blueShift<Format>();
514#ifdef Q_COMPILER_CONSTEXPR
515 static_assert(rWidth == bWidth);
516#endif
517 constexpr uint redBlueMask = (1 << rWidth) - 1;
518 constexpr uint alphaGreenMask = (((1 << aWidth) - 1) << aShift)
519 | (((1 << gWidth) - 1) << gShift);
520 constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
521
522 for (int i = 0; i < count; ++i) {
523 const uint c = qFetchPixel<bpp>(src, i);
524 const uint r = (c >> rShift) & redBlueMask;
525 const uint b = (c >> bShift) & redBlueMask;
526 const uint t = (c & alphaGreenMask)
527 | (r << bShift)
528 | (b << rShift);
529 storePixel<bpp>(dst, i, t);
530 }
531}
532
533static void QT_FASTCALL rbSwap_rgb32(uchar *d, const uchar *s, int count)
534{
535 const uint *src = reinterpret_cast<const uint *>(s);
536 uint *dest = reinterpret_cast<uint *>(d);
537 for (int i = 0; i < count; ++i) {
538 const uint c = src[i];
539 const uint ag = c & 0xff00ff00;
540 const uint rb = c & 0x00ff00ff;
541 dest[i] = ag | (rb << 16) | (rb >> 16);
542 }
543}
544
545#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
546template<>
547void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count)
548{
549 return rbSwap_rgb32(d, s, count);
550}
551#else
552template<>
553void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count)
554{
555 const uint *src = reinterpret_cast<const uint *>(s);
556 uint *dest = reinterpret_cast<uint *>(d);
557 for (int i = 0; i < count; ++i) {
558 const uint c = src[i];
559 const uint rb = c & 0xff00ff00;
560 const uint ga = c & 0x00ff00ff;
561 dest[i] = ga | (rb << 16) | (rb >> 16);
562 }
563}
564#endif
565
566static void QT_FASTCALL rbSwap_rgb30(uchar *d, const uchar *s, int count)
567{
568 const uint *src = reinterpret_cast<const uint *>(s);
569 uint *dest = reinterpret_cast<uint *>(d);
570 UNALIASED_CONVERSION_LOOP(dest, src, count, qRgbSwapRgb30);
571}
572
573template<QImage::Format Format> constexpr static inline QPixelLayout pixelLayoutRGB()
574{
575 return QPixelLayout{
576 false,
577 false,
578 bitsPerPixel<Format>(),
579 rbSwap<Format>,
580 convertToRGB32<Format>,
581 convertToRGB64<Format>,
582 fetchRGBToRGB32<Format>,
583 fetchRGBToRGB64<Format>,
584 storeRGBFromARGB32PM<Format, false>,
585 storeRGBFromARGB32PM<Format, true>
586 };
587}
588
589template<QImage::Format Format> constexpr static inline QPixelLayout pixelLayoutARGBPM()
590{
591 return QPixelLayout{
592 true,
593 true,
594 bitsPerPixel<Format>(),
595 rbSwap<Format>,
596 convertARGBPMToARGB32PM<Format>,
597 convertARGBPMToRGBA64PM<Format>,
598 fetchARGBPMToARGB32PM<Format>,
599 fetchARGBPMToRGBA64PM<Format>,
600 storeARGBPMFromARGB32PM<Format, false>,
601 storeARGBPMFromARGB32PM<Format, true>
602 };
603}
604
605static void QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, int count, const QList<QRgb> *clut)
606{
607 for (int i = 0; i < count; ++i)
608 buffer[i] = qPremultiply(clut->at(buffer[i]));
609}
610
611template<QPixelLayout::BPP BPP>
612static const uint *QT_FASTCALL fetchIndexedToARGB32PM(uint *buffer, const uchar *src, int index, int count,
613 const QList<QRgb> *clut, QDitherInfo *)
614{
615 for (int i = 0; i < count; ++i) {
616 const uint s = qFetchPixel<BPP>(src, index + i);
617 buffer[i] = qPremultiply(clut->at(s));
618 }
619 return buffer;
620}
621
622template<QPixelLayout::BPP BPP>
623static const QRgba64 *QT_FASTCALL fetchIndexedToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
624 const QList<QRgb> *clut, QDitherInfo *)
625{
626 for (int i = 0; i < count; ++i) {
627 const uint s = qFetchPixel<BPP>(src, index + i);
628 buffer[i] = QRgba64::fromArgb32(clut->at(s)).premultiplied();
629 }
630 return buffer;
631}
632
633static const QRgba64 *QT_FASTCALL convertIndexedToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
634 const QList<QRgb> *clut, QDitherInfo *)
635{
636 for (int i = 0; i < count; ++i)
637 buffer[i] = QRgba64::fromArgb32(clut->at(src[i])).premultiplied();
638 return buffer;
639}
640
641static void QT_FASTCALL convertPassThrough(uint *, int, const QList<QRgb> *)
642{
643}
644
645static const uint *QT_FASTCALL fetchPassThrough(uint *, const uchar *src, int index, int,
646 const QList<QRgb> *, QDitherInfo *)
647{
648 return reinterpret_cast<const uint *>(src) + index;
649}
650
651static const QRgba64 *QT_FASTCALL fetchPassThrough64(QRgba64 *, const uchar *src, int index, int,
652 const QList<QRgb> *, QDitherInfo *)
653{
654 return reinterpret_cast<const QRgba64 *>(src) + index;
655}
656
657static void QT_FASTCALL storePassThrough(uchar *dest, const uint *src, int index, int count,
658 const QList<QRgb> *, QDitherInfo *)
659{
660 uint *d = reinterpret_cast<uint *>(dest) + index;
661 if (d != src)
662 memcpy(d, src, count * sizeof(uint));
663}
664
665static void QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
666{
667 qt_convertARGB32ToARGB32PM(buffer, buffer, count);
668}
669
670static const uint *QT_FASTCALL fetchARGB32ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
671 const QList<QRgb> *, QDitherInfo *)
672{
673 return qt_convertARGB32ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count);
674}
675
676static void QT_FASTCALL convertRGBA8888PMToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
677{
678 for (int i = 0; i < count; ++i)
679 buffer[i] = RGBA2ARGB(buffer[i]);
680}
681
682static const uint *QT_FASTCALL fetchRGBA8888PMToARGB32PM(uint *buffer, const uchar *src, int index, int count,
683 const QList<QRgb> *, QDitherInfo *)
684{
685 const uint *s = reinterpret_cast<const uint *>(src) + index;
686 UNALIASED_CONVERSION_LOOP(buffer, s, count, RGBA2ARGB);
687 return buffer;
688}
689
690static void QT_FASTCALL convertRGBA8888ToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
691{
692 qt_convertRGBA8888ToARGB32PM(buffer, buffer, count);
693}
694
695static const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
696 const QList<QRgb> *, QDitherInfo *)
697{
698 return qt_convertRGBA8888ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count);
699}
700
701static void QT_FASTCALL convertAlpha8ToRGB32(uint *buffer, int count, const QList<QRgb> *)
702{
703 for (int i = 0; i < count; ++i)
704 buffer[i] = qRgba(0, 0, 0, buffer[i]);
705}
706
707static const uint *QT_FASTCALL fetchAlpha8ToRGB32(uint *buffer, const uchar *src, int index, int count,
708 const QList<QRgb> *, QDitherInfo *)
709{
710 for (int i = 0; i < count; ++i)
711 buffer[i] = qRgba(0, 0, 0, src[index + i]);
712 return buffer;
713}
714
715static const QRgba64 *QT_FASTCALL convertAlpha8ToRGB64(QRgba64 *buffer, const uint *src, int count,
716 const QList<QRgb> *, QDitherInfo *)
717{
718 for (int i = 0; i < count; ++i)
719 buffer[i] = QRgba64::fromRgba(0, 0, 0, src[i]);
720 return buffer;
721}
722static const QRgba64 *QT_FASTCALL fetchAlpha8ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
723 const QList<QRgb> *, QDitherInfo *)
724{
725 for (int i = 0; i < count; ++i)
726 buffer[i] = QRgba64::fromRgba(0, 0, 0, src[index + i]);
727 return buffer;
728}
729
730static void QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, int count, const QList<QRgb> *)
731{
732 for (int i = 0; i < count; ++i) {
733 const uint s = buffer[i];
734 buffer[i] = qRgb(s, s, s);
735 }
736}
737
738static const uint *QT_FASTCALL fetchGrayscale8ToRGB32(uint *buffer, const uchar *src, int index, int count,
739 const QList<QRgb> *, QDitherInfo *)
740{
741 for (int i = 0; i < count; ++i) {
742 const uint s = src[index + i];
743 buffer[i] = qRgb(s, s, s);
744 }
745 return buffer;
746}
747
748static const QRgba64 *QT_FASTCALL convertGrayscale8ToRGB64(QRgba64 *buffer, const uint *src, int count,
749 const QList<QRgb> *, QDitherInfo *)
750{
751 for (int i = 0; i < count; ++i)
752 buffer[i] = QRgba64::fromRgba(src[i], src[i], src[i], 255);
753 return buffer;
754}
755
756static const QRgba64 *QT_FASTCALL fetchGrayscale8ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
757 const QList<QRgb> *, QDitherInfo *)
758{
759 for (int i = 0; i < count; ++i) {
760 const uint s = src[index + i];
761 buffer[i] = QRgba64::fromRgba(s, s, s, 255);
762 }
763 return buffer;
764}
765
766static void QT_FASTCALL convertGrayscale16ToRGB32(uint *buffer, int count, const QList<QRgb> *)
767{
768 for (int i = 0; i < count; ++i) {
769 const uint x = qt_div_257(buffer[i]);
770 buffer[i] = qRgb(x, x, x);
771 }
772}
773
774static const uint *QT_FASTCALL fetchGrayscale16ToRGB32(uint *buffer, const uchar *src, int index, int count,
775 const QList<QRgb> *, QDitherInfo *)
776{
777 const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index;
778 for (int i = 0; i < count; ++i) {
779 const uint x = qt_div_257(s[i]);
780 buffer[i] = qRgb(x, x, x);
781 }
782 return buffer;
783}
784
785static const QRgba64 *QT_FASTCALL convertGrayscale16ToRGBA64(QRgba64 *buffer, const uint *src, int count,
786 const QList<QRgb> *, QDitherInfo *)
787{
788 const unsigned short *s = reinterpret_cast<const unsigned short *>(src);
789 for (int i = 0; i < count; ++i)
790 buffer[i] = QRgba64::fromRgba64(s[i], s[i], s[i], 65535);
791 return buffer;
792}
793
794static const QRgba64 *QT_FASTCALL fetchGrayscale16ToRGBA64(QRgba64 *buffer, const uchar *src, int index, int count,
795 const QList<QRgb> *, QDitherInfo *)
796{
797 const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index;
798 for (int i = 0; i < count; ++i) {
799 buffer[i] = QRgba64::fromRgba64(s[i], s[i], s[i], 65535);
800 }
801 return buffer;
802}
803
804static void QT_FASTCALL storeARGB32FromARGB32PM(uchar *dest, const uint *src, int index, int count,
805 const QList<QRgb> *, QDitherInfo *)
806{
807 uint *d = reinterpret_cast<uint *>(dest) + index;
808 UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return qUnpremultiply(c); });
809}
810
811static void QT_FASTCALL storeRGBA8888PMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
812 const QList<QRgb> *, QDitherInfo *)
813{
814 uint *d = reinterpret_cast<uint *>(dest) + index;
815 UNALIASED_CONVERSION_LOOP(d, src, count, ARGB2RGBA);
816}
817
818#ifdef __SSE2__
819template<bool RGBA, bool maskAlpha>
820static inline void qConvertARGB32PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count)
821{
822 if (count <= 0)
823 return;
824
825 const __m128i amask = _mm_set1_epi32(0xff000000);
826 int i = 0;
827 for (; ((uintptr_t)buffer & 0xf) && i < count; ++i) {
828 uint s = *src++;
829 if (maskAlpha)
830 s = s | 0xff000000;
831 if (RGBA)
832 s = RGBA2ARGB(s);
833 *buffer++ = QRgba64::fromArgb32(s);
834 }
835 for (; i < count-3; i += 4) {
836 __m128i vs = _mm_loadu_si128((const __m128i*)src);
837 if (maskAlpha)
838 vs = _mm_or_si128(vs, amask);
839 src += 4;
840 __m128i v1 = _mm_unpacklo_epi8(vs, vs);
841 __m128i v2 = _mm_unpackhi_epi8(vs, vs);
842 if (!RGBA) {
843 v1 = _mm_shufflelo_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2));
844 v2 = _mm_shufflelo_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2));
845 v1 = _mm_shufflehi_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2));
846 v2 = _mm_shufflehi_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2));
847 }
848 _mm_store_si128((__m128i*)(buffer), v1);
849 buffer += 2;
850 _mm_store_si128((__m128i*)(buffer), v2);
851 buffer += 2;
852 }
853
854 SIMD_EPILOGUE(i, count, 3) {
855 uint s = *src++;
856 if (maskAlpha)
857 s = s | 0xff000000;
858 if (RGBA)
859 s = RGBA2ARGB(s);
860 *buffer++ = QRgba64::fromArgb32(s);
861 }
862}
863
864template<QtPixelOrder PixelOrder>
865static inline void qConvertRGBA64PMToA2RGB30PM_sse2(uint *dest, const QRgba64 *buffer, int count)
866{
867 const __m128i gmask = _mm_set1_epi32(0x000ffc00);
868 const __m128i cmask = _mm_set1_epi32(0x000003ff);
869 int i = 0;
870 __m128i vr, vg, vb, va;
871 for (; i < count && uintptr_t(buffer) & 0xF; ++i) {
872 *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
873 }
874
875 for (; i < count-15; i += 16) {
876 // Repremultiplying is really expensive and hard to do in SIMD without AVX2,
877 // so we try to avoid it by checking if it is needed 16 samples at a time.
878 __m128i vOr = _mm_set1_epi32(0);
879 __m128i vAnd = _mm_set1_epi32(0xffffffff);
880 for (int j = 0; j < 16; j += 2) {
881 __m128i vs = _mm_load_si128((const __m128i*)(buffer + j));
882 vOr = _mm_or_si128(vOr, vs);
883 vAnd = _mm_and_si128(vAnd, vs);
884 }
885 const quint16 orAlpha = ((uint)_mm_extract_epi16(vOr, 3)) | ((uint)_mm_extract_epi16(vOr, 7));
886 const quint16 andAlpha = ((uint)_mm_extract_epi16(vAnd, 3)) & ((uint)_mm_extract_epi16(vAnd, 7));
887
888 if (andAlpha == 0xffff) {
889 for (int j = 0; j < 16; j += 2) {
890 __m128i vs = _mm_load_si128((const __m128i*)buffer);
891 buffer += 2;
892 vr = _mm_srli_epi64(vs, 6);
893 vg = _mm_srli_epi64(vs, 16 + 6 - 10);
894 vb = _mm_srli_epi64(vs, 32 + 6);
895 vr = _mm_and_si128(vr, cmask);
896 vg = _mm_and_si128(vg, gmask);
897 vb = _mm_and_si128(vb, cmask);
898 va = _mm_srli_epi64(vs, 48 + 14);
899 if (PixelOrder == PixelOrderRGB)
900 vr = _mm_slli_epi32(vr, 20);
901 else
902 vb = _mm_slli_epi32(vb, 20);
903 va = _mm_slli_epi32(va, 30);
904 __m128i vd = _mm_or_si128(_mm_or_si128(vr, vg), _mm_or_si128(vb, va));
905 vd = _mm_shuffle_epi32(vd, _MM_SHUFFLE(3, 1, 2, 0));
906 _mm_storel_epi64((__m128i*)dest, vd);
907 dest += 2;
908 }
909 } else if (orAlpha == 0) {
910 for (int j = 0; j < 16; ++j) {
911 *dest++ = 0;
912 buffer++;
913 }
914 } else {
915 for (int j = 0; j < 16; ++j)
916 *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
917 }
918 }
919
920 SIMD_EPILOGUE(i, count, 15)
921 *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
922}
923#elif defined(__ARM_NEON__)
924template<bool RGBA, bool maskAlpha>
925static inline void qConvertARGB32PMToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count)
926{
927 if (count <= 0)
928 return;
929
930 const uint32x4_t amask = vdupq_n_u32(0xff000000);
931#if defined(Q_PROCESSOR_ARM_64)
932 const uint8x16_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15};
933#else
934 const uint8x8_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7 };
935#endif
936 int i = 0;
937 for (; i < count-3; i += 4) {
938 uint32x4_t vs32 = vld1q_u32(src);
939 src += 4;
940 if (maskAlpha)
941 vs32 = vorrq_u32(vs32, amask);
942 uint8x16_t vs8 = vreinterpretq_u8_u32(vs32);
943 if (!RGBA) {
944#if defined(Q_PROCESSOR_ARM_64)
945 vs8 = vqtbl1q_u8(vs8, rgbaMask);
946#else
947 // no vqtbl1q_u8
948 const uint8x8_t vlo = vtbl1_u8(vget_low_u8(vs8), rgbaMask);
949 const uint8x8_t vhi = vtbl1_u8(vget_high_u8(vs8), rgbaMask);
950 vs8 = vcombine_u8(vlo, vhi);
951#endif
952 }
953 uint8x16x2_t v = vzipq_u8(vs8, vs8);
954
955 vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[0]));
956 buffer += 2;
957 vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[1]));
958 buffer += 2;
959 }
960
961 SIMD_EPILOGUE(i, count, 3) {
962 uint s = *src++;
963 if (maskAlpha)
964 s = s | 0xff000000;
965 if (RGBA)
966 s = RGBA2ARGB(s);
967 *buffer++ = QRgba64::fromArgb32(s);
968 }
969}
970#endif
971
972static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count,
973 const QList<QRgb> *, QDitherInfo *)
974{
975#ifdef __SSE2__
976 qConvertARGB32PMToRGBA64PM_sse2<false, true>(buffer, src, count);
977#elif defined(__ARM_NEON__)
978 qConvertARGB32PMToRGBA64PM_neon<false, true>(buffer, src, count);
979#else
980 for (int i = 0; i < count; ++i)
981 buffer[i] = QRgba64::fromArgb32(0xff000000 | src[i]);
982#endif
983 return buffer;
984}
985
986static const QRgba64 *QT_FASTCALL fetchRGB32ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
987 const QList<QRgb> *, QDitherInfo *)
988{
989 return convertRGB32ToRGB64(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
990}
991
992static const QRgba64 *QT_FASTCALL convertARGB32ToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
993 const QList<QRgb> *, QDitherInfo *)
994{
995 for (int i = 0; i < count; ++i)
996 buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied();
997 return buffer;
998}
999
1000static const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1001 const QList<QRgb> *, QDitherInfo *)
1002{
1003 return convertARGB32ToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1004}
1005
1006static const QRgba64 *QT_FASTCALL convertARGB32PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1007 const QList<QRgb> *, QDitherInfo *)
1008{
1009#ifdef __SSE2__
1010 qConvertARGB32PMToRGBA64PM_sse2<false, false>(buffer, src, count);
1011#elif defined(__ARM_NEON__)
1012 qConvertARGB32PMToRGBA64PM_neon<false, false>(buffer, src, count);
1013#else
1014 for (int i = 0; i < count; ++i)
1015 buffer[i] = QRgba64::fromArgb32(src[i]);
1016#endif
1017 return buffer;
1018}
1019
1020static const QRgba64 *QT_FASTCALL fetchARGB32PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1021 const QList<QRgb> *, QDitherInfo *)
1022{
1023 return convertARGB32PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1024}
1025
1026static const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1027 const QList<QRgb> *, QDitherInfo *)
1028{
1029 const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
1030 for (int i = 0; i < count; ++i)
1031 buffer[i] = QRgba64::fromRgba64(s[i]).premultiplied();
1032 return buffer;
1033}
1034
1035static const QRgba64 *QT_FASTCALL convertRGBA8888ToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1036 const QList<QRgb> *, QDitherInfo *)
1037{
1038 for (int i = 0; i < count; ++i)
1039 buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied();
1040 return buffer;
1041}
1042
1043static const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1044 const QList<QRgb> *, QDitherInfo *)
1045{
1046 return convertRGBA8888ToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1047}
1048
1049static const QRgba64 *QT_FASTCALL convertRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1050 const QList<QRgb> *, QDitherInfo *)
1051{
1052#ifdef __SSE2__
1053 qConvertARGB32PMToRGBA64PM_sse2<true, false>(buffer, src, count);
1054#elif defined(__ARM_NEON__)
1055 qConvertARGB32PMToRGBA64PM_neon<true, false>(buffer, src, count);
1056#else
1057 for (int i = 0; i < count; ++i)
1058 buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i]));
1059#endif
1060 return buffer;
1061}
1062
1063static const QRgba64 *QT_FASTCALL fetchRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1064 const QList<QRgb> *, QDitherInfo *)
1065{
1066 return convertRGBA8888PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1067}
1068
1069static void QT_FASTCALL storeRGBA8888FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1070 const QList<QRgb> *, QDitherInfo *)
1071{
1072 uint *d = reinterpret_cast<uint *>(dest) + index;
1073 UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(qUnpremultiply(c)); });
1074}
1075
1076static void QT_FASTCALL storeRGBXFromRGB32(uchar *dest, const uint *src, int index, int count,
1077 const QList<QRgb> *, QDitherInfo *)
1078{
1079 uint *d = reinterpret_cast<uint *>(dest) + index;
1080 UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | c); });
1081}
1082
1083static void QT_FASTCALL storeRGBXFromARGB32PM(uchar *dest, const uint *src, int index, int count,
1084 const QList<QRgb> *, QDitherInfo *)
1085{
1086 uint *d = reinterpret_cast<uint *>(dest) + index;
1087 UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | qUnpremultiply(c)); });
1088}
1089
1090template<QtPixelOrder PixelOrder>
1091static void QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
1092{
1093 for (int i = 0; i < count; ++i)
1094 buffer[i] = qConvertA2rgb30ToArgb32<PixelOrder>(buffer[i]);
1095}
1096
1097template<QtPixelOrder PixelOrder>
1098static const uint *QT_FASTCALL fetchA2RGB30PMToARGB32PM(uint *buffer, const uchar *s, int index, int count,
1099 const QList<QRgb> *, QDitherInfo *dither)
1100{
1101 const uint *src = reinterpret_cast<const uint *>(s) + index;
1102 if (!dither) {
1103 UNALIASED_CONVERSION_LOOP(buffer, src, count, qConvertA2rgb30ToArgb32<PixelOrder>);
1104 } else {
1105 for (int i = 0; i < count; ++i) {
1106 const uint c = src[i];
1107 short d10 = (qt_bayer_matrix[dither->y & 15][(dither->x + i) & 15] << 2);
1108 short a10 = (c >> 30) * 0x155;
1109 short r10 = ((c >> 20) & 0x3ff);
1110 short g10 = ((c >> 10) & 0x3ff);
1111 short b10 = (c & 0x3ff);
1112 if (PixelOrder == PixelOrderBGR)
1113 std::swap(r10, b10);
1114 short a8 = (a10 + ((d10 - a10) >> 8)) >> 2;
1115 short r8 = (r10 + ((d10 - r10) >> 8)) >> 2;
1116 short g8 = (g10 + ((d10 - g10) >> 8)) >> 2;
1117 short b8 = (b10 + ((d10 - b10) >> 8)) >> 2;
1118 buffer[i] = qRgba(r8, g8, b8, a8);
1119 }
1120 }
1121 return buffer;
1122}
1123
1124#ifdef __SSE2__
1125template<QtPixelOrder PixelOrder>
1126static inline void qConvertA2RGB30PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count)
1127{
1128 if (count <= 0)
1129 return;
1130
1131 const __m128i rmask = _mm_set1_epi32(0x3ff00000);
1132 const __m128i gmask = _mm_set1_epi32(0x000ffc00);
1133 const __m128i bmask = _mm_set1_epi32(0x000003ff);
1134 const __m128i afactor = _mm_set1_epi16(0x5555);
1135 int i = 0;
1136
1137 for (; ((uintptr_t)buffer & 0xf) && i < count; ++i)
1138 *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++);
1139
1140 for (; i < count-3; i += 4) {
1141 __m128i vs = _mm_loadu_si128((const __m128i*)src);
1142 src += 4;
1143 __m128i va = _mm_srli_epi32(vs, 30);
1144 __m128i vr = _mm_and_si128(vs, rmask);
1145 __m128i vb = _mm_and_si128(vs, bmask);
1146 __m128i vg = _mm_and_si128(vs, gmask);
1147 va = _mm_mullo_epi16(va, afactor);
1148 vr = _mm_or_si128(_mm_srli_epi32(vr, 14), _mm_srli_epi32(vr, 24));
1149 vg = _mm_or_si128(_mm_srli_epi32(vg, 4), _mm_srli_epi32(vg, 14));
1150 vb = _mm_or_si128(_mm_slli_epi32(vb, 6), _mm_srli_epi32(vb, 4));
1151 __m128i vrb;
1152 if (PixelOrder == PixelOrderRGB)
1153 vrb = _mm_or_si128(vr, _mm_slli_si128(vb, 2));
1154 else
1155 vrb = _mm_or_si128(vb, _mm_slli_si128(vr, 2));
1156 __m128i vga = _mm_or_si128(vg, _mm_slli_si128(va, 2));
1157 _mm_store_si128((__m128i*)(buffer), _mm_unpacklo_epi16(vrb, vga));
1158 buffer += 2;
1159 _mm_store_si128((__m128i*)(buffer), _mm_unpackhi_epi16(vrb, vga));
1160 buffer += 2;
1161 }
1162
1163 SIMD_EPILOGUE(i, count, 3)
1164 *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++);
1165}
1166#endif
1167
1168template<QtPixelOrder PixelOrder>
1169static const QRgba64 *QT_FASTCALL convertA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1170 const QList<QRgb> *, QDitherInfo *)
1171{
1172#ifdef __SSE2__
1173 qConvertA2RGB30PMToRGBA64PM_sse2<PixelOrder>(buffer, src, count);
1174#else
1175 for (int i = 0; i < count; ++i)
1176 buffer[i] = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]);
1177#endif
1178 return buffer;
1179}
1180
1181template<QtPixelOrder PixelOrder>
1182static const QRgba64 *QT_FASTCALL fetchA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1183 const QList<QRgb> *, QDitherInfo *)
1184{
1185 return convertA2RGB30PMToRGBA64PM<PixelOrder>(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1186}
1187
1188template<QtPixelOrder PixelOrder>
1189static void QT_FASTCALL storeA2RGB30PMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
1190 const QList<QRgb> *, QDitherInfo *)
1191{
1192 uint *d = reinterpret_cast<uint *>(dest) + index;
1193 UNALIASED_CONVERSION_LOOP(d, src, count, qConvertArgb32ToA2rgb30<PixelOrder>);
1194}
1195
1196template<QtPixelOrder PixelOrder>
1197static void QT_FASTCALL storeRGB30FromRGB32(uchar *dest, const uint *src, int index, int count,
1198 const QList<QRgb> *, QDitherInfo *)
1199{
1200 uint *d = reinterpret_cast<uint *>(dest) + index;
1201 UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>);
1202}
1203
1204template<QtPixelOrder PixelOrder>
1205static void QT_FASTCALL storeRGB30FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1206 const QList<QRgb> *, QDitherInfo *)
1207{
1208 uint *d = reinterpret_cast<uint *>(dest) + index;
1209 UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>);
1210}
1211
1212template<bool RGBA>
1213void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count)
1214{
1215 int i = 0;
1216#ifdef __SSE2__
1217 if (((uintptr_t)dst & 0x7) && count > 0) {
1218 uint s = (*src++).toArgb32();
1219 if (RGBA)
1220 s = ARGB2RGBA(s);
1221 *dst++ = s;
1222 i++;
1223 }
1224 const __m128i vhalf = _mm_set1_epi32(0x80);
1225 const __m128i vzero = _mm_setzero_si128();
1226 for (; i < count-1; i += 2) {
1227 __m128i vs = _mm_loadu_si128((const __m128i*)src);
1228 src += 2;
1229 if (!RGBA) {
1230 vs = _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2));
1231 vs = _mm_shufflehi_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2));
1232 }
1233 __m128i v1 = _mm_unpacklo_epi16(vs, vzero);
1234 __m128i v2 = _mm_unpackhi_epi16(vs, vzero);
1235 v1 = _mm_add_epi32(v1, vhalf);
1236 v2 = _mm_add_epi32(v2, vhalf);
1237 v1 = _mm_sub_epi32(v1, _mm_srli_epi32(v1, 8));
1238 v2 = _mm_sub_epi32(v2, _mm_srli_epi32(v2, 8));
1239 v1 = _mm_srli_epi32(v1, 8);
1240 v2 = _mm_srli_epi32(v2, 8);
1241 v1 = _mm_packs_epi32(v1, v2);
1242 v1 = _mm_packus_epi16(v1, vzero);
1243 _mm_storel_epi64((__m128i*)(dst), v1);
1244 dst += 2;
1245 }
1246#endif
1247 for (; i < count; i++) {
1248 uint s = (*src++).toArgb32();
1249 if (RGBA)
1250 s = ARGB2RGBA(s);
1251 *dst++ = s;
1252 }
1253}
1254template void qt_convertRGBA64ToARGB32<false>(uint *dst, const QRgba64 *src, int count);
1255template void qt_convertRGBA64ToARGB32<true>(uint *dst, const QRgba64 *src, int count);
1256
1257
1258static void QT_FASTCALL storeAlpha8FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1259 const QList<QRgb> *, QDitherInfo *)
1260{
1261 for (int i = 0; i < count; ++i)
1262 dest[index + i] = qAlpha(src[i]);
1263}
1264
1265static void QT_FASTCALL storeGrayscale8FromRGB32(uchar *dest, const uint *src, int index, int count,
1266 const QList<QRgb> *, QDitherInfo *)
1267{
1268 for (int i = 0; i < count; ++i)
1269 dest[index + i] = qGray(src[i]);
1270}
1271
1272static void QT_FASTCALL storeGrayscale8FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1273 const QList<QRgb> *, QDitherInfo *)
1274{
1275 for (int i = 0; i < count; ++i)
1276 dest[index + i] = qGray(qUnpremultiply(src[i]));
1277}
1278
1279static void QT_FASTCALL storeGrayscale16FromRGB32(uchar *dest, const uint *src, int index, int count,
1280 const QList<QRgb> *, QDitherInfo *)
1281{
1282 unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index;
1283 for (int i = 0; i < count; ++i)
1284 d[i] = qGray(src[i]) * 257;
1285}
1286
1287static void QT_FASTCALL storeGrayscale16FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1288 const QList<QRgb> *, QDitherInfo *)
1289{
1290 unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index;
1291 for (int i = 0; i < count; ++i)
1292 d[i] = qGray(qUnpremultiply(src[i])) * 257;
1293}
1294
1295static const uint *QT_FASTCALL fetchRGB64ToRGB32(uint *buffer, const uchar *src, int index, int count,
1296 const QList<QRgb> *, QDitherInfo *)
1297{
1298 const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
1299 for (int i = 0; i < count; ++i)
1300 buffer[i] = toArgb32(s[i]);
1301 return buffer;
1302}
1303
1304static void QT_FASTCALL storeRGB64FromRGB32(uchar *dest, const uint *src, int index, int count,
1305 const QList<QRgb> *, QDitherInfo *)
1306{
1307 QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
1308 for (int i = 0; i < count; ++i)
1309 d[i] = QRgba64::fromArgb32(src[i]);
1310}
1311
1312static const uint *QT_FASTCALL fetchRGBA64ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
1313 const QList<QRgb> *, QDitherInfo *)
1314{
1315 const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
1316 for (int i = 0; i < count; ++i)
1317 buffer[i] = toArgb32(s[i].premultiplied());
1318 return buffer;
1319}
1320
1321static void QT_FASTCALL storeRGBA64FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1322 const QList<QRgb> *, QDitherInfo *)
1323{
1324 QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
1325 for (int i = 0; i < count; ++i)
1326 d[i] = QRgba64::fromArgb32(src[i]).unpremultiplied();
1327}
1328
1329// Note:
1330// convertToArgb32() assumes that no color channel is less than 4 bits.
1331// storeRGBFromARGB32PM() assumes that no color channel is more than 8 bits.
1332// QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits.
1333QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
1334 { false, false, QPixelLayout::BPPNone, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }, // Format_Invalid
1335 { false, false, QPixelLayout::BPP1MSB, nullptr,
1336 convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
1337 fetchIndexedToARGB32PM<QPixelLayout::BPP1MSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1MSB>,
1338 nullptr, nullptr }, // Format_Mono
1339 { false, false, QPixelLayout::BPP1LSB, nullptr,
1340 convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
1341 fetchIndexedToARGB32PM<QPixelLayout::BPP1LSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1LSB>,
1342 nullptr, nullptr }, // Format_MonoLSB
1343 { false, false, QPixelLayout::BPP8, nullptr,
1344 convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
1345 fetchIndexedToARGB32PM<QPixelLayout::BPP8>, fetchIndexedToRGBA64PM<QPixelLayout::BPP8>,
1346 nullptr, nullptr }, // Format_Indexed8
1347 // Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong,
1348 // but everywhere this generic conversion would be wrong is currently overloaded.
1349 { false, false, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough,
1350 convertRGB32ToRGB64, fetchPassThrough, fetchRGB32ToRGB64, storePassThrough, storePassThrough }, // Format_RGB32
1351 { true, false, QPixelLayout::BPP32, rbSwap_rgb32, convertARGB32ToARGB32PM,
1352 convertARGB32ToRGBA64PM, fetchARGB32ToARGB32PM, fetchARGB32ToRGBA64PM, storeARGB32FromARGB32PM, storePassThrough }, // Format_ARGB32
1353 { true, true, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough,
1354 convertARGB32PMToRGBA64PM, fetchPassThrough, fetchARGB32PMToRGBA64PM, storePassThrough, storePassThrough }, // Format_ARGB32_Premultiplied
1355 pixelLayoutRGB<QImage::Format_RGB16>(),
1356 pixelLayoutARGBPM<QImage::Format_ARGB8565_Premultiplied>(),
1357 pixelLayoutRGB<QImage::Format_RGB666>(),
1358 pixelLayoutARGBPM<QImage::Format_ARGB6666_Premultiplied>(),
1359 pixelLayoutRGB<QImage::Format_RGB555>(),
1360 pixelLayoutARGBPM<QImage::Format_ARGB8555_Premultiplied>(),
1361 pixelLayoutRGB<QImage::Format_RGB888>(),
1362 pixelLayoutRGB<QImage::Format_RGB444>(),
1363 pixelLayoutARGBPM<QImage::Format_ARGB4444_Premultiplied>(),
1364 { false, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM,
1365 convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBXFromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBX8888
1366 { true, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888ToARGB32PM,
1367 convertRGBA8888ToRGBA64PM, fetchRGBA8888ToARGB32PM, fetchRGBA8888ToRGBA64PM, storeRGBA8888FromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBA8888
1368 { true, true, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM,
1369 convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBA8888PMFromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBA8888_Premultiplied
1370 { false, false, QPixelLayout::BPP32, rbSwap_rgb30,
1371 convertA2RGB30PMToARGB32PM<PixelOrderBGR>,
1372 convertA2RGB30PMToRGBA64PM<PixelOrderBGR>,
1373 fetchA2RGB30PMToARGB32PM<PixelOrderBGR>,
1374 fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>,
1375 storeRGB30FromARGB32PM<PixelOrderBGR>,
1376 storeRGB30FromRGB32<PixelOrderBGR>
1377 }, // Format_BGR30
1378 { true, true, QPixelLayout::BPP32, rbSwap_rgb30,
1379 convertA2RGB30PMToARGB32PM<PixelOrderBGR>,
1380 convertA2RGB30PMToRGBA64PM<PixelOrderBGR>,
1381 fetchA2RGB30PMToARGB32PM<PixelOrderBGR>,
1382 fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>,
1383 storeA2RGB30PMFromARGB32PM<PixelOrderBGR>,
1384 storeRGB30FromRGB32<PixelOrderBGR>
1385 }, // Format_A2BGR30_Premultiplied
1386 { false, false, QPixelLayout::BPP32, rbSwap_rgb30,
1387 convertA2RGB30PMToARGB32PM<PixelOrderRGB>,
1388 convertA2RGB30PMToRGBA64PM<PixelOrderRGB>,
1389 fetchA2RGB30PMToARGB32PM<PixelOrderRGB>,
1390 fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>,
1391 storeRGB30FromARGB32PM<PixelOrderRGB>,
1392 storeRGB30FromRGB32<PixelOrderRGB>
1393 }, // Format_RGB30
1394 { true, true, QPixelLayout::BPP32, rbSwap_rgb30,
1395 convertA2RGB30PMToARGB32PM<PixelOrderRGB>,
1396 convertA2RGB30PMToRGBA64PM<PixelOrderRGB>,
1397 fetchA2RGB30PMToARGB32PM<PixelOrderRGB>,
1398 fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>,
1399 storeA2RGB30PMFromARGB32PM<PixelOrderRGB>,
1400 storeRGB30FromRGB32<PixelOrderRGB>
1401 }, // Format_A2RGB30_Premultiplied
1402 { true, true, QPixelLayout::BPP8, nullptr,
1403 convertAlpha8ToRGB32, convertAlpha8ToRGB64,
1404 fetchAlpha8ToRGB32, fetchAlpha8ToRGB64,
1405 storeAlpha8FromARGB32PM, nullptr }, // Format_Alpha8
1406 { false, false, QPixelLayout::BPP8, nullptr,
1407 convertGrayscale8ToRGB32, convertGrayscale8ToRGB64,
1408 fetchGrayscale8ToRGB32, fetchGrayscale8ToRGB64,
1409 storeGrayscale8FromARGB32PM, storeGrayscale8FromRGB32 }, // Format_Grayscale8
1410 { false, false, QPixelLayout::BPP64, nullptr,
1411 convertPassThrough, nullptr,
1412 fetchRGB64ToRGB32, fetchPassThrough64,
1413 storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBX64
1414 { true, false, QPixelLayout::BPP64, nullptr,
1415 convertARGB32ToARGB32PM, nullptr,
1416 fetchRGBA64ToARGB32PM, fetchRGBA64ToRGBA64PM,
1417 storeRGBA64FromARGB32PM, storeRGB64FromRGB32 }, // Format_RGBA64
1418 { true, true, QPixelLayout::BPP64, nullptr,
1419 convertPassThrough, nullptr,
1420 fetchRGB64ToRGB32, fetchPassThrough64,
1421 storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied
1422 { false, false, QPixelLayout::BPP16, nullptr,
1423 convertGrayscale16ToRGB32, convertGrayscale16ToRGBA64,
1424 fetchGrayscale16ToRGB32, fetchGrayscale16ToRGBA64,
1425 storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 }, // Format_Grayscale16
1426 pixelLayoutRGB<QImage::Format_BGR888>(),
1427};
1428
1429static_assert(sizeof(qPixelLayouts) / sizeof(*qPixelLayouts) == QImage::NImageFormats);
1430
1431static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int length)
1432{
1433 for (int i = 0; i < length; ++i) {
1434 dest[i] = toArgb32(src[i]);
1435 }
1436}
1437
1438template<QImage::Format format>
1439static void QT_FASTCALL storeGenericFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1440 const QList<QRgb> *clut, QDitherInfo *dither)
1441{
1442 uint buffer[BufferSize];
1443 convertFromRgb64(buffer, src, count);
1444 qPixelLayouts[format].storeFromARGB32PM(dest, buffer, index, count, clut, dither);
1445}
1446
1447static void QT_FASTCALL storeARGB32FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1448 const QList<QRgb> *, QDitherInfo *)
1449{
1450 uint *d = (uint*)dest + index;
1451 for (int i = 0; i < count; ++i)
1452 d[i] = toArgb32(src[i].unpremultiplied());
1453}
1454
1455static void QT_FASTCALL storeRGBA8888FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1456 const QList<QRgb> *, QDitherInfo *)
1457{
1458 uint *d = (uint*)dest + index;
1459 for (int i = 0; i < count; ++i)
1460 d[i] = toRgba8888(src[i].unpremultiplied());
1461}
1462
1463template<QtPixelOrder PixelOrder>
1464static void QT_FASTCALL storeRGB30FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1465 const QList<QRgb> *, QDitherInfo *)
1466{
1467 uint *d = (uint*)dest + index;
1468#ifdef __SSE2__
1469 qConvertRGBA64PMToA2RGB30PM_sse2<PixelOrder>(d, src, count);
1470#else
1471 for (int i = 0; i < count; ++i)
1472 d[i] = qConvertRgb64ToRgb30<PixelOrder>(src[i]);
1473#endif
1474}
1475
1476static void QT_FASTCALL storeRGBX64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1477 const QList<QRgb> *, QDitherInfo *)
1478{
1479 QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
1480 for (int i = 0; i < count; ++i) {
1481 d[i] = src[i].unpremultiplied();
1482 d[i].setAlpha(65535);
1483 }
1484}
1485
1486static void QT_FASTCALL storeRGBA64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1487 const QList<QRgb> *, QDitherInfo *)
1488{
1489 QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
1490 for (int i = 0; i < count; ++i)
1491 d[i] = src[i].unpremultiplied();
1492}
1493
1494static void QT_FASTCALL storeRGBA64PMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1495 const QList<QRgb> *, QDitherInfo *)
1496{
1497 QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
1498 if (d != src)
1499 memcpy(d, src, count * sizeof(QRgba64));
1500}
1501
1502static void QT_FASTCALL storeGray16FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1503 const QList<QRgb> *, QDitherInfo *)
1504{
1505 quint16 *d = reinterpret_cast<quint16*>(dest) + index;
1506 for (int i = 0; i < count; ++i) {
1507 QRgba64 s = src[i].unpremultiplied();
1508 d[i] = qGray(s.red(), s.green(), s.blue());
1509 }
1510}
1511
1512ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats] = {
1513 nullptr,
1514 nullptr,
1515 nullptr,
1516 nullptr,
1517 storeGenericFromRGBA64PM<QImage::Format_RGB32>,
1518 storeARGB32FromRGBA64PM,
1519 storeGenericFromRGBA64PM<QImage::Format_ARGB32_Premultiplied>,
1520 storeGenericFromRGBA64PM<QImage::Format_RGB16>,
1521 storeGenericFromRGBA64PM<QImage::Format_ARGB8565_Premultiplied>,
1522 storeGenericFromRGBA64PM<QImage::Format_RGB666>,
1523 storeGenericFromRGBA64PM<QImage::Format_ARGB6666_Premultiplied>,
1524 storeGenericFromRGBA64PM<QImage::Format_RGB555>,
1525 storeGenericFromRGBA64PM<QImage::Format_ARGB8555_Premultiplied>,
1526 storeGenericFromRGBA64PM<QImage::Format_RGB888>,
1527 storeGenericFromRGBA64PM<QImage::Format_RGB444>,
1528 storeGenericFromRGBA64PM<QImage::Format_ARGB4444_Premultiplied>,
1529 storeGenericFromRGBA64PM<QImage::Format_RGBX8888>,
1530 storeRGBA8888FromRGBA64PM,
1531 storeGenericFromRGBA64PM<QImage::Format_RGBA8888_Premultiplied>,
1532 storeRGB30FromRGBA64PM<PixelOrderBGR>,
1533 storeRGB30FromRGBA64PM<PixelOrderBGR>,
1534 storeRGB30FromRGBA64PM<PixelOrderRGB>,
1535 storeRGB30FromRGBA64PM<PixelOrderRGB>,
1536 storeGenericFromRGBA64PM<QImage::Format_Alpha8>,
1537 storeGenericFromRGBA64PM<QImage::Format_Grayscale8>,
1538 storeRGBX64FromRGBA64PM,
1539 storeRGBA64FromRGBA64PM,
1540 storeRGBA64PMFromRGBA64PM,
1541 storeGray16FromRGBA64PM,
1542 storeGenericFromRGBA64PM<QImage::Format_BGR888>,
1543};
1544
1545QT_END_NAMESPACE
1546