Coverage Report

Created: 2026-07-30 07:17

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