Coverage Report

Created: 2025-07-23 08:13

/src/qtbase/src/gui/painting/qdrawhelper.cpp
Line
Count
Source (jump to first uncovered line)
1
/****************************************************************************
2
**
3
** Copyright (C) 2018 The Qt Company Ltd.
4
** Copyright (C) 2018 Intel Corporation.
5
** Contact: https://www.qt.io/licensing/
6
**
7
** This file is part of the QtGui module of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** Commercial License Usage
11
** Licensees holding valid commercial Qt licenses may use this file in
12
** accordance with the commercial license agreement provided with the
13
** Software or, alternatively, in accordance with the terms contained in
14
** a written agreement between you and The Qt Company. For licensing terms
15
** and conditions see https://www.qt.io/terms-conditions. For further
16
** information use the contact form at https://www.qt.io/contact-us.
17
**
18
** GNU Lesser General Public License Usage
19
** Alternatively, this file may be used under the terms of the GNU Lesser
20
** General Public License version 3 as published by the Free Software
21
** Foundation and appearing in the file LICENSE.LGPL3 included in the
22
** packaging of this file. Please review the following information to
23
** ensure the GNU Lesser General Public License version 3 requirements
24
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25
**
26
** GNU General Public License Usage
27
** Alternatively, this file may be used under the terms of the GNU
28
** General Public License version 2.0 or (at your option) the GNU General
29
** Public license version 3 or any later version approved by the KDE Free
30
** Qt Foundation. The licenses are as published by the Free Software
31
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32
** included in the packaging of this file. Please review the following
33
** information to ensure the GNU General Public License requirements will
34
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35
** https://www.gnu.org/licenses/gpl-3.0.html.
36
**
37
** $QT_END_LICENSE$
38
**
39
****************************************************************************/
40
41
#include <qglobal.h>
42
43
#include <qstylehints.h>
44
#include <qguiapplication.h>
45
#include <qatomic.h>
46
#include <private/qcolortrclut_p.h>
47
#include <private/qdrawhelper_p.h>
48
#include <private/qpaintengine_raster_p.h>
49
#include <private/qpainter_p.h>
50
#include <private/qdrawhelper_x86_p.h>
51
#include <private/qdrawingprimitive_sse2_p.h>
52
#include <private/qdrawhelper_neon_p.h>
53
#if defined(QT_COMPILER_SUPPORTS_MIPS_DSP) || defined(QT_COMPILER_SUPPORTS_MIPS_DSPR2)
54
#include <private/qdrawhelper_mips_dsp_p.h>
55
#endif
56
#include <private/qguiapplication_p.h>
57
#include <private/qrgba64_p.h>
58
#include <qendian.h>
59
#include <qloggingcategory.h>
60
#include <qmath.h>
61
62
QT_BEGIN_NAMESPACE
63
64
Q_LOGGING_CATEGORY(lcQtGuiDrawHelper, "qt.gui.drawhelper")
65
66
#define MASK(src, a) src = BYTE_MUL(src, a)
67
68
/*
69
  constants and structures
70
*/
71
72
enum {
73
    fixed_scale = 1 << 16,
74
    half_point = 1 << 15
75
};
76
77
template<QImage::Format> Q_DECL_CONSTEXPR uint redWidth();
78
template<QImage::Format> Q_DECL_CONSTEXPR uint redShift();
79
template<QImage::Format> Q_DECL_CONSTEXPR uint greenWidth();
80
template<QImage::Format> Q_DECL_CONSTEXPR uint greenShift();
81
template<QImage::Format> Q_DECL_CONSTEXPR uint blueWidth();
82
template<QImage::Format> Q_DECL_CONSTEXPR uint blueShift();
83
template<QImage::Format> Q_DECL_CONSTEXPR uint alphaWidth();
84
template<QImage::Format> Q_DECL_CONSTEXPR uint alphaShift();
85
86
0
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB16>() { return 5; }
87
0
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB444>() { return 4; }
88
0
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB555>() { return 5; }
89
0
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB666>() { return 6; }
90
0
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB888>() { return 8; }
91
0
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_BGR888>() { return 8; }
92
0
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
93
0
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
94
0
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
95
0
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
96
0
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBX8888>() { return 8; }
97
0
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBA8888>() { return 8; }
98
0
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
99
100
0
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB16>() { return  11; }
101
0
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB444>() { return  8; }
102
0
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB555>() { return 10; }
103
0
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB666>() { return 12; }
104
0
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB888>() { return 16; }
105
0
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_BGR888>() { return 0; }
106
0
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB4444_Premultiplied>() { return  8; }
107
0
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8555_Premultiplied>() { return 18; }
108
0
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8565_Premultiplied>() { return 19; }
109
0
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB6666_Premultiplied>() { return 12; }
110
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
111
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBX8888>() { return 24; }
112
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888>() { return 24; }
113
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; }
114
#else
115
0
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBX8888>() { return 0; }
116
0
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888>() { return 0; }
117
0
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; }
118
#endif
119
0
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB16>() { return 6; }
120
0
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB444>() { return 4; }
121
0
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB555>() { return 5; }
122
0
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB666>() { return 6; }
123
0
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB888>() { return 8; }
124
0
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_BGR888>() { return 8; }
125
0
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
126
0
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
127
0
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8565_Premultiplied>() { return 6; }
128
0
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
129
0
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBX8888>() { return 8; }
130
0
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBA8888>() { return 8; }
131
0
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
132
133
0
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB16>() { return  5; }
134
0
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB444>() { return 4; }
135
0
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB555>() { return 5; }
136
0
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB666>() { return 6; }
137
0
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB888>() { return 8; }
138
0
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_BGR888>() { return 8; }
139
0
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB4444_Premultiplied>() { return  4; }
140
0
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8555_Premultiplied>() { return 13; }
141
0
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8565_Premultiplied>() { return 13; }
142
0
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB6666_Premultiplied>() { return  6; }
143
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
144
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBX8888>() { return 16; }
145
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888>() { return 16; }
146
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; }
147
#else
148
0
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBX8888>() { return 8; }
149
0
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888>() { return 8; }
150
0
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
151
#endif
152
0
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB16>() { return 5; }
153
0
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB444>() { return 4; }
154
0
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB555>() { return 5; }
155
0
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB666>() { return 6; }
156
0
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB888>() { return 8; }
157
0
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_BGR888>() { return 8; }
158
0
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
159
0
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
160
0
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
161
0
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
162
0
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBX8888>() { return 8; }
163
0
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBA8888>() { return 8; }
164
0
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
165
166
0
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB16>() { return 0; }
167
0
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB444>() { return 0; }
168
0
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB555>() { return 0; }
169
0
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB666>() { return 0; }
170
0
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB888>() { return 0; }
171
0
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_BGR888>() { return 16; }
172
0
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB4444_Premultiplied>() { return 0; }
173
0
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8555_Premultiplied>() { return 8; }
174
0
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8565_Premultiplied>() { return 8; }
175
0
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB6666_Premultiplied>() { return 0; }
176
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
177
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBX8888>() { return 8; }
178
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888>() { return 8; }
179
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
180
#else
181
0
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBX8888>() { return 16; }
182
0
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888>() { return 16; }
183
0
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; }
184
#endif
185
0
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB16>() { return 0; }
186
0
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB444>() { return 0; }
187
0
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB555>() { return 0; }
188
0
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB666>() { return 0; }
189
0
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB888>() { return 0; }
190
0
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_BGR888>() { return 0; }
191
0
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB4444_Premultiplied>() { return  4; }
192
0
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8555_Premultiplied>() { return  8; }
193
0
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8565_Premultiplied>() { return  8; }
194
0
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB6666_Premultiplied>() { return  6; }
195
0
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBX8888>() { return 0; }
196
0
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBA8888>() { return 8; }
197
0
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
198
199
0
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB16>() { return 0; }
200
0
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB444>() { return 0; }
201
0
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB555>() { return 0; }
202
0
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB666>() { return 0; }
203
0
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB888>() { return 0; }
204
0
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_BGR888>() { return 0; }
205
0
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB4444_Premultiplied>() { return 12; }
206
0
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8555_Premultiplied>() { return  0; }
207
0
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8565_Premultiplied>() { return  0; }
208
0
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB6666_Premultiplied>() { return 18; }
209
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
210
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBX8888>() { return 0; }
211
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888>() { return 0; }
212
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; }
213
#else
214
0
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBX8888>() { return 24; }
215
0
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888>() { return 24; }
216
0
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; }
217
#endif
218
219
template<QImage::Format> constexpr QPixelLayout::BPP bitsPerPixel();
220
0
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB16>() { return QPixelLayout::BPP16; }
221
0
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB444>() { return QPixelLayout::BPP16; }
222
0
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB555>() { return QPixelLayout::BPP16; }
223
0
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB666>() { return QPixelLayout::BPP24; }
224
0
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB888>() { return QPixelLayout::BPP24; }
225
0
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_BGR888>() { return QPixelLayout::BPP24; }
226
0
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB4444_Premultiplied>() { return QPixelLayout::BPP16; }
227
0
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8555_Premultiplied>() { return QPixelLayout::BPP24; }
228
0
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8565_Premultiplied>() { return QPixelLayout::BPP24; }
229
0
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB6666_Premultiplied>() { return QPixelLayout::BPP24; }
230
0
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBX8888>() { return QPixelLayout::BPP32; }
231
0
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888>() { return QPixelLayout::BPP32; }
232
0
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888_Premultiplied>() { return QPixelLayout::BPP32; }
233
234
235
typedef const uint *(QT_FASTCALL *FetchPixelsFunc)(uint *buffer, const uchar *src, int index, int count);
236
237
template <QPixelLayout::BPP bpp> static
238
uint QT_FASTCALL fetchPixel(const uchar *, int)
239
0
{
240
0
    Q_UNREACHABLE();
241
0
    return 0;
242
0
}
243
244
template <>
245
inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP1LSB>(const uchar *src, int index)
246
0
{
247
0
    return (src[index >> 3] >> (index & 7)) & 1;
248
0
}
249
250
template <>
251
inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP1MSB>(const uchar *src, int index)
252
0
{
253
0
    return (src[index >> 3] >> (~index & 7)) & 1;
254
0
}
255
256
template <>
257
inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP8>(const uchar *src, int index)
258
0
{
259
0
    return src[index];
260
0
}
261
262
template <>
263
inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP16>(const uchar *src, int index)
264
0
{
265
0
    return reinterpret_cast<const quint16 *>(src)[index];
266
0
}
267
268
template <>
269
inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP24>(const uchar *src, int index)
270
0
{
271
0
    return reinterpret_cast<const quint24 *>(src)[index];
272
0
}
273
274
template <>
275
inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP32>(const uchar *src, int index)
276
0
{
277
0
    return reinterpret_cast<const uint *>(src)[index];
278
0
}
279
280
template <>
281
inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP64>(const uchar *src, int index)
282
0
{
283
    // We have to do the conversion in fetch to fit into a 32bit uint
284
0
    QRgba64 c = reinterpret_cast<const QRgba64 *>(src)[index];
285
0
    return c.toArgb32();
286
0
}
287
288
template <QPixelLayout::BPP bpp>
289
static quint64 QT_FASTCALL fetchPixel64(const uchar *src, int index)
290
{
291
    Q_STATIC_ASSERT(bpp != QPixelLayout::BPP64);
292
    return fetchPixel<bpp>(src, index);
293
}
294
295
template <QPixelLayout::BPP width> static
296
void QT_FASTCALL storePixel(uchar *dest, int index, uint pixel);
297
298
template <>
299
inline void QT_FASTCALL storePixel<QPixelLayout::BPP16>(uchar *dest, int index, uint pixel)
300
0
{
301
0
    reinterpret_cast<quint16 *>(dest)[index] = quint16(pixel);
302
0
}
303
304
template <>
305
inline void QT_FASTCALL storePixel<QPixelLayout::BPP24>(uchar *dest, int index, uint pixel)
306
0
{
307
0
    reinterpret_cast<quint24 *>(dest)[index] = quint24(pixel);
308
0
}
309
310
typedef uint (QT_FASTCALL *FetchPixelFunc)(const uchar *src, int index);
311
312
static const FetchPixelFunc qFetchPixel[QPixelLayout::BPPCount] = {
313
    nullptr, // BPPNone
314
    fetchPixel<QPixelLayout::BPP1MSB>, // BPP1MSB
315
    fetchPixel<QPixelLayout::BPP1LSB>, // BPP1LSB
316
    fetchPixel<QPixelLayout::BPP8>, // BPP8
317
    fetchPixel<QPixelLayout::BPP16>, // BPP16
318
    fetchPixel<QPixelLayout::BPP24>, // BPP24
319
    fetchPixel<QPixelLayout::BPP32>, // BPP32
320
    fetchPixel<QPixelLayout::BPP64> // BPP64
321
};
322
323
template<QImage::Format Format>
324
static Q_ALWAYS_INLINE uint convertPixelToRGB32(uint s)
325
0
{
326
0
    Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1);
327
0
    Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1);
328
0
    Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1);
329
330
0
    Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>();
331
0
    Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>();
332
0
    Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>();
333
334
0
    Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8;
335
0
    Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8;
336
0
    Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8;
337
338
0
    uint red   = (s >> redShift<Format>()) & redMask;
339
0
    uint green = (s >> greenShift<Format>()) & greenMask;
340
0
    uint blue  = (s >> blueShift<Format>()) & blueMask;
341
342
0
    red = ((red << redLeftShift) | (red >> redRightShift)) << 16;
343
0
    green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8;
344
0
    blue = (blue << blueLeftShift) | (blue >> blueRightShift);
345
0
    return 0xff000000 | red | green | blue;
346
0
}
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToRGB32<(QImage::Format)7>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToRGB32<(QImage::Format)8>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToRGB32<(QImage::Format)9>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToRGB32<(QImage::Format)10>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToRGB32<(QImage::Format)11>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToRGB32<(QImage::Format)12>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToRGB32<(QImage::Format)13>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToRGB32<(QImage::Format)14>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToRGB32<(QImage::Format)15>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToRGB32<(QImage::Format)29>(unsigned int)
347
348
template<QImage::Format Format>
349
static void QT_FASTCALL convertToRGB32(uint *buffer, int count, const QVector<QRgb> *)
350
0
{
351
0
    for (int i = 0; i < count; ++i)
352
0
        buffer[i] = convertPixelToRGB32<Format>(buffer[i]);
353
0
}
Unexecuted instantiation: qdrawhelper.cpp:void convertToRGB32<(QImage::Format)7>(unsigned int*, int, QVector<unsigned int> const*)
Unexecuted instantiation: qdrawhelper.cpp:void convertToRGB32<(QImage::Format)9>(unsigned int*, int, QVector<unsigned int> const*)
Unexecuted instantiation: qdrawhelper.cpp:void convertToRGB32<(QImage::Format)11>(unsigned int*, int, QVector<unsigned int> const*)
Unexecuted instantiation: qdrawhelper.cpp:void convertToRGB32<(QImage::Format)13>(unsigned int*, int, QVector<unsigned int> const*)
Unexecuted instantiation: qdrawhelper.cpp:void convertToRGB32<(QImage::Format)14>(unsigned int*, int, QVector<unsigned int> const*)
Unexecuted instantiation: qdrawhelper.cpp:void convertToRGB32<(QImage::Format)29>(unsigned int*, int, QVector<unsigned int> const*)
354
355
#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
356
extern const uint * QT_FASTCALL fetchPixelsBPP24_ssse3(uint *dest, const uchar*src, int index, int count);
357
#endif
358
359
template<QImage::Format Format>
360
static const uint *QT_FASTCALL fetchRGBToRGB32(uint *buffer, const uchar *src, int index, int count,
361
                                               const QVector<QRgb> *, QDitherInfo *)
362
0
{
363
0
    constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
364
0
#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
365
0
    if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) {
366
        // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3
367
        // to vectorize the deforested version below.
368
0
        fetchPixelsBPP24_ssse3(buffer, src, index, count);
369
0
        convertToRGB32<Format>(buffer, count, nullptr);
370
0
        return buffer;
371
0
    }
372
0
#endif
373
0
    for (int i = 0; i < count; ++i)
374
0
        buffer[i] = convertPixelToRGB32<Format>(fetchPixel<BPP>(src, index + i));
375
0
    return buffer;
376
0
}
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchRGBToRGB32<(QImage::Format)7>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchRGBToRGB32<(QImage::Format)9>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchRGBToRGB32<(QImage::Format)11>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchRGBToRGB32<(QImage::Format)13>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchRGBToRGB32<(QImage::Format)14>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchRGBToRGB32<(QImage::Format)29>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
377
378
template<QImage::Format Format>
379
static Q_ALWAYS_INLINE QRgba64 convertPixelToRGB64(uint s)
380
0
{
381
0
    return QRgba64::fromArgb32(convertPixelToRGB32<Format>(s));
382
0
}
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGB64<(QImage::Format)7>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGB64<(QImage::Format)8>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGB64<(QImage::Format)9>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGB64<(QImage::Format)10>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGB64<(QImage::Format)11>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGB64<(QImage::Format)12>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGB64<(QImage::Format)13>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGB64<(QImage::Format)14>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGB64<(QImage::Format)15>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGB64<(QImage::Format)29>(unsigned int)
383
384
template<QImage::Format Format>
385
static const QRgba64 *QT_FASTCALL convertToRGB64(QRgba64 *buffer, const uint *src, int count,
386
                                                 const QVector<QRgb> *, QDitherInfo *)
387
0
{
388
0
    for (int i = 0; i < count; ++i)
389
0
        buffer[i] = convertPixelToRGB64<Format>(src[i]);
390
0
    return buffer;
391
0
}
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* convertToRGB64<(QImage::Format)7>(QRgba64*, unsigned int const*, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* convertToRGB64<(QImage::Format)9>(QRgba64*, unsigned int const*, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* convertToRGB64<(QImage::Format)11>(QRgba64*, unsigned int const*, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* convertToRGB64<(QImage::Format)13>(QRgba64*, unsigned int const*, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* convertToRGB64<(QImage::Format)14>(QRgba64*, unsigned int const*, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* convertToRGB64<(QImage::Format)29>(QRgba64*, unsigned int const*, int, QVector<unsigned int> const*, QDitherInfo*)
392
393
template<QImage::Format Format>
394
static const QRgba64 *QT_FASTCALL fetchRGBToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
395
                                                  const QVector<QRgb> *, QDitherInfo *)
396
0
{
397
0
    for (int i = 0; i < count; ++i)
398
0
        buffer[i] = convertPixelToRGB64<Format>(fetchPixel<bitsPerPixel<Format>()>(src, index + i));
399
0
    return buffer;
400
0
}
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchRGBToRGB64<(QImage::Format)7>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchRGBToRGB64<(QImage::Format)9>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchRGBToRGB64<(QImage::Format)11>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchRGBToRGB64<(QImage::Format)13>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchRGBToRGB64<(QImage::Format)14>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchRGBToRGB64<(QImage::Format)29>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
401
402
template<QImage::Format Format>
403
static Q_ALWAYS_INLINE uint convertPixelToARGB32PM(uint s)
404
0
{
405
0
    Q_CONSTEXPR uint alphaMask = ((1 << alphaWidth<Format>()) - 1);
406
0
    Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1);
407
0
    Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1);
408
0
    Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1);
409
410
0
    Q_CONSTEXPR uchar alphaLeftShift = 8 - alphaWidth<Format>();
411
0
    Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>();
412
0
    Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>();
413
0
    Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>();
414
415
0
    Q_CONSTEXPR uchar alphaRightShift = 2 * alphaWidth<Format>() - 8;
416
0
    Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8;
417
0
    Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8;
418
0
    Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8;
419
420
0
    Q_CONSTEXPR bool mustMin = (alphaWidth<Format>() != redWidth<Format>()) ||
421
0
                               (alphaWidth<Format>() != greenWidth<Format>()) ||
422
0
                               (alphaWidth<Format>() != blueWidth<Format>());
423
424
0
    uint alpha = (s >> alphaShift<Format>()) & alphaMask;
425
0
    uint red   = (s >> redShift<Format>()) & redMask;
426
0
    uint green = (s >> greenShift<Format>()) & greenMask;
427
0
    uint blue  = (s >> blueShift<Format>()) & blueMask;
428
429
0
    alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift);
430
0
    red   = (red << redLeftShift) | (red >> redRightShift);
431
0
    green = (green << greenLeftShift) | (green >> greenRightShift);
432
0
    blue  = (blue << blueLeftShift) | (blue >> blueRightShift);
433
434
0
    if (mustMin) {
435
0
        red   = qMin(alpha, red);
436
0
        green = qMin(alpha, green);
437
0
        blue  = qMin(alpha, blue);
438
0
    }
439
440
0
    return (alpha << 24) | (red << 16) | (green << 8) | blue;
441
0
}
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToARGB32PM<(QImage::Format)8>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToARGB32PM<(QImage::Format)10>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToARGB32PM<(QImage::Format)12>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int convertPixelToARGB32PM<(QImage::Format)15>(unsigned int)
442
443
template<QImage::Format Format>
444
static void QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, int count, const QVector<QRgb> *)
445
0
{
446
0
    for (int i = 0; i < count; ++i)
447
0
        buffer[i] = convertPixelToARGB32PM<Format>(buffer[i]);
448
0
}
Unexecuted instantiation: qdrawhelper.cpp:void convertARGBPMToARGB32PM<(QImage::Format)8>(unsigned int*, int, QVector<unsigned int> const*)
Unexecuted instantiation: qdrawhelper.cpp:void convertARGBPMToARGB32PM<(QImage::Format)10>(unsigned int*, int, QVector<unsigned int> const*)
Unexecuted instantiation: qdrawhelper.cpp:void convertARGBPMToARGB32PM<(QImage::Format)12>(unsigned int*, int, QVector<unsigned int> const*)
Unexecuted instantiation: qdrawhelper.cpp:void convertARGBPMToARGB32PM<(QImage::Format)15>(unsigned int*, int, QVector<unsigned int> const*)
449
450
template<QImage::Format Format>
451
static const uint *QT_FASTCALL fetchARGBPMToARGB32PM(uint *buffer, const uchar *src, int index, int count,
452
                                                     const QVector<QRgb> *, QDitherInfo *)
453
0
{
454
0
    constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
455
0
#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
456
0
    if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) {
457
        // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3
458
        // to vectorize the deforested version below.
459
0
        fetchPixelsBPP24_ssse3(buffer, src, index, count);
460
0
        convertARGBPMToARGB32PM<Format>(buffer, count, nullptr);
461
0
        return buffer;
462
0
    }
463
0
#endif
464
0
    for (int i = 0; i < count; ++i)
465
0
        buffer[i] = convertPixelToARGB32PM<Format>(fetchPixel<BPP>(src, index + i));
466
0
    return buffer;
467
0
}
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchARGBPMToARGB32PM<(QImage::Format)8>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchARGBPMToARGB32PM<(QImage::Format)10>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchARGBPMToARGB32PM<(QImage::Format)12>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchARGBPMToARGB32PM<(QImage::Format)15>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
468
469
template<QImage::Format Format>
470
static Q_ALWAYS_INLINE QRgba64 convertPixelToRGBA64PM(uint s)
471
0
{
472
0
    return QRgba64::fromArgb32(convertPixelToARGB32PM<Format>(s));
473
0
}
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGBA64PM<(QImage::Format)8>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGBA64PM<(QImage::Format)10>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGBA64PM<(QImage::Format)12>(unsigned int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 convertPixelToRGBA64PM<(QImage::Format)15>(unsigned int)
474
475
template<QImage::Format Format>
476
static const QRgba64 *QT_FASTCALL convertARGBPMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
477
                                                          const QVector<QRgb> *, QDitherInfo *)
478
0
{
479
0
    for (int i = 0; i < count; ++i)
480
0
        buffer[i] = convertPixelToRGB64<Format>(src[i]);
481
0
    return buffer;
482
0
}
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* convertARGBPMToRGBA64PM<(QImage::Format)8>(QRgba64*, unsigned int const*, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* convertARGBPMToRGBA64PM<(QImage::Format)10>(QRgba64*, unsigned int const*, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* convertARGBPMToRGBA64PM<(QImage::Format)12>(QRgba64*, unsigned int const*, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* convertARGBPMToRGBA64PM<(QImage::Format)15>(QRgba64*, unsigned int const*, int, QVector<unsigned int> const*, QDitherInfo*)
483
484
template<QImage::Format Format>
485
static const QRgba64 *QT_FASTCALL fetchARGBPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
486
                                                        const QVector<QRgb> *, QDitherInfo *)
487
0
{
488
0
    constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
489
0
    for (int i = 0; i < count; ++i)
490
0
        buffer[i] = convertPixelToRGBA64PM<Format>(fetchPixel<bpp>(src, index + i));
491
0
    return buffer;
492
0
}
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchARGBPMToRGBA64PM<(QImage::Format)8>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchARGBPMToRGBA64PM<(QImage::Format)10>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchARGBPMToRGBA64PM<(QImage::Format)12>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchARGBPMToRGBA64PM<(QImage::Format)15>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
493
494
template<QImage::Format Format, bool fromRGB>
495
static void QT_FASTCALL storeRGBFromARGB32PM(uchar *dest, const uint *src, int index, int count,
496
                                             const QVector<QRgb> *, QDitherInfo *dither)
497
0
{
498
0
    Q_CONSTEXPR uchar rWidth = redWidth<Format>();
499
0
    Q_CONSTEXPR uchar gWidth = greenWidth<Format>();
500
0
    Q_CONSTEXPR uchar bWidth = blueWidth<Format>();
501
0
    constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
502
503
    // RGB32 -> RGB888 is not a precision loss.
504
0
    if (!dither || (rWidth == 8 && gWidth == 8 && bWidth == 8)) {
505
0
        Q_CONSTEXPR uint rMask = (1 << redWidth<Format>()) - 1;
506
0
        Q_CONSTEXPR uint gMask = (1 << greenWidth<Format>()) - 1;
507
0
        Q_CONSTEXPR uint bMask = (1 << blueWidth<Format>()) - 1;
508
0
        Q_CONSTEXPR uchar rRightShift = 24 - redWidth<Format>();
509
0
        Q_CONSTEXPR uchar gRightShift = 16 - greenWidth<Format>();
510
0
        Q_CONSTEXPR uchar bRightShift =  8 - blueWidth<Format>();
511
512
0
        for (int i = 0; i < count; ++i) {
513
0
            const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]);
514
0
            const uint r = ((c >> rRightShift) & rMask) << redShift<Format>();
515
0
            const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>();
516
0
            const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>();
517
0
            storePixel<BPP>(dest, index + i, r | g | b);
518
0
        };
519
0
    } else {
520
        // We do ordered dither by using a rounding conversion, but instead of
521
        // adding half of input precision, we add the adjusted result from the
522
        // bayer matrix before narrowing.
523
        // Note: Rounding conversion in itself is different from the naive
524
        // conversion we do above for non-dithering.
525
0
        const uint *bayer_line = qt_bayer_matrix[dither->y & 15];
526
0
        for (int i = 0; i < count; ++i) {
527
0
            const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]);
528
0
            const int d = bayer_line[(dither->x + i) & 15];
529
0
            const int dr = d - ((d + 1) >> rWidth);
530
0
            const int dg = d - ((d + 1) >> gWidth);
531
0
            const int db = d - ((d + 1) >> bWidth);
532
0
            int r = qRed(c);
533
0
            int g = qGreen(c);
534
0
            int b = qBlue(c);
535
0
            r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth);
536
0
            g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth);
537
0
            b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth);
538
0
            const uint s = (r << redShift<Format>())
539
0
                         | (g << greenShift<Format>())
540
0
                         | (b << blueShift<Format>());
541
0
            storePixel<BPP>(dest, index + i, s);
542
0
        }
543
0
    }
544
0
}
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBFromARGB32PM<(QImage::Format)7, false>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBFromARGB32PM<(QImage::Format)7, true>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBFromARGB32PM<(QImage::Format)9, false>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBFromARGB32PM<(QImage::Format)9, true>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBFromARGB32PM<(QImage::Format)11, false>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBFromARGB32PM<(QImage::Format)11, true>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBFromARGB32PM<(QImage::Format)13, false>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBFromARGB32PM<(QImage::Format)13, true>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBFromARGB32PM<(QImage::Format)14, false>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBFromARGB32PM<(QImage::Format)14, true>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBFromARGB32PM<(QImage::Format)29, false>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBFromARGB32PM<(QImage::Format)29, true>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
545
546
template<QImage::Format Format, bool fromRGB>
547
static void QT_FASTCALL storeARGBPMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
548
                                                const QVector<QRgb> *, QDitherInfo *dither)
549
0
{
550
0
    constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
551
0
    if (!dither) {
552
0
        Q_CONSTEXPR uint aMask = (1 << alphaWidth<Format>()) - 1;
553
0
        Q_CONSTEXPR uint rMask = (1 << redWidth<Format>()) - 1;
554
0
        Q_CONSTEXPR uint gMask = (1 << greenWidth<Format>()) - 1;
555
0
        Q_CONSTEXPR uint bMask = (1 << blueWidth<Format>()) - 1;
556
557
0
        Q_CONSTEXPR uchar aRightShift = 32 - alphaWidth<Format>();
558
0
        Q_CONSTEXPR uchar rRightShift = 24 - redWidth<Format>();
559
0
        Q_CONSTEXPR uchar gRightShift = 16 - greenWidth<Format>();
560
0
        Q_CONSTEXPR uchar bRightShift =  8 - blueWidth<Format>();
561
562
0
        Q_CONSTEXPR uint aOpaque = aMask << alphaShift<Format>();
563
0
        for (int i = 0; i < count; ++i) {
564
0
            const uint c = src[i];
565
0
            const uint a = fromRGB ? aOpaque : (((c >> aRightShift) & aMask) << alphaShift<Format>());
566
0
            const uint r = ((c >> rRightShift) & rMask) << redShift<Format>();
567
0
            const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>();
568
0
            const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>();
569
0
            storePixel<BPP>(dest, index + i, a | r | g | b);
570
0
        };
571
0
    } else {
572
0
        Q_CONSTEXPR uchar aWidth = alphaWidth<Format>();
573
0
        Q_CONSTEXPR uchar rWidth = redWidth<Format>();
574
0
        Q_CONSTEXPR uchar gWidth = greenWidth<Format>();
575
0
        Q_CONSTEXPR uchar bWidth = blueWidth<Format>();
576
577
0
        const uint *bayer_line = qt_bayer_matrix[dither->y & 15];
578
0
        for (int i = 0; i < count; ++i) {
579
0
            const uint c = src[i];
580
0
            const int d = bayer_line[(dither->x + i) & 15];
581
0
            const int da = d - ((d + 1) >> aWidth);
582
0
            const int dr = d - ((d + 1) >> rWidth);
583
0
            const int dg = d - ((d + 1) >> gWidth);
584
0
            const int db = d - ((d + 1) >> bWidth);
585
0
            int a = qAlpha(c);
586
0
            int r = qRed(c);
587
0
            int g = qGreen(c);
588
0
            int b = qBlue(c);
589
0
            if (fromRGB)
590
0
                a = (1 << aWidth) - 1;
591
0
            else
592
0
                a = (a + ((da - a) >> aWidth) + 1) >> (8 - aWidth);
593
0
            r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth);
594
0
            g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth);
595
0
            b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth);
596
0
            uint s = (a << alphaShift<Format>())
597
0
                   | (r << redShift<Format>())
598
0
                   | (g << greenShift<Format>())
599
0
                   | (b << blueShift<Format>());
600
0
            storePixel<BPP>(dest, index + i, s);
601
0
        }
602
0
    }
603
0
}
Unexecuted instantiation: qdrawhelper.cpp:void storeARGBPMFromARGB32PM<(QImage::Format)8, false>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeARGBPMFromARGB32PM<(QImage::Format)8, true>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeARGBPMFromARGB32PM<(QImage::Format)10, false>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeARGBPMFromARGB32PM<(QImage::Format)10, true>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeARGBPMFromARGB32PM<(QImage::Format)12, false>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeARGBPMFromARGB32PM<(QImage::Format)12, true>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeARGBPMFromARGB32PM<(QImage::Format)15, false>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeARGBPMFromARGB32PM<(QImage::Format)15, true>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
604
605
template<QImage::Format Format>
606
static void QT_FASTCALL rbSwap(uchar *dst, const uchar *src, int count)
607
0
{
608
0
    Q_CONSTEXPR uchar aWidth = alphaWidth<Format>();
609
0
    Q_CONSTEXPR uchar aShift = alphaShift<Format>();
610
0
    Q_CONSTEXPR uchar rWidth = redWidth<Format>();
611
0
    Q_CONSTEXPR uchar rShift = redShift<Format>();
612
0
    Q_CONSTEXPR uchar gWidth = greenWidth<Format>();
613
0
    Q_CONSTEXPR uchar gShift = greenShift<Format>();
614
0
    Q_CONSTEXPR uchar bWidth = blueWidth<Format>();
615
0
    Q_CONSTEXPR uchar bShift = blueShift<Format>();
616
0
#ifdef Q_COMPILER_CONSTEXPR
617
0
    Q_STATIC_ASSERT(rWidth == bWidth);
618
0
#endif
619
0
    Q_CONSTEXPR uint redBlueMask = (1 << rWidth) - 1;
620
0
    Q_CONSTEXPR uint alphaGreenMask = (((1 << aWidth) - 1) << aShift)
621
0
                                    | (((1 << gWidth) - 1) << gShift);
622
0
    constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
623
624
0
    for (int i = 0; i < count; ++i) {
625
0
        const uint c = fetchPixel<bpp>(src, i);
626
0
        const uint r = (c >> rShift) & redBlueMask;
627
0
        const uint b = (c >> bShift) & redBlueMask;
628
0
        const uint t = (c & alphaGreenMask)
629
0
                     | (r << bShift)
630
0
                     | (b << rShift);
631
0
        storePixel<bpp>(dst, i, t);
632
0
    }
633
0
}
Unexecuted instantiation: qdrawhelper.cpp:void rbSwap<(QImage::Format)7>(unsigned char*, unsigned char const*, int)
Unexecuted instantiation: qdrawhelper.cpp:void rbSwap<(QImage::Format)8>(unsigned char*, unsigned char const*, int)
Unexecuted instantiation: qdrawhelper.cpp:void rbSwap<(QImage::Format)9>(unsigned char*, unsigned char const*, int)
Unexecuted instantiation: qdrawhelper.cpp:void rbSwap<(QImage::Format)10>(unsigned char*, unsigned char const*, int)
Unexecuted instantiation: qdrawhelper.cpp:void rbSwap<(QImage::Format)11>(unsigned char*, unsigned char const*, int)
Unexecuted instantiation: qdrawhelper.cpp:void rbSwap<(QImage::Format)12>(unsigned char*, unsigned char const*, int)
Unexecuted instantiation: qdrawhelper.cpp:void rbSwap<(QImage::Format)13>(unsigned char*, unsigned char const*, int)
Unexecuted instantiation: qdrawhelper.cpp:void rbSwap<(QImage::Format)14>(unsigned char*, unsigned char const*, int)
Unexecuted instantiation: qdrawhelper.cpp:void rbSwap<(QImage::Format)15>(unsigned char*, unsigned char const*, int)
Unexecuted instantiation: qdrawhelper.cpp:void rbSwap<(QImage::Format)29>(unsigned char*, unsigned char const*, int)
634
635
static void QT_FASTCALL rbSwap_rgb32(uchar *d, const uchar *s, int count)
636
0
{
637
0
    const uint *src = reinterpret_cast<const uint *>(s);
638
0
    uint *dest = reinterpret_cast<uint *>(d);
639
0
    for (int i = 0; i < count; ++i) {
640
0
        const uint c = src[i];
641
0
        const uint ag = c & 0xff00ff00;
642
0
        const uint rb = c & 0x00ff00ff;
643
0
        dest[i] = ag | (rb << 16) | (rb >> 16);
644
0
    }
645
0
}
646
647
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
648
template<>
649
void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count)
650
0
{
651
0
    return rbSwap_rgb32(d, s, count);
652
0
}
653
#else
654
template<>
655
void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count)
656
{
657
    const uint *src = reinterpret_cast<const uint *>(s);
658
    uint *dest = reinterpret_cast<uint *>(d);
659
    for (int i = 0; i < count; ++i) {
660
        const uint c = src[i];
661
        const uint rb = c & 0xff00ff00;
662
        const uint ga = c & 0x00ff00ff;
663
        dest[i] = ga | (rb << 16) | (rb >> 16);
664
    }
665
}
666
#endif
667
668
static void QT_FASTCALL rbSwap_rgb30(uchar *d, const uchar *s, int count)
669
0
{
670
0
    const uint *src = reinterpret_cast<const uint *>(s);
671
0
    uint *dest = reinterpret_cast<uint *>(d);
672
0
    UNALIASED_CONVERSION_LOOP(dest, src, count, qRgbSwapRgb30);
673
0
}
674
675
template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutRGB()
676
0
{
677
0
    return QPixelLayout{
678
0
        false,
679
0
        false,
680
0
        bitsPerPixel<Format>(),
681
0
        rbSwap<Format>,
682
0
        convertToRGB32<Format>,
683
0
        convertToRGB64<Format>,
684
0
        fetchRGBToRGB32<Format>,
685
0
        fetchRGBToRGB64<Format>,
686
0
        storeRGBFromARGB32PM<Format, false>,
687
0
        storeRGBFromARGB32PM<Format, true>
688
0
    };
689
0
}
Unexecuted instantiation: qdrawhelper.cpp:QPixelLayout pixelLayoutRGB<(QImage::Format)7>()
Unexecuted instantiation: qdrawhelper.cpp:QPixelLayout pixelLayoutRGB<(QImage::Format)9>()
Unexecuted instantiation: qdrawhelper.cpp:QPixelLayout pixelLayoutRGB<(QImage::Format)11>()
Unexecuted instantiation: qdrawhelper.cpp:QPixelLayout pixelLayoutRGB<(QImage::Format)13>()
Unexecuted instantiation: qdrawhelper.cpp:QPixelLayout pixelLayoutRGB<(QImage::Format)14>()
Unexecuted instantiation: qdrawhelper.cpp:QPixelLayout pixelLayoutRGB<(QImage::Format)29>()
690
691
template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutARGBPM()
692
0
{
693
0
    return QPixelLayout{
694
0
        true,
695
0
        true,
696
0
        bitsPerPixel<Format>(),
697
0
        rbSwap<Format>,
698
0
        convertARGBPMToARGB32PM<Format>,
699
0
        convertARGBPMToRGBA64PM<Format>,
700
0
        fetchARGBPMToARGB32PM<Format>,
701
0
        fetchARGBPMToRGBA64PM<Format>,
702
0
        storeARGBPMFromARGB32PM<Format, false>,
703
0
        storeARGBPMFromARGB32PM<Format, true>
704
0
    };
705
0
}
Unexecuted instantiation: qdrawhelper.cpp:QPixelLayout pixelLayoutARGBPM<(QImage::Format)8>()
Unexecuted instantiation: qdrawhelper.cpp:QPixelLayout pixelLayoutARGBPM<(QImage::Format)10>()
Unexecuted instantiation: qdrawhelper.cpp:QPixelLayout pixelLayoutARGBPM<(QImage::Format)12>()
Unexecuted instantiation: qdrawhelper.cpp:QPixelLayout pixelLayoutARGBPM<(QImage::Format)15>()
706
707
static void QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, int count, const QVector<QRgb> *clut)
708
0
{
709
0
    for (int i = 0; i < count; ++i)
710
0
        buffer[i] = qPremultiply(clut->at(buffer[i]));
711
0
}
712
713
template<QPixelLayout::BPP BPP>
714
static const uint *QT_FASTCALL fetchIndexedToARGB32PM(uint *buffer, const uchar *src, int index, int count,
715
                                                      const QVector<QRgb> *clut, QDitherInfo *)
716
0
{
717
0
    for (int i = 0; i < count; ++i) {
718
0
        const uint s = fetchPixel<BPP>(src, index + i);
719
0
        buffer[i] = qPremultiply(clut->at(s));
720
0
    }
721
0
    return buffer;
722
0
}
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchIndexedToARGB32PM<(QPixelLayout::BPP)1>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchIndexedToARGB32PM<(QPixelLayout::BPP)2>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchIndexedToARGB32PM<(QPixelLayout::BPP)3>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
723
724
template<QPixelLayout::BPP BPP>
725
static const QRgba64 *QT_FASTCALL fetchIndexedToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
726
                                                         const QVector<QRgb> *clut, QDitherInfo *)
727
0
{
728
0
    for (int i = 0; i < count; ++i) {
729
0
        const uint s = fetchPixel<BPP>(src, index + i);
730
0
        buffer[i] = QRgba64::fromArgb32(clut->at(s)).premultiplied();
731
0
    }
732
0
    return buffer;
733
0
}
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchIndexedToRGBA64PM<(QPixelLayout::BPP)1>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchIndexedToRGBA64PM<(QPixelLayout::BPP)2>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchIndexedToRGBA64PM<(QPixelLayout::BPP)3>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
734
735
static const QRgba64 *QT_FASTCALL convertIndexedToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
736
                                                           const QVector<QRgb> *clut, QDitherInfo *)
737
0
{
738
0
    for (int i = 0; i < count; ++i)
739
0
        buffer[i] = QRgba64::fromArgb32(clut->at(src[i])).premultiplied();
740
0
    return buffer;
741
0
}
742
743
static void QT_FASTCALL convertPassThrough(uint *, int, const QVector<QRgb> *)
744
0
{
745
0
}
746
747
static const uint *QT_FASTCALL fetchPassThrough(uint *, const uchar *src, int index, int,
748
                                                const QVector<QRgb> *, QDitherInfo *)
749
0
{
750
0
    return reinterpret_cast<const uint *>(src) + index;
751
0
}
752
753
static const QRgba64 *QT_FASTCALL fetchPassThrough64(QRgba64 *, const uchar *src, int index, int,
754
                                                     const QVector<QRgb> *, QDitherInfo *)
755
0
{
756
0
    return reinterpret_cast<const QRgba64 *>(src) + index;
757
0
}
758
759
static void QT_FASTCALL storePassThrough(uchar *dest, const uint *src, int index, int count,
760
                                         const QVector<QRgb> *, QDitherInfo *)
761
0
{
762
0
    uint *d = reinterpret_cast<uint *>(dest) + index;
763
0
    if (d != src)
764
0
        memcpy(d, src, count * sizeof(uint));
765
0
}
766
767
static void QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, int count, const QVector<QRgb> *)
768
0
{
769
0
    qt_convertARGB32ToARGB32PM(buffer, buffer, count);
770
0
}
771
772
static const uint *QT_FASTCALL fetchARGB32ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
773
                                                     const QVector<QRgb> *, QDitherInfo *)
774
0
{
775
0
    return qt_convertARGB32ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count);
776
0
}
777
778
static void QT_FASTCALL convertRGBA8888PMToARGB32PM(uint *buffer, int count, const QVector<QRgb> *)
779
0
{
780
0
    for (int i = 0; i < count; ++i)
781
0
        buffer[i] = RGBA2ARGB(buffer[i]);
782
0
}
783
784
static const uint *QT_FASTCALL fetchRGBA8888PMToARGB32PM(uint *buffer, const uchar *src, int index, int count,
785
                                                         const QVector<QRgb> *, QDitherInfo *)
786
0
{
787
0
    const uint *s  = reinterpret_cast<const uint *>(src) + index;
788
0
    UNALIASED_CONVERSION_LOOP(buffer, s, count, RGBA2ARGB);
789
0
    return buffer;
790
0
}
791
792
static void QT_FASTCALL convertRGBA8888ToARGB32PM(uint *buffer, int count, const QVector<QRgb> *)
793
0
{
794
0
    qt_convertRGBA8888ToARGB32PM(buffer, buffer, count);
795
0
}
796
797
static const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
798
                                                       const QVector<QRgb> *, QDitherInfo *)
799
0
{
800
0
    return qt_convertRGBA8888ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count);
801
0
}
802
803
static void QT_FASTCALL convertAlpha8ToRGB32(uint *buffer, int count, const QVector<QRgb> *)
804
0
{
805
0
    for (int i = 0; i < count; ++i)
806
0
        buffer[i] = qRgba(0, 0, 0, buffer[i]);
807
0
}
808
809
static const uint *QT_FASTCALL fetchAlpha8ToRGB32(uint *buffer, const uchar *src, int index, int count,
810
                                                  const QVector<QRgb> *, QDitherInfo *)
811
0
{
812
0
    for (int i = 0; i < count; ++i)
813
0
        buffer[i] = qRgba(0, 0, 0, src[index + i]);
814
0
    return buffer;
815
0
}
816
817
static const QRgba64 *QT_FASTCALL convertAlpha8ToRGB64(QRgba64 *buffer, const uint *src, int count,
818
                                                       const QVector<QRgb> *, QDitherInfo *)
819
0
{
820
0
    for (int i = 0; i < count; ++i)
821
0
        buffer[i] = QRgba64::fromRgba(0, 0, 0, src[i]);
822
0
    return buffer;
823
0
}
824
static const QRgba64 *QT_FASTCALL fetchAlpha8ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
825
                                                     const QVector<QRgb> *, QDitherInfo *)
826
0
{
827
0
    for (int i = 0; i < count; ++i)
828
0
        buffer[i] = QRgba64::fromRgba(0, 0, 0, src[index + i]);
829
0
    return buffer;
830
0
}
831
832
static void QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, int count, const QVector<QRgb> *)
833
0
{
834
0
    for (int i = 0; i < count; ++i) {
835
0
        const uint s = buffer[i];
836
0
        buffer[i] = qRgb(s, s, s);
837
0
    }
838
0
}
839
840
static const uint *QT_FASTCALL fetchGrayscale8ToRGB32(uint *buffer, const uchar *src, int index, int count,
841
                                                      const QVector<QRgb> *, QDitherInfo *)
842
0
{
843
0
    for (int i = 0; i < count; ++i) {
844
0
        const uint s = src[index + i];
845
0
        buffer[i] = qRgb(s, s, s);
846
0
    }
847
0
    return buffer;
848
0
}
849
850
static const QRgba64 *QT_FASTCALL convertGrayscale8ToRGB64(QRgba64 *buffer, const uint *src, int count,
851
                                                           const QVector<QRgb> *, QDitherInfo *)
852
0
{
853
0
    for (int i = 0; i < count; ++i)
854
0
        buffer[i] = QRgba64::fromRgba(src[i], src[i], src[i], 255);
855
0
    return buffer;
856
0
}
857
858
static const QRgba64 *QT_FASTCALL fetchGrayscale8ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
859
                                                         const QVector<QRgb> *, QDitherInfo *)
860
0
{
861
0
    for (int i = 0; i < count; ++i) {
862
0
        const uint s = src[index + i];
863
0
        buffer[i] = QRgba64::fromRgba(s, s, s, 255);
864
0
    }
865
0
    return buffer;
866
0
}
867
868
static void QT_FASTCALL convertGrayscale16ToRGB32(uint *buffer, int count, const QVector<QRgb> *)
869
0
{
870
0
    for (int i = 0; i < count; ++i) {
871
0
        const uint x = qt_div_257(buffer[i]);
872
0
        buffer[i] = qRgb(x, x, x);
873
0
    }
874
0
}
875
876
static const uint *QT_FASTCALL fetchGrayscale16ToRGB32(uint *buffer, const uchar *src, int index, int count,
877
                                                      const QVector<QRgb> *, QDitherInfo *)
878
0
{
879
0
    const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index;
880
0
    for (int i = 0; i < count; ++i) {
881
0
        const uint x = qt_div_257(s[i]);
882
0
        buffer[i] = qRgb(x, x, x);
883
0
    }
884
0
    return buffer;
885
0
}
886
887
static const QRgba64 *QT_FASTCALL convertGrayscale16ToRGBA64(QRgba64 *buffer, const uint *src, int count,
888
                                                           const QVector<QRgb> *, QDitherInfo *)
889
0
{
890
0
    for (int i = 0; i < count; ++i)
891
0
        buffer[i] = QRgba64::fromRgba64(src[i], src[i], src[i], 65535);
892
0
    return buffer;
893
0
}
894
895
static const QRgba64 *QT_FASTCALL fetchGrayscale16ToRGBA64(QRgba64 *buffer, const uchar *src, int index, int count,
896
                                                         const QVector<QRgb> *, QDitherInfo *)
897
0
{
898
0
    const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index;
899
0
    for (int i = 0; i < count; ++i) {
900
0
        buffer[i] = QRgba64::fromRgba64(s[i], s[i], s[i], 65535);
901
0
    }
902
0
    return buffer;
903
0
}
904
905
static void QT_FASTCALL storeARGB32FromARGB32PM(uchar *dest, const uint *src, int index, int count,
906
                                                const QVector<QRgb> *, QDitherInfo *)
907
0
{
908
0
    uint *d = reinterpret_cast<uint *>(dest) + index;
909
0
    UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return qUnpremultiply(c); });
910
0
}
911
912
static void QT_FASTCALL storeRGBA8888PMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
913
                                                    const QVector<QRgb> *, QDitherInfo *)
914
0
{
915
0
    uint *d = reinterpret_cast<uint *>(dest) + index;
916
0
    UNALIASED_CONVERSION_LOOP(d, src, count, ARGB2RGBA);
917
0
}
918
919
#ifdef __SSE2__
920
template<bool RGBA, bool maskAlpha>
921
static inline void qConvertARGB32PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count)
922
0
{
923
0
    if (count <= 0)
924
0
        return;
925
926
0
    const __m128i amask = _mm_set1_epi32(0xff000000);
927
0
    int i = 0;
928
0
    for (; ((uintptr_t)buffer & 0xf) && i < count; ++i) {
929
0
        uint s = *src++;
930
0
        if (maskAlpha)
931
0
            s = s | 0xff000000;
932
0
        if (RGBA)
933
0
            s = RGBA2ARGB(s);
934
0
        *buffer++ = QRgba64::fromArgb32(s);
935
0
    }
936
0
    for (; i < count-3; i += 4) {
937
0
        __m128i vs = _mm_loadu_si128((const __m128i*)src);
938
0
        if (maskAlpha)
939
0
            vs = _mm_or_si128(vs, amask);
940
0
        src += 4;
941
0
        __m128i v1 = _mm_unpacklo_epi8(vs, vs);
942
0
        __m128i v2 = _mm_unpackhi_epi8(vs, vs);
943
0
        if (!RGBA) {
944
0
            v1 = _mm_shufflelo_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2));
945
0
            v2 = _mm_shufflelo_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2));
946
0
            v1 = _mm_shufflehi_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2));
947
0
            v2 = _mm_shufflehi_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2));
948
0
        }
949
0
        _mm_store_si128((__m128i*)(buffer), v1);
950
0
        buffer += 2;
951
0
        _mm_store_si128((__m128i*)(buffer), v2);
952
0
        buffer += 2;
953
0
    }
954
955
0
    SIMD_EPILOGUE(i, count, 3) {
956
0
        uint s = *src++;
957
0
        if (maskAlpha)
958
0
            s = s | 0xff000000;
959
0
        if (RGBA)
960
0
            s = RGBA2ARGB(s);
961
0
        *buffer++ = QRgba64::fromArgb32(s);
962
0
    }
963
0
}
Unexecuted instantiation: qdrawhelper.cpp:void qConvertARGB32PMToRGBA64PM_sse2<false, true>(QRgba64*, unsigned int const*, int)
Unexecuted instantiation: qdrawhelper.cpp:void qConvertARGB32PMToRGBA64PM_sse2<false, false>(QRgba64*, unsigned int const*, int)
Unexecuted instantiation: qdrawhelper.cpp:void qConvertARGB32PMToRGBA64PM_sse2<true, false>(QRgba64*, unsigned int const*, int)
964
965
template<QtPixelOrder PixelOrder>
966
static inline void qConvertRGBA64PMToA2RGB30PM_sse2(uint *dest, const QRgba64 *buffer, int count)
967
0
{
968
0
    const __m128i gmask = _mm_set1_epi32(0x000ffc00);
969
0
    const __m128i cmask = _mm_set1_epi32(0x000003ff);
970
0
    int i = 0;
971
0
    __m128i vr, vg, vb, va;
972
0
    for (; i < count && uintptr_t(buffer) & 0xF; ++i) {
973
0
        *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
974
0
    }
975
976
0
    for (; i < count-15; i += 16) {
977
        // Repremultiplying is really expensive and hard to do in SIMD without AVX2,
978
        // so we try to avoid it by checking if it is needed 16 samples at a time.
979
0
        __m128i vOr = _mm_set1_epi32(0);
980
0
        __m128i vAnd = _mm_set1_epi32(0xffffffff);
981
0
        for (int j = 0; j < 16; j += 2) {
982
0
            __m128i vs = _mm_load_si128((const __m128i*)(buffer + j));
983
0
            vOr = _mm_or_si128(vOr, vs);
984
0
            vAnd = _mm_and_si128(vAnd, vs);
985
0
        }
986
0
        const quint16 orAlpha = ((uint)_mm_extract_epi16(vOr, 3)) | ((uint)_mm_extract_epi16(vOr, 7));
987
0
        const quint16 andAlpha = ((uint)_mm_extract_epi16(vAnd, 3)) & ((uint)_mm_extract_epi16(vAnd, 7));
988
989
0
        if (andAlpha == 0xffff) {
990
0
            for (int j = 0; j < 16; j += 2) {
991
0
                __m128i vs = _mm_load_si128((const __m128i*)buffer);
992
0
                buffer += 2;
993
0
                vr = _mm_srli_epi64(vs, 6);
994
0
                vg = _mm_srli_epi64(vs, 16 + 6 - 10);
995
0
                vb = _mm_srli_epi64(vs, 32 + 6);
996
0
                vr = _mm_and_si128(vr, cmask);
997
0
                vg = _mm_and_si128(vg, gmask);
998
0
                vb = _mm_and_si128(vb, cmask);
999
0
                va = _mm_srli_epi64(vs, 48 + 14);
1000
0
                if (PixelOrder == PixelOrderRGB)
1001
0
                    vr = _mm_slli_epi32(vr, 20);
1002
0
                else
1003
0
                    vb = _mm_slli_epi32(vb, 20);
1004
0
                va = _mm_slli_epi32(va, 30);
1005
0
                __m128i vd = _mm_or_si128(_mm_or_si128(vr, vg), _mm_or_si128(vb, va));
1006
0
                vd = _mm_shuffle_epi32(vd, _MM_SHUFFLE(3, 1, 2, 0));
1007
0
                _mm_storel_epi64((__m128i*)dest, vd);
1008
0
                dest += 2;
1009
0
            }
1010
0
        } else if (orAlpha == 0) {
1011
0
            for (int j = 0; j < 16; ++j) {
1012
0
                *dest++ = 0;
1013
0
                buffer++;
1014
0
            }
1015
0
        } else {
1016
0
            for (int j = 0; j < 16; ++j)
1017
0
                *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
1018
0
        }
1019
0
    }
1020
1021
0
    SIMD_EPILOGUE(i, count, 15)
1022
0
        *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
1023
0
}
Unexecuted instantiation: qdrawhelper.cpp:void qConvertRGBA64PMToA2RGB30PM_sse2<(QtPixelOrder)1>(unsigned int*, QRgba64 const*, int)
Unexecuted instantiation: qdrawhelper.cpp:void qConvertRGBA64PMToA2RGB30PM_sse2<(QtPixelOrder)0>(unsigned int*, QRgba64 const*, int)
1024
#elif defined(__ARM_NEON__)
1025
template<bool RGBA, bool maskAlpha>
1026
static inline void qConvertARGB32PMToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count)
1027
{
1028
    if (count <= 0)
1029
        return;
1030
1031
    const uint32x4_t amask = vdupq_n_u32(0xff000000);
1032
#if defined(Q_PROCESSOR_ARM_64)
1033
    const uint8x16_t rgbaMask  = { 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15};
1034
#else
1035
    const uint8x8_t rgbaMask  = { 2, 1, 0, 3, 6, 5, 4, 7 };
1036
#endif
1037
    int i = 0;
1038
    for (; i < count-3; i += 4) {
1039
        uint32x4_t vs32 = vld1q_u32(src);
1040
        src += 4;
1041
        if (maskAlpha)
1042
            vs32 = vorrq_u32(vs32, amask);
1043
        uint8x16_t vs8 = vreinterpretq_u8_u32(vs32);
1044
        if (!RGBA) {
1045
#if defined(Q_PROCESSOR_ARM_64)
1046
            vs8 = vqtbl1q_u8(vs8, rgbaMask);
1047
#else
1048
            // no vqtbl1q_u8
1049
            const uint8x8_t vlo = vtbl1_u8(vget_low_u8(vs8), rgbaMask);
1050
            const uint8x8_t vhi = vtbl1_u8(vget_high_u8(vs8), rgbaMask);
1051
            vs8 = vcombine_u8(vlo, vhi);
1052
#endif
1053
        }
1054
        uint8x16x2_t v = vzipq_u8(vs8, vs8);
1055
1056
        vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[0]));
1057
        buffer += 2;
1058
        vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[1]));
1059
        buffer += 2;
1060
    }
1061
1062
    SIMD_EPILOGUE(i, count, 3) {
1063
        uint s = *src++;
1064
        if (maskAlpha)
1065
            s = s | 0xff000000;
1066
        if (RGBA)
1067
            s = RGBA2ARGB(s);
1068
        *buffer++ = QRgba64::fromArgb32(s);
1069
    }
1070
}
1071
#endif
1072
1073
static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count,
1074
                                                      const QVector<QRgb> *, QDitherInfo *)
1075
0
{
1076
0
#ifdef __SSE2__
1077
0
    qConvertARGB32PMToRGBA64PM_sse2<false, true>(buffer, src, count);
1078
#elif defined(__ARM_NEON__)
1079
    qConvertARGB32PMToRGBA64PM_neon<false, true>(buffer, src, count);
1080
#else
1081
    for (int i = 0; i < count; ++i)
1082
        buffer[i] = QRgba64::fromArgb32(0xff000000 | src[i]);
1083
#endif
1084
0
    return buffer;
1085
0
}
1086
1087
static const QRgba64 *QT_FASTCALL fetchRGB32ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
1088
                                                    const QVector<QRgb> *, QDitherInfo *)
1089
0
{
1090
0
    return convertRGB32ToRGB64(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1091
0
}
1092
1093
static const QRgba64 *QT_FASTCALL convertARGB32ToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1094
                                                          const QVector<QRgb> *, QDitherInfo *)
1095
0
{
1096
0
    for (int i = 0; i < count; ++i)
1097
0
        buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied();
1098
0
    return buffer;
1099
0
}
1100
1101
static const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1102
                                                        const QVector<QRgb> *, QDitherInfo *)
1103
0
{
1104
0
    return convertARGB32ToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1105
0
}
1106
1107
static const QRgba64 *QT_FASTCALL convertARGB32PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1108
                                                            const QVector<QRgb> *, QDitherInfo *)
1109
0
{
1110
0
#ifdef __SSE2__
1111
0
    qConvertARGB32PMToRGBA64PM_sse2<false, false>(buffer, src, count);
1112
#elif defined(__ARM_NEON__)
1113
    qConvertARGB32PMToRGBA64PM_neon<false, false>(buffer, src, count);
1114
#else
1115
    for (int i = 0; i < count; ++i)
1116
        buffer[i] = QRgba64::fromArgb32(src[i]);
1117
#endif
1118
0
    return buffer;
1119
0
}
1120
1121
static const QRgba64 *QT_FASTCALL fetchARGB32PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1122
                                                          const QVector<QRgb> *, QDitherInfo *)
1123
0
{
1124
0
    return convertARGB32PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1125
0
}
1126
1127
#if QT_CONFIG(raster_64bit)
1128
static void convertRGBA64ToRGBA64PM(QRgba64 *buffer, int count)
1129
0
{
1130
0
    for (int i = 0; i < count; ++i)
1131
0
        buffer[i] = buffer[i].premultiplied();
1132
0
}
1133
1134
static void convertRGBA64PMToRGBA64PM(QRgba64 *, int)
1135
0
{
1136
0
}
1137
#endif
1138
1139
static const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1140
                                                        const QVector<QRgb> *, QDitherInfo *)
1141
0
{
1142
0
    const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
1143
0
    for (int i = 0; i < count; ++i)
1144
0
        buffer[i] = QRgba64::fromRgba64(s[i]).premultiplied();
1145
0
    return buffer;
1146
0
}
1147
1148
static const QRgba64 *QT_FASTCALL convertRGBA8888ToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1149
                                                            const QVector<QRgb> *, QDitherInfo *)
1150
0
{
1151
0
    for (int i = 0; i < count; ++i)
1152
0
        buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied();
1153
0
    return buffer;
1154
0
}
1155
1156
static const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1157
                                                          const QVector<QRgb> *, QDitherInfo *)
1158
0
{
1159
0
    return convertRGBA8888ToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1160
0
}
1161
1162
static const QRgba64 *QT_FASTCALL convertRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1163
                                                              const QVector<QRgb> *, QDitherInfo *)
1164
0
{
1165
0
#ifdef __SSE2__
1166
0
    qConvertARGB32PMToRGBA64PM_sse2<true, false>(buffer, src, count);
1167
#elif defined(__ARM_NEON__)
1168
    qConvertARGB32PMToRGBA64PM_neon<true, false>(buffer, src, count);
1169
#else
1170
    for (int i = 0; i < count; ++i)
1171
        buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i]));
1172
#endif
1173
0
    return buffer;
1174
0
}
1175
1176
static const QRgba64 *QT_FASTCALL fetchRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1177
                                                            const QVector<QRgb> *, QDitherInfo *)
1178
0
{
1179
0
    return convertRGBA8888PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1180
0
}
1181
1182
static void QT_FASTCALL storeRGBA8888FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1183
                                                  const QVector<QRgb> *, QDitherInfo *)
1184
0
{
1185
0
    uint *d = reinterpret_cast<uint *>(dest) + index;
1186
0
    UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(qUnpremultiply(c)); });
1187
0
}
1188
1189
static void QT_FASTCALL storeRGBXFromRGB32(uchar *dest, const uint *src, int index, int count,
1190
                                           const QVector<QRgb> *, QDitherInfo *)
1191
0
{
1192
0
    uint *d = reinterpret_cast<uint *>(dest) + index;
1193
0
    UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | c); });
1194
0
}
1195
1196
static void QT_FASTCALL storeRGBXFromARGB32PM(uchar *dest, const uint *src, int index, int count,
1197
                                              const QVector<QRgb> *, QDitherInfo *)
1198
0
{
1199
0
    uint *d = reinterpret_cast<uint *>(dest) + index;
1200
0
    UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | qUnpremultiply(c)); });
1201
0
}
1202
1203
template<QtPixelOrder PixelOrder>
1204
static void QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, int count, const QVector<QRgb> *)
1205
0
{
1206
0
    for (int i = 0; i < count; ++i)
1207
0
        buffer[i] = qConvertA2rgb30ToArgb32<PixelOrder>(buffer[i]);
1208
0
}
Unexecuted instantiation: qdrawhelper.cpp:void convertA2RGB30PMToARGB32PM<(QtPixelOrder)1>(unsigned int*, int, QVector<unsigned int> const*)
Unexecuted instantiation: qdrawhelper.cpp:void convertA2RGB30PMToARGB32PM<(QtPixelOrder)0>(unsigned int*, int, QVector<unsigned int> const*)
1209
1210
template<QtPixelOrder PixelOrder>
1211
static const uint *QT_FASTCALL fetchA2RGB30PMToARGB32PM(uint *buffer, const uchar *s, int index, int count,
1212
                                                        const QVector<QRgb> *, QDitherInfo *dither)
1213
0
{
1214
0
    const uint *src = reinterpret_cast<const uint *>(s) + index;
1215
0
    if (!dither) {
1216
0
        UNALIASED_CONVERSION_LOOP(buffer, src, count, qConvertA2rgb30ToArgb32<PixelOrder>);
1217
0
    } else {
1218
0
        for (int i = 0; i < count; ++i) {
1219
0
            const uint c = src[i];
1220
0
            short d10 = (qt_bayer_matrix[dither->y & 15][(dither->x + i) & 15] << 2);
1221
0
            short a10 = (c >> 30) * 0x155;
1222
0
            short r10 = ((c >> 20) & 0x3ff);
1223
0
            short g10 = ((c >> 10) & 0x3ff);
1224
0
            short b10 = (c & 0x3ff);
1225
0
            if (PixelOrder == PixelOrderBGR)
1226
0
                std::swap(r10, b10);
1227
0
            short a8 = (a10 + ((d10 - a10) >> 8)) >> 2;
1228
0
            short r8 = (r10 + ((d10 - r10) >> 8)) >> 2;
1229
0
            short g8 = (g10 + ((d10 - g10) >> 8)) >> 2;
1230
0
            short b8 = (b10 + ((d10 - b10) >> 8)) >> 2;
1231
0
            buffer[i] = qRgba(r8, g8, b8, a8);
1232
0
        }
1233
0
    }
1234
0
    return buffer;
1235
0
}
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchA2RGB30PMToARGB32PM<(QtPixelOrder)1>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchA2RGB30PMToARGB32PM<(QtPixelOrder)0>(unsigned int*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
1236
1237
#ifdef __SSE2__
1238
template<QtPixelOrder PixelOrder>
1239
static inline void qConvertA2RGB30PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count)
1240
0
{
1241
0
    if (count <= 0)
1242
0
        return;
1243
1244
0
    const __m128i rmask = _mm_set1_epi32(0x3ff00000);
1245
0
    const __m128i gmask = _mm_set1_epi32(0x000ffc00);
1246
0
    const __m128i bmask = _mm_set1_epi32(0x000003ff);
1247
0
    const __m128i afactor = _mm_set1_epi16(0x5555);
1248
0
    int i = 0;
1249
1250
0
    for (; ((uintptr_t)buffer & 0xf) && i < count; ++i)
1251
0
        *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++);
1252
1253
0
    for (; i < count-3; i += 4) {
1254
0
        __m128i vs = _mm_loadu_si128((const __m128i*)src);
1255
0
        src += 4;
1256
0
        __m128i va = _mm_srli_epi32(vs, 30);
1257
0
        __m128i vr = _mm_and_si128(vs, rmask);
1258
0
        __m128i vb = _mm_and_si128(vs, bmask);
1259
0
        __m128i vg = _mm_and_si128(vs, gmask);
1260
0
        va = _mm_mullo_epi16(va, afactor);
1261
0
        vr = _mm_or_si128(_mm_srli_epi32(vr, 14), _mm_srli_epi32(vr, 24));
1262
0
        vg = _mm_or_si128(_mm_srli_epi32(vg, 4), _mm_srli_epi32(vg, 14));
1263
0
        vb = _mm_or_si128(_mm_slli_epi32(vb, 6), _mm_srli_epi32(vb, 4));
1264
0
        __m128i vrb;
1265
0
        if (PixelOrder == PixelOrderRGB)
1266
0
             vrb = _mm_or_si128(vr, _mm_slli_si128(vb, 2));
1267
0
        else
1268
0
             vrb = _mm_or_si128(vb, _mm_slli_si128(vr, 2));
1269
0
        __m128i vga = _mm_or_si128(vg, _mm_slli_si128(va, 2));
1270
0
        _mm_store_si128((__m128i*)(buffer), _mm_unpacklo_epi16(vrb, vga));
1271
0
        buffer += 2;
1272
0
        _mm_store_si128((__m128i*)(buffer), _mm_unpackhi_epi16(vrb, vga));
1273
0
        buffer += 2;
1274
0
    }
1275
1276
0
    SIMD_EPILOGUE(i, count, 3)
1277
0
        *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++);
1278
0
}
Unexecuted instantiation: qdrawhelper.cpp:void qConvertA2RGB30PMToRGBA64PM_sse2<(QtPixelOrder)1>(QRgba64*, unsigned int const*, int)
Unexecuted instantiation: qdrawhelper.cpp:void qConvertA2RGB30PMToRGBA64PM_sse2<(QtPixelOrder)0>(QRgba64*, unsigned int const*, int)
1279
#endif
1280
1281
template<QtPixelOrder PixelOrder>
1282
static const QRgba64 *QT_FASTCALL convertA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
1283
                                                             const QVector<QRgb> *, QDitherInfo *)
1284
0
{
1285
0
#ifdef __SSE2__
1286
0
    qConvertA2RGB30PMToRGBA64PM_sse2<PixelOrder>(buffer, src, count);
1287
#else
1288
    for (int i = 0; i < count; ++i)
1289
        buffer[i] = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]);
1290
#endif
1291
0
    return buffer;
1292
0
}
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* convertA2RGB30PMToRGBA64PM<(QtPixelOrder)1>(QRgba64*, unsigned int const*, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* convertA2RGB30PMToRGBA64PM<(QtPixelOrder)0>(QRgba64*, unsigned int const*, int, QVector<unsigned int> const*, QDitherInfo*)
1293
1294
template<QtPixelOrder PixelOrder>
1295
static const QRgba64 *QT_FASTCALL fetchA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
1296
                                                           const QVector<QRgb> *, QDitherInfo *)
1297
0
{
1298
0
    return convertA2RGB30PMToRGBA64PM<PixelOrder>(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
1299
0
}
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchA2RGB30PMToRGBA64PM<(QtPixelOrder)1>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchA2RGB30PMToRGBA64PM<(QtPixelOrder)0>(QRgba64*, unsigned char const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
1300
1301
template<QtPixelOrder PixelOrder>
1302
static void QT_FASTCALL storeA2RGB30PMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
1303
                                                   const QVector<QRgb> *, QDitherInfo *)
1304
0
{
1305
0
    uint *d = reinterpret_cast<uint *>(dest) + index;
1306
0
    UNALIASED_CONVERSION_LOOP(d, src, count, qConvertArgb32ToA2rgb30<PixelOrder>);
1307
0
}
Unexecuted instantiation: qdrawhelper.cpp:void storeA2RGB30PMFromARGB32PM<(QtPixelOrder)1>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeA2RGB30PMFromARGB32PM<(QtPixelOrder)0>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
1308
1309
template<QtPixelOrder PixelOrder>
1310
static void QT_FASTCALL storeRGB30FromRGB32(uchar *dest, const uint *src, int index, int count,
1311
                                            const QVector<QRgb> *, QDitherInfo *)
1312
0
{
1313
0
    uint *d = reinterpret_cast<uint *>(dest) + index;
1314
0
    UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>);
1315
0
}
Unexecuted instantiation: qdrawhelper.cpp:void storeRGB30FromRGB32<(QtPixelOrder)1>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGB30FromRGB32<(QtPixelOrder)0>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
1316
1317
template<QtPixelOrder PixelOrder>
1318
static void QT_FASTCALL storeRGB30FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1319
                                               const QVector<QRgb> *, QDitherInfo *)
1320
0
{
1321
0
    uint *d = reinterpret_cast<uint *>(dest) + index;
1322
0
    UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>);
1323
0
}
Unexecuted instantiation: qdrawhelper.cpp:void storeRGB30FromARGB32PM<(QtPixelOrder)1>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGB30FromARGB32PM<(QtPixelOrder)0>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
1324
1325
template<bool RGBA>
1326
void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count)
1327
0
{
1328
0
    int i = 0;
1329
0
#ifdef __SSE2__
1330
0
    if (((uintptr_t)dst & 0x7) && count > 0) {
1331
0
        uint s = (*src++).toArgb32();
1332
0
        if (RGBA)
1333
0
            s = ARGB2RGBA(s);
1334
0
        *dst++ = s;
1335
0
        i++;
1336
0
    }
1337
0
    const __m128i vhalf = _mm_set1_epi32(0x80);
1338
0
    const __m128i vzero = _mm_setzero_si128();
1339
0
    for (; i < count-1; i += 2) {
1340
0
        __m128i vs = _mm_loadu_si128((const __m128i*)src);
1341
0
        src += 2;
1342
0
        if (!RGBA) {
1343
0
            vs = _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2));
1344
0
            vs = _mm_shufflehi_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2));
1345
0
        }
1346
0
        __m128i v1 = _mm_unpacklo_epi16(vs, vzero);
1347
0
        __m128i v2 = _mm_unpackhi_epi16(vs, vzero);
1348
0
        v1 = _mm_add_epi32(v1, vhalf);
1349
0
        v2 = _mm_add_epi32(v2, vhalf);
1350
0
        v1 = _mm_sub_epi32(v1, _mm_srli_epi32(v1, 8));
1351
0
        v2 = _mm_sub_epi32(v2, _mm_srli_epi32(v2, 8));
1352
0
        v1 = _mm_srli_epi32(v1, 8);
1353
0
        v2 = _mm_srli_epi32(v2, 8);
1354
0
        v1 = _mm_packs_epi32(v1, v2);
1355
0
        v1 = _mm_packus_epi16(v1, vzero);
1356
0
        _mm_storel_epi64((__m128i*)(dst), v1);
1357
0
        dst += 2;
1358
0
    }
1359
0
#endif
1360
0
    for (; i < count; i++) {
1361
0
        uint s = (*src++).toArgb32();
1362
0
        if (RGBA)
1363
0
            s = ARGB2RGBA(s);
1364
0
        *dst++ = s;
1365
0
    }
1366
0
}
Unexecuted instantiation: void qt_convertRGBA64ToARGB32<false>(unsigned int*, QRgba64 const*, int)
Unexecuted instantiation: void qt_convertRGBA64ToARGB32<true>(unsigned int*, QRgba64 const*, int)
1367
template void qt_convertRGBA64ToARGB32<false>(uint *dst, const QRgba64 *src, int count);
1368
template void qt_convertRGBA64ToARGB32<true>(uint *dst, const QRgba64 *src, int count);
1369
1370
1371
static void QT_FASTCALL storeAlpha8FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1372
                                                const QVector<QRgb> *, QDitherInfo *)
1373
0
{
1374
0
    for (int i = 0; i < count; ++i)
1375
0
        dest[index + i] = qAlpha(src[i]);
1376
0
}
1377
1378
static void QT_FASTCALL storeGrayscale8FromRGB32(uchar *dest, const uint *src, int index, int count,
1379
                                                 const QVector<QRgb> *, QDitherInfo *)
1380
0
{
1381
0
    for (int i = 0; i < count; ++i)
1382
0
        dest[index + i] = qGray(src[i]);
1383
0
}
1384
1385
static void QT_FASTCALL storeGrayscale8FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1386
                                                    const QVector<QRgb> *, QDitherInfo *)
1387
0
{
1388
0
    for (int i = 0; i < count; ++i)
1389
0
        dest[index + i] = qGray(qUnpremultiply(src[i]));
1390
0
}
1391
1392
static void QT_FASTCALL storeGrayscale16FromRGB32(uchar *dest, const uint *src, int index, int count,
1393
                                                 const QVector<QRgb> *, QDitherInfo *)
1394
0
{
1395
0
    unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index;
1396
0
    for (int i = 0; i < count; ++i)
1397
0
        d[i] = qGray(src[i]) * 257;
1398
0
}
1399
1400
static void QT_FASTCALL storeGrayscale16FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1401
                                                    const QVector<QRgb> *, QDitherInfo *)
1402
0
{
1403
0
    unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index;
1404
0
    for (int i = 0; i < count; ++i)
1405
0
        d[i] = qGray(qUnpremultiply(src[i])) * 257;
1406
0
}
1407
1408
static const uint *QT_FASTCALL fetchRGB64ToRGB32(uint *buffer, const uchar *src, int index, int count,
1409
                                                 const QVector<QRgb> *, QDitherInfo *)
1410
0
{
1411
0
    const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
1412
0
    for (int i = 0; i < count; ++i)
1413
0
        buffer[i] = toArgb32(s[i]);
1414
0
    return buffer;
1415
0
}
1416
1417
static void QT_FASTCALL storeRGB64FromRGB32(uchar *dest, const uint *src, int index, int count,
1418
                                            const QVector<QRgb> *, QDitherInfo *)
1419
0
{
1420
0
    QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
1421
0
    for (int i = 0; i < count; ++i)
1422
0
        d[i] = QRgba64::fromArgb32(src[i] | 0xff000000);
1423
0
}
1424
1425
static const uint *QT_FASTCALL fetchRGBA64ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
1426
                                                     const QVector<QRgb> *, QDitherInfo *)
1427
0
{
1428
0
    const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
1429
0
    for (int i = 0; i < count; ++i)
1430
0
        buffer[i] = toArgb32(s[i].premultiplied());
1431
0
    return buffer;
1432
0
}
1433
1434
template<bool Mask>
1435
static void QT_FASTCALL storeRGBA64FromARGB32PM(uchar *dest, const uint *src, int index, int count,
1436
                                                const QVector<QRgb> *, QDitherInfo *)
1437
0
{
1438
0
    QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
1439
0
    for (int i = 0; i < count; ++i) {
1440
0
        d[i] = QRgba64::fromArgb32(src[i]).unpremultiplied();
1441
0
        if (Mask)
1442
0
            d[i].setAlpha(65535);
1443
0
    }
1444
0
}
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBA64FromARGB32PM<true>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGBA64FromARGB32PM<false>(unsigned char*, unsigned int const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
1445
1446
static void QT_FASTCALL storeRGBA64FromARGB32(uchar *dest, const uint *src, int index, int count,
1447
                                              const QVector<QRgb> *, QDitherInfo *)
1448
0
{
1449
0
    QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
1450
0
    for (int i = 0; i < count; ++i)
1451
0
        d[i] = QRgba64::fromArgb32(src[i]);
1452
0
}
1453
1454
// Note:
1455
// convertToArgb32() assumes that no color channel is less than 4 bits.
1456
// storeRGBFromARGB32PM() assumes that no color channel is more than 8 bits.
1457
// QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits.
1458
QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
1459
    { false, false, QPixelLayout::BPPNone, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }, // Format_Invalid
1460
    { false, false, QPixelLayout::BPP1MSB, nullptr,
1461
      convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
1462
      fetchIndexedToARGB32PM<QPixelLayout::BPP1MSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1MSB>,
1463
      nullptr, nullptr }, // Format_Mono
1464
    { false, false, QPixelLayout::BPP1LSB, nullptr,
1465
      convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
1466
      fetchIndexedToARGB32PM<QPixelLayout::BPP1LSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1LSB>,
1467
      nullptr, nullptr }, // Format_MonoLSB
1468
    { false, false, QPixelLayout::BPP8, nullptr,
1469
      convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
1470
      fetchIndexedToARGB32PM<QPixelLayout::BPP8>, fetchIndexedToRGBA64PM<QPixelLayout::BPP8>,
1471
      nullptr, nullptr }, // Format_Indexed8
1472
    // Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong,
1473
    // but everywhere this generic conversion would be wrong is currently overloaded.
1474
    { false, false, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough,
1475
      convertRGB32ToRGB64, fetchPassThrough, fetchRGB32ToRGB64, storePassThrough, storePassThrough }, // Format_RGB32
1476
    { true, false, QPixelLayout::BPP32, rbSwap_rgb32, convertARGB32ToARGB32PM,
1477
      convertARGB32ToRGBA64PM, fetchARGB32ToARGB32PM, fetchARGB32ToRGBA64PM, storeARGB32FromARGB32PM, storePassThrough }, // Format_ARGB32
1478
    { true, true, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough,
1479
      convertARGB32PMToRGBA64PM, fetchPassThrough, fetchARGB32PMToRGBA64PM, storePassThrough, storePassThrough }, // Format_ARGB32_Premultiplied
1480
    pixelLayoutRGB<QImage::Format_RGB16>(),
1481
    pixelLayoutARGBPM<QImage::Format_ARGB8565_Premultiplied>(),
1482
    pixelLayoutRGB<QImage::Format_RGB666>(),
1483
    pixelLayoutARGBPM<QImage::Format_ARGB6666_Premultiplied>(),
1484
    pixelLayoutRGB<QImage::Format_RGB555>(),
1485
    pixelLayoutARGBPM<QImage::Format_ARGB8555_Premultiplied>(),
1486
    pixelLayoutRGB<QImage::Format_RGB888>(),
1487
    pixelLayoutRGB<QImage::Format_RGB444>(),
1488
    pixelLayoutARGBPM<QImage::Format_ARGB4444_Premultiplied>(),
1489
    { false, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM,
1490
      convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBXFromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBX8888
1491
    { true, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888ToARGB32PM,
1492
      convertRGBA8888ToRGBA64PM, fetchRGBA8888ToARGB32PM, fetchRGBA8888ToRGBA64PM, storeRGBA8888FromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBA8888
1493
    { true, true, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM,
1494
      convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBA8888PMFromARGB32PM, storeRGBXFromRGB32 },  // Format_RGBA8888_Premultiplied
1495
    { false, false, QPixelLayout::BPP32, rbSwap_rgb30,
1496
      convertA2RGB30PMToARGB32PM<PixelOrderBGR>,
1497
      convertA2RGB30PMToRGBA64PM<PixelOrderBGR>,
1498
      fetchA2RGB30PMToARGB32PM<PixelOrderBGR>,
1499
      fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>,
1500
      storeRGB30FromARGB32PM<PixelOrderBGR>,
1501
      storeRGB30FromRGB32<PixelOrderBGR>
1502
    }, // Format_BGR30
1503
    { true, true, QPixelLayout::BPP32, rbSwap_rgb30,
1504
      convertA2RGB30PMToARGB32PM<PixelOrderBGR>,
1505
      convertA2RGB30PMToRGBA64PM<PixelOrderBGR>,
1506
      fetchA2RGB30PMToARGB32PM<PixelOrderBGR>,
1507
      fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>,
1508
      storeA2RGB30PMFromARGB32PM<PixelOrderBGR>,
1509
      storeRGB30FromRGB32<PixelOrderBGR>
1510
    },  // Format_A2BGR30_Premultiplied
1511
    { false, false, QPixelLayout::BPP32, rbSwap_rgb30,
1512
      convertA2RGB30PMToARGB32PM<PixelOrderRGB>,
1513
      convertA2RGB30PMToRGBA64PM<PixelOrderRGB>,
1514
      fetchA2RGB30PMToARGB32PM<PixelOrderRGB>,
1515
      fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>,
1516
      storeRGB30FromARGB32PM<PixelOrderRGB>,
1517
      storeRGB30FromRGB32<PixelOrderRGB>
1518
    }, // Format_RGB30
1519
    { true, true, QPixelLayout::BPP32, rbSwap_rgb30,
1520
      convertA2RGB30PMToARGB32PM<PixelOrderRGB>,
1521
      convertA2RGB30PMToRGBA64PM<PixelOrderRGB>,
1522
      fetchA2RGB30PMToARGB32PM<PixelOrderRGB>,
1523
      fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>,
1524
      storeA2RGB30PMFromARGB32PM<PixelOrderRGB>,
1525
      storeRGB30FromRGB32<PixelOrderRGB>
1526
    },  // Format_A2RGB30_Premultiplied
1527
    { true, true, QPixelLayout::BPP8, nullptr,
1528
      convertAlpha8ToRGB32, convertAlpha8ToRGB64,
1529
      fetchAlpha8ToRGB32, fetchAlpha8ToRGB64,
1530
      storeAlpha8FromARGB32PM, nullptr }, // Format_Alpha8
1531
    { false, false, QPixelLayout::BPP8, nullptr,
1532
      convertGrayscale8ToRGB32, convertGrayscale8ToRGB64,
1533
      fetchGrayscale8ToRGB32, fetchGrayscale8ToRGB64,
1534
      storeGrayscale8FromARGB32PM, storeGrayscale8FromRGB32 }, // Format_Grayscale8
1535
    { false, false, QPixelLayout::BPP64, nullptr,
1536
      convertPassThrough, nullptr,
1537
      fetchRGB64ToRGB32, fetchPassThrough64,
1538
      storeRGBA64FromARGB32PM<true>, storeRGB64FromRGB32 }, // Format_RGBX64
1539
    { true, false, QPixelLayout::BPP64, nullptr,
1540
      convertARGB32ToARGB32PM, nullptr,
1541
      fetchRGBA64ToARGB32PM, fetchRGBA64ToRGBA64PM,
1542
      storeRGBA64FromARGB32PM<false>, storeRGB64FromRGB32 }, // Format_RGBA64
1543
    { true, true, QPixelLayout::BPP64, nullptr,
1544
      convertPassThrough, nullptr,
1545
      fetchRGB64ToRGB32, fetchPassThrough64,
1546
      storeRGBA64FromARGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied
1547
    { false, false, QPixelLayout::BPP16, nullptr,
1548
      convertGrayscale16ToRGB32, convertGrayscale16ToRGBA64,
1549
      fetchGrayscale16ToRGB32, fetchGrayscale16ToRGBA64,
1550
      storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 }, // Format_Grayscale16
1551
    pixelLayoutRGB<QImage::Format_BGR888>(),
1552
};
1553
1554
Q_STATIC_ASSERT(sizeof(qPixelLayouts) / sizeof(*qPixelLayouts) == QImage::NImageFormats);
1555
1556
static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int length)
1557
0
{
1558
0
    for (int i = 0; i < length; ++i) {
1559
0
        dest[i] = toArgb32(src[i]);
1560
0
    }
1561
0
}
1562
1563
template<QImage::Format format>
1564
static void QT_FASTCALL storeGenericFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1565
                                                 const QVector<QRgb> *clut, QDitherInfo *dither)
1566
0
{
1567
0
    uint buffer[BufferSize];
1568
0
    convertFromRgb64(buffer, src, count);
1569
0
    qPixelLayouts[format].storeFromARGB32PM(dest, buffer, index, count, clut, dither);
1570
0
}
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)4>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)6>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)7>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)8>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)9>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)10>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)11>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)12>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)13>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)14>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)15>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)16>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)18>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)23>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)24>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeGenericFromRGBA64PM<(QImage::Format)29>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
1571
1572
static void QT_FASTCALL storeARGB32FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1573
                                                const QVector<QRgb> *, QDitherInfo *)
1574
0
{
1575
0
    uint *d = (uint*)dest + index;
1576
0
    for (int i = 0; i < count; ++i)
1577
0
        d[i] = toArgb32(src[i].unpremultiplied());
1578
0
}
1579
1580
static void QT_FASTCALL storeRGBA8888FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1581
                                                  const QVector<QRgb> *, QDitherInfo *)
1582
0
{
1583
0
    uint *d = (uint*)dest + index;
1584
0
    for (int i = 0; i < count; ++i)
1585
0
        d[i] = toRgba8888(src[i].unpremultiplied());
1586
0
}
1587
1588
template<QtPixelOrder PixelOrder>
1589
static void QT_FASTCALL storeRGB30FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1590
                                               const QVector<QRgb> *, QDitherInfo *)
1591
0
{
1592
0
    uint *d = (uint*)dest + index;
1593
0
#ifdef __SSE2__
1594
0
    qConvertRGBA64PMToA2RGB30PM_sse2<PixelOrder>(d, src, count);
1595
#else
1596
    for (int i = 0; i < count; ++i)
1597
        d[i] = qConvertRgb64ToRgb30<PixelOrder>(src[i]);
1598
#endif
1599
0
}
Unexecuted instantiation: qdrawhelper.cpp:void storeRGB30FromRGBA64PM<(QtPixelOrder)1>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
Unexecuted instantiation: qdrawhelper.cpp:void storeRGB30FromRGBA64PM<(QtPixelOrder)0>(unsigned char*, QRgba64 const*, int, int, QVector<unsigned int> const*, QDitherInfo*)
1600
1601
static void QT_FASTCALL storeRGBX64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1602
                                                const QVector<QRgb> *, QDitherInfo *)
1603
0
{
1604
0
    QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
1605
0
    for (int i = 0; i < count; ++i) {
1606
0
        d[i] = src[i].unpremultiplied();
1607
0
        d[i].setAlpha(65535);
1608
0
    }
1609
0
}
1610
1611
static void QT_FASTCALL storeRGBA64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1612
                                                const QVector<QRgb> *, QDitherInfo *)
1613
0
{
1614
0
    QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
1615
0
    for (int i = 0; i < count; ++i)
1616
0
        d[i] = src[i].unpremultiplied();
1617
0
}
1618
1619
static void QT_FASTCALL storeRGBA64PMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1620
                                                  const QVector<QRgb> *, QDitherInfo *)
1621
0
{
1622
0
    QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
1623
0
    if (d != src)
1624
0
        memcpy(d, src, count * sizeof(QRgba64));
1625
0
}
1626
1627
static void QT_FASTCALL storeGray16FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
1628
                                                const QVector<QRgb> *, QDitherInfo *)
1629
0
{
1630
0
    quint16 *d = reinterpret_cast<quint16*>(dest) + index;
1631
0
    for (int i = 0; i < count; ++i) {
1632
0
        QRgba64 s =  src[i].unpremultiplied();
1633
0
        d[i] = qGray(s.red(), s.green(), s.blue());
1634
0
    }
1635
0
}
1636
1637
ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats] = {
1638
    nullptr,
1639
    nullptr,
1640
    nullptr,
1641
    nullptr,
1642
    storeGenericFromRGBA64PM<QImage::Format_RGB32>,
1643
    storeARGB32FromRGBA64PM,
1644
    storeGenericFromRGBA64PM<QImage::Format_ARGB32_Premultiplied>,
1645
    storeGenericFromRGBA64PM<QImage::Format_RGB16>,
1646
    storeGenericFromRGBA64PM<QImage::Format_ARGB8565_Premultiplied>,
1647
    storeGenericFromRGBA64PM<QImage::Format_RGB666>,
1648
    storeGenericFromRGBA64PM<QImage::Format_ARGB6666_Premultiplied>,
1649
    storeGenericFromRGBA64PM<QImage::Format_RGB555>,
1650
    storeGenericFromRGBA64PM<QImage::Format_ARGB8555_Premultiplied>,
1651
    storeGenericFromRGBA64PM<QImage::Format_RGB888>,
1652
    storeGenericFromRGBA64PM<QImage::Format_RGB444>,
1653
    storeGenericFromRGBA64PM<QImage::Format_ARGB4444_Premultiplied>,
1654
    storeGenericFromRGBA64PM<QImage::Format_RGBX8888>,
1655
    storeRGBA8888FromRGBA64PM,
1656
    storeGenericFromRGBA64PM<QImage::Format_RGBA8888_Premultiplied>,
1657
    storeRGB30FromRGBA64PM<PixelOrderBGR>,
1658
    storeRGB30FromRGBA64PM<PixelOrderBGR>,
1659
    storeRGB30FromRGBA64PM<PixelOrderRGB>,
1660
    storeRGB30FromRGBA64PM<PixelOrderRGB>,
1661
    storeGenericFromRGBA64PM<QImage::Format_Alpha8>,
1662
    storeGenericFromRGBA64PM<QImage::Format_Grayscale8>,
1663
    storeRGBX64FromRGBA64PM,
1664
    storeRGBA64FromRGBA64PM,
1665
    storeRGBA64PMFromRGBA64PM,
1666
    storeGray16FromRGBA64PM,
1667
    storeGenericFromRGBA64PM<QImage::Format_BGR888>,
1668
};
1669
1670
/*
1671
  Destination fetch. This is simple as we don't have to do bounds checks or
1672
  transformations
1673
*/
1674
1675
static uint * QT_FASTCALL destFetchMono(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
1676
0
{
1677
0
    uchar *Q_DECL_RESTRICT data = (uchar *)rasterBuffer->scanLine(y);
1678
0
    uint *start = buffer;
1679
0
    const uint *end = buffer + length;
1680
0
    while (buffer < end) {
1681
0
        *buffer = data[x>>3] & (0x80 >> (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
1682
0
        ++buffer;
1683
0
        ++x;
1684
0
    }
1685
0
    return start;
1686
0
}
1687
1688
static uint * QT_FASTCALL destFetchMonoLsb(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
1689
0
{
1690
0
    uchar *Q_DECL_RESTRICT data = (uchar *)rasterBuffer->scanLine(y);
1691
0
    uint *start = buffer;
1692
0
    const uint *end = buffer + length;
1693
0
    while (buffer < end) {
1694
0
        *buffer = data[x>>3] & (0x1 << (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
1695
0
        ++buffer;
1696
0
        ++x;
1697
0
    }
1698
0
    return start;
1699
0
}
1700
1701
static uint * QT_FASTCALL destFetchARGB32P(uint *, QRasterBuffer *rasterBuffer, int x, int y, int)
1702
0
{
1703
0
    return (uint *)rasterBuffer->scanLine(y) + x;
1704
0
}
1705
1706
static uint * QT_FASTCALL destFetchRGB16(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
1707
0
{
1708
0
    const ushort *Q_DECL_RESTRICT data = (const ushort *)rasterBuffer->scanLine(y) + x;
1709
0
    for (int i = 0; i < length; ++i)
1710
0
        buffer[i] = qConvertRgb16To32(data[i]);
1711
0
    return buffer;
1712
0
}
1713
1714
static uint *QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
1715
0
{
1716
0
    const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
1717
0
    return const_cast<uint *>(layout->fetchToARGB32PM(buffer, rasterBuffer->scanLine(y), x, length, nullptr, nullptr));
1718
0
}
1719
1720
static uint *QT_FASTCALL destFetchUndefined(uint *buffer, QRasterBuffer *, int, int, int)
1721
0
{
1722
0
    return buffer;
1723
0
}
1724
1725
static DestFetchProc destFetchProc[QImage::NImageFormats] =
1726
{
1727
    nullptr,            // Format_Invalid
1728
    destFetchMono,      // Format_Mono,
1729
    destFetchMonoLsb,   // Format_MonoLSB
1730
    nullptr,            // Format_Indexed8
1731
    destFetchARGB32P,   // Format_RGB32
1732
    destFetch,          // Format_ARGB32,
1733
    destFetchARGB32P,   // Format_ARGB32_Premultiplied
1734
    destFetchRGB16,     // Format_RGB16
1735
    destFetch,          // Format_ARGB8565_Premultiplied
1736
    destFetch,          // Format_RGB666
1737
    destFetch,          // Format_ARGB6666_Premultiplied
1738
    destFetch,          // Format_RGB555
1739
    destFetch,          // Format_ARGB8555_Premultiplied
1740
    destFetch,          // Format_RGB888
1741
    destFetch,          // Format_RGB444
1742
    destFetch,          // Format_ARGB4444_Premultiplied
1743
    destFetch,          // Format_RGBX8888
1744
    destFetch,          // Format_RGBA8888
1745
    destFetch,          // Format_RGBA8888_Premultiplied
1746
    destFetch,          // Format_BGR30
1747
    destFetch,          // Format_A2BGR30_Premultiplied
1748
    destFetch,          // Format_RGB30
1749
    destFetch,          // Format_A2RGB30_Premultiplied
1750
    destFetch,          // Format_Alpha8
1751
    destFetch,          // Format_Grayscale8
1752
    destFetch,          // Format_RGBX64
1753
    destFetch,          // Format_RGBA64
1754
    destFetch,          // Format_RGBA64_Premultiplied
1755
    destFetch,          // Format_Grayscale16
1756
    destFetch,          // Format_BGR888
1757
};
1758
1759
#if QT_CONFIG(raster_64bit)
1760
static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
1761
0
{
1762
0
    const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
1763
0
    return const_cast<QRgba64 *>(layout->fetchToRGBA64PM(buffer, rasterBuffer->scanLine(y), x, length, nullptr, nullptr));
1764
0
}
1765
1766
static QRgba64 * QT_FASTCALL destFetchRGB64(QRgba64 *, QRasterBuffer *rasterBuffer, int x, int y, int)
1767
0
{
1768
0
    return (QRgba64 *)rasterBuffer->scanLine(y) + x;
1769
0
}
1770
1771
static QRgba64 * QT_FASTCALL destFetch64Undefined(QRgba64 *buffer, QRasterBuffer *, int, int, int)
1772
0
{
1773
0
    return buffer;
1774
0
}
1775
1776
static DestFetchProc64 destFetchProc64[QImage::NImageFormats] =
1777
{
1778
    nullptr,            // Format_Invalid
1779
    nullptr,            // Format_Mono,
1780
    nullptr,            // Format_MonoLSB
1781
    nullptr,            // Format_Indexed8
1782
    destFetch64,        // Format_RGB32
1783
    destFetch64,        // Format_ARGB32,
1784
    destFetch64,        // Format_ARGB32_Premultiplied
1785
    destFetch64,        // Format_RGB16
1786
    destFetch64,        // Format_ARGB8565_Premultiplied
1787
    destFetch64,        // Format_RGB666
1788
    destFetch64,        // Format_ARGB6666_Premultiplied
1789
    destFetch64,        // Format_RGB555
1790
    destFetch64,        // Format_ARGB8555_Premultiplied
1791
    destFetch64,        // Format_RGB888
1792
    destFetch64,        // Format_RGB444
1793
    destFetch64,        // Format_ARGB4444_Premultiplied
1794
    destFetch64,        // Format_RGBX8888
1795
    destFetch64,        // Format_RGBA8888
1796
    destFetch64,        // Format_RGBA8888_Premultiplied
1797
    destFetch64,        // Format_BGR30
1798
    destFetch64,        // Format_A2BGR30_Premultiplied
1799
    destFetch64,        // Format_RGB30
1800
    destFetch64,        // Format_A2RGB30_Premultiplied
1801
    destFetch64,        // Format_Alpha8
1802
    destFetch64,        // Format_Grayscale8
1803
    destFetchRGB64,     // Format_RGBX64
1804
    destFetch64,        // Format_RGBA64
1805
    destFetchRGB64,     // Format_RGBA64_Premultiplied
1806
    destFetch64,        // Format_Grayscale16
1807
    destFetch64,        // Format_BGR888
1808
};
1809
#endif
1810
1811
/*
1812
   Returns the color in the mono destination color table
1813
   that is the "nearest" to /color/.
1814
*/
1815
static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf)
1816
0
{
1817
0
    QRgb color_0 = qPremultiply(rbuf->destColor0);
1818
0
    QRgb color_1 = qPremultiply(rbuf->destColor1);
1819
0
    color = qPremultiply(color);
1820
1821
0
    int r = qRed(color);
1822
0
    int g = qGreen(color);
1823
0
    int b = qBlue(color);
1824
0
    int rx, gx, bx;
1825
0
    int dist_0, dist_1;
1826
1827
0
    rx = r - qRed(color_0);
1828
0
    gx = g - qGreen(color_0);
1829
0
    bx = b - qBlue(color_0);
1830
0
    dist_0 = rx*rx + gx*gx + bx*bx;
1831
1832
0
    rx = r - qRed(color_1);
1833
0
    gx = g - qGreen(color_1);
1834
0
    bx = b - qBlue(color_1);
1835
0
    dist_1 = rx*rx + gx*gx + bx*bx;
1836
1837
0
    if (dist_0 < dist_1)
1838
0
        return color_0;
1839
0
    return color_1;
1840
0
}
1841
1842
/*
1843
  Destination store.
1844
*/
1845
1846
static void QT_FASTCALL destStoreMono(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
1847
0
{
1848
0
    uchar *Q_DECL_RESTRICT data = (uchar *)rasterBuffer->scanLine(y);
1849
0
    if (rasterBuffer->monoDestinationWithClut) {
1850
0
        for (int i = 0; i < length; ++i) {
1851
0
            if (buffer[i] == rasterBuffer->destColor0) {
1852
0
                data[x >> 3] &= ~(0x80 >> (x & 7));
1853
0
            } else if (buffer[i] == rasterBuffer->destColor1) {
1854
0
                data[x >> 3] |= 0x80 >> (x & 7);
1855
0
            } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
1856
0
                data[x >> 3] &= ~(0x80 >> (x & 7));
1857
0
            } else {
1858
0
                data[x >> 3] |= 0x80 >> (x & 7);
1859
0
            }
1860
0
            ++x;
1861
0
        }
1862
0
    } else {
1863
0
        for (int i = 0; i < length; ++i) {
1864
0
            if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
1865
0
                data[x >> 3] |= 0x80 >> (x & 7);
1866
0
            else
1867
0
                data[x >> 3] &= ~(0x80 >> (x & 7));
1868
0
            ++x;
1869
0
        }
1870
0
    }
1871
0
}
1872
1873
static void QT_FASTCALL destStoreMonoLsb(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
1874
0
{
1875
0
    uchar *Q_DECL_RESTRICT data = (uchar *)rasterBuffer->scanLine(y);
1876
0
    if (rasterBuffer->monoDestinationWithClut) {
1877
0
        for (int i = 0; i < length; ++i) {
1878
0
            if (buffer[i] == rasterBuffer->destColor0) {
1879
0
                data[x >> 3] &= ~(1 << (x & 7));
1880
0
            } else if (buffer[i] == rasterBuffer->destColor1) {
1881
0
                data[x >> 3] |= 1 << (x & 7);
1882
0
            } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
1883
0
                data[x >> 3] &= ~(1 << (x & 7));
1884
0
            } else {
1885
0
                data[x >> 3] |= 1 << (x & 7);
1886
0
            }
1887
0
            ++x;
1888
0
        }
1889
0
    } else {
1890
0
        for (int i = 0; i < length; ++i) {
1891
0
            if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
1892
0
                data[x >> 3] |= 1 << (x & 7);
1893
0
            else
1894
0
                data[x >> 3] &= ~(1 << (x & 7));
1895
0
            ++x;
1896
0
        }
1897
0
    }
1898
0
}
1899
1900
static void QT_FASTCALL destStoreRGB16(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
1901
0
{
1902
0
    quint16 *data = (quint16*)rasterBuffer->scanLine(y) + x;
1903
0
    for (int i = 0; i < length; ++i)
1904
0
        data[i] = qConvertRgb32To16(buffer[i]);
1905
0
}
1906
1907
static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
1908
0
{
1909
0
    const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
1910
0
    ConvertAndStorePixelsFunc store = layout->storeFromARGB32PM;
1911
0
    if (!layout->premultiplied && !layout->hasAlphaChannel)
1912
0
        store = layout->storeFromRGB32;
1913
0
    uchar *dest = rasterBuffer->scanLine(y);
1914
0
    store(dest, buffer, x, length, nullptr, nullptr);
1915
0
}
1916
1917
static DestStoreProc destStoreProc[QImage::NImageFormats] =
1918
{
1919
    nullptr,            // Format_Invalid
1920
    destStoreMono,      // Format_Mono,
1921
    destStoreMonoLsb,   // Format_MonoLSB
1922
    nullptr,            // Format_Indexed8
1923
    nullptr,            // Format_RGB32
1924
    destStore,          // Format_ARGB32,
1925
    nullptr,            // Format_ARGB32_Premultiplied
1926
    destStoreRGB16,     // Format_RGB16
1927
    destStore,          // Format_ARGB8565_Premultiplied
1928
    destStore,          // Format_RGB666
1929
    destStore,          // Format_ARGB6666_Premultiplied
1930
    destStore,          // Format_RGB555
1931
    destStore,          // Format_ARGB8555_Premultiplied
1932
    destStore,          // Format_RGB888
1933
    destStore,          // Format_RGB444
1934
    destStore,          // Format_ARGB4444_Premultiplied
1935
    destStore,          // Format_RGBX8888
1936
    destStore,          // Format_RGBA8888
1937
    destStore,          // Format_RGBA8888_Premultiplied
1938
    destStore,          // Format_BGR30
1939
    destStore,          // Format_A2BGR30_Premultiplied
1940
    destStore,          // Format_RGB30
1941
    destStore,          // Format_A2RGB30_Premultiplied
1942
    destStore,          // Format_Alpha8
1943
    destStore,          // Format_Grayscale8
1944
    destStore,          // Format_RGBX64
1945
    destStore,          // Format_RGBA64
1946
    destStore,          // Format_RGBA64_Premultiplied
1947
    destStore,          // Format_Grayscale16
1948
    destStore,          // Format_BGR888
1949
};
1950
1951
#if QT_CONFIG(raster_64bit)
1952
static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length)
1953
0
{
1954
0
    auto store = qStoreFromRGBA64PM[rasterBuffer->format];
1955
0
    uchar *dest = rasterBuffer->scanLine(y);
1956
0
    store(dest, buffer, x, length, nullptr, nullptr);
1957
0
}
1958
1959
static void QT_FASTCALL destStore64RGBA64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length)
1960
0
{
1961
0
    QRgba64 *dest = reinterpret_cast<QRgba64*>(rasterBuffer->scanLine(y)) + x;
1962
0
    for (int i = 0; i < length; ++i) {
1963
0
        dest[i] = buffer[i].unpremultiplied();
1964
0
    }
1965
0
}
1966
1967
static DestStoreProc64 destStoreProc64[QImage::NImageFormats] =
1968
{
1969
    nullptr,            // Format_Invalid
1970
    nullptr,            // Format_Mono,
1971
    nullptr,            // Format_MonoLSB
1972
    nullptr,            // Format_Indexed8
1973
    destStore64,        // Format_RGB32
1974
    destStore64,        // Format_ARGB32,
1975
    destStore64,        // Format_ARGB32_Premultiplied
1976
    destStore64,        // Format_RGB16
1977
    destStore64,        // Format_ARGB8565_Premultiplied
1978
    destStore64,        // Format_RGB666
1979
    destStore64,        // Format_ARGB6666_Premultiplied
1980
    destStore64,        // Format_RGB555
1981
    destStore64,        // Format_ARGB8555_Premultiplied
1982
    destStore64,        // Format_RGB888
1983
    destStore64,        // Format_RGB444
1984
    destStore64,        // Format_ARGB4444_Premultiplied
1985
    destStore64,        // Format_RGBX8888
1986
    destStore64,        // Format_RGBA8888
1987
    destStore64,        // Format_RGBA8888_Premultiplied
1988
    destStore64,        // Format_BGR30
1989
    destStore64,        // Format_A2BGR30_Premultiplied
1990
    destStore64,        // Format_RGB30
1991
    destStore64,        // Format_A2RGB30_Premultiplied
1992
    destStore64,        // Format_Alpha8
1993
    destStore64,        // Format_Grayscale8
1994
    nullptr,            // Format_RGBX64
1995
    destStore64RGBA64,  // Format_RGBA64
1996
    nullptr,            // Format_RGBA64_Premultiplied
1997
    destStore64,        // Format_Grayscale16
1998
    destStore64,        // Format_BGR888
1999
};
2000
#endif
2001
2002
/*
2003
  Source fetches
2004
2005
  This is a bit more complicated, as we need several fetch routines for every surface type
2006
2007
  We need 5 fetch methods per surface type:
2008
  untransformed
2009
  transformed (tiled and not tiled)
2010
  transformed bilinear (tiled and not tiled)
2011
2012
  We don't need bounds checks for untransformed, but we need them for the other ones.
2013
2014
  The generic implementation does pixel by pixel fetches
2015
*/
2016
2017
enum TextureBlendType {
2018
    BlendUntransformed,
2019
    BlendTiled,
2020
    BlendTransformed,
2021
    BlendTransformedTiled,
2022
    BlendTransformedBilinear,
2023
    BlendTransformedBilinearTiled,
2024
    NBlendTypes
2025
};
2026
2027
static const uint *QT_FASTCALL fetchUntransformed(uint *buffer, const Operator *,
2028
                                                  const QSpanData *data, int y, int x, int length)
2029
0
{
2030
0
    const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
2031
0
    return layout->fetchToARGB32PM(buffer, data->texture.scanLine(y), x, length, data->texture.colorTable, nullptr);
2032
0
}
2033
2034
static const uint *QT_FASTCALL fetchUntransformedARGB32PM(uint *, const Operator *,
2035
                                                          const QSpanData *data, int y, int x, int)
2036
0
{
2037
0
    const uchar *scanLine = data->texture.scanLine(y);
2038
0
    return reinterpret_cast<const uint *>(scanLine) + x;
2039
0
}
2040
2041
static const uint *QT_FASTCALL fetchUntransformedRGB16(uint *buffer, const Operator *,
2042
                                                       const QSpanData *data, int y, int x,
2043
                                                       int length)
2044
0
{
2045
0
    const quint16 *scanLine = (const quint16 *)data->texture.scanLine(y) + x;
2046
0
    for (int i = 0; i < length; ++i)
2047
0
        buffer[i] = qConvertRgb16To32(scanLine[i]);
2048
0
    return buffer;
2049
0
}
2050
2051
#if QT_CONFIG(raster_64bit)
2052
static const QRgba64 *QT_FASTCALL fetchUntransformed64(QRgba64 *buffer, const Operator *,
2053
                                                       const QSpanData *data, int y, int x, int length)
2054
0
{
2055
0
    const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
2056
0
    return layout->fetchToRGBA64PM(buffer, data->texture.scanLine(y), x, length, data->texture.colorTable, nullptr);
2057
0
}
2058
2059
static const QRgba64 *QT_FASTCALL fetchUntransformedRGBA64PM(QRgba64 *, const Operator *,
2060
                                                             const QSpanData *data, int y, int x, int)
2061
0
{
2062
0
    const uchar *scanLine = data->texture.scanLine(y);
2063
0
    return reinterpret_cast<const QRgba64 *>(scanLine) + x;
2064
0
}
2065
#endif
2066
2067
template<TextureBlendType blendType>
2068
inline void fetchTransformed_pixelBounds(int max, int l1, int l2, int &v)
2069
0
{
2070
0
    Q_STATIC_ASSERT(blendType == BlendTransformed || blendType == BlendTransformedTiled);
2071
0
    if (blendType == BlendTransformedTiled) {
2072
0
        if (v < 0 || v >= max) {
2073
0
            v %= max;
2074
0
            if (v < 0) v += max;
2075
0
        }
2076
0
    } else {
2077
0
        v = qBound(l1, v, l2);
2078
0
    }
2079
0
}
Unexecuted instantiation: void fetchTransformed_pixelBounds<(TextureBlendType)2>(int, int, int, int&)
Unexecuted instantiation: void fetchTransformed_pixelBounds<(TextureBlendType)3>(int, int, int, int&)
2080
2081
static inline bool canUseFastMatrixPath(const qreal cx, const qreal cy, const qsizetype length, const QSpanData *data)
2082
0
{
2083
0
    if (Q_UNLIKELY(!data->fast_matrix))
2084
0
        return false;
2085
2086
0
    qreal fx = (data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale;
2087
0
    qreal fy = (data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale;
2088
0
    qreal minc = std::min(fx, fy);
2089
0
    qreal maxc = std::max(fx, fy);
2090
0
    fx += std::trunc(data->m11 * fixed_scale) * length;
2091
0
    fy += std::trunc(data->m12 * fixed_scale) * length;
2092
0
    minc = std::min(minc, std::min(fx, fy));
2093
0
    maxc = std::max(maxc, std::max(fx, fy));
2094
2095
0
    return minc >= std::numeric_limits<int>::min() && maxc <= std::numeric_limits<int>::max();
2096
0
}
2097
2098
template<TextureBlendType blendType, QPixelLayout::BPP bpp, typename T>
2099
static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *data,
2100
                                                 int y, int x, int length)
2101
0
{
2102
0
    Q_STATIC_ASSERT(blendType == BlendTransformed || blendType == BlendTransformedTiled);
2103
0
    const QTextureData &image = data->texture;
2104
2105
0
    const qreal cx = x + qreal(0.5);
2106
0
    const qreal cy = y + qreal(0.5);
2107
2108
0
    constexpr bool useFetch = (bpp < QPixelLayout::BPP32) && sizeof(T) == sizeof(uint);
2109
0
    const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
2110
0
    if (!useFetch)
2111
0
        Q_ASSERT(layout->bpp == bpp);
2112
    // When templated 'fetch' should be inlined at compile time:
2113
0
    const FetchPixelFunc fetch = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout->bpp] : FetchPixelFunc(fetchPixel<bpp>);
2114
2115
0
    if (canUseFastMatrixPath(cx, cy, length, data)) {
2116
        // The increment pr x in the scanline
2117
0
        int fdx = (int)(data->m11 * fixed_scale);
2118
0
        int fdy = (int)(data->m12 * fixed_scale);
2119
2120
0
        int fx = int((data->m21 * cy
2121
0
                      + data->m11 * cx + data->dx) * fixed_scale);
2122
0
        int fy = int((data->m22 * cy
2123
0
                      + data->m12 * cx + data->dy) * fixed_scale);
2124
2125
0
        if (fdy == 0) { // simple scale, no rotation or shear
2126
0
            int py = (fy >> 16);
2127
0
            fetchTransformed_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, py);
2128
0
            const uchar *src = image.scanLine(py);
2129
2130
0
            int i = 0;
2131
0
            if (blendType == BlendTransformed) {
2132
0
                int fastLen = length;
2133
0
                if (fdx > 0)
2134
0
                    fastLen = qMin(fastLen, int((qint64(image.x2 - 1) * fixed_scale - fx) / fdx));
2135
0
                else if (fdx < 0)
2136
0
                    fastLen = qMin(fastLen, int((qint64(image.x1) * fixed_scale - fx) / fdx));
2137
2138
0
                for (; i < fastLen; ++i) {
2139
0
                    int x1 = (fx >> 16);
2140
0
                    int x2 = x1;
2141
0
                    fetchTransformed_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1);
2142
0
                    if (x1 == x2)
2143
0
                        break;
2144
0
                    if (useFetch)
2145
0
                        buffer[i] = fetch(src, x1);
2146
0
                    else
2147
0
                        buffer[i] = reinterpret_cast<const T*>(src)[x1];
2148
0
                    fx += fdx;
2149
0
                }
2150
2151
0
                for (; i < fastLen; ++i) {
2152
0
                    int px = (fx >> 16);
2153
0
                    if (useFetch)
2154
0
                        buffer[i] = fetch(src, px);
2155
0
                    else
2156
0
                        buffer[i] = reinterpret_cast<const T*>(src)[px];
2157
0
                    fx += fdx;
2158
0
                }
2159
0
            }
2160
2161
0
            for (; i < length; ++i) {
2162
0
                int px = (fx >> 16);
2163
0
                fetchTransformed_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, px);
2164
0
                if (useFetch)
2165
0
                    buffer[i] = fetch(src, px);
2166
0
                else
2167
0
                    buffer[i] = reinterpret_cast<const T*>(src)[px];
2168
0
                fx += fdx;
2169
0
            }
2170
0
        } else { // rotation or shear
2171
0
            int i = 0;
2172
0
            if (blendType == BlendTransformed) {
2173
0
                int fastLen = length;
2174
0
                if (fdx > 0)
2175
0
                    fastLen = qMin(fastLen, int((qint64(image.x2 - 1) * fixed_scale - fx) / fdx));
2176
0
                else if (fdx < 0)
2177
0
                    fastLen = qMin(fastLen, int((qint64(image.x1) * fixed_scale - fx) / fdx));
2178
0
                if (fdy > 0)
2179
0
                    fastLen = qMin(fastLen, int((qint64(image.y2 - 1) * fixed_scale - fy) / fdy));
2180
0
                else if (fdy < 0)
2181
0
                    fastLen = qMin(fastLen, int((qint64(image.y1) * fixed_scale - fy) / fdy));
2182
2183
0
                for (; i < fastLen; ++i) {
2184
0
                    int x1 = (fx >> 16);
2185
0
                    int y1 = (fy >> 16);
2186
0
                    int x2 = x1;
2187
0
                    int y2 = y1;
2188
0
                    fetchTransformed_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1);
2189
0
                    fetchTransformed_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1);
2190
0
                    if (x1 == x2 && y1 == y2)
2191
0
                        break;
2192
0
                    if (useFetch)
2193
0
                        buffer[i] = fetch(image.scanLine(y1), x1);
2194
0
                    else
2195
0
                        buffer[i] = reinterpret_cast<const T*>(image.scanLine(y1))[x1];
2196
0
                    fx += fdx;
2197
0
                    fy += fdy;
2198
0
                }
2199
2200
0
                for (; i < fastLen; ++i) {
2201
0
                    int px = (fx >> 16);
2202
0
                    int py = (fy >> 16);
2203
0
                    if (useFetch)
2204
0
                        buffer[i] = fetch(image.scanLine(py), px);
2205
0
                    else
2206
0
                        buffer[i] = reinterpret_cast<const T*>(image.scanLine(py))[px];
2207
0
                    fx += fdx;
2208
0
                    fy += fdy;
2209
0
                }
2210
0
            }
2211
2212
0
            for (; i < length; ++i) {
2213
0
                int px = (fx >> 16);
2214
0
                int py = (fy >> 16);
2215
0
                fetchTransformed_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, px);
2216
0
                fetchTransformed_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, py);
2217
0
                if (useFetch)
2218
0
                    buffer[i] = fetch(image.scanLine(py), px);
2219
0
                else
2220
0
                    buffer[i] = reinterpret_cast<const T*>(image.scanLine(py))[px];
2221
0
                fx += fdx;
2222
0
                fy += fdy;
2223
0
            }
2224
0
        }
2225
0
    } else {
2226
0
        const qreal fdx = data->m11;
2227
0
        const qreal fdy = data->m12;
2228
0
        const qreal fdw = data->m13;
2229
2230
0
        qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
2231
0
        qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
2232
0
        qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
2233
2234
0
        T *const end = buffer + length;
2235
0
        T *b = buffer;
2236
0
        while (b < end) {
2237
0
            const qreal iw = fw == 0 ? 1 : 1 / fw;
2238
0
            const qreal tx = fx * iw;
2239
0
            const qreal ty = fy * iw;
2240
0
            int px = qFloor(tx);
2241
0
            int py = qFloor(ty);
2242
2243
0
            fetchTransformed_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, py);
2244
0
            fetchTransformed_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, px);
2245
0
            if (useFetch)
2246
0
                *b = fetch(image.scanLine(py), px);
2247
0
            else
2248
0
                *b = reinterpret_cast<const T*>(image.scanLine(py))[px];
2249
2250
0
            fx += fdx;
2251
0
            fy += fdy;
2252
0
            fw += fdw;
2253
            //force increment to avoid /0
2254
0
            if (!fw) {
2255
0
                fw += fdw;
2256
0
            }
2257
0
            ++b;
2258
0
        }
2259
0
    }
2260
0
}
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformed_fetcher<(TextureBlendType)2, (QPixelLayout::BPP)6, unsigned int>(unsigned int*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformed_fetcher<(TextureBlendType)3, (QPixelLayout::BPP)6, unsigned int>(unsigned int*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformed_fetcher<(TextureBlendType)2, (QPixelLayout::BPP)4, unsigned int>(unsigned int*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformed_fetcher<(TextureBlendType)3, (QPixelLayout::BPP)4, unsigned int>(unsigned int*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformed_fetcher<(TextureBlendType)2, (QPixelLayout::BPP)0, unsigned int>(unsigned int*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformed_fetcher<(TextureBlendType)3, (QPixelLayout::BPP)0, unsigned int>(unsigned int*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformed_fetcher<(TextureBlendType)2, (QPixelLayout::BPP)7, QRgba64>(QRgba64*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformed_fetcher<(TextureBlendType)3, (QPixelLayout::BPP)7, QRgba64>(QRgba64*, QSpanData const*, int, int, int)
2261
2262
template<TextureBlendType blendType, QPixelLayout::BPP bpp>
2263
static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data,
2264
                                                int y, int x, int length)
2265
0
{
2266
0
    Q_STATIC_ASSERT(blendType == BlendTransformed || blendType == BlendTransformedTiled);
2267
0
    const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
2268
0
    fetchTransformed_fetcher<blendType, bpp, uint>(buffer, data, y, x, length);
2269
0
    layout->convertToARGB32PM(buffer, length, data->texture.colorTable);
2270
0
    return buffer;
2271
0
}
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformed<(TextureBlendType)2, (QPixelLayout::BPP)6>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformed<(TextureBlendType)3, (QPixelLayout::BPP)6>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformed<(TextureBlendType)2, (QPixelLayout::BPP)4>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformed<(TextureBlendType)3, (QPixelLayout::BPP)4>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformed<(TextureBlendType)2, (QPixelLayout::BPP)0>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformed<(TextureBlendType)3, (QPixelLayout::BPP)0>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
2272
2273
#if QT_CONFIG(raster_64bit)
2274
template<TextureBlendType blendType>  /* either BlendTransformed or BlendTransformedTiled */
2275
static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Operator *, const QSpanData *data,
2276
                                                     int y, int x, int length)
2277
0
{
2278
0
    const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
2279
0
    if (layout->bpp != QPixelLayout::BPP64) {
2280
0
        uint buffer32[BufferSize];
2281
0
        Q_ASSERT(length <= BufferSize);
2282
0
        if (layout->bpp == QPixelLayout::BPP32)
2283
0
            fetchTransformed_fetcher<blendType, QPixelLayout::BPP32, uint>(buffer32, data, y, x, length);
2284
0
        else
2285
0
            fetchTransformed_fetcher<blendType, QPixelLayout::BPPNone, uint>(buffer32, data, y, x, length);
2286
0
        return layout->convertToRGBA64PM(buffer, buffer32, length, data->texture.colorTable, nullptr);
2287
0
    }
2288
2289
0
    fetchTransformed_fetcher<blendType, QPixelLayout::BPP64, QRgba64>(buffer, data, y, x, length);
2290
0
    if (data->texture.format == QImage::Format_RGBA64)
2291
0
        convertRGBA64ToRGBA64PM(buffer, length);
2292
0
    return buffer;
2293
0
}
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchTransformed64<(TextureBlendType)2>(QRgba64*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchTransformed64<(TextureBlendType)3>(QRgba64*, Operator const*, QSpanData const*, int, int, int)
2294
#endif
2295
2296
/** \internal
2297
  interpolate 4 argb pixels with the distx and disty factor.
2298
  distx and disty must be between 0 and 16
2299
 */
2300
static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, uint distx, uint disty)
2301
0
{
2302
0
    uint distxy = distx * disty;
2303
0
    //idistx * disty = (16-distx) * disty = 16*disty - distxy
2304
0
    //idistx * idisty = (16-distx) * (16-disty) = 16*16 - 16*distx -16*disty + distxy
2305
0
    uint tlrb = (tl & 0x00ff00ff)         * (16*16 - 16*distx - 16*disty + distxy);
2306
0
    uint tlag = ((tl & 0xff00ff00) >> 8)  * (16*16 - 16*distx - 16*disty + distxy);
2307
0
    uint trrb = ((tr & 0x00ff00ff)        * (distx*16 - distxy));
2308
0
    uint trag = (((tr & 0xff00ff00) >> 8) * (distx*16 - distxy));
2309
0
    uint blrb = ((bl & 0x00ff00ff)        * (disty*16 - distxy));
2310
0
    uint blag = (((bl & 0xff00ff00) >> 8) * (disty*16 - distxy));
2311
0
    uint brrb = ((br & 0x00ff00ff)        * (distxy));
2312
0
    uint brag = (((br & 0xff00ff00) >> 8) * (distxy));
2313
0
    return (((tlrb + trrb + blrb + brrb) >> 8) & 0x00ff00ff) | ((tlag + trag + blag + brag) & 0xff00ff00);
2314
0
}
2315
2316
#if defined(__SSE2__)
2317
0
#define interpolate_4_pixels_16_sse2(tl, tr, bl, br, distx, disty, colorMask, v_256, b)  \
2318
0
{ \
2319
0
    const __m128i dxdy = _mm_mullo_epi16 (distx, disty); \
2320
0
    const __m128i distx_ = _mm_slli_epi16(distx, 4); \
2321
0
    const __m128i disty_ = _mm_slli_epi16(disty, 4); \
2322
0
    const __m128i idxidy =  _mm_add_epi16(dxdy, _mm_sub_epi16(v_256, _mm_add_epi16(distx_, disty_))); \
2323
0
    const __m128i dxidy =  _mm_sub_epi16(distx_, dxdy); \
2324
0
    const __m128i idxdy =  _mm_sub_epi16(disty_, dxdy); \
2325
0
 \
2326
0
    __m128i tlAG = _mm_srli_epi16(tl, 8); \
2327
0
    __m128i tlRB = _mm_and_si128(tl, colorMask); \
2328
0
    __m128i trAG = _mm_srli_epi16(tr, 8); \
2329
0
    __m128i trRB = _mm_and_si128(tr, colorMask); \
2330
0
    __m128i blAG = _mm_srli_epi16(bl, 8); \
2331
0
    __m128i blRB = _mm_and_si128(bl, colorMask); \
2332
0
    __m128i brAG = _mm_srli_epi16(br, 8); \
2333
0
    __m128i brRB = _mm_and_si128(br, colorMask); \
2334
0
 \
2335
0
    tlAG = _mm_mullo_epi16(tlAG, idxidy); \
2336
0
    tlRB = _mm_mullo_epi16(tlRB, idxidy); \
2337
0
    trAG = _mm_mullo_epi16(trAG, dxidy); \
2338
0
    trRB = _mm_mullo_epi16(trRB, dxidy); \
2339
0
    blAG = _mm_mullo_epi16(blAG, idxdy); \
2340
0
    blRB = _mm_mullo_epi16(blRB, idxdy); \
2341
0
    brAG = _mm_mullo_epi16(brAG, dxdy); \
2342
0
    brRB = _mm_mullo_epi16(brRB, dxdy); \
2343
0
 \
2344
0
    /* Add the values, and shift to only keep 8 significant bits per colors */ \
2345
0
    __m128i rAG =_mm_add_epi16(_mm_add_epi16(tlAG, trAG), _mm_add_epi16(blAG, brAG)); \
2346
0
    __m128i rRB =_mm_add_epi16(_mm_add_epi16(tlRB, trRB), _mm_add_epi16(blRB, brRB)); \
2347
0
    rAG = _mm_andnot_si128(colorMask, rAG); \
2348
0
    rRB = _mm_srli_epi16(rRB, 8); \
2349
0
    _mm_storeu_si128((__m128i*)(b), _mm_or_si128(rAG, rRB)); \
2350
0
}
2351
#endif
2352
2353
#if defined(__ARM_NEON__)
2354
#define interpolate_4_pixels_16_neon(tl, tr, bl, br, distx, disty, disty_, colorMask, invColorMask, v_256, b)  \
2355
{ \
2356
    const int16x8_t dxdy = vmulq_s16(distx, disty); \
2357
    const int16x8_t distx_ = vshlq_n_s16(distx, 4); \
2358
    const int16x8_t idxidy =  vaddq_s16(dxdy, vsubq_s16(v_256, vaddq_s16(distx_, disty_))); \
2359
    const int16x8_t dxidy =  vsubq_s16(distx_, dxdy); \
2360
    const int16x8_t idxdy =  vsubq_s16(disty_, dxdy); \
2361
 \
2362
    int16x8_t tlAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tl), 8)); \
2363
    int16x8_t tlRB = vandq_s16(tl, colorMask); \
2364
    int16x8_t trAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tr), 8)); \
2365
    int16x8_t trRB = vandq_s16(tr, colorMask); \
2366
    int16x8_t blAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bl), 8)); \
2367
    int16x8_t blRB = vandq_s16(bl, colorMask); \
2368
    int16x8_t brAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(br), 8)); \
2369
    int16x8_t brRB = vandq_s16(br, colorMask); \
2370
 \
2371
    int16x8_t rAG = vmulq_s16(tlAG, idxidy); \
2372
    int16x8_t rRB = vmulq_s16(tlRB, idxidy); \
2373
    rAG = vmlaq_s16(rAG, trAG, dxidy); \
2374
    rRB = vmlaq_s16(rRB, trRB, dxidy); \
2375
    rAG = vmlaq_s16(rAG, blAG, idxdy); \
2376
    rRB = vmlaq_s16(rRB, blRB, idxdy); \
2377
    rAG = vmlaq_s16(rAG, brAG, dxdy); \
2378
    rRB = vmlaq_s16(rRB, brRB, dxdy); \
2379
 \
2380
    rAG = vandq_s16(invColorMask, rAG); \
2381
    rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8)); \
2382
    vst1q_s16((int16_t*)(b), vorrq_s16(rAG, rRB)); \
2383
}
2384
#endif
2385
2386
template<TextureBlendType blendType>
2387
void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2);
2388
2389
template<>
2390
inline void fetchTransformedBilinear_pixelBounds<BlendTransformedBilinearTiled>(int max, int, int, int &v1, int &v2)
2391
0
{
2392
0
    v1 %= max;
2393
0
    if (v1 < 0)
2394
0
        v1 += max;
2395
0
    v2 = v1 + 1;
2396
0
    if (v2 == max)
2397
0
        v2 = 0;
2398
0
    Q_ASSERT(v1 >= 0 && v1 < max);
2399
0
    Q_ASSERT(v2 >= 0 && v2 < max);
2400
0
}
2401
2402
template<>
2403
inline void fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(int, int l1, int l2, int &v1, int &v2)
2404
0
{
2405
0
    if (v1 < l1)
2406
0
        v2 = v1 = l1;
2407
0
    else if (v1 >= l2)
2408
0
        v2 = v1 = l2;
2409
0
    else
2410
0
        v2 = v1 + 1;
2411
0
    Q_ASSERT(v1 >= l1 && v1 <= l2);
2412
0
    Q_ASSERT(v2 >= l1 && v2 <= l2);
2413
0
}
2414
2415
enum FastTransformTypes {
2416
    SimpleScaleTransform,
2417
    UpscaleTransform,
2418
    DownscaleTransform,
2419
    RotateTransform,
2420
    FastRotateTransform,
2421
    NFastTransformTypes
2422
};
2423
2424
// Completes the partial interpolation stored in IntermediateBuffer.
2425
// by performing the x-axis interpolation and joining the RB and AG buffers.
2426
static void QT_FASTCALL intermediate_adder(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx)
2427
0
{
2428
0
#if defined(QT_COMPILER_SUPPORTS_AVX2)
2429
0
    extern void QT_FASTCALL intermediate_adder_avx2(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx);
2430
0
    if (qCpuHasFeature(ArchHaswell))
2431
0
        return intermediate_adder_avx2(b, end, intermediate, offset, fx, fdx);
2432
0
#endif
2433
2434
    // Switch to intermediate buffer coordinates
2435
0
    fx -= offset * fixed_scale;
2436
2437
0
    while (b < end) {
2438
0
        const int x = (fx >> 16);
2439
2440
0
        const uint distx = (fx & 0x0000ffff) >> 8;
2441
0
        const uint idistx = 256 - distx;
2442
0
        const uint rb = (intermediate.buffer_rb[x] * idistx + intermediate.buffer_rb[x + 1] * distx) & 0xff00ff00;
2443
0
        const uint ag = (intermediate.buffer_ag[x] * idistx + intermediate.buffer_ag[x + 1] * distx) & 0xff00ff00;
2444
0
        *b = (rb >> 8) | ag;
2445
0
        b++;
2446
0
        fx += fdx;
2447
0
    }
2448
0
    fx += offset * fixed_scale;
2449
0
}
2450
2451
typedef void (QT_FASTCALL *BilinearFastTransformHelper)(uint *b, uint *end, const QTextureData &image, int &fx, int &fy, int fdx, int fdy);
2452
2453
template<TextureBlendType blendType>
2454
static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper(uint *b, uint *end, const QTextureData &image,
2455
                                                                             int &fx, int &fy, int fdx, int /*fdy*/)
2456
0
{
2457
0
    int y1 = (fy >> 16);
2458
0
    int y2;
2459
0
    fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
2460
0
    const uint *s1 = (const uint *)image.scanLine(y1);
2461
0
    const uint *s2 = (const uint *)image.scanLine(y2);
2462
2463
0
    const int disty = (fy & 0x0000ffff) >> 8;
2464
0
    const int idisty = 256 - disty;
2465
0
    const int length = end - b;
2466
2467
    // The intermediate buffer is generated in the positive direction
2468
0
    const int adjust = (fdx < 0) ? fdx * length : 0;
2469
0
    const int offset = (fx + adjust) >> 16;
2470
0
    int x = offset;
2471
2472
0
    IntermediateBuffer intermediate;
2473
    // count is the size used in the intermediate.buffer.
2474
0
    int count = (qint64(length) * qAbs(fdx) + fixed_scale - 1) / fixed_scale + 2;
2475
    // length is supposed to be <= BufferSize either because data->m11 < 1 or
2476
    // data->m11 < 2, and any larger buffers split
2477
0
    Q_ASSERT(count <= BufferSize + 2);
2478
0
    int f = 0;
2479
0
    int lim = count;
2480
0
    if (blendType == BlendTransformedBilinearTiled) {
2481
0
        x %= image.width;
2482
0
        if (x < 0) x += image.width;
2483
0
    } else {
2484
0
        lim = qMin(count, image.x2 - x);
2485
0
        if (x < image.x1) {
2486
0
            Q_ASSERT(x < image.x2);
2487
0
            uint t = s1[image.x1];
2488
0
            uint b = s2[image.x1];
2489
0
            quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
2490
0
            quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
2491
0
            do {
2492
0
                intermediate.buffer_rb[f] = rb;
2493
0
                intermediate.buffer_ag[f] = ag;
2494
0
                f++;
2495
0
                x++;
2496
0
            } while (x < image.x1 && f < lim);
2497
0
        }
2498
0
    }
2499
2500
0
    if (blendType != BlendTransformedBilinearTiled) {
2501
0
#if defined(__SSE2__)
2502
0
        const __m128i disty_ = _mm_set1_epi16(disty);
2503
0
        const __m128i idisty_ = _mm_set1_epi16(idisty);
2504
0
        const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
2505
2506
0
        lim -= 3;
2507
0
        for (; f < lim; x += 4, f += 4) {
2508
            // Load 4 pixels from s1, and split the alpha-green and red-blue component
2509
0
            __m128i top = _mm_loadu_si128((const __m128i*)((const uint *)(s1)+x));
2510
0
            __m128i topAG = _mm_srli_epi16(top, 8);
2511
0
            __m128i topRB = _mm_and_si128(top, colorMask);
2512
            // Multiplies each color component by idisty
2513
0
            topAG = _mm_mullo_epi16 (topAG, idisty_);
2514
0
            topRB = _mm_mullo_epi16 (topRB, idisty_);
2515
2516
            // Same for the s2 vector
2517
0
            __m128i bottom = _mm_loadu_si128((const __m128i*)((const uint *)(s2)+x));
2518
0
            __m128i bottomAG = _mm_srli_epi16(bottom, 8);
2519
0
            __m128i bottomRB = _mm_and_si128(bottom, colorMask);
2520
0
            bottomAG = _mm_mullo_epi16 (bottomAG, disty_);
2521
0
            bottomRB = _mm_mullo_epi16 (bottomRB, disty_);
2522
2523
            // Add the values, and shift to only keep 8 significant bits per colors
2524
0
            __m128i rAG =_mm_add_epi16(topAG, bottomAG);
2525
0
            rAG = _mm_srli_epi16(rAG, 8);
2526
0
            _mm_storeu_si128((__m128i*)(&intermediate.buffer_ag[f]), rAG);
2527
0
            __m128i rRB =_mm_add_epi16(topRB, bottomRB);
2528
0
            rRB = _mm_srli_epi16(rRB, 8);
2529
0
            _mm_storeu_si128((__m128i*)(&intermediate.buffer_rb[f]), rRB);
2530
0
        }
2531
#elif defined(__ARM_NEON__)
2532
        const int16x8_t disty_ = vdupq_n_s16(disty);
2533
        const int16x8_t idisty_ = vdupq_n_s16(idisty);
2534
        const int16x8_t colorMask = vdupq_n_s16(0x00ff);
2535
2536
        lim -= 3;
2537
        for (; f < lim; x += 4, f += 4) {
2538
            // Load 4 pixels from s1, and split the alpha-green and red-blue component
2539
            int16x8_t top = vld1q_s16((int16_t*)((const uint *)(s1)+x));
2540
            int16x8_t topAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(top), 8));
2541
            int16x8_t topRB = vandq_s16(top, colorMask);
2542
            // Multiplies each color component by idisty
2543
            topAG = vmulq_s16(topAG, idisty_);
2544
            topRB = vmulq_s16(topRB, idisty_);
2545
2546
            // Same for the s2 vector
2547
            int16x8_t bottom = vld1q_s16((int16_t*)((const uint *)(s2)+x));
2548
            int16x8_t bottomAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bottom), 8));
2549
            int16x8_t bottomRB = vandq_s16(bottom, colorMask);
2550
            bottomAG = vmulq_s16(bottomAG, disty_);
2551
            bottomRB = vmulq_s16(bottomRB, disty_);
2552
2553
            // Add the values, and shift to only keep 8 significant bits per colors
2554
            int16x8_t rAG = vaddq_s16(topAG, bottomAG);
2555
            rAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rAG), 8));
2556
            vst1q_s16((int16_t*)(&intermediate.buffer_ag[f]), rAG);
2557
            int16x8_t rRB = vaddq_s16(topRB, bottomRB);
2558
            rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8));
2559
            vst1q_s16((int16_t*)(&intermediate.buffer_rb[f]), rRB);
2560
        }
2561
#endif
2562
0
    }
2563
0
    for (; f < count; f++) { // Same as above but without simd
2564
0
        if (blendType == BlendTransformedBilinearTiled) {
2565
0
            if (x >= image.width) x -= image.width;
2566
0
        } else {
2567
0
            x = qMin(x, image.x2 - 1);
2568
0
        }
2569
2570
0
        uint t = s1[x];
2571
0
        uint b = s2[x];
2572
2573
0
        intermediate.buffer_rb[f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
2574
0
        intermediate.buffer_ag[f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
2575
0
        x++;
2576
0
    }
2577
2578
    // Now interpolate the values from the intermediate.buffer to get the final result.
2579
0
    intermediate_adder(b, end, intermediate, offset, fx, fdx);
2580
0
}
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinearARGB32PM_simple_scale_helper<(TextureBlendType)4>(unsigned int*, unsigned int*, QTextureData const&, int&, int&, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinearARGB32PM_simple_scale_helper<(TextureBlendType)5>(unsigned int*, unsigned int*, QTextureData const&, int&, int&, int, int)
2581
2582
template<TextureBlendType blendType>
2583
static void QT_FASTCALL fetchTransformedBilinearARGB32PM_upscale_helper(uint *b, uint *end, const QTextureData &image,
2584
                                                                        int &fx, int &fy, int fdx, int /*fdy*/)
2585
0
{
2586
0
    int y1 = (fy >> 16);
2587
0
    int y2;
2588
0
    fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
2589
0
    const uint *s1 = (const uint *)image.scanLine(y1);
2590
0
    const uint *s2 = (const uint *)image.scanLine(y2);
2591
0
    const int disty = (fy & 0x0000ffff) >> 8;
2592
2593
0
    if (blendType != BlendTransformedBilinearTiled) {
2594
0
        const qint64 min_fx = qint64(image.x1) * fixed_scale;
2595
0
        const qint64 max_fx = qint64(image.x2 - 1) * fixed_scale;
2596
0
        while (b < end) {
2597
0
            int x1 = (fx >> 16);
2598
0
            int x2;
2599
0
            fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
2600
0
            if (x1 != x2)
2601
0
                break;
2602
0
            uint top = s1[x1];
2603
0
            uint bot = s2[x1];
2604
0
            *b = INTERPOLATE_PIXEL_256(top, 256 - disty, bot, disty);
2605
0
            fx += fdx;
2606
0
            ++b;
2607
0
        }
2608
0
        uint *boundedEnd = end;
2609
0
        if (fdx > 0)
2610
0
            boundedEnd = qMin(boundedEnd, b + (max_fx - fx) / fdx);
2611
0
        else if (fdx < 0)
2612
0
            boundedEnd = qMin(boundedEnd, b + (min_fx - fx) / fdx);
2613
2614
        // A fast middle part without boundary checks
2615
0
        while (b < boundedEnd) {
2616
0
            int x = (fx >> 16);
2617
0
            int distx = (fx & 0x0000ffff) >> 8;
2618
0
            *b = interpolate_4_pixels(s1 + x, s2 + x, distx, disty);
2619
0
            fx += fdx;
2620
0
            ++b;
2621
0
        }
2622
0
    }
2623
2624
0
    while (b < end) {
2625
0
        int x1 = (fx >> 16);
2626
0
        int x2;
2627
0
        fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1 , x1, x2);
2628
0
        uint tl = s1[x1];
2629
0
        uint tr = s1[x2];
2630
0
        uint bl = s2[x1];
2631
0
        uint br = s2[x2];
2632
0
        int distx = (fx & 0x0000ffff) >> 8;
2633
0
        *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
2634
2635
0
        fx += fdx;
2636
0
        ++b;
2637
0
    }
2638
0
}
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinearARGB32PM_upscale_helper<(TextureBlendType)4>(unsigned int*, unsigned int*, QTextureData const&, int&, int&, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinearARGB32PM_upscale_helper<(TextureBlendType)5>(unsigned int*, unsigned int*, QTextureData const&, int&, int&, int, int)
2639
2640
template<TextureBlendType blendType>
2641
static void QT_FASTCALL fetchTransformedBilinearARGB32PM_downscale_helper(uint *b, uint *end, const QTextureData &image,
2642
                                                                          int &fx, int &fy, int fdx, int /*fdy*/)
2643
0
{
2644
0
    int y1 = (fy >> 16);
2645
0
    int y2;
2646
0
    fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
2647
0
    const uint *s1 = (const uint *)image.scanLine(y1);
2648
0
    const uint *s2 = (const uint *)image.scanLine(y2);
2649
0
    const int disty8 = (fy & 0x0000ffff) >> 8;
2650
0
    const int disty4 = (disty8 + 0x08) >> 4;
2651
2652
0
    if (blendType != BlendTransformedBilinearTiled) {
2653
0
        const qint64 min_fx = qint64(image.x1) * fixed_scale;
2654
0
        const qint64 max_fx = qint64(image.x2 - 1) * fixed_scale;
2655
0
        while (b < end) {
2656
0
            int x1 = (fx >> 16);
2657
0
            int x2;
2658
0
            fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
2659
0
            if (x1 != x2)
2660
0
                break;
2661
0
            uint top = s1[x1];
2662
0
            uint bot = s2[x1];
2663
0
            *b = INTERPOLATE_PIXEL_256(top, 256 - disty8, bot, disty8);
2664
0
            fx += fdx;
2665
0
            ++b;
2666
0
        }
2667
0
        uint *boundedEnd = end;
2668
0
        if (fdx > 0)
2669
0
            boundedEnd = qMin(boundedEnd, b + (max_fx - fx) / fdx);
2670
0
        else if (fdx < 0)
2671
0
            boundedEnd = qMin(boundedEnd, b + (min_fx - fx) / fdx);
2672
        // A fast middle part without boundary checks
2673
0
#if defined(__SSE2__)
2674
0
        const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
2675
0
        const __m128i v_256 = _mm_set1_epi16(256);
2676
0
        const __m128i v_disty = _mm_set1_epi16(disty4);
2677
0
        const __m128i v_fdx = _mm_set1_epi32(fdx*4);
2678
0
        const __m128i v_fx_r = _mm_set1_epi32(0x8);
2679
0
        __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx);
2680
2681
0
        while (b < boundedEnd - 3) {
2682
0
            __m128i offset = _mm_srli_epi32(v_fx, 16);
2683
0
            const int offset0 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
2684
0
            const int offset1 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
2685
0
            const int offset2 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
2686
0
            const int offset3 = _mm_cvtsi128_si32(offset);
2687
0
            const __m128i tl = _mm_setr_epi32(s1[offset0], s1[offset1], s1[offset2], s1[offset3]);
2688
0
            const __m128i tr = _mm_setr_epi32(s1[offset0 + 1], s1[offset1 + 1], s1[offset2 + 1], s1[offset3 + 1]);
2689
0
            const __m128i bl = _mm_setr_epi32(s2[offset0], s2[offset1], s2[offset2], s2[offset3]);
2690
0
            const __m128i br = _mm_setr_epi32(s2[offset0 + 1], s2[offset1 + 1], s2[offset2 + 1], s2[offset3 + 1]);
2691
2692
0
            __m128i v_distx = _mm_srli_epi16(v_fx, 8);
2693
0
            v_distx = _mm_srli_epi16(_mm_add_epi32(v_distx, v_fx_r), 4);
2694
0
            v_distx = _mm_shufflehi_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
2695
0
            v_distx = _mm_shufflelo_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
2696
2697
0
            interpolate_4_pixels_16_sse2(tl, tr, bl, br, v_distx, v_disty, colorMask, v_256, b);
2698
0
            b += 4;
2699
0
            v_fx = _mm_add_epi32(v_fx, v_fdx);
2700
0
        }
2701
0
        fx = _mm_cvtsi128_si32(v_fx);
2702
#elif defined(__ARM_NEON__)
2703
        const int16x8_t colorMask = vdupq_n_s16(0x00ff);
2704
        const int16x8_t invColorMask = vmvnq_s16(colorMask);
2705
        const int16x8_t v_256 = vdupq_n_s16(256);
2706
        const int16x8_t v_disty = vdupq_n_s16(disty4);
2707
        const int16x8_t v_disty_ = vshlq_n_s16(v_disty, 4);
2708
        int32x4_t v_fdx = vdupq_n_s32(fdx*4);
2709
2710
        int32x4_t v_fx = vmovq_n_s32(fx);
2711
        v_fx = vsetq_lane_s32(fx + fdx, v_fx, 1);
2712
        v_fx = vsetq_lane_s32(fx + fdx * 2, v_fx, 2);
2713
        v_fx = vsetq_lane_s32(fx + fdx * 3, v_fx, 3);
2714
2715
        const int32x4_t v_ffff_mask = vdupq_n_s32(0x0000ffff);
2716
        const int32x4_t v_fx_r = vdupq_n_s32(0x0800);
2717
2718
        while (b < boundedEnd - 3) {
2719
            uint32x4x2_t v_top, v_bot;
2720
2721
            int x1 = (fx >> 16);
2722
            fx += fdx;
2723
            v_top = vld2q_lane_u32(s1 + x1, v_top, 0);
2724
            v_bot = vld2q_lane_u32(s2 + x1, v_bot, 0);
2725
            x1 = (fx >> 16);
2726
            fx += fdx;
2727
            v_top = vld2q_lane_u32(s1 + x1, v_top, 1);
2728
            v_bot = vld2q_lane_u32(s2 + x1, v_bot, 1);
2729
            x1 = (fx >> 16);
2730
            fx += fdx;
2731
            v_top = vld2q_lane_u32(s1 + x1, v_top, 2);
2732
            v_bot = vld2q_lane_u32(s2 + x1, v_bot, 2);
2733
            x1 = (fx >> 16);
2734
            fx += fdx;
2735
            v_top = vld2q_lane_u32(s1 + x1, v_top, 3);
2736
            v_bot = vld2q_lane_u32(s2 + x1, v_bot, 3);
2737
2738
            int32x4_t v_distx = vshrq_n_s32(vaddq_s32(vandq_s32(v_fx, v_ffff_mask), v_fx_r), 12);
2739
            v_distx = vorrq_s32(v_distx, vshlq_n_s32(v_distx, 16));
2740
2741
            interpolate_4_pixels_16_neon(
2742
                        vreinterpretq_s16_u32(v_top.val[0]), vreinterpretq_s16_u32(v_top.val[1]),
2743
                    vreinterpretq_s16_u32(v_bot.val[0]), vreinterpretq_s16_u32(v_bot.val[1]),
2744
                    vreinterpretq_s16_s32(v_distx), v_disty, v_disty_,
2745
                    colorMask, invColorMask, v_256, b);
2746
            b+=4;
2747
            v_fx = vaddq_s32(v_fx, v_fdx);
2748
        }
2749
#endif
2750
0
        while (b < boundedEnd) {
2751
0
            int x = (fx >> 16);
2752
0
            if (hasFastInterpolate4()) {
2753
0
                int distx8 = (fx & 0x0000ffff) >> 8;
2754
0
                *b = interpolate_4_pixels(s1 + x, s2 + x, distx8, disty8);
2755
0
            } else {
2756
0
                int distx4 = ((fx & 0x0000ffff) + 0x0800) >> 12;
2757
0
                *b = interpolate_4_pixels_16(s1[x], s1[x + 1], s2[x], s2[x + 1], distx4, disty4);
2758
0
            }
2759
0
            fx += fdx;
2760
0
            ++b;
2761
0
        }
2762
0
    }
2763
2764
0
    while (b < end) {
2765
0
        int x1 = (fx >> 16);
2766
0
        int x2;
2767
0
        fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
2768
0
        uint tl = s1[x1];
2769
0
        uint tr = s1[x2];
2770
0
        uint bl = s2[x1];
2771
0
        uint br = s2[x2];
2772
0
        if (hasFastInterpolate4()) {
2773
0
            int distx8 = (fx & 0x0000ffff) >> 8;
2774
0
            *b = interpolate_4_pixels(tl, tr, bl, br, distx8, disty8);
2775
0
        } else {
2776
0
            int distx4 = ((fx & 0x0000ffff) + 0x0800) >> 12;
2777
0
            *b = interpolate_4_pixels_16(tl, tr, bl, br, distx4, disty4);
2778
0
        }
2779
0
        fx += fdx;
2780
0
        ++b;
2781
0
    }
2782
0
}
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinearARGB32PM_downscale_helper<(TextureBlendType)4>(unsigned int*, unsigned int*, QTextureData const&, int&, int&, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinearARGB32PM_downscale_helper<(TextureBlendType)5>(unsigned int*, unsigned int*, QTextureData const&, int&, int&, int, int)
2783
2784
template<TextureBlendType blendType>
2785
static void QT_FASTCALL fetchTransformedBilinearARGB32PM_rotate_helper(uint *b, uint *end, const QTextureData &image,
2786
                                                                       int &fx, int &fy, int fdx, int fdy)
2787
0
{
2788
    // if we are zooming more than 8 times, we use 8bit precision for the position.
2789
0
    while (b < end) {
2790
0
        int x1 = (fx >> 16);
2791
0
        int x2;
2792
0
        int y1 = (fy >> 16);
2793
0
        int y2;
2794
2795
0
        fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
2796
0
        fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
2797
2798
0
        const uint *s1 = (const uint *)image.scanLine(y1);
2799
0
        const uint *s2 = (const uint *)image.scanLine(y2);
2800
2801
0
        uint tl = s1[x1];
2802
0
        uint tr = s1[x2];
2803
0
        uint bl = s2[x1];
2804
0
        uint br = s2[x2];
2805
2806
0
        int distx = (fx & 0x0000ffff) >> 8;
2807
0
        int disty = (fy & 0x0000ffff) >> 8;
2808
2809
0
        *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
2810
2811
0
        fx += fdx;
2812
0
        fy += fdy;
2813
0
        ++b;
2814
0
    }
2815
0
}
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinearARGB32PM_rotate_helper<(TextureBlendType)4>(unsigned int*, unsigned int*, QTextureData const&, int&, int&, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinearARGB32PM_rotate_helper<(TextureBlendType)5>(unsigned int*, unsigned int*, QTextureData const&, int&, int&, int, int)
2816
2817
template<TextureBlendType blendType>
2818
static void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper(uint *b, uint *end, const QTextureData &image,
2819
                                                                            int &fx, int &fy, int fdx, int fdy)
2820
0
{
2821
    //we are zooming less than 8x, use 4bit precision
2822
0
    if (blendType != BlendTransformedBilinearTiled) {
2823
0
        const qint64 min_fx = qint64(image.x1) * fixed_scale;
2824
0
        const qint64 max_fx = qint64(image.x2 - 1) * fixed_scale;
2825
0
        const qint64 min_fy = qint64(image.y1) * fixed_scale;
2826
0
        const qint64 max_fy = qint64(image.y2 - 1) * fixed_scale;
2827
        // first handle the possibly bounded part in the beginning
2828
0
        while (b < end) {
2829
0
            int x1 = (fx >> 16);
2830
0
            int x2;
2831
0
            int y1 = (fy >> 16);
2832
0
            int y2;
2833
0
            fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
2834
0
            fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
2835
0
            if (x1 != x2 && y1 != y2)
2836
0
                break;
2837
0
            const uint *s1 = (const uint *)image.scanLine(y1);
2838
0
            const uint *s2 = (const uint *)image.scanLine(y2);
2839
0
            uint tl = s1[x1];
2840
0
            uint tr = s1[x2];
2841
0
            uint bl = s2[x1];
2842
0
            uint br = s2[x2];
2843
0
            if (hasFastInterpolate4()) {
2844
0
                int distx = (fx & 0x0000ffff) >> 8;
2845
0
                int disty = (fy & 0x0000ffff) >> 8;
2846
0
                *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
2847
0
            } else {
2848
0
                int distx = ((fx & 0x0000ffff) + 0x0800) >> 12;
2849
0
                int disty = ((fy & 0x0000ffff) + 0x0800) >> 12;
2850
0
                *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
2851
0
            }
2852
0
            fx += fdx;
2853
0
            fy += fdy;
2854
0
            ++b;
2855
0
        }
2856
0
        uint *boundedEnd = end;
2857
0
        if (fdx > 0)
2858
0
            boundedEnd = qMin(boundedEnd, b + (max_fx - fx) / fdx);
2859
0
        else if (fdx < 0)
2860
0
            boundedEnd = qMin(boundedEnd, b + (min_fx - fx) / fdx);
2861
0
        if (fdy > 0)
2862
0
            boundedEnd = qMin(boundedEnd, b + (max_fy - fy) / fdy);
2863
0
        else if (fdy < 0)
2864
0
            boundedEnd = qMin(boundedEnd, b + (min_fy - fy) / fdy);
2865
2866
        // until boundedEnd we can now have a fast middle part without boundary checks
2867
0
#if defined(__SSE2__)
2868
0
        const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
2869
0
        const __m128i v_256 = _mm_set1_epi16(256);
2870
0
        const __m128i v_fdx = _mm_set1_epi32(fdx*4);
2871
0
        const __m128i v_fdy = _mm_set1_epi32(fdy*4);
2872
0
        const __m128i v_fxy_r = _mm_set1_epi32(0x8);
2873
0
        __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx);
2874
0
        __m128i v_fy = _mm_setr_epi32(fy, fy + fdy, fy + fdy + fdy, fy + fdy + fdy + fdy);
2875
2876
0
        const uchar *textureData = image.imageData;
2877
0
        const qsizetype bytesPerLine = image.bytesPerLine;
2878
0
        const __m128i vbpl = _mm_shufflelo_epi16(_mm_cvtsi32_si128(bytesPerLine/4), _MM_SHUFFLE(0, 0, 0, 0));
2879
2880
0
        while (b < boundedEnd - 3) {
2881
0
            const __m128i vy = _mm_packs_epi32(_mm_srli_epi32(v_fy, 16), _mm_setzero_si128());
2882
            // 4x16bit * 4x16bit -> 4x32bit
2883
0
            __m128i offset = _mm_unpacklo_epi16(_mm_mullo_epi16(vy, vbpl), _mm_mulhi_epi16(vy, vbpl));
2884
0
            offset = _mm_add_epi32(offset, _mm_srli_epi32(v_fx, 16));
2885
0
            const int offset0 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
2886
0
            const int offset1 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
2887
0
            const int offset2 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
2888
0
            const int offset3 = _mm_cvtsi128_si32(offset);
2889
0
            const uint *topData = (const uint *)(textureData);
2890
0
            const __m128i tl = _mm_setr_epi32(topData[offset0], topData[offset1], topData[offset2], topData[offset3]);
2891
0
            const __m128i tr = _mm_setr_epi32(topData[offset0 + 1], topData[offset1 + 1], topData[offset2 + 1], topData[offset3 + 1]);
2892
0
            const uint *bottomData = (const uint *)(textureData + bytesPerLine);
2893
0
            const __m128i bl = _mm_setr_epi32(bottomData[offset0], bottomData[offset1], bottomData[offset2], bottomData[offset3]);
2894
0
            const __m128i br = _mm_setr_epi32(bottomData[offset0 + 1], bottomData[offset1 + 1], bottomData[offset2 + 1], bottomData[offset3 + 1]);
2895
2896
0
            __m128i v_distx = _mm_srli_epi16(v_fx, 8);
2897
0
            __m128i v_disty = _mm_srli_epi16(v_fy, 8);
2898
0
            v_distx = _mm_srli_epi16(_mm_add_epi32(v_distx, v_fxy_r), 4);
2899
0
            v_disty = _mm_srli_epi16(_mm_add_epi32(v_disty, v_fxy_r), 4);
2900
0
            v_distx = _mm_shufflehi_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
2901
0
            v_distx = _mm_shufflelo_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
2902
0
            v_disty = _mm_shufflehi_epi16(v_disty, _MM_SHUFFLE(2,2,0,0));
2903
0
            v_disty = _mm_shufflelo_epi16(v_disty, _MM_SHUFFLE(2,2,0,0));
2904
2905
0
            interpolate_4_pixels_16_sse2(tl, tr, bl, br, v_distx, v_disty, colorMask, v_256, b);
2906
0
            b += 4;
2907
0
            v_fx = _mm_add_epi32(v_fx, v_fdx);
2908
0
            v_fy = _mm_add_epi32(v_fy, v_fdy);
2909
0
        }
2910
0
        fx = _mm_cvtsi128_si32(v_fx);
2911
0
        fy = _mm_cvtsi128_si32(v_fy);
2912
#elif defined(__ARM_NEON__)
2913
        const int16x8_t colorMask = vdupq_n_s16(0x00ff);
2914
        const int16x8_t invColorMask = vmvnq_s16(colorMask);
2915
        const int16x8_t v_256 = vdupq_n_s16(256);
2916
        int32x4_t v_fdx = vdupq_n_s32(fdx * 4);
2917
        int32x4_t v_fdy = vdupq_n_s32(fdy * 4);
2918
2919
        const uchar *textureData = image.imageData;
2920
        const int bytesPerLine = image.bytesPerLine;
2921
2922
        int32x4_t v_fx = vmovq_n_s32(fx);
2923
        int32x4_t v_fy = vmovq_n_s32(fy);
2924
        v_fx = vsetq_lane_s32(fx + fdx, v_fx, 1);
2925
        v_fy = vsetq_lane_s32(fy + fdy, v_fy, 1);
2926
        v_fx = vsetq_lane_s32(fx + fdx * 2, v_fx, 2);
2927
        v_fy = vsetq_lane_s32(fy + fdy * 2, v_fy, 2);
2928
        v_fx = vsetq_lane_s32(fx + fdx * 3, v_fx, 3);
2929
        v_fy = vsetq_lane_s32(fy + fdy * 3, v_fy, 3);
2930
2931
        const int32x4_t v_ffff_mask = vdupq_n_s32(0x0000ffff);
2932
        const int32x4_t v_round = vdupq_n_s32(0x0800);
2933
2934
        while (b < boundedEnd - 3) {
2935
            uint32x4x2_t v_top, v_bot;
2936
2937
            int x1 = (fx >> 16);
2938
            int y1 = (fy >> 16);
2939
            fx += fdx; fy += fdy;
2940
            const uchar *sl = textureData + bytesPerLine * y1;
2941
            const uint *s1 = reinterpret_cast<const uint *>(sl);
2942
            const uint *s2 = reinterpret_cast<const uint *>(sl + bytesPerLine);
2943
            v_top = vld2q_lane_u32(s1 + x1, v_top, 0);
2944
            v_bot = vld2q_lane_u32(s2 + x1, v_bot, 0);
2945
            x1 = (fx >> 16);
2946
            y1 = (fy >> 16);
2947
            fx += fdx; fy += fdy;
2948
            sl = textureData + bytesPerLine * y1;
2949
            s1 = reinterpret_cast<const uint *>(sl);
2950
            s2 = reinterpret_cast<const uint *>(sl + bytesPerLine);
2951
            v_top = vld2q_lane_u32(s1 + x1, v_top, 1);
2952
            v_bot = vld2q_lane_u32(s2 + x1, v_bot, 1);
2953
            x1 = (fx >> 16);
2954
            y1 = (fy >> 16);
2955
            fx += fdx; fy += fdy;
2956
            sl = textureData + bytesPerLine * y1;
2957
            s1 = reinterpret_cast<const uint *>(sl);
2958
            s2 = reinterpret_cast<const uint *>(sl + bytesPerLine);
2959
            v_top = vld2q_lane_u32(s1 + x1, v_top, 2);
2960
            v_bot = vld2q_lane_u32(s2 + x1, v_bot, 2);
2961
            x1 = (fx >> 16);
2962
            y1 = (fy >> 16);
2963
            fx += fdx; fy += fdy;
2964
            sl = textureData + bytesPerLine * y1;
2965
            s1 = reinterpret_cast<const uint *>(sl);
2966
            s2 = reinterpret_cast<const uint *>(sl + bytesPerLine);
2967
            v_top = vld2q_lane_u32(s1 + x1, v_top, 3);
2968
            v_bot = vld2q_lane_u32(s2 + x1, v_bot, 3);
2969
2970
            int32x4_t v_distx = vshrq_n_s32(vaddq_s32(vandq_s32(v_fx, v_ffff_mask), v_round), 12);
2971
            int32x4_t v_disty = vshrq_n_s32(vaddq_s32(vandq_s32(v_fy, v_ffff_mask), v_round), 12);
2972
            v_distx = vorrq_s32(v_distx, vshlq_n_s32(v_distx, 16));
2973
            v_disty = vorrq_s32(v_disty, vshlq_n_s32(v_disty, 16));
2974
            int16x8_t v_disty_ = vshlq_n_s16(vreinterpretq_s16_s32(v_disty), 4);
2975
2976
            interpolate_4_pixels_16_neon(
2977
                        vreinterpretq_s16_u32(v_top.val[0]), vreinterpretq_s16_u32(v_top.val[1]),
2978
                        vreinterpretq_s16_u32(v_bot.val[0]), vreinterpretq_s16_u32(v_bot.val[1]),
2979
                        vreinterpretq_s16_s32(v_distx), vreinterpretq_s16_s32(v_disty),
2980
                        v_disty_, colorMask, invColorMask, v_256, b);
2981
            b += 4;
2982
            v_fx = vaddq_s32(v_fx, v_fdx);
2983
            v_fy = vaddq_s32(v_fy, v_fdy);
2984
        }
2985
#endif
2986
0
        while (b < boundedEnd) {
2987
0
            int x = (fx >> 16);
2988
0
            int y = (fy >> 16);
2989
2990
0
            const uint *s1 = (const uint *)image.scanLine(y);
2991
0
            const uint *s2 = (const uint *)image.scanLine(y + 1);
2992
2993
0
            if (hasFastInterpolate4()) {
2994
0
                int distx = (fx & 0x0000ffff) >> 8;
2995
0
                int disty = (fy & 0x0000ffff) >> 8;
2996
0
                *b = interpolate_4_pixels(s1 + x, s2 + x, distx, disty);
2997
0
            } else {
2998
0
                int distx = ((fx & 0x0000ffff) + 0x0800) >> 12;
2999
0
                int disty = ((fy & 0x0000ffff) + 0x0800) >> 12;
3000
0
                *b = interpolate_4_pixels_16(s1[x], s1[x + 1], s2[x], s2[x + 1], distx, disty);
3001
0
            }
3002
3003
0
            fx += fdx;
3004
0
            fy += fdy;
3005
0
            ++b;
3006
0
        }
3007
0
    }
3008
3009
0
    while (b < end) {
3010
0
        int x1 = (fx >> 16);
3011
0
        int x2;
3012
0
        int y1 = (fy >> 16);
3013
0
        int y2;
3014
3015
0
        fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
3016
0
        fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
3017
3018
0
        const uint *s1 = (const uint *)image.scanLine(y1);
3019
0
        const uint *s2 = (const uint *)image.scanLine(y2);
3020
3021
0
        uint tl = s1[x1];
3022
0
        uint tr = s1[x2];
3023
0
        uint bl = s2[x1];
3024
0
        uint br = s2[x2];
3025
3026
0
        if (hasFastInterpolate4()) {
3027
0
            int distx = (fx & 0x0000ffff) >> 8;
3028
0
            int disty = (fy & 0x0000ffff) >> 8;
3029
0
            *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
3030
0
        } else {
3031
0
            int distx = ((fx & 0x0000ffff) + 0x0800) >> 12;
3032
0
            int disty = ((fy & 0x0000ffff) + 0x0800) >> 12;
3033
0
            *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
3034
0
        }
3035
3036
0
        fx += fdx;
3037
0
        fy += fdy;
3038
0
        ++b;
3039
0
    }
3040
0
}
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinearARGB32PM_fast_rotate_helper<(TextureBlendType)4>(unsigned int*, unsigned int*, QTextureData const&, int&, int&, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinearARGB32PM_fast_rotate_helper<(TextureBlendType)5>(unsigned int*, unsigned int*, QTextureData const&, int&, int&, int, int)
3041
3042
3043
static BilinearFastTransformHelper bilinearFastTransformHelperARGB32PM[2][NFastTransformTypes] = {
3044
    {
3045
        fetchTransformedBilinearARGB32PM_simple_scale_helper<BlendTransformedBilinear>,
3046
        fetchTransformedBilinearARGB32PM_upscale_helper<BlendTransformedBilinear>,
3047
        fetchTransformedBilinearARGB32PM_downscale_helper<BlendTransformedBilinear>,
3048
        fetchTransformedBilinearARGB32PM_rotate_helper<BlendTransformedBilinear>,
3049
        fetchTransformedBilinearARGB32PM_fast_rotate_helper<BlendTransformedBilinear>
3050
    },
3051
    {
3052
        fetchTransformedBilinearARGB32PM_simple_scale_helper<BlendTransformedBilinearTiled>,
3053
        fetchTransformedBilinearARGB32PM_upscale_helper<BlendTransformedBilinearTiled>,
3054
        fetchTransformedBilinearARGB32PM_downscale_helper<BlendTransformedBilinearTiled>,
3055
        fetchTransformedBilinearARGB32PM_rotate_helper<BlendTransformedBilinearTiled>,
3056
        fetchTransformedBilinearARGB32PM_fast_rotate_helper<BlendTransformedBilinearTiled>
3057
    }
3058
};
3059
3060
template<TextureBlendType blendType> /* blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled */
3061
static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, const Operator *,
3062
                                                                 const QSpanData *data, int y, int x,
3063
                                                                 int length)
3064
0
{
3065
0
    const qreal cx = x + qreal(0.5);
3066
0
    const qreal cy = y + qreal(0.5);
3067
0
    Q_CONSTEXPR int tiled = (blendType == BlendTransformedBilinearTiled) ? 1 : 0;
3068
3069
0
    uint *end = buffer + length;
3070
0
    uint *b = buffer;
3071
0
    if (canUseFastMatrixPath(cx, cy, length, data)) {
3072
        // The increment pr x in the scanline
3073
0
        int fdx = (int)(data->m11 * fixed_scale);
3074
0
        int fdy = (int)(data->m12 * fixed_scale);
3075
3076
0
        int fx = int((data->m21 * cy
3077
0
                      + data->m11 * cx + data->dx) * fixed_scale);
3078
0
        int fy = int((data->m22 * cy
3079
0
                      + data->m12 * cx + data->dy) * fixed_scale);
3080
3081
0
        fx -= half_point;
3082
0
        fy -= half_point;
3083
3084
0
        if (fdy == 0) { // simple scale, no rotation or shear
3085
0
            if (qAbs(fdx) <= fixed_scale) {
3086
                // simple scale up on X
3087
0
                bilinearFastTransformHelperARGB32PM[tiled][SimpleScaleTransform](b, end, data->texture, fx, fy, fdx, fdy);
3088
0
            } else if (qAbs(fdx) <= 2 * fixed_scale) {
3089
                // simple scale down on X, less than 2x
3090
0
                const int mid = (length * 2 < BufferSize) ? length : ((length + 1) / 2);
3091
0
                bilinearFastTransformHelperARGB32PM[tiled][SimpleScaleTransform](buffer, buffer + mid, data->texture, fx, fy, fdx, fdy);
3092
0
                if (mid != length)
3093
0
                    bilinearFastTransformHelperARGB32PM[tiled][SimpleScaleTransform](buffer + mid, buffer + length, data->texture, fx, fy, fdx, fdy);
3094
0
            } else if (qAbs(data->m22) < qreal(1./8.)) {
3095
                // scale up more than 8x (on Y)
3096
0
                bilinearFastTransformHelperARGB32PM[tiled][UpscaleTransform](b, end, data->texture, fx, fy, fdx, fdy);
3097
0
            } else {
3098
                // scale down on X
3099
0
                bilinearFastTransformHelperARGB32PM[tiled][DownscaleTransform](b, end, data->texture, fx, fy, fdx, fdy);
3100
0
            }
3101
0
        } else { // rotation or shear
3102
0
            if (qAbs(data->m11) < qreal(1./8.) || qAbs(data->m22) < qreal(1./8.) ) {
3103
                // if we are zooming more than 8 times, we use 8bit precision for the position.
3104
0
                bilinearFastTransformHelperARGB32PM[tiled][RotateTransform](b, end, data->texture, fx, fy, fdx, fdy);
3105
0
            } else {
3106
                // we are zooming less than 8x, use 4bit precision
3107
0
                bilinearFastTransformHelperARGB32PM[tiled][FastRotateTransform](b, end, data->texture, fx, fy, fdx, fdy);
3108
0
            }
3109
0
        }
3110
0
    } else {
3111
0
        const QTextureData &image = data->texture;
3112
3113
0
        const qreal fdx = data->m11;
3114
0
        const qreal fdy = data->m12;
3115
0
        const qreal fdw = data->m13;
3116
3117
0
        qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
3118
0
        qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
3119
0
        qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
3120
3121
0
        while (b < end) {
3122
0
            const qreal iw = fw == 0 ? 1 : 1 / fw;
3123
0
            const qreal px = fx * iw - qreal(0.5);
3124
0
            const qreal py = fy * iw - qreal(0.5);
3125
3126
0
            int x1 = int(px) - (px < 0);
3127
0
            int x2;
3128
0
            int y1 = int(py) - (py < 0);
3129
0
            int y2;
3130
3131
0
            int distx = int((px - x1) * 256);
3132
0
            int disty = int((py - y1) * 256);
3133
3134
0
            fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
3135
0
            fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
3136
3137
0
            const uint *s1 = (const uint *)data->texture.scanLine(y1);
3138
0
            const uint *s2 = (const uint *)data->texture.scanLine(y2);
3139
3140
0
            uint tl = s1[x1];
3141
0
            uint tr = s1[x2];
3142
0
            uint bl = s2[x1];
3143
0
            uint br = s2[x2];
3144
3145
0
            *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
3146
3147
0
            fx += fdx;
3148
0
            fy += fdy;
3149
0
            fw += fdw;
3150
            //force increment to avoid /0
3151
0
            if (!fw) {
3152
0
                fw += fdw;
3153
0
            }
3154
0
            ++b;
3155
0
        }
3156
0
    }
3157
3158
0
    return buffer;
3159
0
}
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformedBilinearARGB32PM<(TextureBlendType)4>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformedBilinearARGB32PM<(TextureBlendType)5>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
3160
3161
template<TextureBlendType blendType>
3162
static void QT_FASTCALL fetchTransformedBilinear_simple_scale_helper(uint *b, uint *end, const QTextureData &image,
3163
                                                                     int &fx, int &fy, int fdx, int /*fdy*/)
3164
0
{
3165
0
    const QPixelLayout *layout = &qPixelLayouts[image.format];
3166
0
    const QVector<QRgb> *clut = image.colorTable;
3167
0
    const FetchAndConvertPixelsFunc fetch = layout->fetchToARGB32PM;
3168
3169
0
    int y1 = (fy >> 16);
3170
0
    int y2;
3171
0
    fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
3172
0
    const uchar *s1 = image.scanLine(y1);
3173
0
    const uchar *s2 = image.scanLine(y2);
3174
3175
0
    const int disty = (fy & 0x0000ffff) >> 8;
3176
0
    const int idisty = 256 - disty;
3177
0
    const int length = end - b;
3178
3179
    // The intermediate buffer is generated in the positive direction
3180
0
    const int adjust = (fdx < 0) ? fdx * length : 0;
3181
0
    const int offset = (fx + adjust) >> 16;
3182
0
    int x = offset;
3183
3184
0
    IntermediateBuffer intermediate;
3185
0
    uint *buf1 = intermediate.buffer_rb;
3186
0
    uint *buf2 = intermediate.buffer_ag;
3187
0
    const uint *ptr1;
3188
0
    const uint *ptr2;
3189
3190
0
    int count = (qint64(length) * qAbs(fdx) + fixed_scale - 1) / fixed_scale + 2;
3191
0
    Q_ASSERT(count <= BufferSize + 2);
3192
3193
0
    if (blendType == BlendTransformedBilinearTiled) {
3194
0
        x %= image.width;
3195
0
        if (x < 0)
3196
0
            x += image.width;
3197
0
        int len1 = qMin(count, image.width - x);
3198
0
        int len2 = qMin(x, count - len1);
3199
3200
0
        ptr1 = fetch(buf1, s1, x, len1, clut, nullptr);
3201
0
        ptr2 = fetch(buf2, s2, x, len1, clut, nullptr);
3202
0
        for (int i = 0; i < len1; ++i) {
3203
0
            uint t = ptr1[i];
3204
0
            uint b = ptr2[i];
3205
0
            buf1[i] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
3206
0
            buf2[i] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
3207
0
        }
3208
3209
0
        if (len2) {
3210
0
            ptr1 = fetch(buf1 + len1, s1, 0, len2, clut, nullptr);
3211
0
            ptr2 = fetch(buf2 + len1, s2, 0, len2, clut, nullptr);
3212
0
            for (int i = 0; i < len2; ++i) {
3213
0
                uint t = ptr1[i];
3214
0
                uint b = ptr2[i];
3215
0
                buf1[i + len1] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
3216
0
                buf2[i + len1] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
3217
0
            }
3218
0
        }
3219
        // Generate the rest by repeatedly repeating the previous set of pixels
3220
0
        for (int i = image.width; i < count; ++i) {
3221
0
            buf1[i] = buf1[i - image.width];
3222
0
            buf2[i] = buf2[i - image.width];
3223
0
        }
3224
0
    } else {
3225
0
        int start = qMax(x, image.x1);
3226
0
        int end = qMin(x + count, image.x2);
3227
0
        int len = qMax(1, end - start);
3228
0
        int leading = start - x;
3229
3230
0
        ptr1 = fetch(buf1 + leading, s1, start, len, clut, nullptr);
3231
0
        ptr2 = fetch(buf2 + leading, s2, start, len, clut, nullptr);
3232
3233
0
        for (int i = 0; i < len; ++i) {
3234
0
            uint t = ptr1[i];
3235
0
            uint b = ptr2[i];
3236
0
            buf1[i + leading] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
3237
0
            buf2[i + leading] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
3238
0
        }
3239
3240
0
        for (int i = 0; i < leading; ++i) {
3241
0
            buf1[i] = buf1[leading];
3242
0
            buf2[i] = buf2[leading];
3243
0
        }
3244
0
        for (int i = leading + len; i < count; ++i) {
3245
0
            buf1[i] = buf1[i - 1];
3246
0
            buf2[i] = buf2[i - 1];
3247
0
        }
3248
0
    }
3249
3250
    // Now interpolate the values from the intermediate.buffer to get the final result.
3251
0
    intermediate_adder(b, end, intermediate, offset, fx, fdx);
3252
0
}
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinear_simple_scale_helper<(TextureBlendType)4>(unsigned int*, unsigned int*, QTextureData const&, int&, int&, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinear_simple_scale_helper<(TextureBlendType)5>(unsigned int*, unsigned int*, QTextureData const&, int&, int&, int, int)
3253
3254
3255
template<TextureBlendType blendType, QPixelLayout::BPP bpp, typename T>
3256
static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const int len, const QTextureData &image,
3257
                                                         int fx, int fy, const int fdx, const int fdy)
3258
0
{
3259
0
    const QPixelLayout &layout = qPixelLayouts[image.format];
3260
0
    constexpr bool useFetch = (bpp < QPixelLayout::BPP32);
3261
0
    if (useFetch)
3262
0
        Q_ASSERT(sizeof(T) == sizeof(uint));
3263
0
    else
3264
0
        Q_ASSERT(layout.bpp == bpp);
3265
0
    const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout.bpp] : fetchPixel<bpp>;
3266
0
    if (fdy == 0) {
3267
0
        int y1 = (fy >> 16);
3268
0
        int y2;
3269
0
        fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
3270
0
        const uchar *s1 = image.scanLine(y1);
3271
0
        const uchar *s2 = image.scanLine(y2);
3272
3273
0
        int i = 0;
3274
0
        if (blendType == BlendTransformedBilinear) {
3275
0
            for (; i < len; ++i) {
3276
0
                int x1 = (fx >> 16);
3277
0
                int x2;
3278
0
                fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
3279
0
                if (x1 != x2)
3280
0
                    break;
3281
0
                if (useFetch) {
3282
0
                    buf1[i * 2 + 0] = buf1[i * 2 + 1] = fetch1(s1, x1);
3283
0
                    buf2[i * 2 + 0] = buf2[i * 2 + 1] = fetch1(s2, x1);
3284
0
                } else {
3285
0
                    buf1[i * 2 + 0] = buf1[i * 2 + 1] = reinterpret_cast<const T *>(s1)[x1];
3286
0
                    buf2[i * 2 + 0] = buf2[i * 2 + 1] = reinterpret_cast<const T *>(s2)[x1];
3287
0
                }
3288
0
                fx += fdx;
3289
0
            }
3290
0
            int fastLen = len;
3291
0
            if (fdx > 0)
3292
0
                fastLen = qMin(fastLen, int((qint64(image.x2 - 1) * fixed_scale - fx) / fdx));
3293
0
            else if (fdx < 0)
3294
0
                fastLen = qMin(fastLen, int((qint64(image.x1) * fixed_scale - fx) / fdx));
3295
3296
0
            for (; i < fastLen; ++i) {
3297
0
                int x = (fx >> 16);
3298
0
                if (useFetch) {
3299
0
                    buf1[i * 2 + 0] = fetch1(s1, x);
3300
0
                    buf1[i * 2 + 1] = fetch1(s1, x + 1);
3301
0
                    buf2[i * 2 + 0] = fetch1(s2, x);
3302
0
                    buf2[i * 2 + 1] = fetch1(s2, x + 1);
3303
0
                } else {
3304
0
                    buf1[i * 2 + 0] = reinterpret_cast<const T *>(s1)[x];
3305
0
                    buf1[i * 2 + 1] = reinterpret_cast<const T *>(s1)[x + 1];
3306
0
                    buf2[i * 2 + 0] = reinterpret_cast<const T *>(s2)[x];
3307
0
                    buf2[i * 2 + 1] = reinterpret_cast<const T *>(s2)[x + 1];
3308
0
                }
3309
0
                fx += fdx;
3310
0
            }
3311
0
        }
3312
3313
0
        for (; i < len; ++i) {
3314
0
            int x1 = (fx >> 16);
3315
0
            int x2;
3316
0
            fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
3317
0
            if (useFetch) {
3318
0
                buf1[i * 2 + 0] = fetch1(s1, x1);
3319
0
                buf1[i * 2 + 1] = fetch1(s1, x2);
3320
0
                buf2[i * 2 + 0] = fetch1(s2, x1);
3321
0
                buf2[i * 2 + 1] = fetch1(s2, x2);
3322
0
            } else {
3323
0
                buf1[i * 2 + 0] = reinterpret_cast<const T *>(s1)[x1];
3324
0
                buf1[i * 2 + 1] = reinterpret_cast<const T *>(s1)[x2];
3325
0
                buf2[i * 2 + 0] = reinterpret_cast<const T *>(s2)[x1];
3326
0
                buf2[i * 2 + 1] = reinterpret_cast<const T *>(s2)[x2];
3327
0
            }
3328
0
            fx += fdx;
3329
0
        }
3330
0
    } else {
3331
0
        int i = 0;
3332
0
        if (blendType == BlendTransformedBilinear) {
3333
0
            for (; i < len; ++i) {
3334
0
                int x1 = (fx >> 16);
3335
0
                int x2;
3336
0
                int y1 = (fy >> 16);
3337
0
                int y2;
3338
0
                fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
3339
0
                fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
3340
0
                if (x1 != x2 && y1 != y2)
3341
0
                    break;
3342
0
                const uchar *s1 = image.scanLine(y1);
3343
0
                const uchar *s2 = image.scanLine(y2);
3344
0
                if (useFetch) {
3345
0
                    buf1[i * 2 + 0] = fetch1(s1, x1);
3346
0
                    buf1[i * 2 + 1] = fetch1(s1, x2);
3347
0
                    buf2[i * 2 + 0] = fetch1(s2, x1);
3348
0
                    buf2[i * 2 + 1] = fetch1(s2, x2);
3349
0
                } else {
3350
0
                    buf1[i * 2 + 0] = reinterpret_cast<const T *>(s1)[x1];
3351
0
                    buf1[i * 2 + 1] = reinterpret_cast<const T *>(s1)[x2];
3352
0
                    buf2[i * 2 + 0] = reinterpret_cast<const T *>(s2)[x1];
3353
0
                    buf2[i * 2 + 1] = reinterpret_cast<const T *>(s2)[x2];
3354
0
                }
3355
0
                fx += fdx;
3356
0
                fy += fdy;
3357
0
            }
3358
0
            int fastLen = len;
3359
0
            if (fdx > 0)
3360
0
                fastLen = qMin(fastLen, int((qint64(image.x2 - 1) * fixed_scale - fx) / fdx));
3361
0
            else if (fdx < 0)
3362
0
                fastLen = qMin(fastLen, int((qint64(image.x1) * fixed_scale - fx) / fdx));
3363
0
            if (fdy > 0)
3364
0
                fastLen = qMin(fastLen, int((qint64(image.y2 - 1) * fixed_scale - fy) / fdy));
3365
0
            else if (fdy < 0)
3366
0
                fastLen = qMin(fastLen, int((qint64(image.y1) * fixed_scale - fy) / fdy));
3367
3368
0
            for (; i < fastLen; ++i) {
3369
0
                int x = (fx >> 16);
3370
0
                int y = (fy >> 16);
3371
0
                const uchar *s1 = image.scanLine(y);
3372
0
                const uchar *s2 = s1 + image.bytesPerLine;
3373
0
                if (useFetch) {
3374
0
                    buf1[i * 2 + 0] = fetch1(s1, x);
3375
0
                    buf1[i * 2 + 1] = fetch1(s1, x + 1);
3376
0
                    buf2[i * 2 + 0] = fetch1(s2, x);
3377
0
                    buf2[i * 2 + 1] = fetch1(s2, x + 1);
3378
0
                } else {
3379
0
                    buf1[i * 2 + 0] = reinterpret_cast<const T *>(s1)[x];
3380
0
                    buf1[i * 2 + 1] = reinterpret_cast<const T *>(s1)[x + 1];
3381
0
                    buf2[i * 2 + 0] = reinterpret_cast<const T *>(s2)[x];
3382
0
                    buf2[i * 2 + 1] = reinterpret_cast<const T *>(s2)[x + 1];
3383
0
                }
3384
0
                fx += fdx;
3385
0
                fy += fdy;
3386
0
            }
3387
0
        }
3388
3389
0
        for (; i < len; ++i) {
3390
0
            int x1 = (fx >> 16);
3391
0
            int x2;
3392
0
            int y1 = (fy >> 16);
3393
0
            int y2;
3394
0
            fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
3395
0
            fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
3396
3397
0
            const uchar *s1 = image.scanLine(y1);
3398
0
            const uchar *s2 = image.scanLine(y2);
3399
0
            if (useFetch) {
3400
0
                buf1[i * 2 + 0] = fetch1(s1, x1);
3401
0
                buf1[i * 2 + 1] = fetch1(s1, x2);
3402
0
                buf2[i * 2 + 0] = fetch1(s2, x1);
3403
0
                buf2[i * 2 + 1] = fetch1(s2, x2);
3404
0
            } else {
3405
0
                buf1[i * 2 + 0] = reinterpret_cast<const T *>(s1)[x1];
3406
0
                buf1[i * 2 + 1] = reinterpret_cast<const T *>(s1)[x2];
3407
0
                buf2[i * 2 + 0] = reinterpret_cast<const T *>(s2)[x1];
3408
0
                buf2[i * 2 + 1] = reinterpret_cast<const T *>(s2)[x2];
3409
0
            }
3410
0
            fx += fdx;
3411
0
            fy += fdy;
3412
0
        }
3413
0
    }
3414
0
}
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinear_fetcher<(TextureBlendType)4, (QPixelLayout::BPP)4, unsigned int>(unsigned int*, unsigned int*, int, QTextureData const&, int, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinear_fetcher<(TextureBlendType)5, (QPixelLayout::BPP)4, unsigned int>(unsigned int*, unsigned int*, int, QTextureData const&, int, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinear_fetcher<(TextureBlendType)4, (QPixelLayout::BPP)6, unsigned int>(unsigned int*, unsigned int*, int, QTextureData const&, int, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinear_fetcher<(TextureBlendType)5, (QPixelLayout::BPP)6, unsigned int>(unsigned int*, unsigned int*, int, QTextureData const&, int, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinear_fetcher<(TextureBlendType)4, (QPixelLayout::BPP)0, unsigned int>(unsigned int*, unsigned int*, int, QTextureData const&, int, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinear_fetcher<(TextureBlendType)5, (QPixelLayout::BPP)0, unsigned int>(unsigned int*, unsigned int*, int, QTextureData const&, int, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinear_fetcher<(TextureBlendType)4, (QPixelLayout::BPP)7, QRgba64>(QRgba64*, QRgba64*, int, QTextureData const&, int, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void fetchTransformedBilinear_fetcher<(TextureBlendType)5, (QPixelLayout::BPP)7, QRgba64>(QRgba64*, QRgba64*, int, QTextureData const&, int, int, int, int)
3415
3416
// blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled
3417
template<TextureBlendType blendType, QPixelLayout::BPP bpp>
3418
static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *,
3419
                                                        const QSpanData *data, int y, int x, int length)
3420
0
{
3421
0
    const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
3422
0
    const QVector<QRgb> *clut = data->texture.colorTable;
3423
0
    Q_ASSERT(bpp == QPixelLayout::BPPNone || layout->bpp == bpp);
3424
3425
0
    const qreal cx = x + qreal(0.5);
3426
0
    const qreal cy = y + qreal(0.5);
3427
3428
0
    if (canUseFastMatrixPath(cx, cy, length, data)) {
3429
        // The increment pr x in the scanline
3430
0
        int fdx = (int)(data->m11 * fixed_scale);
3431
0
        int fdy = (int)(data->m12 * fixed_scale);
3432
3433
0
        int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
3434
0
        int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
3435
3436
0
        fx -= half_point;
3437
0
        fy -= half_point;
3438
3439
0
        if (fdy == 0) { // simple scale, no rotation or shear
3440
0
            if (qAbs(fdx) <= fixed_scale) { // scale up on X
3441
0
                fetchTransformedBilinear_simple_scale_helper<blendType>(buffer, buffer + length, data->texture, fx, fy, fdx, fdy);
3442
0
            } else if (qAbs(fdx) <= 2 * fixed_scale) { // scale down on X less than 2x
3443
0
                const int mid = (length * 2 < BufferSize) ? length : ((length + 1) / 2);
3444
0
                fetchTransformedBilinear_simple_scale_helper<blendType>(buffer, buffer + mid, data->texture, fx, fy, fdx, fdy);
3445
0
                if (mid != length)
3446
0
                    fetchTransformedBilinear_simple_scale_helper<blendType>(buffer + mid, buffer + length, data->texture, fx, fy, fdx, fdy);
3447
0
            } else {
3448
0
                const auto fetcher = fetchTransformedBilinear_fetcher<blendType,bpp,uint>;
3449
3450
0
                uint buf1[BufferSize];
3451
0
                uint buf2[BufferSize];
3452
0
                uint *b = buffer;
3453
0
                while (length) {
3454
0
                    int len = qMin(length, BufferSize / 2);
3455
0
                    fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, 0);
3456
0
                    layout->convertToARGB32PM(buf1, len * 2, clut);
3457
0
                    layout->convertToARGB32PM(buf2, len * 2, clut);
3458
3459
0
                    if (hasFastInterpolate4() || qAbs(data->m22) < qreal(1./8.)) { // scale up more than 8x (on Y)
3460
0
                        int disty = (fy & 0x0000ffff) >> 8;
3461
0
                        for (int i = 0; i < len; ++i) {
3462
0
                            int distx = (fx & 0x0000ffff) >> 8;
3463
0
                            b[i] = interpolate_4_pixels(buf1 + i * 2, buf2 + i * 2, distx, disty);
3464
0
                            fx += fdx;
3465
0
                        }
3466
0
                    } else {
3467
0
                        int disty = ((fy & 0x0000ffff) + 0x0800) >> 12;
3468
0
                        for (int i = 0; i < len; ++i) {
3469
0
                            uint tl = buf1[i * 2 + 0];
3470
0
                            uint tr = buf1[i * 2 + 1];
3471
0
                            uint bl = buf2[i * 2 + 0];
3472
0
                            uint br = buf2[i * 2 + 1];
3473
0
                            int distx = ((fx & 0x0000ffff) + 0x0800) >> 12;
3474
0
                            b[i] = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
3475
0
                            fx += fdx;
3476
0
                        }
3477
0
                    }
3478
0
                    length -= len;
3479
0
                    b += len;
3480
0
                }
3481
0
            }
3482
0
        } else { // rotation or shear
3483
0
            const auto fetcher = fetchTransformedBilinear_fetcher<blendType,bpp,uint>;
3484
3485
0
            uint buf1[BufferSize];
3486
0
            uint buf2[BufferSize];
3487
0
            uint *b = buffer;
3488
0
            while (length) {
3489
0
                int len = qMin(length, BufferSize / 2);
3490
0
                fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, fdy);
3491
0
                layout->convertToARGB32PM(buf1, len * 2, clut);
3492
0
                layout->convertToARGB32PM(buf2, len * 2, clut);
3493
3494
0
                if (hasFastInterpolate4() || qAbs(data->m11) < qreal(1./8.) || qAbs(data->m22) < qreal(1./8.)) {
3495
                    // If we are zooming more than 8 times, we use 8bit precision for the position.
3496
0
                    for (int i = 0; i < len; ++i) {
3497
0
                        int distx = (fx & 0x0000ffff) >> 8;
3498
0
                        int disty = (fy & 0x0000ffff) >> 8;
3499
3500
0
                        b[i] = interpolate_4_pixels(buf1 + i * 2, buf2 + i * 2, distx, disty);
3501
0
                        fx += fdx;
3502
0
                        fy += fdy;
3503
0
                    }
3504
0
                } else {
3505
                    // We are zooming less than 8x, use 4bit precision
3506
0
                    for (int i = 0; i < len; ++i) {
3507
0
                        uint tl = buf1[i * 2 + 0];
3508
0
                        uint tr = buf1[i * 2 + 1];
3509
0
                        uint bl = buf2[i * 2 + 0];
3510
0
                        uint br = buf2[i * 2 + 1];
3511
3512
0
                        int distx = ((fx & 0x0000ffff) + 0x0800) >> 12;
3513
0
                        int disty = ((fy & 0x0000ffff) + 0x0800) >> 12;
3514
3515
0
                        b[i] = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
3516
0
                        fx += fdx;
3517
0
                        fy += fdy;
3518
0
                    }
3519
0
                }
3520
3521
0
                length -= len;
3522
0
                b += len;
3523
0
            }
3524
0
        }
3525
0
    } else {
3526
        // When templated 'fetch' should be inlined at compile time:
3527
0
        const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout->bpp] : fetchPixel<bpp>;
3528
3529
0
        const QTextureData &image = data->texture;
3530
3531
0
        const qreal fdx = data->m11;
3532
0
        const qreal fdy = data->m12;
3533
0
        const qreal fdw = data->m13;
3534
3535
0
        qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
3536
0
        qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
3537
0
        qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
3538
3539
0
        uint buf1[BufferSize];
3540
0
        uint buf2[BufferSize];
3541
0
        uint *b = buffer;
3542
3543
0
        int distxs[BufferSize / 2];
3544
0
        int distys[BufferSize / 2];
3545
3546
0
        while (length) {
3547
0
            int len = qMin(length, BufferSize / 2);
3548
0
            for (int i = 0; i < len; ++i) {
3549
0
                const qreal iw = fw == 0 ? 1 : 1 / fw;
3550
0
                const qreal px = fx * iw - qreal(0.5);
3551
0
                const qreal py = fy * iw - qreal(0.5);
3552
3553
0
                int x1 = int(px) - (px < 0);
3554
0
                int x2;
3555
0
                int y1 = int(py) - (py < 0);
3556
0
                int y2;
3557
3558
0
                distxs[i] = int((px - x1) * 256);
3559
0
                distys[i] = int((py - y1) * 256);
3560
3561
0
                fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
3562
0
                fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
3563
3564
0
                const uchar *s1 = data->texture.scanLine(y1);
3565
0
                const uchar *s2 = data->texture.scanLine(y2);
3566
0
                buf1[i * 2 + 0] = fetch1(s1, x1);
3567
0
                buf1[i * 2 + 1] = fetch1(s1, x2);
3568
0
                buf2[i * 2 + 0] = fetch1(s2, x1);
3569
0
                buf2[i * 2 + 1] = fetch1(s2, x2);
3570
3571
0
                fx += fdx;
3572
0
                fy += fdy;
3573
0
                fw += fdw;
3574
                //force increment to avoid /0
3575
0
                if (!fw)
3576
0
                    fw += fdw;
3577
0
            }
3578
3579
0
            layout->convertToARGB32PM(buf1, len * 2, clut);
3580
0
            layout->convertToARGB32PM(buf2, len * 2, clut);
3581
3582
0
            for (int i = 0; i < len; ++i) {
3583
0
                int distx = distxs[i];
3584
0
                int disty = distys[i];
3585
3586
0
                b[i] = interpolate_4_pixels(buf1 + i * 2, buf2 + i * 2, distx, disty);
3587
0
            }
3588
0
            length -= len;
3589
0
            b += len;
3590
0
        }
3591
0
    }
3592
3593
0
    return buffer;
3594
0
}
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformedBilinear<(TextureBlendType)4, (QPixelLayout::BPP)4>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformedBilinear<(TextureBlendType)5, (QPixelLayout::BPP)4>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformedBilinear<(TextureBlendType)4, (QPixelLayout::BPP)6>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformedBilinear<(TextureBlendType)5, (QPixelLayout::BPP)6>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformedBilinear<(TextureBlendType)4, (QPixelLayout::BPP)0>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* fetchTransformedBilinear<(TextureBlendType)5, (QPixelLayout::BPP)0>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
3595
3596
#if QT_CONFIG(raster_64bit)
3597
template<TextureBlendType blendType>
3598
static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buffer, const QSpanData *data,
3599
                                                                    int y, int x, int length)
3600
0
{
3601
0
    const QTextureData &texture = data->texture;
3602
0
    const QPixelLayout *layout = &qPixelLayouts[texture.format];
3603
0
    const QVector<QRgb> *clut = data->texture.colorTable;
3604
3605
0
    const qreal cx = x + qreal(0.5);
3606
0
    const qreal cy = y + qreal(0.5);
3607
3608
0
    uint sbuf1[BufferSize];
3609
0
    uint sbuf2[BufferSize];
3610
0
    alignas(8) QRgba64 buf1[BufferSize];
3611
0
    alignas(8) QRgba64 buf2[BufferSize];
3612
0
    QRgba64 *end = buffer + length;
3613
0
    QRgba64 *b = buffer;
3614
3615
0
    if (canUseFastMatrixPath(cx, cy, length, data)) {
3616
        // The increment pr x in the scanline
3617
0
        const int fdx = (int)(data->m11 * fixed_scale);
3618
0
        const int fdy = (int)(data->m12 * fixed_scale);
3619
3620
0
        int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
3621
0
        int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
3622
3623
0
        fx -= half_point;
3624
0
        fy -= half_point;
3625
3626
0
        const auto fetcher =
3627
0
                (layout->bpp == QPixelLayout::BPP32)
3628
0
                        ? fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPP32, uint>
3629
0
                        : fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPPNone, uint>;
3630
3631
0
        if (fdy == 0) { //simple scale, no rotation
3632
0
            while (length) {
3633
0
                int len = qMin(length, BufferSize / 2);
3634
0
                int disty = (fy & 0x0000ffff);
3635
0
#if defined(__SSE2__)
3636
0
                const __m128i vdy = _mm_set1_epi16(disty);
3637
0
                const __m128i vidy = _mm_set1_epi16(0x10000 - disty);
3638
0
#endif
3639
0
                fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
3640
3641
0
                layout->convertToRGBA64PM(buf1, sbuf1, len * 2, clut, nullptr);
3642
0
                if (disty)
3643
0
                    layout->convertToRGBA64PM(buf2, sbuf2, len * 2, clut, nullptr);
3644
3645
0
                for (int i = 0; i < len; ++i) {
3646
0
                    int distx = (fx & 0x0000ffff);
3647
0
#if defined(__SSE2__)
3648
0
                    __m128i vt = _mm_loadu_si128((const __m128i*)(buf1 + i*2));
3649
0
                    if (disty) {
3650
0
                        __m128i vb = _mm_loadu_si128((const __m128i*)(buf2 + i*2));
3651
0
                        vt = _mm_mulhi_epu16(vt, vidy);
3652
0
                        vb = _mm_mulhi_epu16(vb, vdy);
3653
0
                        vt = _mm_add_epi16(vt, vb);
3654
0
                    }
3655
0
                    if (distx) {
3656
0
                        const __m128i vdistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(distx), _MM_SHUFFLE(0, 0, 0, 0));
3657
0
                        const __m128i vidistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(0x10000 - distx), _MM_SHUFFLE(0, 0, 0, 0));
3658
0
                        vt = _mm_mulhi_epu16(vt, _mm_unpacklo_epi64(vidistx, vdistx));
3659
0
                        vt = _mm_add_epi16(vt, _mm_srli_si128(vt, 8));
3660
0
                    }
3661
0
                    _mm_storel_epi64((__m128i*)(b+i), vt);
3662
#else
3663
                    b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty);
3664
#endif
3665
0
                    fx += fdx;
3666
0
                }
3667
0
                length -= len;
3668
0
                b += len;
3669
0
            }
3670
0
        } else { // rotation or shear
3671
0
            while (b < end) {
3672
0
                int len = qMin(length, BufferSize / 2);
3673
3674
0
                fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
3675
3676
0
                layout->convertToRGBA64PM(buf1, sbuf1, len * 2, clut, nullptr);
3677
0
                layout->convertToRGBA64PM(buf2, sbuf2, len * 2, clut, nullptr);
3678
3679
0
                for (int i = 0; i < len; ++i) {
3680
0
                    int distx = (fx & 0x0000ffff);
3681
0
                    int disty = (fy & 0x0000ffff);
3682
0
                    b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty);
3683
0
                    fx += fdx;
3684
0
                    fy += fdy;
3685
0
                }
3686
3687
0
                length -= len;
3688
0
                b += len;
3689
0
            }
3690
0
        }
3691
0
    } else { // !(data->fast_matrix)
3692
0
        const QTextureData &image = data->texture;
3693
3694
0
        const qreal fdx = data->m11;
3695
0
        const qreal fdy = data->m12;
3696
0
        const qreal fdw = data->m13;
3697
3698
0
        qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
3699
0
        qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
3700
0
        qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
3701
3702
0
        FetchPixelFunc fetch = qFetchPixel[layout->bpp];
3703
3704
0
        int distxs[BufferSize / 2];
3705
0
        int distys[BufferSize / 2];
3706
3707
0
        while (b < end) {
3708
0
            int len = qMin(length, BufferSize / 2);
3709
0
            for (int i = 0; i < len; ++i) {
3710
0
                const qreal iw = fw == 0 ? 1 : 1 / fw;
3711
0
                const qreal px = fx * iw - qreal(0.5);
3712
0
                const qreal py = fy * iw - qreal(0.5);
3713
3714
0
                int x1 = qFloor(px);
3715
0
                int x2;
3716
0
                int y1 = qFloor(py);
3717
0
                int y2;
3718
3719
0
                distxs[i] = int((px - x1) * (1<<16));
3720
0
                distys[i] = int((py - y1) * (1<<16));
3721
3722
0
                fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
3723
0
                fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
3724
3725
0
                const uchar *s1 = texture.scanLine(y1);
3726
0
                const uchar *s2 = texture.scanLine(y2);
3727
3728
0
                sbuf1[i * 2 + 0] = fetch(s1, x1);
3729
0
                sbuf1[i * 2 + 1] = fetch(s1, x2);
3730
0
                sbuf2[i * 2 + 0] = fetch(s2, x1);
3731
0
                sbuf2[i * 2 + 1] = fetch(s2, x2);
3732
3733
0
                fx += fdx;
3734
0
                fy += fdy;
3735
0
                fw += fdw;
3736
                //force increment to avoid /0
3737
0
                if (!fw)
3738
0
                    fw += fdw;
3739
0
            }
3740
3741
0
            layout->convertToRGBA64PM(buf1, sbuf1, len * 2, clut, nullptr);
3742
0
            layout->convertToRGBA64PM(buf2, sbuf2, len * 2, clut, nullptr);
3743
3744
0
            for (int i = 0; i < len; ++i) {
3745
0
                int distx = distxs[i];
3746
0
                int disty = distys[i];
3747
0
                b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty);
3748
0
            }
3749
3750
0
            length -= len;
3751
0
            b += len;
3752
0
        }
3753
0
    }
3754
0
    return buffer;
3755
0
}
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchTransformedBilinear64_uint32<(TextureBlendType)4>(QRgba64*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchTransformedBilinear64_uint32<(TextureBlendType)5>(QRgba64*, QSpanData const*, int, int, int)
3756
3757
template<TextureBlendType blendType>
3758
static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint64(QRgba64 *buffer, const QSpanData *data,
3759
                                                                    int y, int x, int length)
3760
0
{
3761
0
    const QTextureData &texture = data->texture;
3762
0
    Q_ASSERT(qPixelLayouts[texture.format].bpp == QPixelLayout::BPP64);
3763
0
    const auto convert = (data->texture.format == QImage::Format_RGBA64) ? convertRGBA64ToRGBA64PM : convertRGBA64PMToRGBA64PM;
3764
3765
0
    const qreal cx = x + qreal(0.5);
3766
0
    const qreal cy = y + qreal(0.5);
3767
3768
0
    alignas(8) QRgba64 buf1[BufferSize];
3769
0
    alignas(8) QRgba64 buf2[BufferSize];
3770
0
    QRgba64 *end = buffer + length;
3771
0
    QRgba64 *b = buffer;
3772
3773
0
    if (canUseFastMatrixPath(cx, cy, length, data)) {
3774
        // The increment pr x in the scanline
3775
0
        const int fdx = (int)(data->m11 * fixed_scale);
3776
0
        const int fdy = (int)(data->m12 * fixed_scale);
3777
3778
0
        int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
3779
0
        int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
3780
3781
0
        fx -= half_point;
3782
0
        fy -= half_point;
3783
0
        const auto fetcher = fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPP64, QRgba64>;
3784
3785
0
        if (fdy == 0) { //simple scale, no rotation
3786
0
            while (length) {
3787
0
                int len = qMin(length, BufferSize / 2);
3788
0
                int disty = (fy & 0x0000ffff);
3789
0
#if defined(__SSE2__)
3790
0
                const __m128i vdy = _mm_set1_epi16(disty);
3791
0
                const __m128i vidy = _mm_set1_epi16(0x10000 - disty);
3792
0
#endif
3793
0
                fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, fdy);
3794
3795
0
                convert(buf1, len * 2);
3796
0
                if (disty)
3797
0
                    convert(buf2, len * 2);
3798
3799
0
                for (int i = 0; i < len; ++i) {
3800
0
                    int distx = (fx & 0x0000ffff);
3801
0
#if defined(__SSE2__)
3802
0
                    __m128i vt = _mm_loadu_si128((const __m128i*)(buf1 + i*2));
3803
0
                    if (disty) {
3804
0
                        __m128i vb = _mm_loadu_si128((const __m128i*)(buf2 + i*2));
3805
0
                        vt = _mm_mulhi_epu16(vt, vidy);
3806
0
                        vb = _mm_mulhi_epu16(vb, vdy);
3807
0
                        vt = _mm_add_epi16(vt, vb);
3808
0
                    }
3809
0
                    if (distx) {
3810
0
                        const __m128i vdistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(distx), _MM_SHUFFLE(0, 0, 0, 0));
3811
0
                        const __m128i vidistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(0x10000 - distx), _MM_SHUFFLE(0, 0, 0, 0));
3812
0
                        vt = _mm_mulhi_epu16(vt, _mm_unpacklo_epi64(vidistx, vdistx));
3813
0
                        vt = _mm_add_epi16(vt, _mm_srli_si128(vt, 8));
3814
0
                    }
3815
0
                    _mm_storel_epi64((__m128i*)(b+i), vt);
3816
#else
3817
                    b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty);
3818
#endif
3819
0
                    fx += fdx;
3820
0
                }
3821
0
                length -= len;
3822
0
                b += len;
3823
0
            }
3824
0
        } else { // rotation or shear
3825
0
            while (b < end) {
3826
0
                int len = qMin(length, BufferSize / 2);
3827
3828
0
                fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, fdy);
3829
3830
0
                convert(buf1, len * 2);
3831
0
                convert(buf2, len * 2);
3832
3833
0
                for (int i = 0; i < len; ++i) {
3834
0
                    int distx = (fx & 0x0000ffff);
3835
0
                    int disty = (fy & 0x0000ffff);
3836
0
                    b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty);
3837
0
                    fx += fdx;
3838
0
                    fy += fdy;
3839
0
                }
3840
3841
0
                length -= len;
3842
0
                b += len;
3843
0
            }
3844
0
        }
3845
0
    } else { // !(data->fast_matrix)
3846
0
        const QTextureData &image = data->texture;
3847
3848
0
        const qreal fdx = data->m11;
3849
0
        const qreal fdy = data->m12;
3850
0
        const qreal fdw = data->m13;
3851
3852
0
        qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
3853
0
        qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
3854
0
        qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
3855
3856
0
        int distxs[BufferSize / 2];
3857
0
        int distys[BufferSize / 2];
3858
3859
0
        while (b < end) {
3860
0
            int len = qMin(length, BufferSize / 2);
3861
0
            for (int i = 0; i < len; ++i) {
3862
0
                const qreal iw = fw == 0 ? 1 : 1 / fw;
3863
0
                const qreal px = fx * iw - qreal(0.5);
3864
0
                const qreal py = fy * iw - qreal(0.5);
3865
3866
0
                int x1 = int(px) - (px < 0);
3867
0
                int x2;
3868
0
                int y1 = int(py) - (py < 0);
3869
0
                int y2;
3870
3871
0
                distxs[i] = int((px - x1) * (1<<16));
3872
0
                distys[i] = int((py - y1) * (1<<16));
3873
3874
0
                fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
3875
0
                fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
3876
3877
0
                const uchar *s1 = texture.scanLine(y1);
3878
0
                const uchar *s2 = texture.scanLine(y2);
3879
3880
0
                buf1[i * 2 + 0] = reinterpret_cast<const QRgba64 *>(s1)[x1];
3881
0
                buf1[i * 2 + 1] = reinterpret_cast<const QRgba64 *>(s1)[x2];
3882
0
                buf2[i * 2 + 0] = reinterpret_cast<const QRgba64 *>(s2)[x1];
3883
0
                buf2[i * 2 + 1] = reinterpret_cast<const QRgba64 *>(s2)[x2];
3884
3885
0
                fx += fdx;
3886
0
                fy += fdy;
3887
0
                fw += fdw;
3888
                //force increment to avoid /0
3889
0
                if (!fw)
3890
0
                    fw += fdw;
3891
0
            }
3892
3893
0
            convert(buf1, len * 2);
3894
0
            convert(buf2, len * 2);
3895
3896
0
            for (int i = 0; i < len; ++i) {
3897
0
                int distx = distxs[i];
3898
0
                int disty = distys[i];
3899
0
                b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty);
3900
0
            }
3901
3902
0
            length -= len;
3903
0
            b += len;
3904
0
        }
3905
0
    }
3906
0
    return buffer;
3907
0
}
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchTransformedBilinear64_uint64<(TextureBlendType)4>(QRgba64*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchTransformedBilinear64_uint64<(TextureBlendType)5>(QRgba64*, QSpanData const*, int, int, int)
3908
3909
template<TextureBlendType blendType>
3910
static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, const Operator *,
3911
                                                             const QSpanData *data, int y, int x, int length)
3912
0
{
3913
0
    if (qPixelLayouts[data->texture.format].bpp == QPixelLayout::BPP64)
3914
0
        return fetchTransformedBilinear64_uint64<blendType>(buffer, data, y, x, length);
3915
0
    return fetchTransformedBilinear64_uint32<blendType>(buffer, data, y, x, length);
3916
0
}
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchTransformedBilinear64<(TextureBlendType)4>(QRgba64*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* fetchTransformedBilinear64<(TextureBlendType)5>(QRgba64*, Operator const*, QSpanData const*, int, int, int)
3917
#endif
3918
3919
// FetchUntransformed can have more specialized methods added depending on SIMD features.
3920
static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = {
3921
    nullptr,                    // Invalid
3922
    fetchUntransformed,         // Mono
3923
    fetchUntransformed,         // MonoLsb
3924
    fetchUntransformed,         // Indexed8
3925
    fetchUntransformedARGB32PM, // RGB32
3926
    fetchUntransformed,         // ARGB32
3927
    fetchUntransformedARGB32PM, // ARGB32_Premultiplied
3928
    fetchUntransformedRGB16,    // RGB16
3929
    fetchUntransformed,         // ARGB8565_Premultiplied
3930
    fetchUntransformed,         // RGB666
3931
    fetchUntransformed,         // ARGB6666_Premultiplied
3932
    fetchUntransformed,         // RGB555
3933
    fetchUntransformed,         // ARGB8555_Premultiplied
3934
    fetchUntransformed,         // RGB888
3935
    fetchUntransformed,         // RGB444
3936
    fetchUntransformed,         // ARGB4444_Premultiplied
3937
    fetchUntransformed,         // RGBX8888
3938
    fetchUntransformed,         // RGBA8888
3939
    fetchUntransformed,         // RGBA8888_Premultiplied
3940
    fetchUntransformed,         // Format_BGR30
3941
    fetchUntransformed,         // Format_A2BGR30_Premultiplied
3942
    fetchUntransformed,         // Format_RGB30
3943
    fetchUntransformed,         // Format_A2RGB30_Premultiplied
3944
    fetchUntransformed,         // Alpha8
3945
    fetchUntransformed,         // Grayscale8
3946
    fetchUntransformed,         // RGBX64
3947
    fetchUntransformed,         // RGBA64
3948
    fetchUntransformed,         // RGBA64_Premultiplied
3949
    fetchUntransformed,         // Grayscale16
3950
    fetchUntransformed,         // BGR888
3951
};
3952
3953
static const SourceFetchProc sourceFetchGeneric[NBlendTypes] = {
3954
    fetchUntransformed,                                                             // Untransformed
3955
    fetchUntransformed,                                                             // Tiled
3956
    fetchTransformed<BlendTransformed, QPixelLayout::BPPNone>,                      // Transformed
3957
    fetchTransformed<BlendTransformedTiled, QPixelLayout::BPPNone>,                 // TransformedTiled
3958
    fetchTransformedBilinear<BlendTransformedBilinear, QPixelLayout::BPPNone>,      // TransformedBilinear
3959
    fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPPNone>  // TransformedBilinearTiled
3960
};
3961
3962
static SourceFetchProc sourceFetchARGB32PM[NBlendTypes] = {
3963
    fetchUntransformedARGB32PM,                                     // Untransformed
3964
    fetchUntransformedARGB32PM,                                     // Tiled
3965
    fetchTransformed<BlendTransformed, QPixelLayout::BPP32>,        // Transformed
3966
    fetchTransformed<BlendTransformedTiled, QPixelLayout::BPP32>,   // TransformedTiled
3967
    fetchTransformedBilinearARGB32PM<BlendTransformedBilinear>,     // Bilinear
3968
    fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled> // BilinearTiled
3969
};
3970
3971
static SourceFetchProc sourceFetchAny16[NBlendTypes] = {
3972
    fetchUntransformed,                                                             // Untransformed
3973
    fetchUntransformed,                                                             // Tiled
3974
    fetchTransformed<BlendTransformed, QPixelLayout::BPP16>,                        // Transformed
3975
    fetchTransformed<BlendTransformedTiled, QPixelLayout::BPP16>,                   // TransformedTiled
3976
    fetchTransformedBilinear<BlendTransformedBilinear, QPixelLayout::BPP16>,        // TransformedBilinear
3977
    fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPP16>    // TransformedBilinearTiled
3978
};
3979
3980
static SourceFetchProc sourceFetchAny32[NBlendTypes] = {
3981
    fetchUntransformed,                                                             // Untransformed
3982
    fetchUntransformed,                                                             // Tiled
3983
    fetchTransformed<BlendTransformed, QPixelLayout::BPP32>,                        // Transformed
3984
    fetchTransformed<BlendTransformedTiled, QPixelLayout::BPP32>,                   // TransformedTiled
3985
    fetchTransformedBilinear<BlendTransformedBilinear, QPixelLayout::BPP32>,        // TransformedBilinear
3986
    fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPP32>    // TransformedBilinearTiled
3987
};
3988
3989
static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage::Format format)
3990
0
{
3991
0
    if (format == QImage::Format_RGB32 || format == QImage::Format_ARGB32_Premultiplied)
3992
0
        return sourceFetchARGB32PM[blendType];
3993
0
    if (blendType == BlendUntransformed || blendType == BlendTiled)
3994
0
        return sourceFetchUntransformed[format];
3995
0
    if (qPixelLayouts[format].bpp == QPixelLayout::BPP16)
3996
0
        return sourceFetchAny16[blendType];
3997
0
    if (qPixelLayouts[format].bpp == QPixelLayout::BPP32)
3998
0
        return sourceFetchAny32[blendType];
3999
0
    return sourceFetchGeneric[blendType];
4000
0
}
4001
4002
#if QT_CONFIG(raster_64bit)
4003
static const SourceFetchProc64 sourceFetchGeneric64[NBlendTypes] = {
4004
    fetchUntransformed64,                                     // Untransformed
4005
    fetchUntransformed64,                                     // Tiled
4006
    fetchTransformed64<BlendTransformed>,                     // Transformed
4007
    fetchTransformed64<BlendTransformedTiled>,                // TransformedTiled
4008
    fetchTransformedBilinear64<BlendTransformedBilinear>,     // Bilinear
4009
    fetchTransformedBilinear64<BlendTransformedBilinearTiled> // BilinearTiled
4010
};
4011
4012
static const SourceFetchProc64 sourceFetchRGBA64PM[NBlendTypes] = {
4013
    fetchUntransformedRGBA64PM,                               // Untransformed
4014
    fetchUntransformedRGBA64PM,                               // Tiled
4015
    fetchTransformed64<BlendTransformed>,                     // Transformed
4016
    fetchTransformed64<BlendTransformedTiled>,                // TransformedTiled
4017
    fetchTransformedBilinear64<BlendTransformedBilinear>,     // Bilinear
4018
    fetchTransformedBilinear64<BlendTransformedBilinearTiled> // BilinearTiled
4019
};
4020
4021
static inline SourceFetchProc64 getSourceFetch64(TextureBlendType blendType, QImage::Format format)
4022
0
{
4023
0
    if (format == QImage::Format_RGBX64 || format == QImage::Format_RGBA64_Premultiplied)
4024
0
        return sourceFetchRGBA64PM[blendType];
4025
0
    return sourceFetchGeneric64[blendType];
4026
0
}
4027
#endif
4028
4029
4030
0
#define FIXPT_BITS 8
4031
0
#define FIXPT_SIZE (1<<FIXPT_BITS)
4032
0
#define FIXPT_MAX (INT_MAX >> (FIXPT_BITS + 1))
4033
4034
static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
4035
0
{
4036
0
    int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
4037
0
    return data->colorTable32[qt_gradient_clamp(data, ipos)];
4038
0
}
4039
4040
#if QT_CONFIG(raster_64bit)
4041
static const QRgba64& qt_gradient_pixel64_fixed(const QGradientData *data, int fixed_pos)
4042
0
{
4043
0
    int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
4044
0
    return data->colorTable64[qt_gradient_clamp(data, ipos)];
4045
0
}
4046
#endif
4047
4048
static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
4049
0
{
4050
0
    v->dx = data->gradient.linear.end.x - data->gradient.linear.origin.x;
4051
0
    v->dy = data->gradient.linear.end.y - data->gradient.linear.origin.y;
4052
0
    v->l = v->dx * v->dx + v->dy * v->dy;
4053
0
    v->off = 0;
4054
0
    if (v->l != 0) {
4055
0
        v->dx /= v->l;
4056
0
        v->dy /= v->l;
4057
0
        v->off = -v->dx * data->gradient.linear.origin.x - v->dy * data->gradient.linear.origin.y;
4058
0
    }
4059
0
}
4060
4061
class GradientBase32
4062
{
4063
public:
4064
    typedef uint Type;
4065
0
    static Type null() { return 0; }
4066
    static Type fetchSingle(const QGradientData& gradient, qreal v)
4067
0
    {
4068
0
        return qt_gradient_pixel(&gradient, v);
4069
0
    }
4070
    static Type fetchSingle(const QGradientData& gradient, int v)
4071
0
    {
4072
0
        return qt_gradient_pixel_fixed(&gradient, v);
4073
0
    }
4074
    static void memfill(Type *buffer, Type fill, int length)
4075
0
    {
4076
0
        qt_memfill32(buffer, fill, length);
4077
0
    }
4078
};
4079
4080
#if QT_CONFIG(raster_64bit)
4081
class GradientBase64
4082
{
4083
public:
4084
    typedef QRgba64 Type;
4085
0
    static Type null() { return QRgba64::fromRgba64(0); }
4086
    static Type fetchSingle(const QGradientData& gradient, qreal v)
4087
0
    {
4088
0
        return qt_gradient_pixel64(&gradient, v);
4089
0
    }
4090
    static Type fetchSingle(const QGradientData& gradient, int v)
4091
0
    {
4092
0
        return qt_gradient_pixel64_fixed(&gradient, v);
4093
0
    }
4094
    static void memfill(Type *buffer, Type fill, int length)
4095
0
    {
4096
0
        qt_memfill64((quint64*)buffer, fill, length);
4097
0
    }
4098
};
4099
#endif
4100
4101
template<class GradientBase, typename BlendType>
4102
static inline const BlendType * QT_FASTCALL qt_fetch_linear_gradient_template(
4103
        BlendType *buffer, const Operator *op, const QSpanData *data,
4104
        int y, int x, int length)
4105
0
{
4106
0
    const BlendType *b = buffer;
4107
0
    qreal t, inc;
4108
4109
0
    bool affine = true;
4110
0
    qreal rx=0, ry=0;
4111
0
    if (op->linear.l == 0) {
4112
0
        t = inc = 0;
4113
0
    } else {
4114
0
        rx = data->m21 * (y + qreal(0.5)) + data->m11 * (x + qreal(0.5)) + data->dx;
4115
0
        ry = data->m22 * (y + qreal(0.5)) + data->m12 * (x + qreal(0.5)) + data->dy;
4116
0
        t = op->linear.dx*rx + op->linear.dy*ry + op->linear.off;
4117
0
        inc = op->linear.dx * data->m11 + op->linear.dy * data->m12;
4118
0
        affine = !data->m13 && !data->m23;
4119
4120
0
        if (affine) {
4121
0
            t *= (GRADIENT_STOPTABLE_SIZE - 1);
4122
0
            inc *= (GRADIENT_STOPTABLE_SIZE - 1);
4123
0
        }
4124
0
    }
4125
4126
0
    const BlendType *end = buffer + length;
4127
0
    if (affine) {
4128
0
        if (inc > qreal(-1e-5) && inc < qreal(1e-5)) {
4129
0
            if (std::abs(t) < FIXPT_MAX)
4130
0
                GradientBase::memfill(buffer, GradientBase::fetchSingle(data->gradient, int(t * FIXPT_SIZE)), length);
4131
0
            else
4132
0
                GradientBase::memfill(buffer, GradientBase::fetchSingle(data->gradient, t / GRADIENT_STOPTABLE_SIZE), length);
4133
0
        } else {
4134
0
            if (std::abs(t) < FIXPT_MAX && std::abs(inc) < FIXPT_MAX && std::abs(t + inc * length) < FIXPT_MAX) {
4135
                // we can use fixed point math
4136
0
                int t_fixed = int(t * FIXPT_SIZE);
4137
0
                int inc_fixed = int(inc * FIXPT_SIZE);
4138
0
                while (buffer < end) {
4139
0
                    *buffer = GradientBase::fetchSingle(data->gradient, t_fixed);
4140
0
                    t_fixed += inc_fixed;
4141
0
                    ++buffer;
4142
0
                }
4143
0
            } else {
4144
                // we have to fall back to float math
4145
0
                while (buffer < end) {
4146
0
                    *buffer = GradientBase::fetchSingle(data->gradient, t/GRADIENT_STOPTABLE_SIZE);
4147
0
                    t += inc;
4148
0
                    ++buffer;
4149
0
                }
4150
0
            }
4151
0
        }
4152
0
    } else { // fall back to float math here as well
4153
0
        qreal rw = data->m23 * (y + qreal(0.5)) + data->m13 * (x + qreal(0.5)) + data->m33;
4154
0
        while (buffer < end) {
4155
0
            qreal x = rx/rw;
4156
0
            qreal y = ry/rw;
4157
0
            t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off;
4158
4159
0
            *buffer = GradientBase::fetchSingle(data->gradient, t);
4160
0
            rx += data->m11;
4161
0
            ry += data->m12;
4162
0
            rw += data->m13;
4163
0
            if (!rw) {
4164
0
                rw += data->m13;
4165
0
            }
4166
0
            ++buffer;
4167
0
        }
4168
0
    }
4169
4170
0
    return b;
4171
0
}
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* qt_fetch_linear_gradient_template<GradientBase32, unsigned int>(unsigned int*, Operator const*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* qt_fetch_linear_gradient_template<GradientBase64, QRgba64>(QRgba64*, Operator const*, QSpanData const*, int, int, int)
4172
4173
static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data,
4174
                                                         int y, int x, int length)
4175
0
{
4176
0
    return qt_fetch_linear_gradient_template<GradientBase32, uint>(buffer, op, data, y, x, length);
4177
0
}
4178
4179
#if QT_CONFIG(raster_64bit)
4180
static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data,
4181
                                                                 int y, int x, int length)
4182
0
{
4183
0
    return qt_fetch_linear_gradient_template<GradientBase64, QRgba64>(buffer, op, data, y, x, length);
4184
0
}
4185
#endif
4186
4187
static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data)
4188
0
{
4189
0
    v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x;
4190
0
    v->dy = data->gradient.radial.center.y - data->gradient.radial.focal.y;
4191
4192
0
    v->dr = data->gradient.radial.center.radius - data->gradient.radial.focal.radius;
4193
0
    v->sqrfr = data->gradient.radial.focal.radius * data->gradient.radial.focal.radius;
4194
4195
0
    v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy;
4196
0
    v->inv2a = 1 / (2 * v->a);
4197
4198
0
    v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0;
4199
0
}
4200
4201
template <class GradientBase>
4202
class RadialFetchPlain : public GradientBase
4203
{
4204
public:
4205
    typedef typename GradientBase::Type BlendType;
4206
    static void fetch(BlendType *buffer, BlendType *end,
4207
                      const Operator *op, const QSpanData *data, qreal det,
4208
                      qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b)
4209
0
    {
4210
0
        if (op->radial.extended) {
4211
0
            while (buffer < end) {
4212
0
                BlendType result = GradientBase::null();
4213
0
                if (det >= 0) {
4214
0
                    qreal w = qSqrt(det) - b;
4215
0
                    if (data->gradient.radial.focal.radius + op->radial.dr * w >= 0)
4216
0
                        result = GradientBase::fetchSingle(data->gradient, w);
4217
0
                }
4218
4219
0
                *buffer = result;
4220
4221
0
                det += delta_det;
4222
0
                delta_det += delta_delta_det;
4223
0
                b += delta_b;
4224
4225
0
                ++buffer;
4226
0
            }
4227
0
        } else {
4228
0
            while (buffer < end) {
4229
0
                *buffer++ = GradientBase::fetchSingle(data->gradient, qSqrt(det) - b);
4230
4231
0
                det += delta_det;
4232
0
                delta_det += delta_delta_det;
4233
0
                b += delta_b;
4234
0
            }
4235
0
        }
4236
0
    }
Unexecuted instantiation: RadialFetchPlain<GradientBase32>::fetch(unsigned int*, unsigned int*, Operator const*, QSpanData const*, double, double, double, double, double)
Unexecuted instantiation: RadialFetchPlain<GradientBase64>::fetch(QRgba64*, QRgba64*, Operator const*, QSpanData const*, double, double, double, double, double)
4237
};
4238
4239
const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data,
4240
                                                        int y, int x, int length)
4241
0
{
4242
0
    return qt_fetch_radial_gradient_template<RadialFetchPlain<GradientBase32>, uint>(buffer, op, data, y, x, length);
4243
0
}
4244
4245
static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain;
4246
4247
#if QT_CONFIG(raster_64bit)
4248
const QRgba64 * QT_FASTCALL qt_fetch_radial_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data,
4249
                                                        int y, int x, int length)
4250
0
{
4251
0
    return qt_fetch_radial_gradient_template<RadialFetchPlain<GradientBase64>, QRgba64>(buffer, op, data, y, x, length);
4252
0
}
4253
#endif
4254
4255
template <class GradientBase, typename BlendType>
4256
static inline const BlendType * QT_FASTCALL qt_fetch_conical_gradient_template(
4257
        BlendType *buffer, const QSpanData *data,
4258
        int y, int x, int length)
4259
0
{
4260
0
    const BlendType *b = buffer;
4261
0
    qreal rx = data->m21 * (y + qreal(0.5))
4262
0
               + data->dx + data->m11 * (x + qreal(0.5));
4263
0
    qreal ry = data->m22 * (y + qreal(0.5))
4264
0
               + data->dy + data->m12 * (x + qreal(0.5));
4265
0
    bool affine = !data->m13 && !data->m23;
4266
4267
0
    const qreal inv2pi = M_1_PI / 2.0;
4268
4269
0
    const BlendType *end = buffer + length;
4270
0
    if (affine) {
4271
0
        rx -= data->gradient.conical.center.x;
4272
0
        ry -= data->gradient.conical.center.y;
4273
0
        while (buffer < end) {
4274
0
            qreal angle = qAtan2(ry, rx) + data->gradient.conical.angle;
4275
4276
0
            *buffer = GradientBase::fetchSingle(data->gradient, 1 - angle * inv2pi);
4277
4278
0
            rx += data->m11;
4279
0
            ry += data->m12;
4280
0
            ++buffer;
4281
0
        }
4282
0
    } else {
4283
0
        qreal rw = data->m23 * (y + qreal(0.5))
4284
0
                   + data->m33 + data->m13 * (x + qreal(0.5));
4285
0
        if (!rw)
4286
0
            rw = 1;
4287
0
        while (buffer < end) {
4288
0
            qreal angle = qAtan2(ry/rw - data->gradient.conical.center.x,
4289
0
                                rx/rw - data->gradient.conical.center.y)
4290
0
                          + data->gradient.conical.angle;
4291
4292
0
            *buffer = GradientBase::fetchSingle(data->gradient, 1 - angle * inv2pi);
4293
4294
0
            rx += data->m11;
4295
0
            ry += data->m12;
4296
0
            rw += data->m13;
4297
0
            if (!rw) {
4298
0
                rw += data->m13;
4299
0
            }
4300
0
            ++buffer;
4301
0
        }
4302
0
    }
4303
0
    return b;
4304
0
}
Unexecuted instantiation: qdrawhelper.cpp:unsigned int const* qt_fetch_conical_gradient_template<GradientBase32, unsigned int>(unsigned int*, QSpanData const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:QRgba64 const* qt_fetch_conical_gradient_template<GradientBase64, QRgba64>(QRgba64*, QSpanData const*, int, int, int)
4305
4306
static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data,
4307
                                                          int y, int x, int length)
4308
0
{
4309
0
    return qt_fetch_conical_gradient_template<GradientBase32, uint>(buffer, data, y, x, length);
4310
0
}
4311
4312
#if QT_CONFIG(raster_64bit)
4313
static const QRgba64 * QT_FASTCALL qt_fetch_conical_gradient_rgb64(QRgba64 *buffer, const Operator *, const QSpanData *data,
4314
                                                                   int y, int x, int length)
4315
0
{
4316
0
    return qt_fetch_conical_gradient_template<GradientBase64, QRgba64>(buffer, data, y, x, length);
4317
0
}
4318
#endif
4319
4320
extern CompositionFunctionSolid qt_functionForModeSolid_C[];
4321
extern CompositionFunctionSolid64 qt_functionForModeSolid64_C[];
4322
4323
static const CompositionFunctionSolid *functionForModeSolid = qt_functionForModeSolid_C;
4324
#if QT_CONFIG(raster_64bit)
4325
static const CompositionFunctionSolid64 *functionForModeSolid64 = qt_functionForModeSolid64_C;
4326
#endif
4327
4328
extern CompositionFunction qt_functionForMode_C[];
4329
extern CompositionFunction64 qt_functionForMode64_C[];
4330
4331
static const CompositionFunction *functionForMode = qt_functionForMode_C;
4332
#if QT_CONFIG(raster_64bit)
4333
static const CompositionFunction64 *functionForMode64 = qt_functionForMode64_C;
4334
#endif
4335
4336
static TextureBlendType getBlendType(const QSpanData *data)
4337
0
{
4338
0
    TextureBlendType ft;
4339
0
    if (data->txop <= QTransform::TxTranslate)
4340
0
        if (data->texture.type == QTextureData::Tiled)
4341
0
            ft = BlendTiled;
4342
0
        else
4343
0
            ft = BlendUntransformed;
4344
0
    else if (data->bilinear)
4345
0
        if (data->texture.type == QTextureData::Tiled)
4346
0
            ft = BlendTransformedBilinearTiled;
4347
0
        else
4348
0
            ft = BlendTransformedBilinear;
4349
0
    else
4350
0
        if (data->texture.type == QTextureData::Tiled)
4351
0
            ft = BlendTransformedTiled;
4352
0
        else
4353
0
            ft = BlendTransformed;
4354
0
    return ft;
4355
0
}
4356
4357
static inline Operator getOperator(const QSpanData *data, const QSpan *spans, int spanCount)
4358
4.74k
{
4359
4.74k
    Operator op;
4360
4.74k
    bool solidSource = false;
4361
4362
4.74k
    switch(data->type) {
4363
4.74k
    case QSpanData::Solid:
4364
4.74k
        solidSource = data->solidColor.isOpaque();
4365
4.74k
        op.srcFetch = nullptr;
4366
4.74k
#if QT_CONFIG(raster_64bit)
4367
4.74k
        op.srcFetch64 = nullptr;
4368
4.74k
#endif
4369
4.74k
        break;
4370
0
    case QSpanData::LinearGradient:
4371
0
        solidSource = !data->gradient.alphaColor;
4372
0
        getLinearGradientValues(&op.linear, data);
4373
0
        op.srcFetch = qt_fetch_linear_gradient;
4374
0
#if QT_CONFIG(raster_64bit)
4375
0
        op.srcFetch64 = qt_fetch_linear_gradient_rgb64;
4376
0
#endif
4377
0
        break;
4378
0
    case QSpanData::RadialGradient:
4379
0
        solidSource = !data->gradient.alphaColor;
4380
0
        getRadialGradientValues(&op.radial, data);
4381
0
        op.srcFetch = qt_fetch_radial_gradient;
4382
0
#if QT_CONFIG(raster_64bit)
4383
0
        op.srcFetch64 = qt_fetch_radial_gradient_rgb64;
4384
0
#endif
4385
0
        break;
4386
0
    case QSpanData::ConicalGradient:
4387
0
        solidSource = !data->gradient.alphaColor;
4388
0
        op.srcFetch = qt_fetch_conical_gradient;
4389
0
#if QT_CONFIG(raster_64bit)
4390
0
        op.srcFetch64 = qt_fetch_conical_gradient_rgb64;
4391
0
#endif
4392
0
        break;
4393
0
    case QSpanData::Texture:
4394
0
        solidSource = !data->texture.hasAlpha;
4395
0
        op.srcFetch = getSourceFetch(getBlendType(data), data->texture.format);
4396
0
#if QT_CONFIG(raster_64bit)
4397
0
        op.srcFetch64 = getSourceFetch64(getBlendType(data), data->texture.format);;
4398
0
#endif
4399
0
        break;
4400
0
    default:
4401
0
        Q_UNREACHABLE();
4402
0
        break;
4403
4.74k
    }
4404
#if !QT_CONFIG(raster_64bit)
4405
    op.srcFetch64 = 0;
4406
#endif
4407
4408
4.74k
    op.mode = data->rasterBuffer->compositionMode;
4409
4.74k
    if (op.mode == QPainter::CompositionMode_SourceOver && solidSource)
4410
4.74k
        op.mode = QPainter::CompositionMode_Source;
4411
4412
4.74k
    op.destFetch = destFetchProc[data->rasterBuffer->format];
4413
4.74k
#if QT_CONFIG(raster_64bit)
4414
4.74k
    op.destFetch64 = destFetchProc64[data->rasterBuffer->format];
4415
#else
4416
    op.destFetch64 = 0;
4417
#endif
4418
4.74k
    if (op.mode == QPainter::CompositionMode_Source &&
4419
4.74k
            (data->type != QSpanData::Texture || data->texture.const_alpha == 256)) {
4420
4.74k
        const QSpan *lastSpan = spans + spanCount;
4421
4.74k
        bool alphaSpans = false;
4422
4.74k
        while (spans < lastSpan) {
4423
0
            if (spans->coverage != 255) {
4424
0
                alphaSpans = true;
4425
0
                break;
4426
0
            }
4427
0
            ++spans;
4428
0
        }
4429
4.74k
        if (!alphaSpans && spanCount > 0) {
4430
            // If all spans are opaque we do not need to fetch dest.
4431
            // But don't clear passthrough destFetch as they are just as fast and save destStore.
4432
0
            if (op.destFetch != destFetchARGB32P)
4433
0
                op.destFetch = destFetchUndefined;
4434
0
#if QT_CONFIG(raster_64bit)
4435
0
            if (op.destFetch64 != destFetchRGB64)
4436
0
                op.destFetch64 = destFetch64Undefined;
4437
0
#endif
4438
0
        }
4439
4.74k
    }
4440
4441
4.74k
    op.destStore = destStoreProc[data->rasterBuffer->format];
4442
4.74k
    op.funcSolid = functionForModeSolid[op.mode];
4443
4.74k
    op.func = functionForMode[op.mode];
4444
4.74k
#if QT_CONFIG(raster_64bit)
4445
4.74k
    op.destStore64 = destStoreProc64[data->rasterBuffer->format];
4446
4.74k
    op.funcSolid64 = functionForModeSolid64[op.mode];
4447
4.74k
    op.func64 = functionForMode64[op.mode];
4448
#else
4449
    op.destStore64 = 0;
4450
    op.funcSolid64 = 0;
4451
    op.func64 = 0;
4452
#endif
4453
4454
4.74k
    return op;
4455
4.74k
}
4456
4457
static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP bpp, int x, int y, int length)
4458
0
{
4459
0
    switch (bpp) {
4460
0
    case QPixelLayout::BPP64: {
4461
0
        quint64 *dest = reinterpret_cast<quint64 *>(rasterBuffer->scanLine(y)) + x;
4462
0
        qt_memfill_template(dest + 1, dest[0], length - 1);
4463
0
        break;
4464
0
    }
4465
0
    case QPixelLayout::BPP32: {
4466
0
        quint32 *dest = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(y)) + x;
4467
0
        qt_memfill_template(dest + 1, dest[0], length - 1);
4468
0
        break;
4469
0
    }
4470
0
    case QPixelLayout::BPP24: {
4471
0
        quint24 *dest = reinterpret_cast<quint24 *>(rasterBuffer->scanLine(y)) + x;
4472
0
        qt_memfill_template(dest + 1, dest[0], length - 1);
4473
0
        break;
4474
0
    }
4475
0
    case QPixelLayout::BPP16: {
4476
0
        quint16 *dest = reinterpret_cast<quint16 *>(rasterBuffer->scanLine(y)) + x;
4477
0
        qt_memfill_template(dest + 1, dest[0], length - 1);
4478
0
        break;
4479
0
    }
4480
0
    case QPixelLayout::BPP8: {
4481
0
        uchar *dest = rasterBuffer->scanLine(y) + x;
4482
0
        memset(dest + 1, dest[0], length - 1);
4483
0
        break;
4484
0
    }
4485
0
    default:
4486
0
        Q_UNREACHABLE();
4487
0
    }
4488
0
}
4489
4490
4491
// -------------------- blend methods ---------------------
4492
4493
static void blend_color_generic(int count, const QSpan *spans, void *userData)
4494
0
{
4495
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4496
0
    uint buffer[BufferSize];
4497
0
    Operator op = getOperator(data, nullptr, 0);
4498
0
    const uint color = data->solidColor.toArgb32();
4499
0
    const bool solidFill = op.mode == QPainter::CompositionMode_Source;
4500
0
    const QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
4501
4502
0
    while (count--) {
4503
0
        int x = spans->x;
4504
0
        int length = spans->len;
4505
0
        if (solidFill && bpp >= QPixelLayout::BPP8 && spans->coverage == 255 && length) {
4506
            // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels
4507
0
            op.destStore(data->rasterBuffer, x, spans->y, &color, 1);
4508
0
            spanfill_from_first(data->rasterBuffer, bpp, x, spans->y, length);
4509
0
            length = 0;
4510
0
        }
4511
4512
0
        while (length) {
4513
0
            int l = qMin(BufferSize, length);
4514
0
            uint *dest = op.destFetch(buffer, data->rasterBuffer, x, spans->y, l);
4515
0
            op.funcSolid(dest, l, color, spans->coverage);
4516
0
            if (op.destStore)
4517
0
                op.destStore(data->rasterBuffer, x, spans->y, dest, l);
4518
0
            length -= l;
4519
0
            x += l;
4520
0
        }
4521
0
        ++spans;
4522
0
    }
4523
0
}
4524
4525
static void blend_color_argb(int count, const QSpan *spans, void *userData)
4526
4.74k
{
4527
4.74k
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4528
4529
4.74k
    const Operator op = getOperator(data, nullptr, 0);
4530
4.74k
    const uint color = data->solidColor.toArgb32();
4531
4532
4.74k
    if (op.mode == QPainter::CompositionMode_Source) {
4533
        // inline for performance
4534
12.6k
        while (count--) {
4535
7.90k
            uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
4536
7.90k
            if (spans->coverage == 255) {
4537
7.90k
                qt_memfill(target, color, spans->len);
4538
7.90k
#ifdef __SSE2__
4539
7.90k
            } else if (spans->len > 16) {
4540
0
                op.funcSolid(target, spans->len, color, spans->coverage);
4541
0
#endif
4542
0
            } else {
4543
0
                uint c = BYTE_MUL(color, spans->coverage);
4544
0
                int ialpha = 255 - spans->coverage;
4545
0
                for (int i = 0; i < spans->len; ++i)
4546
0
                    target[i] = c + BYTE_MUL(target[i], ialpha);
4547
0
            }
4548
7.90k
            ++spans;
4549
7.90k
        }
4550
4.74k
        return;
4551
4.74k
    }
4552
4553
0
    while (count--) {
4554
0
        uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
4555
0
        op.funcSolid(target, spans->len, color, spans->coverage);
4556
0
        ++spans;
4557
0
    }
4558
0
}
4559
4560
void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData)
4561
0
{
4562
0
#if QT_CONFIG(raster_64bit)
4563
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4564
0
    Operator op = getOperator(data, nullptr, 0);
4565
0
    if (!op.funcSolid64) {
4566
0
        qCDebug(lcQtGuiDrawHelper, "blend_color_generic_rgb64: unsupported 64bit blend attempted, falling back to 32-bit");
4567
0
        return blend_color_generic(count, spans, userData);
4568
0
    }
4569
4570
0
    alignas(8) QRgba64 buffer[BufferSize];
4571
0
    const QRgba64 color = data->solidColor;
4572
0
    const bool solidFill = op.mode == QPainter::CompositionMode_Source;
4573
0
    const QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
4574
4575
0
    while (count--) {
4576
0
        int x = spans->x;
4577
0
        int length = spans->len;
4578
0
        if (solidFill && bpp >= QPixelLayout::BPP8 && spans->coverage == 255 && length && op.destStore64) {
4579
            // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels
4580
0
            op.destStore64(data->rasterBuffer, x, spans->y, &color, 1);
4581
0
            spanfill_from_first(data->rasterBuffer, bpp, x, spans->y, length);
4582
0
            length = 0;
4583
0
        }
4584
4585
0
        while (length) {
4586
0
            int l = qMin(BufferSize, length);
4587
0
            QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l);
4588
0
            op.funcSolid64(dest, l, color, spans->coverage);
4589
0
            if (op.destStore64)
4590
0
                op.destStore64(data->rasterBuffer, x, spans->y, dest, l);
4591
0
            length -= l;
4592
0
            x += l;
4593
0
        }
4594
0
        ++spans;
4595
0
    }
4596
#else
4597
    blend_color_generic(count, spans, userData);
4598
#endif
4599
0
}
4600
4601
static void blend_color_rgb16(int count, const QSpan *spans, void *userData)
4602
0
{
4603
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4604
4605
    /*
4606
        We duplicate a little logic from getOperator() and calculate the
4607
        composition mode directly.  This allows blend_color_rgb16 to be used
4608
        from qt_gradient_quint16 with minimal overhead.
4609
     */
4610
0
    QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4611
0
    if (mode == QPainter::CompositionMode_SourceOver && data->solidColor.isOpaque())
4612
0
        mode = QPainter::CompositionMode_Source;
4613
4614
0
    if (mode == QPainter::CompositionMode_Source) {
4615
        // inline for performance
4616
0
        ushort c = data->solidColor.toRgb16();
4617
0
        for (; count--; spans++) {
4618
0
            if (!spans->len)
4619
0
                continue;
4620
0
            ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
4621
0
            if (spans->coverage == 255) {
4622
0
                qt_memfill(target, c, spans->len);
4623
0
            } else {
4624
0
                ushort color = BYTE_MUL_RGB16(c, spans->coverage);
4625
0
                int ialpha = 255 - spans->coverage;
4626
0
                const ushort *end = target + spans->len;
4627
0
                while (target < end) {
4628
0
                    *target = color + BYTE_MUL_RGB16(*target, ialpha);
4629
0
                    ++target;
4630
0
                }
4631
0
            }
4632
0
        }
4633
0
        return;
4634
0
    }
4635
4636
0
    if (mode == QPainter::CompositionMode_SourceOver) {
4637
0
        for (; count--; spans++) {
4638
0
            if (!spans->len)
4639
0
                continue;
4640
0
            uint color = BYTE_MUL(data->solidColor.toArgb32(), spans->coverage);
4641
0
            int ialpha = qAlpha(~color);
4642
0
            ushort c = qConvertRgb32To16(color);
4643
0
            ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
4644
0
            int len = spans->len;
4645
0
            bool pre = (((quintptr)target) & 0x3) != 0;
4646
0
            bool post = false;
4647
0
            if (pre) {
4648
                // skip to word boundary
4649
0
                *target = c + BYTE_MUL_RGB16(*target, ialpha);
4650
0
                ++target;
4651
0
                --len;
4652
0
            }
4653
0
            if (len & 0x1) {
4654
0
                post = true;
4655
0
                --len;
4656
0
            }
4657
0
            uint *target32 = (uint*)target;
4658
0
            uint c32 = c | (c<<16);
4659
0
            len >>= 1;
4660
0
            uint salpha = (ialpha+1) >> 3; // calculate here rather than in loop
4661
0
            while (len--) {
4662
                // blend full words
4663
0
                *target32 = c32 + BYTE_MUL_RGB16_32(*target32, salpha);
4664
0
                ++target32;
4665
0
                target += 2;
4666
0
            }
4667
0
            if (post) {
4668
                // one last pixel beyond a full word
4669
0
                *target = c + BYTE_MUL_RGB16(*target, ialpha);
4670
0
            }
4671
0
        }
4672
0
        return;
4673
0
    }
4674
4675
0
    blend_color_generic(count, spans, userData);
4676
0
}
4677
4678
template <typename T>
4679
void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handler)
4680
0
{
4681
0
    uint const_alpha = 256;
4682
0
    if (data->type == QSpanData::Texture)
4683
0
        const_alpha = data->texture.const_alpha;
4684
4685
0
    int coverage = 0;
4686
0
    while (count) {
4687
0
        if (!spans->len) {
4688
0
            ++spans;
4689
0
            --count;
4690
0
            continue;
4691
0
        }
4692
0
        int x = spans->x;
4693
0
        const int y = spans->y;
4694
0
        int right = x + spans->len;
4695
4696
        // compute length of adjacent spans
4697
0
        for (int i = 1; i < count && spans[i].y == y && spans[i].x == right; ++i)
4698
0
            right += spans[i].len;
4699
0
        int length = right - x;
4700
4701
0
        while (length) {
4702
0
            int l = qMin(BufferSize, length);
4703
0
            length -= l;
4704
4705
0
            int process_length = l;
4706
0
            int process_x = x;
4707
4708
0
            const typename T::BlendType *src = handler.fetch(process_x, y, process_length);
4709
0
            int offset = 0;
4710
0
            while (l > 0) {
4711
0
                if (x == spans->x) // new span?
4712
0
                    coverage = (spans->coverage * const_alpha) >> 8;
4713
4714
0
                int right = spans->x + spans->len;
4715
0
                int len = qMin(l, right - x);
4716
4717
0
                handler.process(x, y, len, coverage, src, offset);
4718
4719
0
                l -= len;
4720
0
                x += len;
4721
0
                offset += len;
4722
4723
0
                if (x == right) { // done with current span?
4724
0
                    ++spans;
4725
0
                    --count;
4726
0
                }
4727
0
            }
4728
0
            handler.store(process_x, y, process_length);
4729
0
        }
4730
0
    }
4731
0
}
Unexecuted instantiation: void handleSpans<BlendSrcGeneric>(int, QT_FT_Span_ const*, QSpanData const*, BlendSrcGeneric&)
Unexecuted instantiation: void handleSpans<BlendSrcGenericRGB64>(int, QT_FT_Span_ const*, QSpanData const*, BlendSrcGenericRGB64&)
4732
4733
template<typename T>
4734
struct QBlendBase
4735
{
4736
    typedef T BlendType;
4737
    QBlendBase(QSpanData *d, const Operator &o)
4738
0
        : data(d)
4739
0
        , op(o)
4740
0
        , dest(nullptr)
4741
0
    {
4742
0
    }
Unexecuted instantiation: QBlendBase<unsigned int>::QBlendBase(QSpanData*, Operator const&)
Unexecuted instantiation: QBlendBase<QRgba64>::QBlendBase(QSpanData*, Operator const&)
4743
4744
    QSpanData *data;
4745
    Operator op;
4746
4747
    BlendType *dest;
4748
4749
    alignas(8) BlendType buffer[BufferSize];
4750
    alignas(8) BlendType src_buffer[BufferSize];
4751
};
4752
4753
class BlendSrcGeneric : public QBlendBase<uint>
4754
{
4755
public:
4756
    BlendSrcGeneric(QSpanData *d, const Operator &o)
4757
0
        : QBlendBase<uint>(d, o)
4758
0
    {
4759
0
    }
4760
4761
    const uint *fetch(int x, int y, int len)
4762
0
    {
4763
0
        dest = op.destFetch(buffer, data->rasterBuffer, x, y, len);
4764
0
        return op.srcFetch(src_buffer, &op, data, y, x, len);
4765
0
    }
4766
4767
    void process(int, int, int len, int coverage, const uint *src, int offset)
4768
0
    {
4769
0
        op.func(dest + offset, src + offset, len, coverage);
4770
0
    }
4771
4772
    void store(int x, int y, int len)
4773
0
    {
4774
0
        if (op.destStore)
4775
0
            op.destStore(data->rasterBuffer, x, y, dest, len);
4776
0
    }
4777
};
4778
4779
#if QT_CONFIG(raster_64bit)
4780
class BlendSrcGenericRGB64 : public QBlendBase<QRgba64>
4781
{
4782
public:
4783
    BlendSrcGenericRGB64(QSpanData *d, const Operator &o)
4784
0
        : QBlendBase<QRgba64>(d, o)
4785
0
    {
4786
0
    }
4787
4788
    bool isSupported() const
4789
0
    {
4790
0
        return op.func64 && op.destFetch64;
4791
0
    }
4792
4793
    const QRgba64 *fetch(int x, int y, int len)
4794
0
    {
4795
0
        dest = op.destFetch64(buffer, data->rasterBuffer, x, y, len);
4796
0
        return op.srcFetch64(src_buffer, &op, data, y, x, len);
4797
0
    }
4798
4799
    void process(int, int, int len, int coverage, const QRgba64 *src, int offset)
4800
0
    {
4801
0
        op.func64(dest + offset, src + offset, len, coverage);
4802
0
    }
4803
4804
    void store(int x, int y, int len)
4805
0
    {
4806
0
        if (op.destStore64)
4807
0
            op.destStore64(data->rasterBuffer, x, y, dest, len);
4808
0
    }
4809
};
4810
#endif
4811
4812
static void blend_src_generic(int count, const QSpan *spans, void *userData)
4813
0
{
4814
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4815
0
    BlendSrcGeneric blend(data, getOperator(data, spans, count));
4816
0
    handleSpans(count, spans, data, blend);
4817
0
}
4818
4819
#if QT_CONFIG(raster_64bit)
4820
static void blend_src_generic_rgb64(int count, const QSpan *spans, void *userData)
4821
0
{
4822
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4823
0
    Operator op = getOperator(data, spans, count);
4824
0
    BlendSrcGenericRGB64 blend64(data, op);
4825
0
    if (blend64.isSupported())
4826
0
        handleSpans(count, spans, data, blend64);
4827
0
    else {
4828
0
        qCDebug(lcQtGuiDrawHelper, "blend_src_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
4829
0
        BlendSrcGeneric blend32(data, op);
4830
0
        handleSpans(count, spans, data, blend32);
4831
0
    }
4832
0
}
4833
#endif
4834
4835
static void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
4836
0
{
4837
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4838
4839
0
    uint buffer[BufferSize];
4840
0
    uint src_buffer[BufferSize];
4841
0
    Operator op = getOperator(data, spans, count);
4842
4843
0
    const int image_width = data->texture.width;
4844
0
    const int image_height = data->texture.height;
4845
0
    int xoff = -qRound(-data->dx);
4846
0
    int yoff = -qRound(-data->dy);
4847
4848
0
    for (; count--; spans++) {
4849
0
        if (!spans->len)
4850
0
            continue;
4851
0
        int x = spans->x;
4852
0
        int length = spans->len;
4853
0
        int sx = xoff + x;
4854
0
        int sy = yoff + spans->y;
4855
0
        if (sy >= 0 && sy < image_height && sx < image_width) {
4856
0
            if (sx < 0) {
4857
0
                x -= sx;
4858
0
                length += sx;
4859
0
                sx = 0;
4860
0
            }
4861
0
            if (sx + length > image_width)
4862
0
                length = image_width - sx;
4863
0
            if (length > 0) {
4864
0
                const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4865
0
                while (length) {
4866
0
                    int l = qMin(BufferSize, length);
4867
0
                    const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l);
4868
0
                    uint *dest = op.destFetch(buffer, data->rasterBuffer, x, spans->y, l);
4869
0
                    op.func(dest, src, l, coverage);
4870
0
                    if (op.destStore)
4871
0
                        op.destStore(data->rasterBuffer, x, spans->y, dest, l);
4872
0
                    x += l;
4873
0
                    sx += l;
4874
0
                    length -= l;
4875
0
                }
4876
0
            }
4877
0
        }
4878
0
    }
4879
0
}
4880
4881
#if QT_CONFIG(raster_64bit)
4882
static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, void *userData)
4883
0
{
4884
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4885
4886
0
    Operator op = getOperator(data, spans, count);
4887
0
    if (!op.func64) {
4888
0
        qCDebug(lcQtGuiDrawHelper, "blend_untransformed_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
4889
0
        return blend_untransformed_generic(count, spans, userData);
4890
0
    }
4891
0
    alignas(8) QRgba64 buffer[BufferSize];
4892
0
    alignas(8) QRgba64 src_buffer[BufferSize];
4893
4894
0
    const int image_width = data->texture.width;
4895
0
    const int image_height = data->texture.height;
4896
0
    int xoff = -qRound(-data->dx);
4897
0
    int yoff = -qRound(-data->dy);
4898
4899
0
    for (; count--; spans++) {
4900
0
        if (!spans->len)
4901
0
            continue;
4902
0
        int x = spans->x;
4903
0
        int length = spans->len;
4904
0
        int sx = xoff + x;
4905
0
        int sy = yoff + spans->y;
4906
0
        if (sy >= 0 && sy < image_height && sx < image_width) {
4907
0
            if (sx < 0) {
4908
0
                x -= sx;
4909
0
                length += sx;
4910
0
                sx = 0;
4911
0
            }
4912
0
            if (sx + length > image_width)
4913
0
                length = image_width - sx;
4914
0
            if (length > 0) {
4915
0
                const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4916
0
                while (length) {
4917
0
                    int l = qMin(BufferSize, length);
4918
0
                    const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l);
4919
0
                    QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l);
4920
0
                    op.func64(dest, src, l, coverage);
4921
0
                    if (op.destStore64)
4922
0
                        op.destStore64(data->rasterBuffer, x, spans->y, dest, l);
4923
0
                    x += l;
4924
0
                    sx += l;
4925
0
                    length -= l;
4926
0
                }
4927
0
            }
4928
0
        }
4929
0
    }
4930
0
}
4931
#endif
4932
4933
static void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
4934
0
{
4935
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4936
0
    if (data->texture.format != QImage::Format_ARGB32_Premultiplied
4937
0
        && data->texture.format != QImage::Format_RGB32) {
4938
0
        blend_untransformed_generic(count, spans, userData);
4939
0
        return;
4940
0
    }
4941
4942
0
    Operator op = getOperator(data, spans, count);
4943
4944
0
    const int image_width = data->texture.width;
4945
0
    const int image_height = data->texture.height;
4946
0
    int xoff = -qRound(-data->dx);
4947
0
    int yoff = -qRound(-data->dy);
4948
4949
0
    for (; count--; spans++) {
4950
0
        if (!spans->len)
4951
0
            continue;
4952
0
        int x = spans->x;
4953
0
        int length = spans->len;
4954
0
        int sx = xoff + x;
4955
0
        int sy = yoff + spans->y;
4956
0
        if (sy >= 0 && sy < image_height && sx < image_width) {
4957
0
            if (sx < 0) {
4958
0
                x -= sx;
4959
0
                length += sx;
4960
0
                sx = 0;
4961
0
            }
4962
0
            if (sx + length > image_width)
4963
0
                length = image_width - sx;
4964
0
            if (length > 0) {
4965
0
                const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4966
0
                const uint *src = (const uint *)data->texture.scanLine(sy) + sx;
4967
0
                uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
4968
0
                op.func(dest, src, length, coverage);
4969
0
            }
4970
0
        }
4971
0
    }
4972
0
}
4973
4974
static inline quint16 interpolate_pixel_rgb16_255(quint16 x, quint8 a,
4975
                                                  quint16 y, quint8 b)
4976
0
{
4977
0
    quint16 t = ((((x & 0x07e0) * a) + ((y & 0x07e0) * b)) >> 5) & 0x07e0;
4978
0
    t |= ((((x & 0xf81f) * a) + ((y & 0xf81f) * b)) >> 5) & 0xf81f;
4979
4980
0
    return t;
4981
0
}
4982
4983
static inline quint32 interpolate_pixel_rgb16x2_255(quint32 x, quint8 a,
4984
                                                    quint32 y, quint8 b)
4985
0
{
4986
0
    uint t;
4987
0
    t = ((((x & 0xf81f07e0) >> 5) * a) + (((y & 0xf81f07e0) >> 5) * b)) & 0xf81f07e0;
4988
0
    t |= ((((x & 0x07e0f81f) * a) + ((y & 0x07e0f81f) * b)) >> 5) & 0x07e0f81f;
4989
0
    return t;
4990
0
}
4991
4992
static inline void blend_sourceOver_rgb16_rgb16(quint16 *Q_DECL_RESTRICT dest,
4993
                                                const quint16 *Q_DECL_RESTRICT src,
4994
                                                int length,
4995
                                                const quint8 alpha,
4996
                                                const quint8 ialpha)
4997
0
{
4998
0
    const int dstAlign = ((quintptr)dest) & 0x3;
4999
0
    if (dstAlign) {
5000
0
        *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
5001
0
        ++dest;
5002
0
        ++src;
5003
0
        --length;
5004
0
    }
5005
0
    const int srcAlign = ((quintptr)src) & 0x3;
5006
0
    int length32 = length >> 1;
5007
0
    if (length32 && srcAlign == 0) {
5008
0
        while (length32--) {
5009
0
            const quint32 *src32 = reinterpret_cast<const quint32*>(src);
5010
0
            quint32 *dest32 = reinterpret_cast<quint32*>(dest);
5011
0
            *dest32 = interpolate_pixel_rgb16x2_255(*src32, alpha,
5012
0
                                                    *dest32, ialpha);
5013
0
            dest += 2;
5014
0
            src += 2;
5015
0
        }
5016
0
        length &= 0x1;
5017
0
    }
5018
0
    while (length--) {
5019
0
        *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
5020
0
        ++dest;
5021
0
        ++src;
5022
0
    }
5023
0
}
5024
5025
static void blend_untransformed_rgb565(int count, const QSpan *spans, void *userData)
5026
0
{
5027
0
    QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5028
0
    QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5029
5030
0
    if (data->texture.format != QImage::Format_RGB16
5031
0
            || (mode != QPainter::CompositionMode_SourceOver
5032
0
                && mode != QPainter::CompositionMode_Source))
5033
0
    {
5034
0
        blend_untransformed_generic(count, spans, userData);
5035
0
        return;
5036
0
    }
5037
5038
0
    const int image_width = data->texture.width;
5039
0
    const int image_height = data->texture.height;
5040
0
    int xoff = -qRound(-data->dx);
5041
0
    int yoff = -qRound(-data->dy);
5042
5043
0
    const QSpan *end = spans + count;
5044
0
    while (spans < end) {
5045
0
        if (!spans->len) {
5046
0
            ++spans;
5047
0
            continue;
5048
0
        }
5049
0
        const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5050
0
        if (coverage == 0) {
5051
0
            ++spans;
5052
0
            continue;
5053
0
        }
5054
5055
0
        int x = spans->x;
5056
0
        int length = spans->len;
5057
0
        int sx = xoff + x;
5058
0
        int sy = yoff + spans->y;
5059
0
        if (sy >= 0 && sy < image_height && sx < image_width) {
5060
0
            if (sx < 0) {
5061
0
                x -= sx;
5062
0
                length += sx;
5063
0
                sx = 0;
5064
0
            }
5065
0
            if (sx + length > image_width)
5066
0
                length = image_width - sx;
5067
0
            if (length > 0) {
5068
0
                quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + x;
5069
0
                const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx;
5070
0
                if (coverage == 255) {
5071
0
                    memcpy(dest, src, length * sizeof(quint16));
5072
0
                } else {
5073
0
                    const quint8 alpha = (coverage + 1) >> 3;
5074
0
                    const quint8 ialpha = 0x20 - alpha;
5075
0
                    if (alpha > 0)
5076
0
                        blend_sourceOver_rgb16_rgb16(dest, src, length, alpha, ialpha);
5077
0
                }
5078
0
            }
5079
0
        }
5080
0
        ++spans;
5081
0
    }
5082
0
}
5083
5084
static void blend_tiled_generic(int count, const QSpan *spans, void *userData)
5085
0
{
5086
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5087
5088
0
    uint buffer[BufferSize];
5089
0
    uint src_buffer[BufferSize];
5090
0
    Operator op = getOperator(data, spans, count);
5091
5092
0
    const int image_width = data->texture.width;
5093
0
    const int image_height = data->texture.height;
5094
0
    int xoff = -qRound(-data->dx) % image_width;
5095
0
    int yoff = -qRound(-data->dy) % image_height;
5096
5097
0
    if (xoff < 0)
5098
0
        xoff += image_width;
5099
0
    if (yoff < 0)
5100
0
        yoff += image_height;
5101
5102
0
    while (count--) {
5103
0
        int x = spans->x;
5104
0
        int length = spans->len;
5105
0
        int sx = (xoff + spans->x) % image_width;
5106
0
        int sy = (spans->y + yoff) % image_height;
5107
0
        if (sx < 0)
5108
0
            sx += image_width;
5109
0
        if (sy < 0)
5110
0
            sy += image_height;
5111
5112
0
        const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5113
0
        while (length) {
5114
0
            int l = qMin(image_width - sx, length);
5115
0
            if (BufferSize < l)
5116
0
                l = BufferSize;
5117
0
            const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l);
5118
0
            uint *dest = op.destFetch(buffer, data->rasterBuffer, x, spans->y, l);
5119
0
            op.func(dest, src, l, coverage);
5120
0
            if (op.destStore)
5121
0
                op.destStore(data->rasterBuffer, x, spans->y, dest, l);
5122
0
            x += l;
5123
0
            sx += l;
5124
0
            length -= l;
5125
0
            if (sx >= image_width)
5126
0
                sx = 0;
5127
0
        }
5128
0
        ++spans;
5129
0
    }
5130
0
}
5131
5132
#if QT_CONFIG(raster_64bit)
5133
static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userData)
5134
0
{
5135
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5136
5137
0
    Operator op = getOperator(data, spans, count);
5138
0
    if (!op.func64) {
5139
0
        qCDebug(lcQtGuiDrawHelper, "blend_tiled_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
5140
0
        return blend_tiled_generic(count, spans, userData);
5141
0
    }
5142
0
    alignas(8) QRgba64 buffer[BufferSize];
5143
0
    alignas(8) QRgba64 src_buffer[BufferSize];
5144
5145
0
    const int image_width = data->texture.width;
5146
0
    const int image_height = data->texture.height;
5147
0
    int xoff = -qRound(-data->dx) % image_width;
5148
0
    int yoff = -qRound(-data->dy) % image_height;
5149
5150
0
    if (xoff < 0)
5151
0
        xoff += image_width;
5152
0
    if (yoff < 0)
5153
0
        yoff += image_height;
5154
5155
0
    bool isBpp32 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP32;
5156
0
    bool isBpp64 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP64;
5157
0
    if (op.destFetch64 == destFetch64Undefined && image_width <= BufferSize && (isBpp32 || isBpp64)) {
5158
        // If destination isn't blended into the result, we can do the tiling directly on destination pixels.
5159
0
        while (count--) {
5160
0
            int x = spans->x;
5161
0
            int y = spans->y;
5162
0
            int length = spans->len;
5163
0
            int sx = (xoff + spans->x) % image_width;
5164
0
            int sy = (spans->y + yoff) % image_height;
5165
0
            if (sx < 0)
5166
0
                sx += image_width;
5167
0
            if (sy < 0)
5168
0
                sy += image_height;
5169
5170
0
            int sl = qMin(image_width, length);
5171
0
            if (sx > 0 && sl > 0) {
5172
0
                int l = qMin(image_width - sx, sl);
5173
0
                const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l);
5174
0
                op.destStore64(data->rasterBuffer, x, y, src, l);
5175
0
                x += l;
5176
0
                sx += l;
5177
0
                sl -= l;
5178
0
                if (sx >= image_width)
5179
0
                    sx = 0;
5180
0
            }
5181
0
            if (sl > 0) {
5182
0
                Q_ASSERT(sx == 0);
5183
0
                const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, sl);
5184
0
                op.destStore64(data->rasterBuffer, x, y, src, sl);
5185
0
                x += sl;
5186
0
                sx += sl;
5187
0
                sl -= sl;
5188
0
                if (sx >= image_width)
5189
0
                    sx = 0;
5190
0
            }
5191
0
            if (isBpp32) {
5192
0
                uint *dest = reinterpret_cast<uint *>(data->rasterBuffer->scanLine(y)) + x - image_width;
5193
0
                for (int i = image_width; i < length; ++i)
5194
0
                    dest[i] = dest[i - image_width];
5195
0
            } else {
5196
0
                quint64 *dest = reinterpret_cast<quint64 *>(data->rasterBuffer->scanLine(y)) + x - image_width;
5197
0
                for (int i = image_width; i < length; ++i)
5198
0
                    dest[i] = dest[i - image_width];
5199
0
            }
5200
0
            ++spans;
5201
0
        }
5202
0
        return;
5203
0
    }
5204
5205
0
    while (count--) {
5206
0
        int x = spans->x;
5207
0
        int length = spans->len;
5208
0
        int sx = (xoff + spans->x) % image_width;
5209
0
        int sy = (spans->y + yoff) % image_height;
5210
0
        if (sx < 0)
5211
0
            sx += image_width;
5212
0
        if (sy < 0)
5213
0
            sy += image_height;
5214
5215
0
        const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5216
0
        while (length) {
5217
0
            int l = qMin(image_width - sx, length);
5218
0
            if (BufferSize < l)
5219
0
                l = BufferSize;
5220
0
            const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l);
5221
0
            QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l);
5222
0
            op.func64(dest, src, l, coverage);
5223
0
            if (op.destStore64)
5224
0
                op.destStore64(data->rasterBuffer, x, spans->y, dest, l);
5225
0
            x += l;
5226
0
            sx += l;
5227
0
            length -= l;
5228
0
            if (sx >= image_width)
5229
0
                sx = 0;
5230
0
        }
5231
0
        ++spans;
5232
0
    }
5233
0
}
5234
#endif
5235
5236
static void blend_tiled_argb(int count, const QSpan *spans, void *userData)
5237
0
{
5238
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5239
0
    if (data->texture.format != QImage::Format_ARGB32_Premultiplied
5240
0
        && data->texture.format != QImage::Format_RGB32) {
5241
0
        blend_tiled_generic(count, spans, userData);
5242
0
        return;
5243
0
    }
5244
5245
0
    Operator op = getOperator(data, spans, count);
5246
5247
0
    int image_width = data->texture.width;
5248
0
    int image_height = data->texture.height;
5249
0
    int xoff = -qRound(-data->dx) % image_width;
5250
0
    int yoff = -qRound(-data->dy) % image_height;
5251
5252
0
    if (xoff < 0)
5253
0
        xoff += image_width;
5254
0
    if (yoff < 0)
5255
0
        yoff += image_height;
5256
5257
0
    while (count--) {
5258
0
        int x = spans->x;
5259
0
        int length = spans->len;
5260
0
        int sx = (xoff + spans->x) % image_width;
5261
0
        int sy = (spans->y + yoff) % image_height;
5262
0
        if (sx < 0)
5263
0
            sx += image_width;
5264
0
        if (sy < 0)
5265
0
            sy += image_height;
5266
5267
0
        const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5268
0
        while (length) {
5269
0
            int l = qMin(image_width - sx, length);
5270
0
            if (BufferSize < l)
5271
0
                l = BufferSize;
5272
0
            const uint *src = (const uint *)data->texture.scanLine(sy) + sx;
5273
0
            uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
5274
0
            op.func(dest, src, l, coverage);
5275
0
            x += l;
5276
0
            sx += l;
5277
0
            length -= l;
5278
0
            if (sx >= image_width)
5279
0
                sx = 0;
5280
0
        }
5281
0
        ++spans;
5282
0
    }
5283
0
}
5284
5285
static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
5286
0
{
5287
0
    QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5288
0
    QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5289
5290
0
    if (data->texture.format != QImage::Format_RGB16
5291
0
            || (mode != QPainter::CompositionMode_SourceOver
5292
0
                && mode != QPainter::CompositionMode_Source))
5293
0
    {
5294
0
        blend_tiled_generic(count, spans, userData);
5295
0
        return;
5296
0
    }
5297
5298
0
    const int image_width = data->texture.width;
5299
0
    const int image_height = data->texture.height;
5300
0
    int xoff = -qRound(-data->dx) % image_width;
5301
0
    int yoff = -qRound(-data->dy) % image_height;
5302
5303
0
    if (xoff < 0)
5304
0
        xoff += image_width;
5305
0
    if (yoff < 0)
5306
0
        yoff += image_height;
5307
5308
0
    while (count--) {
5309
0
        const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5310
0
        if (coverage == 0) {
5311
0
            ++spans;
5312
0
            continue;
5313
0
        }
5314
5315
0
        int x = spans->x;
5316
0
        int length = spans->len;
5317
0
        int sx = (xoff + spans->x) % image_width;
5318
0
        int sy = (spans->y + yoff) % image_height;
5319
0
        if (sx < 0)
5320
0
            sx += image_width;
5321
0
        if (sy < 0)
5322
0
            sy += image_height;
5323
5324
0
        if (coverage == 255) {
5325
            // Copy the first texture block
5326
0
            length = qMin(image_width,length);
5327
0
            int tx = x;
5328
0
            while (length) {
5329
0
                int l = qMin(image_width - sx, length);
5330
0
                if (BufferSize < l)
5331
0
                    l = BufferSize;
5332
0
                quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + tx;
5333
0
                const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx;
5334
0
                memcpy(dest, src, l * sizeof(quint16));
5335
0
                length -= l;
5336
0
                tx += l;
5337
0
                sx += l;
5338
0
                if (sx >= image_width)
5339
0
                    sx = 0;
5340
0
            }
5341
5342
            // Now use the rasterBuffer as the source of the texture,
5343
            // We can now progressively copy larger blocks
5344
            // - Less cpu time in code figuring out what to copy
5345
            // We are dealing with one block of data
5346
            // - More likely to fit in the cache
5347
            // - can use memcpy
5348
0
            int copy_image_width = qMin(image_width, int(spans->len));
5349
0
            length = spans->len - copy_image_width;
5350
0
            quint16 *src = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + x;
5351
0
            quint16 *dest = src + copy_image_width;
5352
0
            while (copy_image_width < length) {
5353
0
                memcpy(dest, src, copy_image_width * sizeof(quint16));
5354
0
                dest += copy_image_width;
5355
0
                length -= copy_image_width;
5356
0
                copy_image_width *= 2;
5357
0
            }
5358
0
            if (length > 0)
5359
0
                memcpy(dest, src, length * sizeof(quint16));
5360
0
        } else {
5361
0
            const quint8 alpha = (coverage + 1) >> 3;
5362
0
            const quint8 ialpha = 0x20 - alpha;
5363
0
            if (alpha > 0) {
5364
0
                while (length) {
5365
0
                    int l = qMin(image_width - sx, length);
5366
0
                    if (BufferSize < l)
5367
0
                        l = BufferSize;
5368
0
                    quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + x;
5369
0
                    const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx;
5370
0
                    blend_sourceOver_rgb16_rgb16(dest, src, l, alpha, ialpha);
5371
0
                    x += l;
5372
0
                    sx += l;
5373
0
                    length -= l;
5374
0
                    if (sx >= image_width)
5375
0
                        sx = 0;
5376
0
                }
5377
0
            }
5378
0
        }
5379
0
        ++spans;
5380
0
    }
5381
0
}
5382
5383
/* Image formats here are target formats */
5384
static const ProcessSpans processTextureSpansARGB32PM[NBlendTypes] = {
5385
    blend_untransformed_argb,           // Untransformed
5386
    blend_tiled_argb,                   // Tiled
5387
    blend_src_generic,                  // Transformed
5388
    blend_src_generic,                  // TransformedTiled
5389
    blend_src_generic,                  // TransformedBilinear
5390
    blend_src_generic                   // TransformedBilinearTiled
5391
};
5392
5393
static const ProcessSpans processTextureSpansRGB16[NBlendTypes] = {
5394
    blend_untransformed_rgb565,         // Untransformed
5395
    blend_tiled_rgb565,                 // Tiled
5396
    blend_src_generic,                  // Transformed
5397
    blend_src_generic,                  // TransformedTiled
5398
    blend_src_generic,                  // TransformedBilinear
5399
    blend_src_generic                   // TransformedBilinearTiled
5400
};
5401
5402
static const ProcessSpans processTextureSpansGeneric[NBlendTypes] = {
5403
    blend_untransformed_generic,        // Untransformed
5404
    blend_tiled_generic,                // Tiled
5405
    blend_src_generic,                  // Transformed
5406
    blend_src_generic,                  // TransformedTiled
5407
    blend_src_generic,                  // TransformedBilinear
5408
    blend_src_generic                   // TransformedBilinearTiled
5409
};
5410
5411
#if QT_CONFIG(raster_64bit)
5412
static const ProcessSpans processTextureSpansGeneric64[NBlendTypes] = {
5413
    blend_untransformed_generic_rgb64,  // Untransformed
5414
    blend_tiled_generic_rgb64,          // Tiled
5415
    blend_src_generic_rgb64,            // Transformed
5416
    blend_src_generic_rgb64,            // TransformedTiled
5417
    blend_src_generic_rgb64,            // TransformedBilinear
5418
    blend_src_generic_rgb64             // TransformedBilinearTiled
5419
};
5420
#endif
5421
5422
void qBlendTexture(int count, const QSpan *spans, void *userData)
5423
0
{
5424
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5425
0
    TextureBlendType blendType = getBlendType(data);
5426
0
    ProcessSpans proc;
5427
0
    switch (data->rasterBuffer->format) {
5428
0
    case QImage::Format_ARGB32_Premultiplied:
5429
0
        proc = processTextureSpansARGB32PM[blendType];
5430
0
        break;
5431
0
    case QImage::Format_RGB16:
5432
0
        proc = processTextureSpansRGB16[blendType];
5433
0
        break;
5434
0
#if QT_CONFIG(raster_64bit)
5435
0
#if defined(__SSE2__) || defined(__ARM_NEON__) || (Q_PROCESSOR_WORDSIZE == 8)
5436
0
    case QImage::Format_ARGB32:
5437
0
    case QImage::Format_RGBA8888:
5438
0
#endif
5439
0
    case QImage::Format_BGR30:
5440
0
    case QImage::Format_A2BGR30_Premultiplied:
5441
0
    case QImage::Format_RGB30:
5442
0
    case QImage::Format_A2RGB30_Premultiplied:
5443
0
    case QImage::Format_RGBX64:
5444
0
    case QImage::Format_RGBA64:
5445
0
    case QImage::Format_RGBA64_Premultiplied:
5446
0
    case QImage::Format_Grayscale16:
5447
0
        proc = processTextureSpansGeneric64[blendType];
5448
0
        break;
5449
0
#endif // QT_CONFIG(raster_64bit)
5450
0
    case QImage::Format_Invalid:
5451
0
        Q_UNREACHABLE();
5452
0
        return;
5453
0
    default:
5454
0
        proc = processTextureSpansGeneric[blendType];
5455
0
        break;
5456
0
    }
5457
0
    proc(count, spans, userData);
5458
0
}
5459
5460
static void blend_vertical_gradient_argb(int count, const QSpan *spans, void *userData)
5461
0
{
5462
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5463
5464
0
    LinearGradientValues linear;
5465
0
    getLinearGradientValues(&linear, data);
5466
5467
0
    CompositionFunctionSolid funcSolid =
5468
0
        functionForModeSolid[data->rasterBuffer->compositionMode];
5469
5470
    /*
5471
        The logic for vertical gradient calculations is a mathematically
5472
        reduced copy of that in fetchLinearGradient() - which is basically:
5473
5474
            qreal ry = data->m22 * (y + 0.5) + data->dy;
5475
            qreal t = linear.dy*ry + linear.off;
5476
            t *= (GRADIENT_STOPTABLE_SIZE - 1);
5477
            quint32 color =
5478
                qt_gradient_pixel_fixed(&data->gradient,
5479
                                        int(t * FIXPT_SIZE));
5480
5481
        This has then been converted to fixed point to improve performance.
5482
     */
5483
0
    const int gss = GRADIENT_STOPTABLE_SIZE - 1;
5484
0
    int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
5485
0
    int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
5486
5487
0
    while (count--) {
5488
0
        int y = spans->y;
5489
0
        int x = spans->x;
5490
5491
0
        quint32 *dst = (quint32 *)(data->rasterBuffer->scanLine(y)) + x;
5492
0
        quint32 color =
5493
0
            qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
5494
5495
0
        funcSolid(dst, spans->len, color, spans->coverage);
5496
0
        ++spans;
5497
0
    }
5498
0
}
5499
5500
template<ProcessSpans blend_color>
5501
static void blend_vertical_gradient(int count, const QSpan *spans, void *userData)
5502
0
{
5503
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5504
5505
0
    LinearGradientValues linear;
5506
0
    getLinearGradientValues(&linear, data);
5507
5508
    // Based on the same logic as blend_vertical_gradient_argb.
5509
5510
0
    const int gss = GRADIENT_STOPTABLE_SIZE - 1;
5511
0
    int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
5512
0
    int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
5513
5514
0
    while (count--) {
5515
0
        int y = spans->y;
5516
5517
0
#if QT_CONFIG(raster_64bit)
5518
0
        data->solidColor = qt_gradient_pixel64_fixed(&data->gradient, yinc * y + off);
5519
#else
5520
        data->solidColor = QRgba64::fromArgb32(qt_gradient_pixel_fixed(&data->gradient, yinc * y + off));
5521
#endif
5522
0
        blend_color(1, spans, userData);
5523
0
        ++spans;
5524
0
    }
5525
0
}
Unexecuted instantiation: qdrawhelper.cpp:void blend_vertical_gradient<&(blend_color_rgb16(int, QT_FT_Span_ const*, void*))>(int, QT_FT_Span_ const*, void*)
Unexecuted instantiation: qdrawhelper.cpp:void blend_vertical_gradient<&(blend_color_generic_rgb64(int, QT_FT_Span_ const*, void*))>(int, QT_FT_Span_ const*, void*)
Unexecuted instantiation: qdrawhelper.cpp:void blend_vertical_gradient<&(blend_color_generic(int, QT_FT_Span_ const*, void*))>(int, QT_FT_Span_ const*, void*)
5526
5527
void qBlendGradient(int count, const QSpan *spans, void *userData)
5528
0
{
5529
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5530
0
    bool isVerticalGradient =
5531
0
        data->txop <= QTransform::TxScale &&
5532
0
        data->type == QSpanData::LinearGradient &&
5533
0
        data->gradient.linear.end.x == data->gradient.linear.origin.x;
5534
0
    switch (data->rasterBuffer->format) {
5535
0
    case QImage::Format_RGB16:
5536
0
        if (isVerticalGradient)
5537
0
            return blend_vertical_gradient<blend_color_rgb16>(count, spans, userData);
5538
0
        return blend_src_generic(count, spans, userData);
5539
0
    case QImage::Format_RGB32:
5540
0
    case QImage::Format_ARGB32_Premultiplied:
5541
0
        if (isVerticalGradient)
5542
0
            return blend_vertical_gradient_argb(count, spans, userData);
5543
0
        return blend_src_generic(count, spans, userData);
5544
0
#if QT_CONFIG(raster_64bit)
5545
0
#if defined(__SSE2__) || defined(__ARM_NEON__) || (Q_PROCESSOR_WORDSIZE == 8)
5546
0
    case QImage::Format_ARGB32:
5547
0
    case QImage::Format_RGBA8888:
5548
0
#endif
5549
0
    case QImage::Format_BGR30:
5550
0
    case QImage::Format_A2BGR30_Premultiplied:
5551
0
    case QImage::Format_RGB30:
5552
0
    case QImage::Format_A2RGB30_Premultiplied:
5553
0
    case QImage::Format_RGBX64:
5554
0
    case QImage::Format_RGBA64:
5555
0
    case QImage::Format_RGBA64_Premultiplied:
5556
0
        if (isVerticalGradient)
5557
0
            return blend_vertical_gradient<blend_color_generic_rgb64>(count, spans, userData);
5558
0
        return blend_src_generic_rgb64(count, spans, userData);
5559
0
#endif // QT_CONFIG(raster_64bit)
5560
0
    case QImage::Format_Invalid:
5561
0
        break;
5562
0
    default:
5563
0
        if (isVerticalGradient)
5564
0
            return blend_vertical_gradient<blend_color_generic>(count, spans, userData);
5565
0
        return blend_src_generic(count, spans, userData);
5566
0
    }
5567
0
    Q_UNREACHABLE();
5568
0
}
5569
5570
template <class DST> static
5571
inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
5572
                                   int x, int y, DST color,
5573
                                   const uchar *map,
5574
                                   int mapWidth, int mapHeight, int mapStride)
5575
0
{
5576
0
    DST *dest = reinterpret_cast<DST *>(rasterBuffer->scanLine(y)) + x;
5577
0
    const int destStride = rasterBuffer->stride<DST>();
5578
5579
0
    if (mapWidth > 8) {
5580
0
        while (mapHeight--) {
5581
0
            int x0 = 0;
5582
0
            int n = 0;
5583
0
            for (int x = 0; x < mapWidth; x += 8) {
5584
0
                uchar s = map[x >> 3];
5585
0
                for (int i = 0; i < 8; ++i) {
5586
0
                    if (s & 0x80) {
5587
0
                        ++n;
5588
0
                    } else {
5589
0
                        if (n) {
5590
0
                            qt_memfill(dest + x0, color, n);
5591
0
                            x0 += n + 1;
5592
0
                            n = 0;
5593
0
                        } else {
5594
0
                            ++x0;
5595
0
                        }
5596
0
                        if (!s) {
5597
0
                            x0 += 8 - 1 - i;
5598
0
                            break;
5599
0
                        }
5600
0
                    }
5601
0
                    s <<= 1;
5602
0
                }
5603
0
            }
5604
0
            if (n)
5605
0
                qt_memfill(dest + x0, color, n);
5606
0
            dest += destStride;
5607
0
            map += mapStride;
5608
0
        }
5609
0
    } else {
5610
0
        while (mapHeight--) {
5611
0
            int x0 = 0;
5612
0
            int n = 0;
5613
0
            for (uchar s = *map; s; s <<= 1) {
5614
0
                if (s & 0x80) {
5615
0
                    ++n;
5616
0
                } else if (n) {
5617
0
                    qt_memfill(dest + x0, color, n);
5618
0
                    x0 += n + 1;
5619
0
                    n = 0;
5620
0
                } else {
5621
0
                    ++x0;
5622
0
                }
5623
0
            }
5624
0
            if (n)
5625
0
                qt_memfill(dest + x0, color, n);
5626
0
            dest += destStride;
5627
0
            map += mapStride;
5628
0
        }
5629
0
    }
5630
0
}
Unexecuted instantiation: qdrawhelper.cpp:void qt_bitmapblit_template<unsigned int>(QRasterBuffer*, int, int, unsigned int, unsigned char const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void qt_bitmapblit_template<unsigned short>(QRasterBuffer*, int, int, unsigned short, unsigned char const*, int, int, int)
5631
5632
inline static void qt_bitmapblit_argb32(QRasterBuffer *rasterBuffer,
5633
                                   int x, int y, const QRgba64 &color,
5634
                                   const uchar *map,
5635
                                   int mapWidth, int mapHeight, int mapStride)
5636
0
{
5637
0
    qt_bitmapblit_template<quint32>(rasterBuffer, x,  y, color.toArgb32(),
5638
0
                                    map, mapWidth, mapHeight, mapStride);
5639
0
}
5640
5641
inline static void qt_bitmapblit_rgba8888(QRasterBuffer *rasterBuffer,
5642
                                   int x, int y, const QRgba64 &color,
5643
                                   const uchar *map,
5644
                                   int mapWidth, int mapHeight, int mapStride)
5645
0
{
5646
0
    qt_bitmapblit_template<quint32>(rasterBuffer, x, y, ARGB2RGBA(color.toArgb32()),
5647
0
                                    map, mapWidth, mapHeight, mapStride);
5648
0
}
5649
5650
template<QtPixelOrder PixelOrder>
5651
inline static void qt_bitmapblit_rgb30(QRasterBuffer *rasterBuffer,
5652
                                   int x, int y, const QRgba64 &color,
5653
                                   const uchar *map,
5654
                                   int mapWidth, int mapHeight, int mapStride)
5655
0
{
5656
0
    qt_bitmapblit_template<quint32>(rasterBuffer, x, y, qConvertRgb64ToRgb30<PixelOrder>(color),
5657
0
                                    map, mapWidth, mapHeight, mapStride);
5658
0
}
Unexecuted instantiation: qdrawhelper.cpp:void qt_bitmapblit_rgb30<(QtPixelOrder)1>(QRasterBuffer*, int, int, QRgba64 const&, unsigned char const*, int, int, int)
Unexecuted instantiation: qdrawhelper.cpp:void qt_bitmapblit_rgb30<(QtPixelOrder)0>(QRasterBuffer*, int, int, QRgba64 const&, unsigned char const*, int, int, int)
5659
5660
inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer,
5661
                                   int x, int y, const QRgba64 &color,
5662
                                   const uchar *map,
5663
                                   int mapWidth, int mapHeight, int mapStride)
5664
0
{
5665
0
    qt_bitmapblit_template<quint16>(rasterBuffer, x,  y, color.toRgb16(),
5666
0
                                    map, mapWidth, mapHeight, mapStride);
5667
0
}
5668
5669
static inline void grayBlendPixel(quint32 *dst, int coverage, QRgba64 srcLinear, const QColorTrcLut *colorProfile)
5670
0
{
5671
    // Do a gammacorrected gray alphablend...
5672
0
    const QRgba64 dstLinear = colorProfile ? colorProfile->toLinear64(*dst) : QRgba64::fromArgb32(*dst);
5673
5674
0
    QRgba64 blend = interpolate255(srcLinear, coverage, dstLinear, 255 - coverage);
5675
5676
0
    *dst = colorProfile ? colorProfile->fromLinear64(blend) : toArgb32(blend);
5677
0
}
5678
5679
static inline void alphamapblend_argb32(quint32 *dst, int coverage, QRgba64 srcLinear, quint32 src, const QColorTrcLut *colorProfile)
5680
0
{
5681
0
    if (coverage == 0) {
5682
        // nothing
5683
0
    } else if (coverage == 255 || !colorProfile) {
5684
0
        blend_pixel(*dst, src, coverage);
5685
0
    } else if (*dst < 0xff000000) {
5686
        // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
5687
0
        blend_pixel(*dst, src, coverage);
5688
0
    } else if (src >= 0xff000000) {
5689
0
        grayBlendPixel(dst, coverage, srcLinear, colorProfile);
5690
0
    } else {
5691
        // First do naive blend with text-color
5692
0
        QRgb s = *dst;
5693
0
        blend_pixel(s, src);
5694
        // Then gamma-corrected blend with glyph shape
5695
0
        QRgba64 s64 = colorProfile ? colorProfile->toLinear64(s) : QRgba64::fromArgb32(s);
5696
0
        grayBlendPixel(dst, coverage, s64, colorProfile);
5697
0
    }
5698
0
}
5699
5700
#if QT_CONFIG(raster_64bit)
5701
5702
static inline void grayBlendPixel(QRgba64 &dst, int coverage, QRgba64 srcLinear, const QColorTrcLut *colorProfile)
5703
0
{
5704
    // Do a gammacorrected gray alphablend...
5705
0
    QRgba64 dstColor = dst;
5706
0
    if (colorProfile) {
5707
0
        if (dstColor.isOpaque())
5708
0
            dstColor = colorProfile->toLinear(dstColor);
5709
0
        else if (!dstColor.isTransparent())
5710
0
            dstColor = colorProfile->toLinear(dstColor.unpremultiplied()).premultiplied();
5711
0
    }
5712
5713
0
    blend_pixel(dstColor, srcLinear, coverage);
5714
5715
0
    if (colorProfile) {
5716
0
        if (dstColor.isOpaque())
5717
0
            dstColor = colorProfile->fromLinear(dstColor);
5718
0
        else if (!dstColor.isTransparent())
5719
0
            dstColor = colorProfile->fromLinear(dstColor.unpremultiplied()).premultiplied();
5720
0
    }
5721
0
    dst = dstColor;
5722
0
}
5723
5724
static inline void alphamapblend_generic(int coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile)
5725
0
{
5726
0
    if (coverage == 0) {
5727
        // nothing
5728
0
    } else if (coverage == 255) {
5729
0
        blend_pixel(dest[x], src);
5730
0
    } else if (src.isOpaque()) {
5731
0
        grayBlendPixel(dest[x], coverage, srcLinear, colorProfile);
5732
0
    } else {
5733
        // First do naive blend with text-color
5734
0
        QRgba64 s = dest[x];
5735
0
        blend_pixel(s, src);
5736
        // Then gamma-corrected blend with glyph shape
5737
0
        if (colorProfile)
5738
0
            s = colorProfile->toLinear(s);
5739
0
        grayBlendPixel(dest[x], coverage, s, colorProfile);
5740
0
    }
5741
0
}
5742
5743
static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
5744
                                    int x, int y, const QRgba64 &color,
5745
                                    const uchar *map,
5746
                                    int mapWidth, int mapHeight, int mapStride,
5747
                                    const QClipData *clip, bool useGammaCorrection)
5748
0
{
5749
0
    if (color.isTransparent())
5750
0
        return;
5751
5752
0
    const QColorTrcLut *colorProfile = nullptr;
5753
5754
0
    if (useGammaCorrection)
5755
0
        colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
5756
5757
0
    QRgba64 srcColor = color;
5758
0
    if (colorProfile && color.isOpaque())
5759
0
        srcColor = colorProfile->toLinear(srcColor);
5760
5761
0
    alignas(8) QRgba64 buffer[BufferSize];
5762
0
    const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
5763
0
    const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format];
5764
5765
0
    if (!clip) {
5766
0
        for (int ly = 0; ly < mapHeight; ++ly) {
5767
0
            int i = x;
5768
0
            int length = mapWidth;
5769
0
            while (length > 0) {
5770
0
                int l = qMin(BufferSize, length);
5771
0
                QRgba64 *dest = destFetch64(buffer, rasterBuffer, i, y + ly, l);
5772
0
                for (int j=0; j < l; ++j) {
5773
0
                    const int coverage = map[j + (i - x)];
5774
0
                    alphamapblend_generic(coverage, dest, j, srcColor, color, colorProfile);
5775
0
                }
5776
0
                if (destStore64)
5777
0
                    destStore64(rasterBuffer, i, y + ly, dest, l);
5778
0
                length -= l;
5779
0
                i += l;
5780
0
            }
5781
0
            map += mapStride;
5782
0
        }
5783
0
    } else {
5784
0
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
5785
5786
0
        int top = qMax(y, 0);
5787
0
        map += (top - y) * mapStride;
5788
5789
0
        const_cast<QClipData *>(clip)->initialize();
5790
0
        for (int yp = top; yp<bottom; ++yp) {
5791
0
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
5792
5793
0
            for (int i=0; i<line.count; ++i) {
5794
0
                const QSpan &clip = line.spans[i];
5795
5796
0
                int start = qMax<int>(x, clip.x);
5797
0
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
5798
0
                if (end <= start)
5799
0
                    continue;
5800
0
                Q_ASSERT(end - start <= BufferSize);
5801
0
                QRgba64 *dest = destFetch64(buffer, rasterBuffer, start, clip.y, end - start);
5802
5803
0
                for (int xp=start; xp<end; ++xp) {
5804
0
                    const int coverage = map[xp - x];
5805
0
                    alphamapblend_generic(coverage, dest, xp - start, srcColor, color, colorProfile);
5806
0
                }
5807
0
                if (destStore64)
5808
0
                    destStore64(rasterBuffer, start, clip.y, dest, end - start);
5809
0
            } // for (i -> line.count)
5810
0
            map += mapStride;
5811
0
        } // for (yp -> bottom)
5812
0
    }
5813
0
}
5814
#else
5815
static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
5816
                                    int x, int y, const QRgba64 &color,
5817
                                    const uchar *map,
5818
                                    int mapWidth, int mapHeight, int mapStride,
5819
                                    const QClipData *clip, bool useGammaCorrection)
5820
{
5821
    if (color.isTransparent())
5822
        return;
5823
5824
    const quint32 c = color.toArgb32();
5825
5826
    const QColorTrcLut *colorProfile = nullptr;
5827
5828
    if (useGammaCorrection)
5829
        colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
5830
5831
    QRgba64 srcColor = color;
5832
    if (colorProfile && color.isOpaque())
5833
        srcColor = colorProfile->toLinear(srcColor);
5834
5835
    quint32 buffer[BufferSize];
5836
    const DestFetchProc destFetch = destFetchProc[rasterBuffer->format];
5837
    const DestStoreProc destStore = destStoreProc[rasterBuffer->format];
5838
5839
    if (!clip) {
5840
        for (int ly = 0; ly < mapHeight; ++ly) {
5841
            int i = x;
5842
            int length = mapWidth;
5843
            while (length > 0) {
5844
                int l = qMin(BufferSize, length);
5845
                quint32 *dest = destFetch(buffer, rasterBuffer, i, y + ly, l);
5846
                for (int j=0; j < l; ++j) {
5847
                    const int coverage = map[j + (i - x)];
5848
                    alphamapblend_argb32(dest + j, coverage, srcColor, c, colorProfile);
5849
                }
5850
                if (destStore)
5851
                    destStore(rasterBuffer, i, y + ly, dest, l);
5852
                length -= l;
5853
                i += l;
5854
            }
5855
            map += mapStride;
5856
        }
5857
    } else {
5858
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
5859
5860
        int top = qMax(y, 0);
5861
        map += (top - y) * mapStride;
5862
5863
        const_cast<QClipData *>(clip)->initialize();
5864
        for (int yp = top; yp<bottom; ++yp) {
5865
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
5866
5867
            for (int i=0; i<line.count; ++i) {
5868
                const QSpan &clip = line.spans[i];
5869
5870
                int start = qMax<int>(x, clip.x);
5871
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
5872
                if (end <= start)
5873
                    continue;
5874
                Q_ASSERT(end - start <= BufferSize);
5875
                quint32 *dest = destFetch(buffer, rasterBuffer, start, clip.y, end - start);
5876
5877
                for (int xp=start; xp<end; ++xp) {
5878
                    const int coverage = map[xp - x];
5879
                    alphamapblend_argb32(dest + xp - x, coverage, srcColor, color, colorProfile);
5880
                }
5881
                if (destStore)
5882
                    destStore(rasterBuffer, start, clip.y, dest, end - start);
5883
            } // for (i -> line.count)
5884
            map += mapStride;
5885
        } // for (yp -> bottom)
5886
    }
5887
}
5888
#endif
5889
5890
static inline void alphamapblend_quint16(int coverage, quint16 *dest, int x, const quint16 srcColor)
5891
0
{
5892
0
    if (coverage == 0) {
5893
        // nothing
5894
0
    } else if (coverage == 255) {
5895
0
        dest[x] = srcColor;
5896
0
    } else {
5897
0
        dest[x] = BYTE_MUL_RGB16(srcColor, coverage)
5898
0
                + BYTE_MUL_RGB16(dest[x], 255 - coverage);
5899
0
    }
5900
0
}
5901
5902
void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
5903
                             int x, int y, const QRgba64 &color,
5904
                             const uchar *map,
5905
                             int mapWidth, int mapHeight, int mapStride,
5906
                             const QClipData *clip, bool useGammaCorrection)
5907
0
{
5908
0
    if (useGammaCorrection || !color.isOpaque()) {
5909
0
        qt_alphamapblit_generic(rasterBuffer, x, y, color, map, mapWidth, mapHeight, mapStride, clip, useGammaCorrection);
5910
0
        return;
5911
0
    }
5912
5913
0
    const quint16 c = color.toRgb16();
5914
5915
0
    if (!clip) {
5916
0
        quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
5917
0
        const int destStride = rasterBuffer->stride<quint16>();
5918
0
        while (mapHeight--) {
5919
0
            for (int i = 0; i < mapWidth; ++i)
5920
0
                alphamapblend_quint16(map[i], dest, i, c);
5921
0
            dest += destStride;
5922
0
            map += mapStride;
5923
0
        }
5924
0
    } else {
5925
0
        int top = qMax(y, 0);
5926
0
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
5927
0
        map += (top - y) * mapStride;
5928
5929
0
        const_cast<QClipData *>(clip)->initialize();
5930
0
        for (int yp = top; yp<bottom; ++yp) {
5931
0
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
5932
5933
0
            quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(yp));
5934
5935
0
            for (int i=0; i<line.count; ++i) {
5936
0
                const QSpan &clip = line.spans[i];
5937
5938
0
                int start = qMax<int>(x, clip.x);
5939
0
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
5940
5941
0
                for (int xp=start; xp<end; ++xp)
5942
0
                    alphamapblend_quint16(map[xp - x], dest, xp, c);
5943
0
            } // for (i -> line.count)
5944
0
            map += mapStride;
5945
0
        } // for (yp -> bottom)
5946
0
    }
5947
0
}
5948
5949
static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer,
5950
                                   int x, int y, const QRgba64 &color,
5951
                                   const uchar *map,
5952
                                   int mapWidth, int mapHeight, int mapStride,
5953
                                   const QClipData *clip, bool useGammaCorrection)
5954
0
{
5955
0
    const quint32 c = color.toArgb32();
5956
0
    const int destStride = rasterBuffer->stride<quint32>();
5957
5958
0
    if (color.isTransparent())
5959
0
        return;
5960
5961
0
    const QColorTrcLut *colorProfile = nullptr;
5962
5963
0
    if (useGammaCorrection)
5964
0
        colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
5965
5966
0
    QRgba64 srcColor = color;
5967
0
    if (colorProfile && color.isOpaque())
5968
0
        srcColor = colorProfile->toLinear(srcColor);
5969
5970
0
    if (!clip) {
5971
0
        quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
5972
0
        while (mapHeight--) {
5973
0
            for (int i = 0; i < mapWidth; ++i) {
5974
0
                const int coverage = map[i];
5975
0
                alphamapblend_argb32(dest + i, coverage, srcColor, c, colorProfile);
5976
0
            }
5977
0
            dest += destStride;
5978
0
            map += mapStride;
5979
0
        }
5980
0
    } else {
5981
0
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
5982
5983
0
        int top = qMax(y, 0);
5984
0
        map += (top - y) * mapStride;
5985
5986
0
        const_cast<QClipData *>(clip)->initialize();
5987
0
        for (int yp = top; yp<bottom; ++yp) {
5988
0
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
5989
5990
0
            quint32 *dest = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
5991
5992
0
            for (int i=0; i<line.count; ++i) {
5993
0
                const QSpan &clip = line.spans[i];
5994
5995
0
                int start = qMax<int>(x, clip.x);
5996
0
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
5997
5998
0
                for (int xp=start; xp<end; ++xp) {
5999
0
                    const int coverage = map[xp - x];
6000
0
                    alphamapblend_argb32(dest + xp, coverage, srcColor, c, colorProfile);
6001
0
                } // for (i -> line.count)
6002
0
            } // for (yp -> bottom)
6003
0
            map += mapStride;
6004
0
        }
6005
0
    }
6006
0
}
6007
6008
static inline int qRgbAvg(QRgb rgb)
6009
0
{
6010
0
    return (qRed(rgb) * 5 + qGreen(rgb) * 6 + qBlue(rgb) * 5) / 16;
6011
0
}
6012
6013
static inline void rgbBlendPixel(quint32 *dst, int coverage, QRgba64 slinear, const QColorTrcLut *colorProfile)
6014
0
{
6015
    // Do a gammacorrected RGB alphablend...
6016
0
    const QRgba64 dlinear = colorProfile ? colorProfile->toLinear64(*dst) : QRgba64::fromArgb32(*dst);
6017
6018
0
    QRgba64 blend = rgbBlend(dlinear, slinear, coverage);
6019
6020
0
    *dst = colorProfile ? colorProfile->fromLinear64(blend) : toArgb32(blend);
6021
0
}
6022
6023
static inline QRgb rgbBlend(QRgb d, QRgb s, uint rgbAlpha)
6024
0
{
6025
0
#if defined(__SSE2__)
6026
0
    __m128i vd = _mm_cvtsi32_si128(d);
6027
0
    __m128i vs = _mm_cvtsi32_si128(s);
6028
0
    __m128i va = _mm_cvtsi32_si128(rgbAlpha);
6029
0
    const __m128i vz = _mm_setzero_si128();
6030
0
    vd = _mm_unpacklo_epi8(vd, vz);
6031
0
    vs = _mm_unpacklo_epi8(vs, vz);
6032
0
    va = _mm_unpacklo_epi8(va, vz);
6033
0
    __m128i vb = _mm_xor_si128(_mm_set1_epi16(255), va);
6034
0
    vs = _mm_mullo_epi16(vs, va);
6035
0
    vd = _mm_mullo_epi16(vd, vb);
6036
0
    vd = _mm_add_epi16(vd, vs);
6037
0
    vd = _mm_add_epi16(vd, _mm_srli_epi16(vd, 8));
6038
0
    vd = _mm_add_epi16(vd, _mm_set1_epi16(0x80));
6039
0
    vd = _mm_srli_epi16(vd, 8);
6040
0
    vd = _mm_packus_epi16(vd, vd);
6041
0
    return _mm_cvtsi128_si32(vd);
6042
#else
6043
    const int dr = qRed(d);
6044
    const int dg = qGreen(d);
6045
    const int db = qBlue(d);
6046
6047
    const int sr = qRed(s);
6048
    const int sg = qGreen(s);
6049
    const int sb = qBlue(s);
6050
6051
    const int mr = qRed(rgbAlpha);
6052
    const int mg = qGreen(rgbAlpha);
6053
    const int mb = qBlue(rgbAlpha);
6054
6055
    const int nr = qt_div_255(sr * mr + dr * (255 - mr));
6056
    const int ng = qt_div_255(sg * mg + dg * (255 - mg));
6057
    const int nb = qt_div_255(sb * mb + db * (255 - mb));
6058
6059
    return 0xff000000 | (nr << 16) | (ng << 8) | nb;
6060
#endif
6061
0
}
6062
6063
static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorTrcLut *colorProfile)
6064
0
{
6065
0
    if (coverage == 0xff000000) {
6066
        // nothing
6067
0
    } else if (coverage == 0xffffffff && qAlpha(src) == 255) {
6068
0
        blend_pixel(*dst, src);
6069
0
    } else if (*dst < 0xff000000) {
6070
        // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
6071
0
        blend_pixel(*dst, src, qRgbAvg(coverage));
6072
0
    } else if (!colorProfile) {
6073
        // First do naive blend with text-color
6074
0
        QRgb s = *dst;
6075
0
        blend_pixel(s, src);
6076
        // Then a naive blend with glyph shape
6077
0
        *dst = rgbBlend(*dst, s, coverage);
6078
0
    } else if (srcLinear.isOpaque()) {
6079
0
        rgbBlendPixel(dst, coverage, srcLinear, colorProfile);
6080
0
    } else {
6081
        // First do naive blend with text-color
6082
0
        QRgb s = *dst;
6083
0
        blend_pixel(s, src);
6084
        // Then gamma-corrected blend with glyph shape
6085
0
        QRgba64 s64 = colorProfile ? colorProfile->toLinear64(s) : QRgba64::fromArgb32(s);
6086
0
        rgbBlendPixel(dst, coverage, s64, colorProfile);
6087
0
    }
6088
0
}
6089
6090
#if QT_CONFIG(raster_64bit)
6091
static inline void rgbBlendPixel(QRgba64 &dst, int coverage, QRgba64 slinear, const QColorTrcLut *colorProfile)
6092
0
{
6093
    // Do a gammacorrected RGB alphablend...
6094
0
    const QRgba64 dlinear = colorProfile ? colorProfile->toLinear(dst) : dst;
6095
6096
0
    QRgba64 blend = rgbBlend(dlinear, slinear, coverage);
6097
6098
0
    dst = colorProfile ? colorProfile->fromLinear(blend) : blend;
6099
0
}
6100
6101
static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile)
6102
0
{
6103
0
    if (coverage == 0xff000000) {
6104
        // nothing
6105
0
    } else if (coverage == 0xffffffff) {
6106
0
        blend_pixel(dest[x], src);
6107
0
    } else if (!dest[x].isOpaque()) {
6108
        // Do a gray alphablend.
6109
0
        alphamapblend_generic(qRgbAvg(coverage), dest, x, srcLinear, src, colorProfile);
6110
0
    } else if (src.isOpaque()) {
6111
0
        rgbBlendPixel(dest[x], coverage, srcLinear, colorProfile);
6112
0
    } else {
6113
        // First do naive blend with text-color
6114
0
        QRgba64 s = dest[x];
6115
0
        blend_pixel(s, src);
6116
        // Then gamma-corrected blend with glyph shape
6117
0
        if (colorProfile)
6118
0
            s = colorProfile->toLinear(s);
6119
0
        rgbBlendPixel(dest[x], coverage, s, colorProfile);
6120
0
    }
6121
0
}
6122
6123
static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
6124
                                    int x, int y, const QRgba64 &color,
6125
                                    const uint *src, int mapWidth, int mapHeight, int srcStride,
6126
                                    const QClipData *clip, bool useGammaCorrection)
6127
0
{
6128
0
    if (color.isTransparent())
6129
0
        return;
6130
6131
0
    const QColorTrcLut *colorProfile = nullptr;
6132
6133
0
    if (useGammaCorrection)
6134
0
        colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
6135
6136
0
    QRgba64 srcColor = color;
6137
0
    if (colorProfile && color.isOpaque())
6138
0
        srcColor = colorProfile->toLinear(srcColor);
6139
6140
0
    alignas(8) QRgba64 buffer[BufferSize];
6141
0
    const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
6142
0
    const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format];
6143
6144
0
    if (!clip) {
6145
0
        for (int ly = 0; ly < mapHeight; ++ly) {
6146
0
            int i = x;
6147
0
            int length = mapWidth;
6148
0
            while (length > 0) {
6149
0
                int l = qMin(BufferSize, length);
6150
0
                QRgba64 *dest = destFetch64(buffer, rasterBuffer, i, y + ly, l);
6151
0
                for (int j=0; j < l; ++j) {
6152
0
                    const uint coverage = src[j + (i - x)];
6153
0
                    alphargbblend_generic(coverage, dest, j, srcColor, color, colorProfile);
6154
0
                }
6155
0
                if (destStore64)
6156
0
                    destStore64(rasterBuffer, i, y + ly, dest, l);
6157
0
                length -= l;
6158
0
                i += l;
6159
0
            }
6160
0
            src += srcStride;
6161
0
        }
6162
0
    } else {
6163
0
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
6164
6165
0
        int top = qMax(y, 0);
6166
0
        src += (top - y) * srcStride;
6167
6168
0
        const_cast<QClipData *>(clip)->initialize();
6169
0
        for (int yp = top; yp<bottom; ++yp) {
6170
0
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
6171
6172
0
            for (int i=0; i<line.count; ++i) {
6173
0
                const QSpan &clip = line.spans[i];
6174
6175
0
                int start = qMax<int>(x, clip.x);
6176
0
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
6177
0
                if (end <= start)
6178
0
                    continue;
6179
0
                Q_ASSERT(end - start <= BufferSize);
6180
0
                QRgba64 *dest = destFetch64(buffer, rasterBuffer, start, clip.y, end - start);
6181
6182
0
                for (int xp=start; xp<end; ++xp) {
6183
0
                    const uint coverage = src[xp - x];
6184
0
                    alphargbblend_generic(coverage, dest, xp - start, srcColor, color, colorProfile);
6185
0
                }
6186
0
                if (destStore64)
6187
0
                    destStore64(rasterBuffer, start, clip.y, dest, end - start);
6188
0
            } // for (i -> line.count)
6189
0
            src += srcStride;
6190
0
        } // for (yp -> bottom)
6191
0
    }
6192
0
}
6193
#else
6194
static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
6195
                                    int x, int y, const QRgba64 &color,
6196
                                    const uint *src, int mapWidth, int mapHeight, int srcStride,
6197
                                    const QClipData *clip, bool useGammaCorrection)
6198
{
6199
    if (color.isTransparent())
6200
        return;
6201
6202
    const quint32 c = color.toArgb32();
6203
6204
    const QColorTrcLut *colorProfile = nullptr;
6205
6206
    if (useGammaCorrection)
6207
        colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
6208
6209
    QRgba64 srcColor = color;
6210
    if (colorProfile && color.isOpaque())
6211
        srcColor = colorProfile->toLinear(srcColor);
6212
6213
    quint32 buffer[BufferSize];
6214
    const DestFetchProc destFetch = destFetchProc[rasterBuffer->format];
6215
    const DestStoreProc destStore = destStoreProc[rasterBuffer->format];
6216
6217
    if (!clip) {
6218
        for (int ly = 0; ly < mapHeight; ++ly) {
6219
            int i = x;
6220
            int length = mapWidth;
6221
            while (length > 0) {
6222
                int l = qMin(BufferSize, length);
6223
                quint32 *dest = destFetch(buffer, rasterBuffer, i, y + ly, l);
6224
                for (int j=0; j < l; ++j) {
6225
                    const uint coverage = src[j + (i - x)];
6226
                    alphargbblend_argb32(dest + j, coverage, srcColor, c, colorProfile);
6227
                }
6228
                if (destStore)
6229
                    destStore(rasterBuffer, i, y + ly, dest, l);
6230
                length -= l;
6231
                i += l;
6232
            }
6233
            src += srcStride;
6234
        }
6235
    } else {
6236
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
6237
6238
        int top = qMax(y, 0);
6239
        src += (top - y) * srcStride;
6240
6241
        const_cast<QClipData *>(clip)->initialize();
6242
        for (int yp = top; yp<bottom; ++yp) {
6243
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
6244
6245
            for (int i=0; i<line.count; ++i) {
6246
                const QSpan &clip = line.spans[i];
6247
6248
                int start = qMax<int>(x, clip.x);
6249
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
6250
                if (end <= start)
6251
                    continue;
6252
                Q_ASSERT(end - start <= BufferSize);
6253
                quint32 *dest = destFetch(buffer, rasterBuffer, start, clip.y, end - start);
6254
6255
                for (int xp=start; xp<end; ++xp) {
6256
                    const uint coverage = src[xp - x];
6257
                    alphargbblend_argb32(dest + xp - start, coverage, srcColor, c, colorProfile);
6258
                }
6259
                if (destStore)
6260
                    destStore(rasterBuffer, start, clip.y, dest, end - start);
6261
            } // for (i -> line.count)
6262
            src += srcStride;
6263
        } // for (yp -> bottom)
6264
    }
6265
}
6266
#endif
6267
6268
static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer,
6269
                                   int x, int y, const QRgba64 &color,
6270
                                   const uint *src, int mapWidth, int mapHeight, int srcStride,
6271
                                   const QClipData *clip, bool useGammaCorrection)
6272
0
{
6273
0
    if (color.isTransparent())
6274
0
        return;
6275
6276
0
    const quint32 c = color.toArgb32();
6277
6278
0
    const QColorTrcLut *colorProfile = nullptr;
6279
6280
0
    if (useGammaCorrection)
6281
0
        colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
6282
6283
0
    QRgba64 srcColor = color;
6284
0
    if (colorProfile && color.isOpaque())
6285
0
        srcColor = colorProfile->toLinear(srcColor);
6286
6287
0
    if (!clip) {
6288
0
        quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
6289
0
        const int destStride = rasterBuffer->stride<quint32>();
6290
0
        while (mapHeight--) {
6291
0
            for (int i = 0; i < mapWidth; ++i) {
6292
0
                const uint coverage = src[i];
6293
0
                alphargbblend_argb32(dst + i, coverage, srcColor, c, colorProfile);
6294
0
            }
6295
6296
0
            dst += destStride;
6297
0
            src += srcStride;
6298
0
        }
6299
0
    } else {
6300
0
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
6301
6302
0
        int top = qMax(y, 0);
6303
0
        src += (top - y) * srcStride;
6304
6305
0
        const_cast<QClipData *>(clip)->initialize();
6306
0
        for (int yp = top; yp<bottom; ++yp) {
6307
0
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
6308
6309
0
            quint32 *dst = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
6310
6311
0
            for (int i=0; i<line.count; ++i) {
6312
0
                const QSpan &clip = line.spans[i];
6313
6314
0
                int start = qMax<int>(x, clip.x);
6315
0
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
6316
6317
0
                for (int xp=start; xp<end; ++xp) {
6318
0
                    const uint coverage = src[xp - x];
6319
0
                    alphargbblend_argb32(dst + xp, coverage, srcColor, c, colorProfile);
6320
0
                }
6321
0
            } // for (i -> line.count)
6322
0
            src += srcStride;
6323
0
        } // for (yp -> bottom)
6324
6325
0
    }
6326
0
}
6327
6328
static void qt_rectfill_argb32(QRasterBuffer *rasterBuffer,
6329
                               int x, int y, int width, int height,
6330
                               const QRgba64 &color)
6331
0
{
6332
0
    qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
6333
0
                         color.toArgb32(), x, y, width, height, rasterBuffer->bytesPerLine());
6334
0
}
6335
6336
static void qt_rectfill_quint16(QRasterBuffer *rasterBuffer,
6337
                                int x, int y, int width, int height,
6338
                                const QRgba64 &color)
6339
0
{
6340
0
    const QPixelLayout &layout = qPixelLayouts[rasterBuffer->format];
6341
0
    quint32 c32 = color.toArgb32();
6342
0
    quint16 c16;
6343
0
    layout.storeFromARGB32PM(reinterpret_cast<uchar *>(&c16), &c32, 0, 1, nullptr, nullptr);
6344
0
    qt_rectfill<quint16>(reinterpret_cast<quint16 *>(rasterBuffer->buffer()),
6345
0
                         c16, x, y, width, height, rasterBuffer->bytesPerLine());
6346
0
}
6347
6348
static void qt_rectfill_quint24(QRasterBuffer *rasterBuffer,
6349
                                int x, int y, int width, int height,
6350
                                const QRgba64 &color)
6351
0
{
6352
0
    const QPixelLayout &layout = qPixelLayouts[rasterBuffer->format];
6353
0
    quint32 c32 = color.toArgb32();
6354
0
    quint24 c24;
6355
0
    layout.storeFromARGB32PM(reinterpret_cast<uchar *>(&c24), &c32, 0, 1, nullptr, nullptr);
6356
0
    qt_rectfill<quint24>(reinterpret_cast<quint24 *>(rasterBuffer->buffer()),
6357
0
                         c24, x, y, width, height, rasterBuffer->bytesPerLine());
6358
0
}
6359
6360
static void qt_rectfill_nonpremul_argb32(QRasterBuffer *rasterBuffer,
6361
                                         int x, int y, int width, int height,
6362
                                         const QRgba64 &color)
6363
0
{
6364
0
    qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
6365
0
                         color.unpremultiplied().toArgb32(), x, y, width, height, rasterBuffer->bytesPerLine());
6366
0
}
6367
6368
static void qt_rectfill_rgba(QRasterBuffer *rasterBuffer,
6369
                             int x, int y, int width, int height,
6370
                             const QRgba64 &color)
6371
0
{
6372
0
    qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
6373
0
                         ARGB2RGBA(color.toArgb32()), x, y, width, height, rasterBuffer->bytesPerLine());
6374
0
}
6375
6376
static void qt_rectfill_nonpremul_rgba(QRasterBuffer *rasterBuffer,
6377
                                       int x, int y, int width, int height,
6378
                                       const QRgba64 &color)
6379
0
{
6380
0
    qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
6381
0
                         ARGB2RGBA(color.unpremultiplied().toArgb32()), x, y, width, height, rasterBuffer->bytesPerLine());
6382
0
}
6383
6384
template<QtPixelOrder PixelOrder>
6385
static void qt_rectfill_rgb30(QRasterBuffer *rasterBuffer,
6386
                              int x, int y, int width, int height,
6387
                              const QRgba64 &color)
6388
0
{
6389
0
    qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
6390
0
                         qConvertRgb64ToRgb30<PixelOrder>(color), x, y, width, height, rasterBuffer->bytesPerLine());
6391
0
}
Unexecuted instantiation: qdrawhelper.cpp:void qt_rectfill_rgb30<(QtPixelOrder)1>(QRasterBuffer*, int, int, int, int, QRgba64 const&)
Unexecuted instantiation: qdrawhelper.cpp:void qt_rectfill_rgb30<(QtPixelOrder)0>(QRasterBuffer*, int, int, int, int, QRgba64 const&)
6392
6393
static void qt_rectfill_alpha(QRasterBuffer *rasterBuffer,
6394
                             int x, int y, int width, int height,
6395
                             const QRgba64 &color)
6396
0
{
6397
0
    qt_rectfill<quint8>(reinterpret_cast<quint8 *>(rasterBuffer->buffer()),
6398
0
                         color.alpha() >> 8, x, y, width, height, rasterBuffer->bytesPerLine());
6399
0
}
6400
6401
static void qt_rectfill_gray(QRasterBuffer *rasterBuffer,
6402
                             int x, int y, int width, int height,
6403
                             const QRgba64 &color)
6404
0
{
6405
0
    qt_rectfill<quint8>(reinterpret_cast<quint8 *>(rasterBuffer->buffer()),
6406
0
                         qGray(color.toArgb32()), x, y, width, height, rasterBuffer->bytesPerLine());
6407
0
}
6408
6409
static void qt_rectfill_quint64(QRasterBuffer *rasterBuffer,
6410
                                int x, int y, int width, int height,
6411
                                const QRgba64 &color)
6412
0
{
6413
0
    const auto store = qStoreFromRGBA64PM[rasterBuffer->format];
6414
0
    quint64 c64;
6415
0
    store(reinterpret_cast<uchar *>(&c64), &color, 0, 1, nullptr, nullptr);
6416
0
    qt_rectfill<quint64>(reinterpret_cast<quint64 *>(rasterBuffer->buffer()),
6417
0
                         c64, x, y, width, height, rasterBuffer->bytesPerLine());
6418
0
}
6419
6420
// Map table for destination image format. Contains function pointers
6421
// for blends of various types unto the destination
6422
6423
DrawHelper qDrawHelper[QImage::NImageFormats] =
6424
{
6425
    // Format_Invalid,
6426
    { nullptr, nullptr, nullptr, nullptr, nullptr },
6427
    // Format_Mono,
6428
    {
6429
        blend_color_generic,
6430
        nullptr, nullptr, nullptr, nullptr
6431
    },
6432
    // Format_MonoLSB,
6433
    {
6434
        blend_color_generic,
6435
        nullptr, nullptr, nullptr, nullptr
6436
    },
6437
    // Format_Indexed8,
6438
    {
6439
        blend_color_generic,
6440
        nullptr, nullptr, nullptr, nullptr
6441
    },
6442
    // Format_RGB32,
6443
    {
6444
        blend_color_argb,
6445
        qt_bitmapblit_argb32,
6446
        qt_alphamapblit_argb32,
6447
        qt_alphargbblit_argb32,
6448
        qt_rectfill_argb32
6449
    },
6450
    // Format_ARGB32,
6451
    {
6452
        blend_color_generic,
6453
        qt_bitmapblit_argb32,
6454
        qt_alphamapblit_argb32,
6455
        qt_alphargbblit_argb32,
6456
        qt_rectfill_nonpremul_argb32
6457
    },
6458
    // Format_ARGB32_Premultiplied
6459
    {
6460
        blend_color_argb,
6461
        qt_bitmapblit_argb32,
6462
        qt_alphamapblit_argb32,
6463
        qt_alphargbblit_argb32,
6464
        qt_rectfill_argb32
6465
    },
6466
    // Format_RGB16
6467
    {
6468
        blend_color_rgb16,
6469
        qt_bitmapblit_quint16,
6470
        qt_alphamapblit_quint16,
6471
        qt_alphargbblit_generic,
6472
        qt_rectfill_quint16
6473
    },
6474
    // Format_ARGB8565_Premultiplied
6475
    {
6476
        blend_color_generic,
6477
        nullptr,
6478
        qt_alphamapblit_generic,
6479
        qt_alphargbblit_generic,
6480
        qt_rectfill_quint24
6481
    },
6482
    // Format_RGB666
6483
    {
6484
        blend_color_generic,
6485
        nullptr,
6486
        qt_alphamapblit_generic,
6487
        qt_alphargbblit_generic,
6488
        qt_rectfill_quint24
6489
    },
6490
    // Format_ARGB6666_Premultiplied
6491
    {
6492
        blend_color_generic,
6493
        nullptr,
6494
        qt_alphamapblit_generic,
6495
        qt_alphargbblit_generic,
6496
        qt_rectfill_quint24
6497
    },
6498
    // Format_RGB555
6499
    {
6500
        blend_color_generic,
6501
        nullptr,
6502
        qt_alphamapblit_generic,
6503
        qt_alphargbblit_generic,
6504
        qt_rectfill_quint16
6505
    },
6506
    // Format_ARGB8555_Premultiplied
6507
    {
6508
        blend_color_generic,
6509
        nullptr,
6510
        qt_alphamapblit_generic,
6511
        qt_alphargbblit_generic,
6512
        qt_rectfill_quint24
6513
    },
6514
    // Format_RGB888
6515
    {
6516
        blend_color_generic,
6517
        nullptr,
6518
        qt_alphamapblit_generic,
6519
        qt_alphargbblit_generic,
6520
        qt_rectfill_quint24
6521
    },
6522
    // Format_RGB444
6523
    {
6524
        blend_color_generic,
6525
        nullptr,
6526
        qt_alphamapblit_generic,
6527
        qt_alphargbblit_generic,
6528
        qt_rectfill_quint16
6529
    },
6530
    // Format_ARGB4444_Premultiplied
6531
    {
6532
        blend_color_generic,
6533
        nullptr,
6534
        qt_alphamapblit_generic,
6535
        qt_alphargbblit_generic,
6536
        qt_rectfill_quint16
6537
    },
6538
    // Format_RGBX8888
6539
    {
6540
        blend_color_generic,
6541
        qt_bitmapblit_rgba8888,
6542
        qt_alphamapblit_generic,
6543
        qt_alphargbblit_generic,
6544
        qt_rectfill_rgba
6545
    },
6546
    // Format_RGBA8888
6547
    {
6548
        blend_color_generic,
6549
        qt_bitmapblit_rgba8888,
6550
        qt_alphamapblit_generic,
6551
        qt_alphargbblit_generic,
6552
        qt_rectfill_nonpremul_rgba
6553
    },
6554
    // Format_RGB8888_Premultiplied
6555
    {
6556
        blend_color_generic,
6557
        qt_bitmapblit_rgba8888,
6558
        qt_alphamapblit_generic,
6559
        qt_alphargbblit_generic,
6560
        qt_rectfill_rgba
6561
    },
6562
    // Format_BGR30
6563
    {
6564
        blend_color_generic_rgb64,
6565
        qt_bitmapblit_rgb30<PixelOrderBGR>,
6566
        qt_alphamapblit_generic,
6567
        qt_alphargbblit_generic,
6568
        qt_rectfill_rgb30<PixelOrderBGR>
6569
    },
6570
    // Format_A2BGR30_Premultiplied
6571
    {
6572
        blend_color_generic_rgb64,
6573
        qt_bitmapblit_rgb30<PixelOrderBGR>,
6574
        qt_alphamapblit_generic,
6575
        qt_alphargbblit_generic,
6576
        qt_rectfill_rgb30<PixelOrderBGR>
6577
    },
6578
    // Format_RGB30
6579
    {
6580
        blend_color_generic_rgb64,
6581
        qt_bitmapblit_rgb30<PixelOrderRGB>,
6582
        qt_alphamapblit_generic,
6583
        qt_alphargbblit_generic,
6584
        qt_rectfill_rgb30<PixelOrderRGB>
6585
    },
6586
    // Format_A2RGB30_Premultiplied
6587
    {
6588
        blend_color_generic_rgb64,
6589
        qt_bitmapblit_rgb30<PixelOrderRGB>,
6590
        qt_alphamapblit_generic,
6591
        qt_alphargbblit_generic,
6592
        qt_rectfill_rgb30<PixelOrderRGB>
6593
    },
6594
    // Format_Alpha8
6595
    {
6596
        blend_color_generic,
6597
        nullptr,
6598
        qt_alphamapblit_generic,
6599
        qt_alphargbblit_generic,
6600
        qt_rectfill_alpha
6601
    },
6602
    // Format_Grayscale8
6603
    {
6604
        blend_color_generic,
6605
        nullptr,
6606
        qt_alphamapblit_generic,
6607
        qt_alphargbblit_generic,
6608
        qt_rectfill_gray
6609
    },
6610
    // Format_RGBX64
6611
    {
6612
        blend_color_generic_rgb64,
6613
        nullptr,
6614
        qt_alphamapblit_generic,
6615
        qt_alphargbblit_generic,
6616
        qt_rectfill_quint64
6617
    },
6618
    // Format_RGBA64
6619
    {
6620
        blend_color_generic_rgb64,
6621
        nullptr,
6622
        qt_alphamapblit_generic,
6623
        qt_alphargbblit_generic,
6624
        qt_rectfill_quint64
6625
    },
6626
    // Format_RGBA64_Premultiplied
6627
    {
6628
        blend_color_generic_rgb64,
6629
        nullptr,
6630
        qt_alphamapblit_generic,
6631
        qt_alphargbblit_generic,
6632
        qt_rectfill_quint64
6633
    },
6634
    // Format_Grayscale16
6635
    {
6636
        blend_color_generic_rgb64,
6637
        nullptr,
6638
        qt_alphamapblit_generic,
6639
        qt_alphargbblit_generic,
6640
        qt_rectfill_quint16
6641
    },
6642
    // Format_BGR888
6643
    {
6644
        blend_color_generic,
6645
        nullptr,
6646
        qt_alphamapblit_generic,
6647
        qt_alphargbblit_generic,
6648
        qt_rectfill_quint24
6649
    },
6650
};
6651
6652
#if !defined(__SSE2__)
6653
void qt_memfill64(quint64 *dest, quint64 color, qsizetype count)
6654
{
6655
    qt_memfill_template<quint64>(dest, color, count);
6656
}
6657
#endif
6658
6659
#if defined(QT_COMPILER_SUPPORTS_SSSE3) && defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG)
6660
__attribute__((optimize("no-tree-vectorize")))
6661
#endif
6662
void qt_memfill24(quint24 *dest, quint24 color, qsizetype count)
6663
0
{
6664
0
#  ifdef QT_COMPILER_SUPPORTS_SSSE3
6665
0
    extern void qt_memfill24_ssse3(quint24 *, quint24, qsizetype);
6666
0
    if (qCpuHasFeature(SSSE3))
6667
0
        return qt_memfill24_ssse3(dest, color, count);
6668
0
#  endif
6669
6670
0
    const quint32 v = color;
6671
0
    quint24 *end = dest + count;
6672
6673
    // prolog: align dest to 32bit
6674
0
    while ((quintptr(dest) & 0x3) && dest < end) {
6675
0
        *dest++ = v;
6676
0
    }
6677
0
    if (dest >= end)
6678
0
        return;
6679
6680
0
    const uint val1 = qFromBigEndian((v <<  8) | (v >> 16));
6681
0
    const uint val2 = qFromBigEndian((v << 16) | (v >>  8));
6682
0
    const uint val3 = qFromBigEndian((v << 24) | (v >>  0));
6683
6684
0
    for ( ; dest <= (end - 4); dest += 4) {
6685
0
       quint32 *dst = reinterpret_cast<quint32 *>(dest);
6686
0
       dst[0] = val1;
6687
0
       dst[1] = val2;
6688
0
       dst[2] = val3;
6689
0
    }
6690
6691
    // less than 4px left
6692
0
    switch (end - dest) {
6693
0
    case 3:
6694
0
        *dest++ = v;
6695
0
        Q_FALLTHROUGH();
6696
0
    case 2:
6697
0
        *dest++ = v;
6698
0
        Q_FALLTHROUGH();
6699
0
    case 1:
6700
0
        *dest++ = v;
6701
0
    }
6702
0
}
6703
6704
void qt_memfill16(quint16 *dest, quint16 value, qsizetype count)
6705
0
{
6706
0
    const int align = quintptr(dest) & 0x3;
6707
0
    if (align) {
6708
0
        *dest++ = value;
6709
0
        --count;
6710
0
    }
6711
6712
0
    if (count & 0x1)
6713
0
        dest[count - 1] = value;
6714
6715
0
    const quint32 value32 = (value << 16) | value;
6716
0
    qt_memfill32(reinterpret_cast<quint32*>(dest), value32, count / 2);
6717
0
}
6718
6719
#if !defined(__SSE2__) && !defined(__ARM_NEON__) && !defined(__MIPS_DSP__)
6720
void qt_memfill32(quint32 *dest, quint32 color, qsizetype count)
6721
{
6722
    qt_memfill_template<quint32>(dest, color, count);
6723
}
6724
#endif
6725
#ifdef __SSE2__
6726
decltype(qt_memfill32_sse2) *qt_memfill32 = nullptr;
6727
decltype(qt_memfill64_sse2) *qt_memfill64 = nullptr;
6728
#endif
6729
6730
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
6731
template<QtPixelOrder> void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, const QVector<QRgb> *, QDitherInfo *);
6732
#endif
6733
6734
extern void qInitBlendFunctions();
6735
6736
static void qInitDrawhelperFunctions()
6737
10
{
6738
    // Set up basic blend function tables.
6739
10
    qInitBlendFunctions();
6740
6741
10
#ifdef __SSE2__
6742
10
#  ifndef __haswell__
6743
10
    qt_memfill32 = qt_memfill32_sse2;
6744
10
    qt_memfill64 = qt_memfill64_sse2;
6745
10
#  endif
6746
10
    qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2;
6747
10
    qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2;
6748
10
    qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2;
6749
10
    qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse2;
6750
10
    qDrawHelper[QImage::Format_RGBX8888].bitmapBlit = qt_bitmapblit8888_sse2;
6751
10
    qDrawHelper[QImage::Format_RGBA8888].bitmapBlit = qt_bitmapblit8888_sse2;
6752
10
    qDrawHelper[QImage::Format_RGBA8888_Premultiplied].bitmapBlit = qt_bitmapblit8888_sse2;
6753
6754
10
    extern void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
6755
10
                                                     const uchar *srcPixels, int sbpl, int srch,
6756
10
                                                     const QRectF &targetRect,
6757
10
                                                     const QRectF &sourceRect,
6758
10
                                                     const QRect &clip,
6759
10
                                                     int const_alpha);
6760
10
    qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2;
6761
10
    qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2;
6762
10
    qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2;
6763
10
    qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2;
6764
6765
10
    extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
6766
10
                                             const uchar *srcPixels, int sbpl,
6767
10
                                             int w, int h,
6768
10
                                             int const_alpha);
6769
10
    extern void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
6770
10
                                               const uchar *srcPixels, int sbpl,
6771
10
                                               int w, int h,
6772
10
                                               int const_alpha);
6773
6774
10
    qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
6775
10
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
6776
10
    qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
6777
10
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
6778
10
    qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_sse2;
6779
10
    qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_sse2;
6780
10
    qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
6781
10
    qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
6782
6783
10
    extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data,
6784
10
                                                                  int y, int x, int length);
6785
6786
10
    qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2;
6787
6788
10
    extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
6789
10
    extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha);
6790
10
    extern void QT_FASTCALL comp_func_Source_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
6791
10
    extern void QT_FASTCALL comp_func_solid_Source_sse2(uint *destPixels, int length, uint color, uint const_alpha);
6792
10
    extern void QT_FASTCALL comp_func_Plus_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
6793
10
    qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_sse2;
6794
10
    qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_sse2;
6795
10
    qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_sse2;
6796
10
    qt_functionForModeSolid_C[QPainter::CompositionMode_Source] = comp_func_solid_Source_sse2;
6797
10
    qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2;
6798
6799
10
#ifdef QT_COMPILER_SUPPORTS_SSSE3
6800
10
    if (qCpuHasFeature(SSSE3)) {
6801
10
        extern void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl,
6802
10
                                                    const uchar *srcPixels, int sbpl,
6803
10
                                                    int w, int h,
6804
10
                                                    int const_alpha);
6805
6806
10
        extern const uint * QT_FASTCALL qt_fetchUntransformed_888_ssse3(uint *buffer, const Operator *, const QSpanData *data,
6807
10
                                                                        int y, int x, int length);
6808
10
        qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
6809
10
        qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
6810
10
        qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
6811
10
        qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
6812
10
        sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_ssse3;
6813
10
        extern void QT_FASTCALL rbSwap_888_ssse3(uchar *dst, const uchar *src, int count);
6814
10
        qPixelLayouts[QImage::Format_RGB888].rbSwap = rbSwap_888_ssse3;
6815
10
        qPixelLayouts[QImage::Format_BGR888].rbSwap = rbSwap_888_ssse3;
6816
10
    }
6817
10
#endif // SSSE3
6818
6819
10
#if defined(QT_COMPILER_SUPPORTS_SSE4_1)
6820
10
    if (qCpuHasFeature(SSE4_1)) {
6821
10
        extern void QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, int count, const QVector<QRgb> *);
6822
10
        extern void QT_FASTCALL convertRGBA8888ToARGB32PM_sse4(uint *buffer, int count, const QVector<QRgb> *);
6823
10
        extern const uint *QT_FASTCALL fetchARGB32ToARGB32PM_sse4(uint *buffer, const uchar *src, int index, int count,
6824
10
                                                                  const QVector<QRgb> *, QDitherInfo *);
6825
10
        extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_sse4(uint *buffer, const uchar *src, int index, int count,
6826
10
                                                                    const QVector<QRgb> *, QDitherInfo *);
6827
10
        extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_sse4(QRgba64 *buffer, const uint *src, int count,
6828
10
                                                                        const QVector<QRgb> *, QDitherInfo *);
6829
10
        extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_sse4(QRgba64 *buffer, const uint *src, int count,
6830
10
                                                                          const QVector<QRgb> *, QDitherInfo *);
6831
10
        extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_sse4(QRgba64 *buffer, const uchar *src, int index, int count,
6832
10
                                                                     const QVector<QRgb> *, QDitherInfo *);
6833
10
        extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_sse4(QRgba64 *buffer, const uchar *src, int index, int count,
6834
10
                                                                       const QVector<QRgb> *, QDitherInfo *);
6835
10
        extern void QT_FASTCALL storeARGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
6836
10
                                                                      const QVector<QRgb> *, QDitherInfo *);
6837
10
        extern void QT_FASTCALL storeRGBA8888FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
6838
10
                                                                        const QVector<QRgb> *, QDitherInfo *);
6839
10
        extern void QT_FASTCALL storeRGBXFromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
6840
10
                                                                    const QVector<QRgb> *, QDitherInfo *);
6841
10
        extern void QT_FASTCALL storeARGB32FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
6842
10
                                                             const QVector<QRgb> *, QDitherInfo *);
6843
10
        extern void QT_FASTCALL storeRGBA8888FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
6844
10
                                                              const QVector<QRgb> *, QDitherInfo *);
6845
10
        extern void QT_FASTCALL destStore64ARGB32_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
6846
10
        extern void QT_FASTCALL destStore64RGBA8888_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
6847
10
#  ifndef __haswell__
6848
10
        qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_sse4;
6849
10
        qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4;
6850
10
        qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_sse4;
6851
10
        qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_sse4;
6852
10
        qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_sse4;
6853
10
        qPixelLayouts[QImage::Format_ARGB32].convertToRGBA64PM = convertARGB32ToRGBA64PM_sse4;
6854
10
        qPixelLayouts[QImage::Format_RGBA8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_sse4;
6855
10
        qPixelLayouts[QImage::Format_RGBA8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_sse4;
6856
10
        qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_sse4;
6857
10
        qPixelLayouts[QImage::Format_RGBX8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_sse4;
6858
10
#  endif
6859
10
        qPixelLayouts[QImage::Format_ARGB32].storeFromARGB32PM = storeARGB32FromARGB32PM_sse4;
6860
10
        qPixelLayouts[QImage::Format_RGBA8888].storeFromARGB32PM = storeRGBA8888FromARGB32PM_sse4;
6861
10
        qPixelLayouts[QImage::Format_RGBX8888].storeFromARGB32PM = storeRGBXFromARGB32PM_sse4;
6862
10
        qPixelLayouts[QImage::Format_A2BGR30_Premultiplied].storeFromARGB32PM = storeA2RGB30PMFromARGB32PM_sse4<PixelOrderBGR>;
6863
10
        qPixelLayouts[QImage::Format_A2RGB30_Premultiplied].storeFromARGB32PM = storeA2RGB30PMFromARGB32PM_sse4<PixelOrderRGB>;
6864
10
        qStoreFromRGBA64PM[QImage::Format_ARGB32] = storeARGB32FromRGBA64PM_sse4;
6865
10
        qStoreFromRGBA64PM[QImage::Format_RGBA8888] = storeRGBA8888FromRGBA64PM_sse4;
6866
10
#if QT_CONFIG(raster_64bit)
6867
10
        destStoreProc64[QImage::Format_ARGB32] = destStore64ARGB32_sse4;
6868
10
        destStoreProc64[QImage::Format_RGBA8888] = destStore64RGBA8888_sse4;
6869
10
#endif
6870
10
    }
6871
10
#endif
6872
6873
10
#if defined(QT_COMPILER_SUPPORTS_AVX2)
6874
10
    if (qCpuHasFeature(ArchHaswell)) {
6875
10
        qt_memfill32 = qt_memfill32_avx2;
6876
10
        qt_memfill64 = qt_memfill64_avx2;
6877
10
        extern void qt_blend_rgb32_on_rgb32_avx2(uchar *destPixels, int dbpl,
6878
10
                                                 const uchar *srcPixels, int sbpl,
6879
10
                                                 int w, int h, int const_alpha);
6880
10
        extern void qt_blend_argb32_on_argb32_avx2(uchar *destPixels, int dbpl,
6881
10
                                                   const uchar *srcPixels, int sbpl,
6882
10
                                                   int w, int h, int const_alpha);
6883
10
        qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_avx2;
6884
10
        qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_avx2;
6885
10
        qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx2;
6886
10
        qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx2;
6887
10
        qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_avx2;
6888
10
        qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_avx2;
6889
10
        qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_avx2;
6890
10
        qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_avx2;
6891
6892
10
        extern void QT_FASTCALL comp_func_Source_avx2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
6893
10
        extern void QT_FASTCALL comp_func_SourceOver_avx2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
6894
10
        extern void QT_FASTCALL comp_func_solid_SourceOver_avx2(uint *destPixels, int length, uint color, uint const_alpha);
6895
10
        qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_avx2;
6896
10
        qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_avx2;
6897
10
        qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_avx2;
6898
10
#if QT_CONFIG(raster_64bit)
6899
10
        extern void QT_FASTCALL comp_func_Source_rgb64_avx2(QRgba64 *destPixels, const QRgba64 *srcPixels, int length, uint const_alpha);
6900
10
        extern void QT_FASTCALL comp_func_SourceOver_rgb64_avx2(QRgba64 *destPixels, const QRgba64 *srcPixels, int length, uint const_alpha);
6901
10
        extern void QT_FASTCALL comp_func_solid_SourceOver_rgb64_avx2(QRgba64 *destPixels, int length, QRgba64 color, uint const_alpha);
6902
10
        qt_functionForMode64_C[QPainter::CompositionMode_Source] = comp_func_Source_rgb64_avx2;
6903
10
        qt_functionForMode64_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_rgb64_avx2;
6904
10
        qt_functionForModeSolid64_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_rgb64_avx2;
6905
10
#endif
6906
6907
10
        extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2(uint *b, uint *end, const QTextureData &image,
6908
10
                                                                                          int &fx, int &fy, int fdx, int /*fdy*/);
6909
10
        extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_downscale_helper_avx2(uint *b, uint *end, const QTextureData &image,
6910
10
                                                                                       int &fx, int &fy, int fdx, int /*fdy*/);
6911
10
        extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2(uint *b, uint *end, const QTextureData &image,
6912
10
                                                                                         int &fx, int &fy, int fdx, int fdy);
6913
6914
10
        bilinearFastTransformHelperARGB32PM[0][SimpleScaleTransform] = fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2;
6915
10
        bilinearFastTransformHelperARGB32PM[0][DownscaleTransform] = fetchTransformedBilinearARGB32PM_downscale_helper_avx2;
6916
10
        bilinearFastTransformHelperARGB32PM[0][FastRotateTransform] = fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2;
6917
6918
10
        extern void QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, int count, const QVector<QRgb> *);
6919
10
        extern void QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, int count, const QVector<QRgb> *);
6920
10
        extern const uint *QT_FASTCALL fetchARGB32ToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count,
6921
10
                                                                  const QVector<QRgb> *, QDitherInfo *);
6922
10
        extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count,
6923
10
                                                                    const QVector<QRgb> *, QDitherInfo *);
6924
10
        qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_avx2;
6925
10
        qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_avx2;
6926
10
        qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_avx2;
6927
10
        qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_avx2;
6928
6929
10
#if QT_CONFIG(raster_64bit)
6930
10
        extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_avx2(QRgba64 *, const uint *, int, const QVector<QRgb> *, QDitherInfo *);
6931
10
        extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_avx2(QRgba64 *, const uint *, int count, const QVector<QRgb> *, QDitherInfo *);
6932
10
        extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_avx2(QRgba64 *, const uchar *, int, int, const QVector<QRgb> *, QDitherInfo *);
6933
10
        extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_avx2(QRgba64 *, const uchar *, int, int, const QVector<QRgb> *, QDitherInfo *);
6934
10
        qPixelLayouts[QImage::Format_ARGB32].convertToRGBA64PM = convertARGB32ToRGBA64PM_avx2;
6935
10
        qPixelLayouts[QImage::Format_RGBX8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_avx2;
6936
10
        qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_avx2;
6937
10
        qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_avx2;
6938
10
#endif
6939
10
    }
6940
10
#endif
6941
6942
10
#endif // SSE2
6943
6944
#if defined(__ARM_NEON__)
6945
    qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
6946
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
6947
    qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
6948
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
6949
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
6950
    qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_neon;
6951
    qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_neon;
6952
    qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_neon;
6953
    qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_neon;
6954
#endif
6955
6956
    qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon;
6957
    qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon;
6958
    qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon;
6959
6960
    extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data,
6961
                                                                  int y, int x, int length);
6962
6963
    qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon;
6964
6965
    sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_neon;
6966
6967
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
6968
    extern void QT_FASTCALL convertARGB32ToARGB32PM_neon(uint *buffer, int count, const QVector<QRgb> *);
6969
    extern void QT_FASTCALL convertRGBA8888ToARGB32PM_neon(uint *buffer, int count, const QVector<QRgb> *);
6970
    extern const uint *QT_FASTCALL fetchARGB32ToARGB32PM_neon(uint *buffer, const uchar *src, int index, int count,
6971
                                                              const QVector<QRgb> *, QDitherInfo *);
6972
    extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_neon(uint *buffer, const uchar *src, int index, int count,
6973
                                                                const QVector<QRgb> *, QDitherInfo *);
6974
   extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count,
6975
                                                                   const QVector<QRgb> *, QDitherInfo *);
6976
   extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count,
6977
                                                                     const QVector<QRgb> *, QDitherInfo *);
6978
   extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_neon(QRgba64 *buffer, const uchar *src, int index, int count,
6979
                                                                const QVector<QRgb> *, QDitherInfo *);
6980
   extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_neon(QRgba64 *buffer, const uchar *src, int index, int count,
6981
                                                                  const QVector<QRgb> *, QDitherInfo *);
6982
    extern void QT_FASTCALL storeARGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
6983
                                                         const QVector<QRgb> *, QDitherInfo *);
6984
    extern void QT_FASTCALL storeRGBA8888FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
6985
                                                           const QVector<QRgb> *, QDitherInfo *);
6986
    extern void QT_FASTCALL storeRGBXFromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
6987
                                                       const QVector<QRgb> *, QDitherInfo *);
6988
    qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_neon;
6989
    qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_neon;
6990
    qPixelLayouts[QImage::Format_ARGB32].storeFromARGB32PM = storeARGB32FromARGB32PM_neon;
6991
    qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_neon;
6992
    qPixelLayouts[QImage::Format_ARGB32].convertToRGBA64PM = convertARGB32ToRGBA64PM_neon;
6993
    qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_neon;
6994
    qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_neon;
6995
    qPixelLayouts[QImage::Format_RGBA8888].storeFromARGB32PM = storeRGBA8888FromARGB32PM_neon;
6996
    qPixelLayouts[QImage::Format_RGBA8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_neon;
6997
    qPixelLayouts[QImage::Format_RGBA8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_neon;
6998
    qPixelLayouts[QImage::Format_RGBX8888].storeFromARGB32PM = storeRGBXFromARGB32PM_neon;
6999
    qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_neon;
7000
    qPixelLayouts[QImage::Format_RGBX8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_neon;
7001
#endif
7002
7003
#if defined(ENABLE_PIXMAN_DRAWHELPERS)
7004
    // The RGB16 helpers are using Arm32 assemblythat has not been ported to AArch64
7005
    qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon;
7006
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB16] = qt_blend_rgb16_on_argb32_neon;
7007
    qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_neon;
7008
7009
    qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16_neon;
7010
    qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16_neon;
7011
7012
    qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16_neon;
7013
    qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16_neon;
7014
7015
    qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon;
7016
7017
    destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon;
7018
    destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon;
7019
7020
    qMemRotateFunctions[QPixelLayout::BPP16][0] = qt_memrotate90_16_neon;
7021
    qMemRotateFunctions[QPixelLayout::BPP16][2] = qt_memrotate270_16_neon;
7022
#endif
7023
#endif // defined(__ARM_NEON__)
7024
7025
#if defined(__MIPS_DSP__)
7026
    // Composition functions are all DSP r1
7027
    qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_asm_mips_dsp;
7028
    qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_mips_dsp;
7029
    qt_functionForMode_C[QPainter::CompositionMode_DestinationOver] = comp_func_DestinationOver_mips_dsp;
7030
    qt_functionForMode_C[QPainter::CompositionMode_SourceIn] = comp_func_SourceIn_mips_dsp;
7031
    qt_functionForMode_C[QPainter::CompositionMode_DestinationIn] = comp_func_DestinationIn_mips_dsp;
7032
    qt_functionForMode_C[QPainter::CompositionMode_DestinationOut] = comp_func_DestinationOut_mips_dsp;
7033
    qt_functionForMode_C[QPainter::CompositionMode_SourceAtop] = comp_func_SourceAtop_mips_dsp;
7034
    qt_functionForMode_C[QPainter::CompositionMode_DestinationAtop] = comp_func_DestinationAtop_mips_dsp;
7035
    qt_functionForMode_C[QPainter::CompositionMode_Xor] = comp_func_XOR_mips_dsp;
7036
    qt_functionForMode_C[QPainter::CompositionMode_SourceOut] = comp_func_SourceOut_mips_dsp;
7037
7038
    qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_mips_dsp;
7039
    qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationOver] = comp_func_solid_DestinationOver_mips_dsp;
7040
    qt_functionForModeSolid_C[QPainter::CompositionMode_SourceIn] = comp_func_solid_SourceIn_mips_dsp;
7041
    qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationIn] = comp_func_solid_DestinationIn_mips_dsp;
7042
    qt_functionForModeSolid_C[QPainter::CompositionMode_SourceAtop] = comp_func_solid_SourceAtop_mips_dsp;
7043
    qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationAtop] = comp_func_solid_DestinationAtop_mips_dsp;
7044
    qt_functionForModeSolid_C[QPainter::CompositionMode_Xor] = comp_func_solid_XOR_mips_dsp;
7045
    qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOut] = comp_func_solid_SourceOut_mips_dsp;
7046
7047
    qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp;
7048
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp;
7049
    qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mips_dsp;
7050
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mips_dsp;
7051
7052
    destFetchProc[QImage::Format_ARGB32] = qt_destFetchARGB32_mips_dsp;
7053
7054
    destStoreProc[QImage::Format_ARGB32] = qt_destStoreARGB32_mips_dsp;
7055
7056
    sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_mips_dsp;
7057
    sourceFetchUntransformed[QImage::Format_RGB444] = qt_fetchUntransformed_444_mips_dsp;
7058
    sourceFetchUntransformed[QImage::Format_ARGB8565_Premultiplied] = qt_fetchUntransformed_argb8565_premultiplied_mips_dsp;
7059
7060
#if defined(__MIPS_DSPR2__)
7061
    qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_mips_dspr2;
7062
    sourceFetchUntransformed[QImage::Format_RGB16] = qt_fetchUntransformedRGB16_mips_dspr2;
7063
#else
7064
    qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_mips_dsp;
7065
#endif // defined(__MIPS_DSPR2__)
7066
#endif // defined(__MIPS_DSP__)
7067
10
}
7068
7069
// Ensure initialization if this object file is linked.
7070
Q_CONSTRUCTOR_FUNCTION(qInitDrawhelperFunctions);
7071
7072
QT_END_NAMESPACE