Coverage Report

Created: 2026-10-27 06:57

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
2.27M
{
354
2.27M
    const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
355
2.27M
    return const_cast<uint *>(layout->fetchToARGB32PM(buffer, rasterBuffer->scanLine(y), x, length, nullptr, nullptr));
356
2.27M
}
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
5.55M
{
409
5.55M
    const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
410
5.55M
    return const_cast<QRgba64 *>(layout->fetchToRGBA64PM(buffer, rasterBuffer->scanLine(y), x, length, nullptr, nullptr));
411
5.55M
}
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
3.62M
{
623
3.62M
    const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
624
3.62M
    ConvertAndStorePixelsFunc store = layout->storeFromARGB32PM;
625
3.62M
    if (!layout->premultiplied && !layout->hasAlphaChannel)
626
3.62M
        store = layout->storeFromRGB32;
627
3.62M
    uchar *dest = rasterBuffer->scanLine(y);
628
3.62M
    store(dest, buffer, x, length, nullptr, nullptr);
629
3.62M
}
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
3.62M
{
860
3.62M
    const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
861
3.62M
    return layout->fetchToARGB32PM(buffer, data->texture.scanLine(y), x, length, data->texture.colorTable, nullptr);
862
3.62M
}
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
6.02M
{
885
6.02M
    const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
886
6.02M
    return layout->fetchToRGBA64PM(buffer, data->texture.scanLine(y), x, length, data->texture.colorTable, nullptr);
887
6.02M
}
888
889
static const QRgba64 *QT_FASTCALL fetchUntransformedRGBA64PM(QRgba64 *, const Operator *,
890
                                                             const QSpanData *data, int y, int x, int)
891
407
{
892
407
    const uchar *scanLine = data->texture.scanLine(y);
893
407
    return reinterpret_cast<const QRgba64 *>(scanLine) + x;
894
407
}
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
304k
{
3325
304k
    if (format == QImage::Format_RGB32 || format == QImage::Format_ARGB32_Premultiplied)
3326
0
        return sourceFetchARGB32PM[blendType];
3327
304k
    if (blendType == BlendUntransformed || blendType == BlendTiled)
3328
304k
        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
304k
{
3361
304k
    if (format == QImage::Format_RGBX64 || format == QImage::Format_RGBA64_Premultiplied)
3362
28.5k
        return sourceFetchRGBA64PM[blendType];
3363
276k
    return sourceFetchGeneric64[blendType];
3364
304k
}
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
304k
{
3381
304k
    return sourceFetchGenericFP[blendType];
3382
304k
}
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
1.21M
{
3771
1.21M
    TextureBlendType ft;
3772
1.21M
    if (data->texture.type == QTextureData::Pattern)
3773
0
        ft = BlendTiled;
3774
1.21M
    else if (data->txop <= QTransform::TxTranslate)
3775
1.21M
        if (data->texture.type == QTextureData::Tiled)
3776
0
            ft = BlendTiled;
3777
1.21M
        else
3778
1.21M
            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
1.21M
    return ft;
3790
1.21M
}
3791
3792
static inline Operator getOperator(const QSpanData *data, const QT_FT_Span *spans, int spanCount)
3793
304k
{
3794
304k
    Operator op;
3795
304k
    bool solidSource = false;
3796
304k
    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
304k
    case QSpanData::Texture:
3838
304k
        solidSource = !data->texture.hasAlpha;
3839
304k
        op.noGradient = {};
3840
304k
        op.srcFetch = getSourceFetch(getBlendType(data), data->texture.format);
3841
304k
#if QT_CONFIG(raster_64bit)
3842
304k
        op.srcFetch64 = getSourceFetch64(getBlendType(data), data->texture.format);
3843
304k
#endif
3844
304k
#if QT_CONFIG(raster_fp)
3845
304k
        op.srcFetchFP = getSourceFetchFP(getBlendType(data), data->texture.format);
3846
304k
#endif
3847
304k
        break;
3848
0
    default:
3849
0
        Q_UNREACHABLE();
3850
0
        break;
3851
304k
    }
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
304k
    op.mode = data->rasterBuffer->compositionMode;
3860
304k
    if (op.mode == QPainter::CompositionMode_SourceOver && solidSource)
3861
11.0k
        op.mode = QPainter::CompositionMode_Source;
3862
3863
304k
    op.destFetch = destFetchProc[data->rasterBuffer->format];
3864
304k
#if QT_CONFIG(raster_64bit)
3865
304k
    op.destFetch64 = destFetchProc64[data->rasterBuffer->format];
3866
#else
3867
    op.destFetch64 = nullptr;
3868
#endif
3869
304k
#if QT_CONFIG(raster_fp)
3870
304k
    op.destFetchFP = destFetchProcFP[data->rasterBuffer->format];
3871
#else
3872
    op.destFetchFP = nullptr;
3873
#endif
3874
304k
    if (op.mode == QPainter::CompositionMode_Source &&
3875
135k
            (data->type != QSpanData::Texture || data->texture.const_alpha == 256)) {
3876
87.5k
        const QT_FT_Span *lastSpan = spans + spanCount;
3877
87.5k
        bool alphaSpans = false;
3878
1.90M
        while (spans < lastSpan) {
3879
1.81M
            if (spans->coverage != 255) {
3880
0
                alphaSpans = true;
3881
0
                break;
3882
0
            }
3883
1.81M
            ++spans;
3884
1.81M
        }
3885
87.5k
        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
87.5k
            if (op.destFetch != destFetchARGB32P)
3889
87.5k
                op.destFetch = destFetchUndefined;
3890
87.5k
#if QT_CONFIG(raster_64bit)
3891
87.5k
            if (op.destFetch64 != destFetchRGB64)
3892
87.5k
                op.destFetch64 = destFetch64Undefined;
3893
87.5k
#endif
3894
87.5k
#if QT_CONFIG(raster_fp)
3895
87.5k
            if (op.destFetchFP != destFetchRGBFP)
3896
87.5k
                op.destFetchFP = destFetchFPUndefined;
3897
87.5k
#endif
3898
87.5k
        }
3899
87.5k
    }
3900
3901
304k
    op.destStore = destStoreProc[data->rasterBuffer->format];
3902
304k
    op.funcSolid = functionForModeSolid[op.mode];
3903
304k
    op.func = functionForMode[op.mode];
3904
304k
#if QT_CONFIG(raster_64bit)
3905
304k
    op.destStore64 = destStoreProc64[data->rasterBuffer->format];
3906
304k
    op.funcSolid64 = functionForModeSolid64[op.mode];
3907
304k
    op.func64 = functionForMode64[op.mode];
3908
    // RGBx64 do not need conversion on writeback if all pixels are opaque
3909
304k
    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
304k
#if QT_CONFIG(raster_fp)
3917
304k
    op.destStoreFP = destStoreFP;
3918
304k
    op.funcSolidFP = functionForModeSolidFP[op.mode];
3919
304k
    op.funcFP = functionForModeFP[op.mode];
3920
#else
3921
    op.destStoreFP = nullptr;
3922
    op.funcSolidFP = nullptr;
3923
    op.funcFP = nullptr;
3924
#endif
3925
3926
304k
    return op;
3927
304k
}
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
// Handing a fill to the thread pool only pays off when the spans cover enough
3973
// pixels, and the limit is higher for solid fills than gradient/texture blends
3974
static constexpr int MinParallelSolidPixels = 1 << 17;
3975
static constexpr int MinParallelBlendPixels = 1 << 15;
3976
3977
// Estimates whether the spans cover at least _limit_ pixels
3978
static inline bool qt_pixelCountAtLeast(int count, const QT_FT_Span *spans, int limit)
3979
0
{
3980
0
    constexpr int MaxProbeSpans = 32;
3981
0
    const int numProbeSpans = qMin(count, MaxProbeSpans);
3982
0
    qint64 numPixels = 0;
3983
0
    for (int i = 0; i < numProbeSpans; ++i)
3984
0
        numPixels += spans[i].len;
3985
0
    return numPixels * count >= qint64(limit) * numProbeSpans;
3986
0
}
3987
3988
// qtGuiThreadPool() locks mutex, so only call it if the fill is worth splitting
3989
#define QT_THREAD_PARALLEL_FILLS(function, minPixels) \
3990
304k
    const int segments = (count + 32) / 64; \
3991
304k
    QThreadPool *threadPool = (segments > 1 \
3992
304k
             && qPixelLayouts[data->rasterBuffer->format].bpp >= QPixelLayout::BPP8 \
3993
304k
             && qt_pixelCountAtLeast(count, spans, minPixels)) \
3994
304k
            ? QGuiApplicationPrivate::qtGuiThreadPool() : nullptr; \
3995
304k
    if (threadPool && !threadPool->contains(QThread::currentThread())) { \
3996
0
        QLatch latch(segments); \
3997
0
        int c = 0; \
3998
0
        for (int i = 0; i < segments; ++i) { \
3999
0
            int cn = (count - c) / (segments - i); \
4000
0
            threadPool->start([&, c, cn]() { \
4001
0
                function(c, c + cn); \
4002
0
                latch.countDown(); \
4003
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
4004
0
            c += cn; \
4005
0
        } \
4006
0
        latch.wait(); \
4007
0
    } else \
4008
304k
        function(0, count)
4009
#else
4010
#define QT_THREAD_PARALLEL_FILLS(function, minPixels) function(0, count)
4011
#endif
4012
4013
static void blend_color_generic(int count, const QT_FT_Span *spans, void *userData)
4014
0
{
4015
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4016
0
    const Operator op = getOperator(data, nullptr, 0);
4017
0
    const uint color = data->solidColor.rgba();
4018
0
    const bool solidFill = op.mode == QPainter::CompositionMode_Source;
4019
0
    const QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
4020
4021
0
    auto function = [=] (int cStart, int cEnd) {
4022
0
        alignas(16) Q_DECL_UNINITIALIZED uint buffer[BufferSize];
4023
0
        for (int c = cStart; c < cEnd; ++c) {
4024
0
            int x = spans[c].x;
4025
0
            int length = spans[c].len;
4026
0
            if (solidFill && bpp >= QPixelLayout::BPP8 && spans[c].coverage == 255 && length && op.destStore) {
4027
                // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels
4028
0
                op.destStore(data->rasterBuffer, x, spans[c].y, &color, 1);
4029
0
                spanfill_from_first(data->rasterBuffer, bpp, x, spans[c].y, length);
4030
0
                length = 0;
4031
0
            }
4032
4033
0
            while (length) {
4034
0
                int l = qMin(BufferSize, length);
4035
0
                uint *dest = op.destFetch(buffer, data->rasterBuffer, x, spans[c].y, l);
4036
0
                op.funcSolid(dest, l, color, spans[c].coverage);
4037
0
                if (op.destStore)
4038
0
                    op.destStore(data->rasterBuffer, x, spans[c].y, dest, l);
4039
0
                length -= l;
4040
0
                x += l;
4041
0
            }
4042
0
        }
4043
0
    };
4044
0
    QT_THREAD_PARALLEL_FILLS(function, MinParallelSolidPixels);
4045
0
}
4046
4047
static void blend_color_argb(int count, const QT_FT_Span *spans, void *userData)
4048
0
{
4049
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4050
4051
0
    const Operator op = getOperator(data, nullptr, 0);
4052
0
    const uint color = data->solidColor.rgba();
4053
4054
0
    if (op.mode == QPainter::CompositionMode_Source) {
4055
        // inline for performance
4056
0
        while (count--) {
4057
0
            uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
4058
0
            if (spans->coverage == 255) {
4059
0
                qt_memfill(target, color, spans->len);
4060
0
#ifdef __SSE2__
4061
0
            } else if (spans->len > 16) {
4062
0
                op.funcSolid(target, spans->len, color, spans->coverage);
4063
0
#endif
4064
0
            } else {
4065
0
                uint c = BYTE_MUL(color, spans->coverage);
4066
0
                int ialpha = 255 - spans->coverage;
4067
0
                for (int i = 0; i < spans->len; ++i)
4068
0
                    target[i] = c + BYTE_MUL(target[i], ialpha);
4069
0
            }
4070
0
            ++spans;
4071
0
        }
4072
0
        return;
4073
0
    }
4074
0
    const auto funcSolid = op.funcSolid;
4075
0
    auto function = [=] (int cStart, int cEnd) {
4076
0
        for (int c = cStart; c < cEnd; ++c) {
4077
0
            uint *target = ((uint *)data->rasterBuffer->scanLine(spans[c].y)) + spans[c].x;
4078
0
            funcSolid(target, spans[c].len, color, spans[c].coverage);
4079
0
        }
4080
0
    };
4081
0
    QT_THREAD_PARALLEL_FILLS(function, MinParallelSolidPixels);
4082
0
}
4083
4084
static void blend_color_generic_rgb64(int count, const QT_FT_Span *spans, void *userData)
4085
0
{
4086
0
#if QT_CONFIG(raster_64bit)
4087
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4088
0
    const Operator op = getOperator(data, nullptr, 0);
4089
0
    if (!op.funcSolid64) {
4090
0
        qCDebug(lcQtGuiDrawHelper, "blend_color_generic_rgb64: unsupported 64bit blend attempted, falling back to 32-bit");
4091
0
        return blend_color_generic(count, spans, userData);
4092
0
    }
4093
4094
0
    const QRgba64 color = data->solidColor.rgba64();
4095
0
    const bool solidFill = op.mode == QPainter::CompositionMode_Source;
4096
0
    const QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
4097
4098
0
    auto function = [=, &op] (int cStart, int cEnd)
4099
0
    {
4100
0
        alignas(16) Q_DECL_UNINITIALIZED QRgba64 buffer[BufferSize];
4101
0
        for (int c = cStart; c < cEnd; ++c) {
4102
0
            int x = spans[c].x;
4103
0
            int length = spans[c].len;
4104
0
            if (solidFill && bpp >= QPixelLayout::BPP8 && spans[c].coverage == 255 && length && op.destStore64) {
4105
                // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels
4106
0
                op.destStore64(data->rasterBuffer, x, spans[c].y, &color, 1);
4107
0
                spanfill_from_first(data->rasterBuffer, bpp, x, spans[c].y, length);
4108
0
                length = 0;
4109
0
            }
4110
4111
0
            while (length) {
4112
0
                int l = qMin(BufferSize, length);
4113
0
                QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans[c].y, l);
4114
0
                op.funcSolid64(dest, l, color, spans[c].coverage);
4115
0
                if (op.destStore64)
4116
0
                    op.destStore64(data->rasterBuffer, x, spans[c].y, dest, l);
4117
0
                length -= l;
4118
0
                x += l;
4119
0
            }
4120
0
        }
4121
0
    };
4122
0
    QT_THREAD_PARALLEL_FILLS(function, MinParallelSolidPixels);
4123
#else
4124
    blend_color_generic(count, spans, userData);
4125
#endif
4126
0
}
4127
4128
static void blend_color_generic_fp(int count, const QT_FT_Span *spans, void *userData)
4129
0
{
4130
0
#if QT_CONFIG(raster_fp)
4131
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4132
0
    const Operator op = getOperator(data, nullptr, 0);
4133
0
    if (!op.funcSolidFP || !op.destFetchFP) {
4134
0
        qCDebug(lcQtGuiDrawHelper, "blend_color_generic_fp: unsupported 4xF16 blend attempted, falling back to 32-bit");
4135
0
        return blend_color_generic(count, spans, userData);
4136
0
    }
4137
4138
0
    float r, g, b, a;
4139
0
    data->solidColor.getRgbF(&r, &g, &b, &a);
4140
0
    const QRgbaFloat32 color{r, g, b, a};
4141
0
    const bool solidFill = op.mode == QPainter::CompositionMode_Source;
4142
0
    QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
4143
4144
0
    auto function = [=, &op] (int cStart, int cEnd)
4145
0
    {
4146
0
        alignas(16) Q_DECL_UNINITIALIZED QRgbaFloat32 buffer[BufferSize];
4147
0
        for (int c = cStart; c < cEnd; ++c) {
4148
0
            int x = spans[c].x;
4149
0
            int length = spans[c].len;
4150
0
            if (solidFill && bpp >= QPixelLayout::BPP8 && spans[c].coverage == 255 && length && op.destStoreFP) {
4151
                // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels
4152
0
                op.destStoreFP(data->rasterBuffer, x, spans[c].y, &color, 1);
4153
0
                spanfill_from_first(data->rasterBuffer, bpp, x, spans[c].y, length);
4154
0
                length = 0;
4155
0
            }
4156
4157
0
            while (length) {
4158
0
                int l = qMin(BufferSize, length);
4159
0
                QRgbaFloat32 *dest = op.destFetchFP(buffer, data->rasterBuffer, x, spans[c].y, l);
4160
0
                op.funcSolidFP(dest, l, color, spans[c].coverage);
4161
0
                if (op.destStoreFP)
4162
0
                    op.destStoreFP(data->rasterBuffer, x, spans[c].y, dest, l);
4163
0
                length -= l;
4164
0
                x += l;
4165
0
            }
4166
0
        }
4167
0
    };
4168
0
    QT_THREAD_PARALLEL_FILLS(function, MinParallelSolidPixels);
4169
#else
4170
    blend_color_generic_rgb64(count, spans, userData);
4171
#endif
4172
0
}
4173
4174
template <typename T>
4175
void handleSpans(int count, const QT_FT_Span *spans, const QSpanData *data, const Operator &op)
4176
0
{
4177
0
    const int const_alpha = (data->type == QSpanData::Texture) ? data->texture.const_alpha : 256;
4178
0
    const bool solidSource = op.mode == QPainter::CompositionMode_Source && const_alpha == 256;
4179
4180
0
    auto function = [=, &op] (int cStart, int cEnd)
4181
0
    {
4182
0
        T Q_DECL_UNINITIALIZED handler(data, op);
4183
0
        int coverage = 0;
4184
0
        for (int c = cStart; c < cEnd;) {
4185
0
            if (!spans[c].len) {
4186
0
                ++c;
4187
0
                continue;
4188
0
            }
4189
0
            int x = spans[c].x;
4190
0
            const int y = spans[c].y;
4191
0
            int right = x + spans[c].len;
4192
0
            const bool fetchDest = !solidSource || spans[c].coverage < 255;
4193
4194
            // compute length of adjacent spans
4195
0
            for (int i = c + 1; i < cEnd && spans[i].y == y && spans[i].x == right && fetchDest == (!solidSource || spans[i].coverage < 255); ++i)
4196
0
                right += spans[i].len;
4197
0
            int length = right - x;
4198
4199
0
            while (length) {
4200
0
                int l = qMin(BufferSize, length);
4201
0
                length -= l;
4202
4203
0
                int process_length = l;
4204
0
                int process_x = x;
4205
4206
0
                const auto *src = handler.fetch(process_x, y, process_length, fetchDest);
4207
0
                int offset = 0;
4208
0
                while (l > 0) {
4209
0
                    if (x == spans[c].x) // new span?
4210
0
                        coverage = (spans[c].coverage * const_alpha) >> 8;
4211
4212
0
                    int right = spans[c].x + spans[c].len;
4213
0
                    int len = qMin(l, right - x);
4214
4215
0
                    handler.process(x, y, len, coverage, src, offset);
4216
4217
0
                    l -= len;
4218
0
                    x += len;
4219
0
                    offset += len;
4220
4221
0
                    if (x == right) // done with current span?
4222
0
                        ++c;
4223
0
                }
4224
0
                handler.store(process_x, y, process_length);
4225
0
            }
4226
0
        }
4227
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
4228
0
    QT_THREAD_PARALLEL_FILLS(function, MinParallelBlendPixels);
4229
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&)
4230
4231
struct QBlendBase
4232
{
4233
    const QSpanData *data;
4234
    const Operator &op;
4235
};
4236
4237
class BlendSrcGeneric : public QBlendBase
4238
{
4239
public:
4240
    uint *dest = nullptr;
4241
    alignas(16) uint buffer[BufferSize];
4242
    alignas(16) uint src_buffer[BufferSize];
4243
    BlendSrcGeneric(const QSpanData *d, const Operator &o)
4244
0
        : QBlendBase{d, o}
4245
0
    {
4246
0
    }
4247
4248
    const uint *fetch(int x, int y, int len, bool fetchDest)
4249
0
    {
4250
0
        if (fetchDest || op.destFetch == destFetchARGB32P)
4251
0
            dest = op.destFetch(buffer, data->rasterBuffer, x, y, len);
4252
0
        else
4253
0
            dest = buffer;
4254
0
        return op.srcFetch(src_buffer, &op, data, y, x, len);
4255
0
    }
4256
4257
    void process(int, int, int len, int coverage, const uint *src, int offset)
4258
0
    {
4259
0
        op.func(dest + offset, src + offset, len, coverage);
4260
0
    }
4261
4262
    void store(int x, int y, int len)
4263
0
    {
4264
0
        if (op.destStore)
4265
0
            op.destStore(data->rasterBuffer, x, y, dest, len);
4266
0
    }
4267
};
4268
4269
#if QT_CONFIG(raster_64bit)
4270
class BlendSrcGenericRGB64 : public QBlendBase
4271
{
4272
public:
4273
    QRgba64 *dest = nullptr;
4274
    alignas(16) QRgba64 buffer[BufferSize];
4275
    alignas(16) QRgba64 src_buffer[BufferSize];
4276
    BlendSrcGenericRGB64(const QSpanData *d, const Operator &o)
4277
0
        : QBlendBase{d, o}
4278
0
    {
4279
0
    }
4280
4281
    bool isSupported() const
4282
0
    {
4283
0
        return op.func64 && op.destFetch64;
4284
0
    }
4285
4286
    const QRgba64 *fetch(int x, int y, int len, bool fetchDest)
4287
0
    {
4288
0
        if (fetchDest || op.destFetch64 == destFetchRGB64)
4289
0
            dest = op.destFetch64(buffer, data->rasterBuffer, x, y, len);
4290
0
        else
4291
0
            dest = buffer;
4292
0
        return op.srcFetch64(src_buffer, &op, data, y, x, len);
4293
0
    }
4294
4295
    void process(int, int, int len, int coverage, const QRgba64 *src, int offset)
4296
0
    {
4297
0
        op.func64(dest + offset, src + offset, len, coverage);
4298
0
    }
4299
4300
    void store(int x, int y, int len)
4301
0
    {
4302
0
        if (op.destStore64)
4303
0
            op.destStore64(data->rasterBuffer, x, y, dest, len);
4304
0
    }
4305
};
4306
#endif
4307
4308
#if QT_CONFIG(raster_fp)
4309
class BlendSrcGenericRGBFP : public QBlendBase
4310
{
4311
public:
4312
    QRgbaFloat32 *dest = nullptr;
4313
    alignas(16) QRgbaFloat32 buffer[BufferSize];
4314
    alignas(16) QRgbaFloat32 src_buffer[BufferSize];
4315
    BlendSrcGenericRGBFP(const QSpanData *d, const Operator &o)
4316
0
        : QBlendBase{d, o}
4317
0
    {
4318
0
    }
4319
4320
    bool isSupported() const
4321
0
    {
4322
0
        return op.funcFP && op.destFetchFP && op.srcFetchFP;
4323
0
    }
4324
4325
    const QRgbaFloat32 *fetch(int x, int y, int len, bool fetchDest)
4326
0
    {
4327
0
        if (fetchDest || op.destFetchFP == destFetchRGBFP)
4328
0
            dest = op.destFetchFP(buffer, data->rasterBuffer, x, y, len);
4329
0
        else
4330
0
            dest = buffer;
4331
0
        return op.srcFetchFP(src_buffer, &op, data, y, x, len);
4332
0
    }
4333
4334
    void process(int, int, int len, int coverage, const QRgbaFloat32 *src, int offset)
4335
0
    {
4336
0
        op.funcFP(dest + offset, src + offset, len, coverage);
4337
0
    }
4338
4339
    void store(int x, int y, int len)
4340
0
    {
4341
0
        if (op.destStoreFP)
4342
0
            op.destStoreFP(data->rasterBuffer, x, y, dest, len);
4343
0
    }
4344
};
4345
#endif
4346
4347
static void blend_src_generic(int count, const QT_FT_Span *spans, void *userData)
4348
0
{
4349
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4350
0
    const Operator op = getOperator(data, nullptr, 0);
4351
0
    handleSpans<BlendSrcGeneric>(count, spans, data, op);
4352
0
}
4353
4354
#if QT_CONFIG(raster_64bit)
4355
static void blend_src_generic_rgb64(int count, const QT_FT_Span *spans, void *userData)
4356
0
{
4357
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4358
0
    const Operator op = getOperator(data, nullptr, 0);
4359
0
    if (op.func64 && op.destFetch64) {
4360
0
        handleSpans<BlendSrcGenericRGB64>(count, spans, data, op);
4361
0
    } else {
4362
0
        qCDebug(lcQtGuiDrawHelper, "blend_src_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
4363
0
        handleSpans<BlendSrcGeneric>(count, spans, data, op);
4364
0
    }
4365
0
}
4366
#endif
4367
4368
#if QT_CONFIG(raster_fp)
4369
static void blend_src_generic_fp(int count, const QT_FT_Span *spans, void *userData)
4370
0
{
4371
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4372
0
    const Operator op = getOperator(data, spans, count);
4373
0
    if (op.funcFP && op.destFetchFP && op.srcFetchFP) {
4374
0
        handleSpans<BlendSrcGenericRGBFP>(count, spans, data, op);
4375
0
    } else {
4376
0
        qCDebug(lcQtGuiDrawHelper, "blend_src_generic_fp: unsupported 4xFP blend attempted, falling back to 32-bit");
4377
0
        handleSpans<BlendSrcGeneric>(count, spans, data, op);
4378
0
    }
4379
0
}
4380
#endif
4381
4382
static void blend_untransformed_generic(int count, const QT_FT_Span *spans, void *userData)
4383
133k
{
4384
133k
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4385
4386
133k
    const Operator op = getOperator(data, spans, count);
4387
4388
133k
    const int image_width = data->texture.width;
4389
133k
    const int image_height = data->texture.height;
4390
133k
    const int const_alpha = data->texture.const_alpha;
4391
133k
    const int xoff = -qRound(-data->dx);
4392
133k
    const int yoff = -qRound(-data->dy);
4393
133k
    const bool solidSource = op.mode == QPainter::CompositionMode_Source && const_alpha == 256 && op.destFetch != destFetchARGB32P;
4394
4395
133k
    auto function = [=, &op] (int cStart, int cEnd)
4396
133k
    {
4397
133k
        alignas(16) Q_DECL_UNINITIALIZED uint buffer[BufferSize];
4398
133k
        alignas(16) Q_DECL_UNINITIALIZED uint src_buffer[BufferSize];
4399
3.75M
        for (int c = cStart; c < cEnd; ++c) {
4400
3.62M
            if (!spans[c].len)
4401
0
                continue;
4402
3.62M
            int x = spans[c].x;
4403
3.62M
            int length = spans[c].len;
4404
3.62M
            int sx = xoff + x;
4405
3.62M
            int sy = yoff + spans[c].y;
4406
3.62M
            const bool fetchDest = !solidSource || spans[c].coverage < 255;
4407
3.62M
            if (sy >= 0 && sy < image_height && sx < image_width) {
4408
3.62M
                if (sx < 0) {
4409
0
                    x -= sx;
4410
0
                    length += sx;
4411
0
                    sx = 0;
4412
0
                }
4413
3.62M
                if (sx + length > image_width)
4414
0
                    length = image_width - sx;
4415
3.62M
                if (length > 0) {
4416
3.62M
                    const int coverage = (spans[c].coverage * const_alpha) >> 8;
4417
7.24M
                    while (length) {
4418
3.62M
                        int l = qMin(BufferSize, length);
4419
3.62M
                        const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l);
4420
3.62M
                        uint *dest = fetchDest ? op.destFetch(buffer, data->rasterBuffer, x, spans[c].y, l) : buffer;
4421
3.62M
                        op.func(dest, src, l, coverage);
4422
3.62M
                        if (op.destStore)
4423
3.62M
                            op.destStore(data->rasterBuffer, x, spans[c].y, dest, l);
4424
3.62M
                        x += l;
4425
3.62M
                        sx += l;
4426
3.62M
                        length -= l;
4427
3.62M
                    }
4428
3.62M
                }
4429
3.62M
            }
4430
3.62M
        }
4431
133k
    };
4432
133k
    QT_THREAD_PARALLEL_FILLS(function, MinParallelBlendPixels);
4433
133k
}
4434
4435
#if QT_CONFIG(raster_64bit)
4436
static void blend_untransformed_generic_rgb64(int count, const QT_FT_Span *spans, void *userData)
4437
170k
{
4438
170k
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4439
4440
170k
    const Operator op = getOperator(data, spans, count);
4441
170k
    if (!op.func64) {
4442
0
        qCDebug(lcQtGuiDrawHelper, "blend_untransformed_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
4443
0
        return blend_untransformed_generic(count, spans, userData);
4444
0
    }
4445
4446
170k
    const int image_width = data->texture.width;
4447
170k
    const int image_height = data->texture.height;
4448
170k
    const int const_alpha = data->texture.const_alpha;
4449
170k
    const int xoff = -qRound(-data->dx);
4450
170k
    const int yoff = -qRound(-data->dy);
4451
170k
    const bool solidSource = op.mode == QPainter::CompositionMode_Source && const_alpha == 256 && op.destFetch64 != destFetchRGB64;
4452
4453
170k
    auto function = [=, &op] (int cStart, int cEnd)
4454
170k
    {
4455
170k
        alignas(16) Q_DECL_UNINITIALIZED QRgba64 buffer[BufferSize];
4456
170k
        alignas(16) Q_DECL_UNINITIALIZED QRgba64 src_buffer[BufferSize];
4457
6.19M
        for (int c = cStart; c < cEnd; ++c) {
4458
6.02M
            if (!spans[c].len)
4459
0
                continue;
4460
6.02M
            int x = spans[c].x;
4461
6.02M
            int length = spans[c].len;
4462
6.02M
            int sx = xoff + x;
4463
6.02M
            int sy = yoff + spans[c].y;
4464
6.02M
            const bool fetchDest = !solidSource || spans[c].coverage < 255;
4465
6.02M
            if (sy >= 0 && sy < image_height && sx < image_width) {
4466
6.02M
                if (sx < 0) {
4467
0
                    x -= sx;
4468
0
                    length += sx;
4469
0
                    sx = 0;
4470
0
                }
4471
6.02M
                if (sx + length > image_width)
4472
0
                    length = image_width - sx;
4473
6.02M
                if (length > 0) {
4474
6.02M
                    const int coverage = (spans[c].coverage * const_alpha) >> 8;
4475
12.0M
                    while (length) {
4476
6.02M
                        int l = qMin(BufferSize, length);
4477
6.02M
                        const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l);
4478
6.02M
                        QRgba64 *dest = fetchDest ? op.destFetch64(buffer, data->rasterBuffer, x, spans[c].y, l) : buffer;
4479
6.02M
                        op.func64(dest, src, l, coverage);
4480
6.02M
                        if (op.destStore64)
4481
6.02M
                            op.destStore64(data->rasterBuffer, x, spans[c].y, dest, l);
4482
6.02M
                        x += l;
4483
6.02M
                        sx += l;
4484
6.02M
                        length -= l;
4485
6.02M
                    }
4486
6.02M
                }
4487
6.02M
            }
4488
6.02M
        }
4489
170k
    };
4490
170k
    QT_THREAD_PARALLEL_FILLS(function, MinParallelBlendPixels);
4491
170k
}
4492
#endif
4493
4494
#if QT_CONFIG(raster_fp)
4495
static void blend_untransformed_generic_fp(int count, const QT_FT_Span *spans, void *userData)
4496
0
{
4497
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4498
4499
0
    const Operator op = getOperator(data, spans, count);
4500
0
    if (!op.funcFP) {
4501
0
        qCDebug(lcQtGuiDrawHelper, "blend_untransformed_generic_rgbaf16: unsupported 4xFP16 blend attempted, falling back to 32-bit");
4502
0
        return blend_untransformed_generic(count, spans, userData);
4503
0
    }
4504
4505
0
    const int image_width = data->texture.width;
4506
0
    const int image_height = data->texture.height;
4507
0
    const int xoff = -qRound(-data->dx);
4508
0
    const int yoff = -qRound(-data->dy);
4509
0
    const bool solidSource = op.mode == QPainter::CompositionMode_Source && data->texture.const_alpha == 256 && op.destFetchFP != destFetchRGBFP;
4510
4511
0
    auto function = [=, &op] (int cStart, int cEnd)
4512
0
    {
4513
0
        alignas(16) Q_DECL_UNINITIALIZED QRgbaFloat32 buffer[BufferSize];
4514
0
        alignas(16) Q_DECL_UNINITIALIZED QRgbaFloat32 src_buffer[BufferSize];
4515
0
        for (int c = cStart; c < cEnd; ++c) {
4516
0
            if (!spans[c].len)
4517
0
                continue;
4518
0
            int x = spans[c].x;
4519
0
            int length = spans[c].len;
4520
0
            int sx = xoff + x;
4521
0
            int sy = yoff + spans[c].y;
4522
0
            const bool fetchDest = !solidSource || spans[c].coverage < 255;
4523
0
            if (sy >= 0 && sy < image_height && sx < image_width) {
4524
0
                if (sx < 0) {
4525
0
                    x -= sx;
4526
0
                    length += sx;
4527
0
                    sx = 0;
4528
0
                }
4529
0
                if (sx + length > image_width)
4530
0
                    length = image_width - sx;
4531
0
                if (length > 0) {
4532
0
                    const int coverage = (spans[c].coverage * data->texture.const_alpha) >> 8;
4533
0
                    while (length) {
4534
0
                        int l = qMin(BufferSize, length);
4535
0
                        const QRgbaFloat32 *src = op.srcFetchFP(src_buffer, &op, data, sy, sx, l);
4536
0
                        QRgbaFloat32 *dest = fetchDest ? op.destFetchFP(buffer, data->rasterBuffer, x, spans[c].y, l) : buffer;
4537
0
                        op.funcFP(dest, src, l, coverage);
4538
0
                        if (op.destStoreFP)
4539
0
                            op.destStoreFP(data->rasterBuffer, x, spans[c].y, dest, l);
4540
0
                        x += l;
4541
0
                        sx += l;
4542
0
                        length -= l;
4543
0
                    }
4544
0
                }
4545
0
            }
4546
0
        }
4547
0
    };
4548
0
    QT_THREAD_PARALLEL_FILLS(function, MinParallelBlendPixels);
4549
0
}
4550
#endif
4551
4552
static void blend_untransformed_argb(int count, const QT_FT_Span *spans, void *userData)
4553
0
{
4554
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4555
0
    if (data->texture.format != QImage::Format_ARGB32_Premultiplied
4556
0
        && data->texture.format != QImage::Format_RGB32) {
4557
0
        blend_untransformed_generic(count, spans, userData);
4558
0
        return;
4559
0
    }
4560
4561
0
    const Operator op = getOperator(data, spans, count);
4562
4563
0
    const int image_width = data->texture.width;
4564
0
    const int image_height = data->texture.height;
4565
0
    const int const_alpha = data->texture.const_alpha;
4566
0
    const int xoff = -qRound(-data->dx);
4567
0
    const int yoff = -qRound(-data->dy);
4568
4569
0
    auto function = [=, &op] (int cStart, int cEnd)
4570
0
    {
4571
0
        for (int c = cStart; c < cEnd; ++c) {
4572
0
            if (!spans[c].len)
4573
0
                continue;
4574
0
            int x = spans[c].x;
4575
0
            int length = spans[c].len;
4576
0
            int sx = xoff + x;
4577
0
            int sy = yoff + spans[c].y;
4578
0
            if (sy >= 0 && sy < image_height && sx < image_width) {
4579
0
                if (sx < 0) {
4580
0
                    x -= sx;
4581
0
                    length += sx;
4582
0
                    sx = 0;
4583
0
                }
4584
0
                if (sx + length > image_width)
4585
0
                    length = image_width - sx;
4586
0
                if (length > 0) {
4587
0
                    const int coverage = (spans[c].coverage * const_alpha) >> 8;
4588
0
                    const uint *src = (const uint *)data->texture.scanLine(sy) + sx;
4589
0
                    uint *dest = ((uint *)data->rasterBuffer->scanLine(spans[c].y)) + x;
4590
0
                    op.func(dest, src, length, coverage);
4591
0
                }
4592
0
            }
4593
0
        }
4594
0
    };
4595
0
    QT_THREAD_PARALLEL_FILLS(function, MinParallelBlendPixels);
4596
0
}
4597
4598
static inline quint16 interpolate_pixel_rgb16_255(quint16 x, quint8 a,
4599
                                                  quint16 y, quint8 b)
4600
0
{
4601
0
    quint16 t = ((((x & 0x07e0) * a) + ((y & 0x07e0) * b)) >> 5) & 0x07e0;
4602
0
    t |= ((((x & 0xf81f) * a) + ((y & 0xf81f) * b)) >> 5) & 0xf81f;
4603
4604
0
    return t;
4605
0
}
4606
4607
static inline quint32 interpolate_pixel_rgb16x2_255(quint32 x, quint8 a,
4608
                                                    quint32 y, quint8 b)
4609
0
{
4610
0
    uint t;
4611
0
    t = ((((x & 0xf81f07e0) >> 5) * a) + (((y & 0xf81f07e0) >> 5) * b)) & 0xf81f07e0;
4612
0
    t |= ((((x & 0x07e0f81f) * a) + ((y & 0x07e0f81f) * b)) >> 5) & 0x07e0f81f;
4613
0
    return t;
4614
0
}
4615
4616
static inline void blend_sourceOver_rgb16_rgb16(quint16 *Q_DECL_RESTRICT dest,
4617
                                                const quint16 *Q_DECL_RESTRICT src,
4618
                                                int length,
4619
                                                const quint8 alpha,
4620
                                                const quint8 ialpha)
4621
0
{
4622
0
    const int dstAlign = ((quintptr)dest) & 0x3;
4623
0
    if (dstAlign) {
4624
0
        *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
4625
0
        ++dest;
4626
0
        ++src;
4627
0
        --length;
4628
0
    }
4629
0
    const int srcAlign = ((quintptr)src) & 0x3;
4630
0
    int length32 = length >> 1;
4631
0
    if (length32 && srcAlign == 0) {
4632
0
        while (length32--) {
4633
0
            const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4634
0
            quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4635
0
            *dest32 = interpolate_pixel_rgb16x2_255(*src32, alpha,
4636
0
                                                    *dest32, ialpha);
4637
0
            dest += 2;
4638
0
            src += 2;
4639
0
        }
4640
0
        length &= 0x1;
4641
0
    }
4642
0
    while (length--) {
4643
0
        *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
4644
0
        ++dest;
4645
0
        ++src;
4646
0
    }
4647
0
}
4648
4649
static void blend_untransformed_rgb565(int count, const QT_FT_Span *spans, void *userData)
4650
0
{
4651
0
    QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4652
0
    QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4653
4654
0
    if (data->texture.format != QImage::Format_RGB16
4655
0
            || (mode != QPainter::CompositionMode_SourceOver
4656
0
                && mode != QPainter::CompositionMode_Source))
4657
0
    {
4658
0
        blend_untransformed_generic(count, spans, userData);
4659
0
        return;
4660
0
    }
4661
4662
0
    const int image_width = data->texture.width;
4663
0
    const int image_height = data->texture.height;
4664
0
    int xoff = -qRound(-data->dx);
4665
0
    int yoff = -qRound(-data->dy);
4666
4667
0
    auto function = [=](int cStart, int cEnd)
4668
0
    {
4669
0
        for (int c = cStart; c < cEnd; ++c) {
4670
0
            if (!spans[c].len)
4671
0
                continue;
4672
0
            const quint8 coverage = (data->texture.const_alpha * spans[c].coverage) >> 8;
4673
0
            if (coverage == 0)
4674
0
                continue;
4675
4676
0
            int x = spans[c].x;
4677
0
            int length = spans[c].len;
4678
0
            int sx = xoff + x;
4679
0
            int sy = yoff + spans[c].y;
4680
0
            if (sy >= 0 && sy < image_height && sx < image_width) {
4681
0
                if (sx < 0) {
4682
0
                    x -= sx;
4683
0
                    length += sx;
4684
0
                    sx = 0;
4685
0
                }
4686
0
                if (sx + length > image_width)
4687
0
                    length = image_width - sx;
4688
0
                if (length > 0) {
4689
0
                    quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans[c].y) + x;
4690
0
                    const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx;
4691
0
                    if (coverage == 255) {
4692
0
                        memcpy(dest, src, length * sizeof(quint16));
4693
0
                    } else {
4694
0
                        const quint8 alpha = (coverage + 1) >> 3;
4695
0
                        const quint8 ialpha = 0x20 - alpha;
4696
0
                        if (alpha > 0)
4697
0
                            blend_sourceOver_rgb16_rgb16(dest, src, length, alpha, ialpha);
4698
0
                    }
4699
0
                }
4700
0
            }
4701
0
        }
4702
0
    };
4703
0
    QT_THREAD_PARALLEL_FILLS(function, MinParallelBlendPixels);
4704
0
}
4705
4706
static void blend_tiled_generic(int count, const QT_FT_Span *spans, void *userData)
4707
0
{
4708
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4709
4710
0
    const Operator op = getOperator(data, spans, count);
4711
4712
0
    const int image_width = data->texture.width;
4713
0
    const int image_height = data->texture.height;
4714
0
    const int const_alpha = data->texture.const_alpha;
4715
0
    int xoff = -qRound(-data->dx) % image_width;
4716
0
    int yoff = -qRound(-data->dy) % image_height;
4717
4718
0
    if (xoff < 0)
4719
0
        xoff += image_width;
4720
0
    if (yoff < 0)
4721
0
        yoff += image_height;
4722
4723
0
    auto function = [=, &op](int cStart, int cEnd)
4724
0
    {
4725
0
        alignas(16) Q_DECL_UNINITIALIZED uint buffer[BufferSize];
4726
0
        alignas(16) Q_DECL_UNINITIALIZED uint src_buffer[BufferSize];
4727
0
        for (int c = cStart; c < cEnd; ++c) {
4728
0
            int x = spans[c].x;
4729
0
            int length = spans[c].len;
4730
0
            int sx = (xoff + spans[c].x) % image_width;
4731
0
            int sy = (spans[c].y + yoff) % image_height;
4732
0
            if (sx < 0)
4733
0
                sx += image_width;
4734
0
            if (sy < 0)
4735
0
                sy += image_height;
4736
4737
0
            const int coverage = (spans[c].coverage * const_alpha) >> 8;
4738
0
            while (length) {
4739
0
                int l = qMin(image_width - sx, length);
4740
0
                if (BufferSize < l)
4741
0
                    l = BufferSize;
4742
0
                const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l);
4743
0
                uint *dest = op.destFetch(buffer, data->rasterBuffer, x, spans[c].y, l);
4744
0
                op.func(dest, src, l, coverage);
4745
0
                if (op.destStore)
4746
0
                    op.destStore(data->rasterBuffer, x, spans[c].y, dest, l);
4747
0
                x += l;
4748
0
                sx += l;
4749
0
                length -= l;
4750
0
                if (sx >= image_width)
4751
0
                    sx = 0;
4752
0
            }
4753
0
        }
4754
0
    };
4755
0
    QT_THREAD_PARALLEL_FILLS(function, MinParallelBlendPixels);
4756
0
}
4757
4758
#if QT_CONFIG(raster_64bit)
4759
static void blend_tiled_generic_rgb64(int count, const QT_FT_Span *spans, void *userData)
4760
0
{
4761
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4762
4763
0
    const Operator op = getOperator(data, spans, count);
4764
0
    if (!op.func64) {
4765
0
        qCDebug(lcQtGuiDrawHelper, "blend_tiled_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
4766
0
        return blend_tiled_generic(count, spans, userData);
4767
0
    }
4768
4769
0
    const int image_width = data->texture.width;
4770
0
    const int image_height = data->texture.height;
4771
0
    int xoff = -qRound(-data->dx) % image_width;
4772
0
    int yoff = -qRound(-data->dy) % image_height;
4773
4774
0
    if (xoff < 0)
4775
0
        xoff += image_width;
4776
0
    if (yoff < 0)
4777
0
        yoff += image_height;
4778
4779
0
    bool isBpp32 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP32;
4780
0
    bool isBpp64 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP64;
4781
0
    if (op.destFetch64 == destFetch64Undefined && image_width <= BufferSize && (isBpp32 || isBpp64)) {
4782
0
        alignas(16) Q_DECL_UNINITIALIZED QRgba64 src_buffer[BufferSize];
4783
        // If destination isn't blended into the result, we can do the tiling directly on destination pixels.
4784
0
        while (count--) {
4785
0
            int x = spans->x;
4786
0
            int y = spans->y;
4787
0
            int length = spans->len;
4788
0
            int sx = (xoff + spans->x) % image_width;
4789
0
            int sy = (spans->y + yoff) % image_height;
4790
0
            if (sx < 0)
4791
0
                sx += image_width;
4792
0
            if (sy < 0)
4793
0
                sy += image_height;
4794
4795
0
            int sl = qMin(image_width, length);
4796
0
            if (sx > 0 && sl > 0) {
4797
0
                int l = qMin(image_width - sx, sl);
4798
0
                const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l);
4799
0
                op.destStore64(data->rasterBuffer, x, y, src, l);
4800
0
                x += l;
4801
0
                sx += l;
4802
0
                sl -= l;
4803
0
                if (sx >= image_width)
4804
0
                    sx = 0;
4805
0
            }
4806
0
            if (sl > 0) {
4807
0
                Q_ASSERT(sx == 0);
4808
0
                const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, sl);
4809
0
                op.destStore64(data->rasterBuffer, x, y, src, sl);
4810
0
                x += sl;
4811
0
                sx += sl;
4812
0
                sl -= sl;
4813
0
                if (sx >= image_width)
4814
0
                    sx = 0;
4815
0
            }
4816
0
            if (isBpp32) {
4817
0
                uint *dest = reinterpret_cast<uint *>(data->rasterBuffer->scanLine(y)) + x - image_width;
4818
0
                for (int i = image_width; i < length; ++i)
4819
0
                    dest[i] = dest[i - image_width];
4820
0
            } else {
4821
0
                quint64 *dest = reinterpret_cast<quint64 *>(data->rasterBuffer->scanLine(y)) + x - image_width;
4822
0
                for (int i = image_width; i < length; ++i)
4823
0
                    dest[i] = dest[i - image_width];
4824
0
            }
4825
0
            ++spans;
4826
0
        }
4827
0
        return;
4828
0
    }
4829
4830
0
    auto function = [=, &op](int cStart, int cEnd)
4831
0
    {
4832
0
        alignas(16) Q_DECL_UNINITIALIZED QRgba64 buffer[BufferSize];
4833
0
        alignas(16) Q_DECL_UNINITIALIZED QRgba64 src_buffer[BufferSize];
4834
0
        for (int c = cStart; c < cEnd; ++c) {
4835
0
            int x = spans[c].x;
4836
0
            int length = spans[c].len;
4837
0
            int sx = (xoff + spans[c].x) % image_width;
4838
0
            int sy = (spans[c].y + yoff) % image_height;
4839
0
            if (sx < 0)
4840
0
                sx += image_width;
4841
0
            if (sy < 0)
4842
0
                sy += image_height;
4843
4844
0
            const int coverage = (spans[c].coverage * data->texture.const_alpha) >> 8;
4845
0
            while (length) {
4846
0
                int l = qMin(image_width - sx, length);
4847
0
                if (BufferSize < l)
4848
0
                    l = BufferSize;
4849
0
                const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l);
4850
0
                QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans[c].y, l);
4851
0
                op.func64(dest, src, l, coverage);
4852
0
                if (op.destStore64)
4853
0
                    op.destStore64(data->rasterBuffer, x, spans[c].y, dest, l);
4854
0
                x += l;
4855
0
                sx += l;
4856
0
                length -= l;
4857
0
                if (sx >= image_width)
4858
0
                    sx = 0;
4859
0
            }
4860
0
        }
4861
0
    };
4862
0
    QT_THREAD_PARALLEL_FILLS(function, MinParallelBlendPixels);
4863
0
}
4864
#endif
4865
4866
#if QT_CONFIG(raster_fp)
4867
static void blend_tiled_generic_fp(int count, const QT_FT_Span *spans, void *userData)
4868
0
{
4869
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4870
4871
0
    const Operator op = getOperator(data, spans, count);
4872
0
    if (!op.funcFP) {
4873
0
        qCDebug(lcQtGuiDrawHelper, "blend_tiled_generic_fp: unsupported 4xFP blend attempted, falling back to 32-bit");
4874
0
        return blend_tiled_generic(count, spans, userData);
4875
0
    }
4876
4877
0
    const int image_width = data->texture.width;
4878
0
    const int image_height = data->texture.height;
4879
0
    int xoff = -qRound(-data->dx) % image_width;
4880
0
    int yoff = -qRound(-data->dy) % image_height;
4881
4882
0
    if (xoff < 0)
4883
0
        xoff += image_width;
4884
0
    if (yoff < 0)
4885
0
        yoff += image_height;
4886
4887
    // Consider tiling optimizing like the other versions.
4888
4889
0
    auto function = [=, &op](int cStart, int cEnd)
4890
0
    {
4891
0
        alignas(16) Q_DECL_UNINITIALIZED QRgbaFloat32 buffer[BufferSize];
4892
0
        alignas(16) Q_DECL_UNINITIALIZED QRgbaFloat32 src_buffer[BufferSize];
4893
0
        for (int c = cStart; c < cEnd; ++c) {
4894
0
            int x = spans[c].x;
4895
0
            int length = spans[c].len;
4896
0
            int sx = (xoff + spans[c].x) % image_width;
4897
0
            int sy = (spans[c].y + yoff) % image_height;
4898
0
            if (sx < 0)
4899
0
                sx += image_width;
4900
0
            if (sy < 0)
4901
0
                sy += image_height;
4902
4903
0
            const int coverage = (spans[c].coverage * data->texture.const_alpha) >> 8;
4904
0
            while (length) {
4905
0
                int l = qMin(image_width - sx, length);
4906
0
                if (BufferSize < l)
4907
0
                    l = BufferSize;
4908
0
                const QRgbaFloat32 *src = op.srcFetchFP(src_buffer, &op, data, sy, sx, l);
4909
0
                QRgbaFloat32 *dest = op.destFetchFP(buffer, data->rasterBuffer, x, spans[c].y, l);
4910
0
                op.funcFP(dest, src, l, coverage);
4911
0
                if (op.destStoreFP)
4912
0
                    op.destStoreFP(data->rasterBuffer, x, spans[c].y, dest, l);
4913
0
                x += l;
4914
0
                sx += l;
4915
0
                length -= l;
4916
0
                if (sx >= image_width)
4917
0
                    sx = 0;
4918
0
            }
4919
0
        }
4920
0
    };
4921
0
    QT_THREAD_PARALLEL_FILLS(function, MinParallelBlendPixels);
4922
0
}
4923
#endif
4924
4925
static void blend_tiled_argb(int count, const QT_FT_Span *spans, void *userData)
4926
0
{
4927
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4928
0
    if (data->texture.format != QImage::Format_ARGB32_Premultiplied
4929
0
        && data->texture.format != QImage::Format_RGB32) {
4930
0
        blend_tiled_generic(count, spans, userData);
4931
0
        return;
4932
0
    }
4933
4934
0
    const Operator op = getOperator(data, spans, count);
4935
4936
0
    const int image_width = data->texture.width;
4937
0
    const int image_height = data->texture.height;
4938
0
    int xoff = -qRound(-data->dx) % image_width;
4939
0
    int yoff = -qRound(-data->dy) % image_height;
4940
4941
0
    if (xoff < 0)
4942
0
        xoff += image_width;
4943
0
    if (yoff < 0)
4944
0
        yoff += image_height;
4945
0
    const auto func = op.func;
4946
0
    const int const_alpha = data->texture.const_alpha;
4947
4948
0
    auto function = [=] (int cStart, int cEnd) {
4949
0
        for (int c = cStart; c < cEnd; ++c) {
4950
0
            int x = spans[c].x;
4951
0
            int length = spans[c].len;
4952
0
            int sx = (xoff + spans[c].x) % image_width;
4953
0
            int sy = (spans[c].y + yoff) % image_height;
4954
0
            if (sx < 0)
4955
0
                sx += image_width;
4956
0
            if (sy < 0)
4957
0
                sy += image_height;
4958
4959
0
            const int coverage = (spans[c].coverage * const_alpha) >> 8;
4960
0
            while (length) {
4961
0
                int l = qMin(image_width - sx, length);
4962
0
                if (BufferSize < l)
4963
0
                    l = BufferSize;
4964
0
                const uint *src = (const uint *)data->texture.scanLine(sy) + sx;
4965
0
                uint *dest = ((uint *)data->rasterBuffer->scanLine(spans[c].y)) + x;
4966
0
                func(dest, src, l, coverage);
4967
0
                x += l;
4968
0
                sx += l;
4969
0
                length -= l;
4970
0
                if (sx >= image_width)
4971
0
                    sx = 0;
4972
0
            }
4973
0
        }
4974
0
    };
4975
0
    QT_THREAD_PARALLEL_FILLS(function, MinParallelBlendPixels);
4976
0
}
4977
4978
static void blend_tiled_rgb565(int count, const QT_FT_Span *spans, void *userData)
4979
0
{
4980
0
    QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4981
0
    QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4982
4983
0
    if (data->texture.format != QImage::Format_RGB16
4984
0
            || (mode != QPainter::CompositionMode_SourceOver
4985
0
                && mode != QPainter::CompositionMode_Source))
4986
0
    {
4987
0
        blend_tiled_generic(count, spans, userData);
4988
0
        return;
4989
0
    }
4990
4991
0
    const int image_width = data->texture.width;
4992
0
    const int image_height = data->texture.height;
4993
0
    int xoff = -qRound(-data->dx) % image_width;
4994
0
    int yoff = -qRound(-data->dy) % image_height;
4995
4996
0
    if (xoff < 0)
4997
0
        xoff += image_width;
4998
0
    if (yoff < 0)
4999
0
        yoff += image_height;
5000
5001
0
    const int const_alpha = data->texture.const_alpha;
5002
0
    auto function = [=] (int cStart, int cEnd) {
5003
0
        for (int c = cStart; c < cEnd; ++c) {
5004
0
            const quint8 coverage = (const_alpha * spans[c].coverage) >> 8;
5005
0
            if (coverage == 0)
5006
0
                continue;
5007
5008
0
            int x = spans[c].x;
5009
0
            int length = spans[c].len;
5010
0
            int sx = (xoff + spans[c].x) % image_width;
5011
0
            int sy = (spans[c].y + yoff) % image_height;
5012
0
            if (sx < 0)
5013
0
                sx += image_width;
5014
0
            if (sy < 0)
5015
0
                sy += image_height;
5016
5017
0
            if (coverage == 255) {
5018
                // Copy the first texture block
5019
0
                length = qMin(image_width,length);
5020
0
                int tx = x;
5021
0
                while (length) {
5022
0
                    int l = qMin(image_width - sx, length);
5023
0
                    if (BufferSize < l)
5024
0
                        l = BufferSize;
5025
0
                    quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans[c].y)) + tx;
5026
0
                    const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx;
5027
0
                    memcpy(dest, src, l * sizeof(quint16));
5028
0
                    length -= l;
5029
0
                    tx += l;
5030
0
                    sx += l;
5031
0
                    if (sx >= image_width)
5032
0
                        sx = 0;
5033
0
                }
5034
5035
                // Now use the rasterBuffer as the source of the texture,
5036
                // We can now progressively copy larger blocks
5037
                // - Less cpu time in code figuring out what to copy
5038
                // We are dealing with one block of data
5039
                // - More likely to fit in the cache
5040
                // - can use memcpy
5041
0
                int copy_image_width = qMin(image_width, int(spans[c].len));
5042
0
                length = spans[c].len - copy_image_width;
5043
0
                quint16 *src = ((quint16 *)data->rasterBuffer->scanLine(spans[c].y)) + x;
5044
0
                quint16 *dest = src + copy_image_width;
5045
0
                while (copy_image_width < length) {
5046
0
                    memcpy(dest, src, copy_image_width * sizeof(quint16));
5047
0
                    dest += copy_image_width;
5048
0
                    length -= copy_image_width;
5049
0
                    copy_image_width *= 2;
5050
0
                }
5051
0
                if (length > 0)
5052
0
                    memcpy(dest, src, length * sizeof(quint16));
5053
0
            } else {
5054
0
                const quint8 alpha = (coverage + 1) >> 3;
5055
0
                const quint8 ialpha = 0x20 - alpha;
5056
0
                if (alpha > 0) {
5057
0
                    while (length) {
5058
0
                        int l = qMin(image_width - sx, length);
5059
0
                        if (BufferSize < l)
5060
0
                            l = BufferSize;
5061
0
                        quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans[c].y)) + x;
5062
0
                        const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx;
5063
0
                        blend_sourceOver_rgb16_rgb16(dest, src, l, alpha, ialpha);
5064
0
                        x += l;
5065
0
                        sx += l;
5066
0
                        length -= l;
5067
0
                        if (sx >= image_width)
5068
0
                            sx = 0;
5069
0
                    }
5070
0
                }
5071
0
            }
5072
0
        }
5073
0
    };
5074
0
    QT_THREAD_PARALLEL_FILLS(function, MinParallelBlendPixels);
5075
0
}
5076
5077
/* Image formats here are target formats */
5078
static const ProcessSpans processTextureSpansARGB32PM[NBlendTypes] = {
5079
    blend_untransformed_argb,           // Untransformed
5080
    blend_tiled_argb,                   // Tiled
5081
    blend_src_generic,                  // Transformed
5082
    blend_src_generic,                  // TransformedTiled
5083
    blend_src_generic,                  // TransformedBilinear
5084
    blend_src_generic                   // TransformedBilinearTiled
5085
};
5086
5087
static const ProcessSpans processTextureSpansRGB16[NBlendTypes] = {
5088
    blend_untransformed_rgb565,         // Untransformed
5089
    blend_tiled_rgb565,                 // Tiled
5090
    blend_src_generic,                  // Transformed
5091
    blend_src_generic,                  // TransformedTiled
5092
    blend_src_generic,                  // TransformedBilinear
5093
    blend_src_generic                   // TransformedBilinearTiled
5094
};
5095
5096
static const ProcessSpans processTextureSpansGeneric[NBlendTypes] = {
5097
    blend_untransformed_generic,        // Untransformed
5098
    blend_tiled_generic,                // Tiled
5099
    blend_src_generic,                  // Transformed
5100
    blend_src_generic,                  // TransformedTiled
5101
    blend_src_generic,                  // TransformedBilinear
5102
    blend_src_generic                   // TransformedBilinearTiled
5103
};
5104
5105
#if QT_CONFIG(raster_64bit)
5106
static const ProcessSpans processTextureSpansGeneric64[NBlendTypes] = {
5107
    blend_untransformed_generic_rgb64,  // Untransformed
5108
    blend_tiled_generic_rgb64,          // Tiled
5109
    blend_src_generic_rgb64,            // Transformed
5110
    blend_src_generic_rgb64,            // TransformedTiled
5111
    blend_src_generic_rgb64,            // TransformedBilinear
5112
    blend_src_generic_rgb64             // TransformedBilinearTiled
5113
};
5114
#endif
5115
5116
#if QT_CONFIG(raster_fp)
5117
static const ProcessSpans processTextureSpansGenericFP[NBlendTypes] = {
5118
    blend_untransformed_generic_fp,     // Untransformed
5119
    blend_tiled_generic_fp,             // Tiled
5120
    blend_src_generic_fp,               // Transformed
5121
    blend_src_generic_fp,               // TransformedTiled
5122
    blend_src_generic_fp,               // TransformedBilinear
5123
    blend_src_generic_fp                // TransformedBilinearTiled
5124
};
5125
#endif
5126
void qBlendTexture(int count, const QT_FT_Span *spans, void *userData)
5127
304k
{
5128
304k
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5129
304k
    TextureBlendType blendType = getBlendType(data);
5130
304k
    ProcessSpans proc;
5131
304k
    switch (data->rasterBuffer->format) {
5132
0
    case QImage::Format_Invalid:
5133
0
        Q_UNREACHABLE_RETURN();
5134
0
    case QImage::Format_ARGB32_Premultiplied:
5135
0
        proc = processTextureSpansARGB32PM[blendType];
5136
0
        break;
5137
0
    case QImage::Format_RGB16:
5138
0
        proc = processTextureSpansRGB16[blendType];
5139
0
        break;
5140
0
#if defined(__SSE2__) || defined(__ARM_NEON__) || defined(QT_COMPILER_SUPPORTS_LSX) || (Q_PROCESSOR_WORDSIZE == 8)
5141
0
    case QImage::Format_ARGB32:
5142
170k
    case QImage::Format_RGBA8888:
5143
170k
#endif
5144
170k
    case QImage::Format_BGR30:
5145
170k
    case QImage::Format_A2BGR30_Premultiplied:
5146
170k
    case QImage::Format_RGB30:
5147
170k
    case QImage::Format_A2RGB30_Premultiplied:
5148
170k
    case QImage::Format_RGBX64:
5149
170k
    case QImage::Format_RGBA64:
5150
170k
    case QImage::Format_RGBA64_Premultiplied:
5151
170k
    case QImage::Format_Grayscale16:
5152
#if !QT_CONFIG(raster_fp)
5153
    case QImage::Format_RGBX16FPx4:
5154
    case QImage::Format_RGBA16FPx4:
5155
    case QImage::Format_RGBA16FPx4_Premultiplied:
5156
    case QImage::Format_RGBX32FPx4:
5157
    case QImage::Format_RGBA32FPx4:
5158
    case QImage::Format_RGBA32FPx4_Premultiplied:
5159
#endif
5160
170k
#if QT_CONFIG(raster_64bit)
5161
170k
        proc = processTextureSpansGeneric64[blendType];
5162
170k
        break;
5163
0
#endif // QT_CONFIG(raster_64bit)
5164
0
#if QT_CONFIG(raster_fp)
5165
0
    case QImage::Format_RGBX16FPx4:
5166
0
    case QImage::Format_RGBA16FPx4:
5167
0
    case QImage::Format_RGBA16FPx4_Premultiplied:
5168
0
    case QImage::Format_RGBX32FPx4:
5169
0
    case QImage::Format_RGBA32FPx4:
5170
0
    case QImage::Format_RGBA32FPx4_Premultiplied:
5171
0
        proc = processTextureSpansGenericFP[blendType];
5172
0
        break;
5173
0
#endif
5174
133k
    default:
5175
133k
        proc = processTextureSpansGeneric[blendType];
5176
133k
        break;
5177
304k
    }
5178
304k
    proc(count, spans, userData);
5179
304k
}
5180
5181
static inline bool calculate_fixed_gradient_factors(int count, const QT_FT_Span *spans,
5182
                                                    const QSpanData *data,
5183
                                                    const LinearGradientValues &linear,
5184
                                                    int *pyinc, int *poff)
5185
0
{
5186
    /*
5187
        The logic for vertical gradient calculations is a mathematically
5188
        reduced copy of that in fetchLinearGradient() - which is basically:
5189
5190
            qreal ry = data->m22 * (y + 0.5) + data->dy;
5191
            qreal t = linear.dy*ry + linear.off;
5192
            t *= (GRADIENT_STOPTABLE_SIZE - 1);
5193
            quint32 color =
5194
                qt_gradient_pixel_fixed(&data->gradient,
5195
                                        int(t * FIXPT_SIZE));
5196
5197
        This has then been converted to fixed point to improve performance.
5198
     */
5199
0
    const int gss = GRADIENT_STOPTABLE_SIZE - 1;
5200
0
    qreal ryinc = linear.dy * data->m22 * gss * FIXPT_SIZE;
5201
0
    qreal roff = (linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss * FIXPT_SIZE;
5202
0
    const qreal limit = qreal(std::numeric_limits<int>::max() - FIXPT_SIZE);
5203
0
    if (count && (std::fabs(ryinc) < limit) && (std::fabs(roff) < limit)
5204
0
        && (std::fabs(ryinc * spans->y + roff) < limit)
5205
0
        && (std::fabs(ryinc * (spans + count - 1)->y + roff) < limit)) {
5206
0
        *pyinc = int(ryinc);
5207
0
        *poff = int(roff);
5208
0
        return true;
5209
0
    }
5210
0
    return false;
5211
0
}
5212
5213
static bool blend_vertical_gradient_argb(int count, const QT_FT_Span *spans, void *userData)
5214
0
{
5215
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5216
5217
0
    LinearGradientValues linear;
5218
0
    getLinearGradientValues(&linear, data);
5219
5220
0
    CompositionFunctionSolid funcSolid =
5221
0
        functionForModeSolid[data->rasterBuffer->compositionMode];
5222
5223
0
    int yinc(0), off(0);
5224
0
    if (!calculate_fixed_gradient_factors(count, spans, data, linear, &yinc, &off))
5225
0
        return false;
5226
5227
0
    while (count--) {
5228
0
        int y = spans->y;
5229
0
        int x = spans->x;
5230
5231
0
        quint32 *dst = (quint32 *)(data->rasterBuffer->scanLine(y)) + x;
5232
0
        quint32 color =
5233
0
            qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
5234
5235
0
        funcSolid(dst, spans->len, color, spans->coverage);
5236
0
        ++spans;
5237
0
    }
5238
0
    return true;
5239
0
}
5240
5241
template<ProcessSpans blend_color>
5242
static bool blend_vertical_gradient(int count, const QT_FT_Span *spans, void *userData)
5243
0
{
5244
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5245
5246
0
    LinearGradientValues linear;
5247
0
    getLinearGradientValues(&linear, data);
5248
5249
0
    int yinc(0), off(0);
5250
0
    if (!calculate_fixed_gradient_factors(count, spans, data, linear, &yinc, &off))
5251
0
        return false;
5252
5253
0
    while (count--) {
5254
0
        int y = spans->y;
5255
5256
0
#if QT_CONFIG(raster_64bit)
5257
0
        data->solidColor = qt_gradient_pixel64_fixed(&data->gradient, yinc * y + off);
5258
#else
5259
        data->solidColor = qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
5260
#endif
5261
0
        blend_color(1, spans, userData);
5262
0
        ++spans;
5263
0
    }
5264
0
    return true;
5265
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*)
5266
5267
void qBlendGradient(int count, const QT_FT_Span *spans, void *userData)
5268
0
{
5269
0
    QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5270
0
    bool isVerticalGradient =
5271
0
        data->txop <= QTransform::TxScale &&
5272
0
        data->type == QSpanData::LinearGradient &&
5273
0
        data->gradient.linear.end.x == data->gradient.linear.origin.x;
5274
0
    switch (data->rasterBuffer->format) {
5275
0
    case QImage::Format_Invalid:
5276
0
        break;
5277
0
    case QImage::Format_RGB32:
5278
0
    case QImage::Format_ARGB32_Premultiplied:
5279
0
        if (isVerticalGradient && blend_vertical_gradient_argb(count, spans, userData))
5280
0
            return;
5281
0
        return blend_src_generic(count, spans, userData);
5282
0
#if defined(__SSE2__) || defined(__ARM_NEON__) || defined(QT_COMPILER_SUPPORTS_LSX) || (Q_PROCESSOR_WORDSIZE == 8)
5283
0
    case QImage::Format_ARGB32:
5284
0
    case QImage::Format_RGBA8888:
5285
0
#endif
5286
0
    case QImage::Format_BGR30:
5287
0
    case QImage::Format_A2BGR30_Premultiplied:
5288
0
    case QImage::Format_RGB30:
5289
0
    case QImage::Format_A2RGB30_Premultiplied:
5290
0
    case QImage::Format_RGBX64:
5291
0
    case QImage::Format_RGBA64:
5292
0
    case QImage::Format_RGBA64_Premultiplied:
5293
#if !QT_CONFIG(raster_fp)
5294
    case QImage::Format_RGBX16FPx4:
5295
    case QImage::Format_RGBA16FPx4:
5296
    case QImage::Format_RGBA16FPx4_Premultiplied:
5297
    case QImage::Format_RGBX32FPx4:
5298
    case QImage::Format_RGBA32FPx4:
5299
    case QImage::Format_RGBA32FPx4_Premultiplied:
5300
#endif
5301
0
#if QT_CONFIG(raster_64bit)
5302
0
        if (isVerticalGradient && blend_vertical_gradient<blend_color_generic_rgb64>(count, spans, userData))
5303
0
            return;
5304
0
        return blend_src_generic_rgb64(count, spans, userData);
5305
0
#endif // QT_CONFIG(raster_64bit)
5306
0
#if QT_CONFIG(raster_fp)
5307
0
    case QImage::Format_RGBX16FPx4:
5308
0
    case QImage::Format_RGBA16FPx4:
5309
0
    case QImage::Format_RGBA16FPx4_Premultiplied:
5310
0
    case QImage::Format_RGBX32FPx4:
5311
0
    case QImage::Format_RGBA32FPx4:
5312
0
    case QImage::Format_RGBA32FPx4_Premultiplied:
5313
0
        if (isVerticalGradient && blend_vertical_gradient<blend_color_generic_fp>(count, spans, userData))
5314
0
            return;
5315
0
        return blend_src_generic_fp(count, spans, userData);
5316
0
#endif
5317
0
    default:
5318
0
        if (isVerticalGradient && blend_vertical_gradient<blend_color_generic>(count, spans, userData))
5319
0
            return;
5320
0
        return blend_src_generic(count, spans, userData);
5321
0
    }
5322
0
    Q_UNREACHABLE();
5323
0
}
5324
5325
template <class DST> static
5326
inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
5327
                                   int x, int y, DST color,
5328
                                   const uchar *map,
5329
                                   int mapWidth, int mapHeight, int mapStride)
5330
0
{
5331
0
    DST *dest = reinterpret_cast<DST *>(rasterBuffer->scanLine(y)) + x;
5332
0
    const int destStride = rasterBuffer->stride<DST>();
5333
5334
0
    if (mapWidth > 8) {
5335
0
        while (--mapHeight >= 0) {
5336
0
            int x0 = 0;
5337
0
            int n = 0;
5338
0
            for (int x = 0; x < mapWidth; x += 8) {
5339
0
                uchar s = map[x >> 3];
5340
0
                for (int i = 0; i < 8; ++i) {
5341
0
                    if (s & 0x80) {
5342
0
                        ++n;
5343
0
                    } else {
5344
0
                        if (n) {
5345
0
                            qt_memfill(dest + x0, color, n);
5346
0
                            x0 += n + 1;
5347
0
                            n = 0;
5348
0
                        } else {
5349
0
                            ++x0;
5350
0
                        }
5351
0
                        if (!s) {
5352
0
                            x0 += 8 - 1 - i;
5353
0
                            break;
5354
0
                        }
5355
0
                    }
5356
0
                    s <<= 1;
5357
0
                }
5358
0
            }
5359
0
            if (n)
5360
0
                qt_memfill(dest + x0, color, n);
5361
0
            dest += destStride;
5362
0
            map += mapStride;
5363
0
        }
5364
0
    } else {
5365
0
        while (--mapHeight >= 0) {
5366
0
            int x0 = 0;
5367
0
            int n = 0;
5368
0
            for (uchar s = *map; s; s <<= 1) {
5369
0
                if (s & 0x80) {
5370
0
                    ++n;
5371
0
                } else if (n) {
5372
0
                    qt_memfill(dest + x0, color, n);
5373
0
                    x0 += n + 1;
5374
0
                    n = 0;
5375
0
                } else {
5376
0
                    ++x0;
5377
0
                }
5378
0
            }
5379
0
            if (n)
5380
0
                qt_memfill(dest + x0, color, n);
5381
0
            dest += destStride;
5382
0
            map += mapStride;
5383
0
        }
5384
0
    }
5385
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)
5386
5387
inline static void qt_bitmapblit_argb32(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, color.toArgb32(),
5393
0
                                    map, mapWidth, mapHeight, mapStride);
5394
0
}
5395
5396
inline static void qt_bitmapblit_rgba8888(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<quint32>(rasterBuffer, x, y, ARGB2RGBA(color.toArgb32()),
5402
0
                                    map, mapWidth, mapHeight, mapStride);
5403
0
}
5404
5405
template<QtPixelOrder PixelOrder>
5406
inline static void qt_bitmapblit_rgb30(QRasterBuffer *rasterBuffer,
5407
                                   int x, int y, const QRgba64 &color,
5408
                                   const uchar *map,
5409
                                   int mapWidth, int mapHeight, int mapStride)
5410
0
{
5411
0
    qt_bitmapblit_template<quint32>(rasterBuffer, x, y, qConvertRgb64ToRgb30<PixelOrder>(color),
5412
0
                                    map, mapWidth, mapHeight, mapStride);
5413
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)
5414
5415
inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer,
5416
                                   int x, int y, const QRgba64 &color,
5417
                                   const uchar *map,
5418
                                   int mapWidth, int mapHeight, int mapStride)
5419
0
{
5420
0
    qt_bitmapblit_template<quint16>(rasterBuffer, x,  y, color.toRgb16(),
5421
0
                                    map, mapWidth, mapHeight, mapStride);
5422
0
}
5423
5424
static inline void grayBlendPixel(quint32 *dst, int coverage, QRgba64 srcLinear, const QColorTrcLut *colorProfile)
5425
0
{
5426
    // Do a gammacorrected gray alphablend...
5427
0
    const QRgba64 dstLinear = colorProfile ? colorProfile->toLinear64(*dst) : QRgba64::fromArgb32(*dst);
5428
5429
0
    QRgba64 blend = interpolate255(srcLinear, coverage, dstLinear, 255 - coverage);
5430
5431
0
    *dst = colorProfile ? colorProfile->fromLinear64(blend) : toArgb32(blend);
5432
0
}
5433
5434
static inline void alphamapblend_argb32(quint32 *dst, int coverage, QRgba64 srcLinear, quint32 src, const QColorTrcLut *colorProfile)
5435
0
{
5436
0
    if (coverage == 0) {
5437
        // nothing
5438
0
    } else if (coverage == 255 || !colorProfile) {
5439
0
        blend_pixel(*dst, src, coverage);
5440
0
    } else if (*dst < 0xff000000) {
5441
        // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
5442
0
        blend_pixel(*dst, src, coverage);
5443
0
    } else if (src >= 0xff000000) {
5444
0
        grayBlendPixel(dst, coverage, srcLinear, colorProfile);
5445
0
    } else {
5446
        // First do naive blend with text-color
5447
0
        QRgb s = *dst;
5448
0
        blend_pixel(s, src);
5449
        // Then gamma-corrected blend with glyph shape
5450
0
        QRgba64 s64 = colorProfile ? colorProfile->toLinear64(s) : QRgba64::fromArgb32(s);
5451
0
        grayBlendPixel(dst, coverage, s64, colorProfile);
5452
0
    }
5453
0
}
5454
5455
#if QT_CONFIG(raster_64bit)
5456
5457
static inline void grayBlendPixel(QRgba64 &dst, int coverage, QRgba64 srcLinear, const QColorTrcLut *colorProfile)
5458
0
{
5459
    // Do a gammacorrected gray alphablend...
5460
0
    QRgba64 dstColor = dst;
5461
0
    if (colorProfile) {
5462
0
        if (dstColor.isOpaque())
5463
0
            dstColor = colorProfile->toLinear(dstColor);
5464
0
        else if (!dstColor.isTransparent())
5465
0
            dstColor = colorProfile->toLinear(dstColor.unpremultiplied()).premultiplied();
5466
0
    }
5467
5468
0
    blend_pixel(dstColor, srcLinear, coverage);
5469
5470
0
    if (colorProfile) {
5471
0
        if (dstColor.isOpaque())
5472
0
            dstColor = colorProfile->fromLinear(dstColor);
5473
0
        else if (!dstColor.isTransparent())
5474
0
            dstColor = colorProfile->fromLinear(dstColor.unpremultiplied()).premultiplied();
5475
0
    }
5476
0
    dst = dstColor;
5477
0
}
5478
5479
static inline void alphamapblend_generic(int coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile)
5480
0
{
5481
0
    if (coverage == 0) {
5482
        // nothing
5483
0
    } else if (coverage == 255) {
5484
0
        blend_pixel(dest[x], src);
5485
0
    } else if (src.isOpaque()) {
5486
0
        grayBlendPixel(dest[x], coverage, srcLinear, colorProfile);
5487
0
    } else {
5488
        // First do naive blend with text-color
5489
0
        QRgba64 s = dest[x];
5490
0
        blend_pixel(s, src);
5491
        // Then gamma-corrected blend with glyph shape
5492
0
        if (colorProfile)
5493
0
            s = colorProfile->toLinear(s);
5494
0
        grayBlendPixel(dest[x], coverage, s, colorProfile);
5495
0
    }
5496
0
}
5497
5498
static void qt_alphamapblit_generic_oneline(const uchar *map, int len,
5499
                                            const QRgba64 srcColor, QRgba64 *dest,
5500
                                            const QRgba64 color,
5501
                                            const QColorTrcLut *colorProfile)
5502
0
{
5503
0
    for (int j = 0; j < len; ++j)
5504
0
        alphamapblend_generic(map[j], dest, j, srcColor, color, colorProfile);
5505
0
}
5506
5507
static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
5508
                                    int x, int y, const QRgba64 &color,
5509
                                    const uchar *map,
5510
                                    int mapWidth, int mapHeight, int mapStride,
5511
                                    const QClipData *clip, bool useGammaCorrection)
5512
0
{
5513
0
    if (color.isTransparent())
5514
0
        return;
5515
5516
0
    const QColorTrcLut *colorProfile = nullptr;
5517
5518
0
    if (useGammaCorrection)
5519
0
        colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
5520
5521
0
    QRgba64 srcColor = color;
5522
0
    if (colorProfile && color.isOpaque())
5523
0
        srcColor = colorProfile->toLinear(srcColor);
5524
5525
0
    alignas(8) Q_DECL_UNINITIALIZED QRgba64 buffer[BufferSize];
5526
0
    const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
5527
0
    const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format];
5528
5529
0
    if (!clip) {
5530
0
        for (int ly = 0; ly < mapHeight; ++ly) {
5531
0
            int i = x;
5532
0
            int length = mapWidth;
5533
0
            while (length > 0) {
5534
0
                int l = qMin(BufferSize, length);
5535
5536
0
                QRgba64 *dest = destFetch64(buffer, rasterBuffer, i, y + ly, l);
5537
0
                qt_alphamapblit_generic_oneline(map + i - x, l,
5538
0
                                                srcColor, dest, color,
5539
0
                                                colorProfile);
5540
0
                if (destStore64)
5541
0
                    destStore64(rasterBuffer, i, y + ly, dest, l);
5542
0
                length -= l;
5543
0
                i += l;
5544
0
            }
5545
0
            map += mapStride;
5546
0
        }
5547
0
    } else {
5548
0
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
5549
5550
0
        int top = qMax(y, 0);
5551
0
        map += (top - y) * mapStride;
5552
5553
0
        const_cast<QClipData *>(clip)->initialize();
5554
0
        for (int yp = top; yp<bottom; ++yp) {
5555
0
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
5556
5557
0
            for (int i=0; i<line.count; ++i) {
5558
0
                const QT_FT_Span &clip = line.spans[i];
5559
5560
0
                int start = qMax<int>(x, clip.x);
5561
0
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
5562
0
                if (end <= start)
5563
0
                    continue;
5564
0
                Q_ASSERT(end - start <= BufferSize);
5565
0
                QRgba64 *dest = destFetch64(buffer, rasterBuffer, start, clip.y, end - start);
5566
0
                qt_alphamapblit_generic_oneline(map + start - x, end - start,
5567
0
                                                srcColor, dest, color,
5568
0
                                                colorProfile);
5569
0
                if (destStore64)
5570
0
                    destStore64(rasterBuffer, start, clip.y, dest, end - start);
5571
0
            } // for (i -> line.count)
5572
0
            map += mapStride;
5573
0
        } // for (yp -> bottom)
5574
0
    }
5575
0
}
5576
#else
5577
static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
5578
                                    int x, int y, const QRgba64 &color,
5579
                                    const uchar *map,
5580
                                    int mapWidth, int mapHeight, int mapStride,
5581
                                    const QClipData *clip, bool useGammaCorrection)
5582
{
5583
    if (color.isTransparent())
5584
        return;
5585
5586
    const quint32 c = color.toArgb32();
5587
5588
    const QColorTrcLut *colorProfile = nullptr;
5589
5590
    if (useGammaCorrection)
5591
        colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
5592
5593
    QRgba64 srcColor = color;
5594
    if (colorProfile && color.isOpaque())
5595
        srcColor = colorProfile->toLinear(srcColor);
5596
5597
    quint32 buffer[BufferSize];
5598
    const DestFetchProc destFetch = destFetchProc[rasterBuffer->format];
5599
    const DestStoreProc destStore = destStoreProc[rasterBuffer->format];
5600
5601
    if (!clip) {
5602
        for (int ly = 0; ly < mapHeight; ++ly) {
5603
            int i = x;
5604
            int length = mapWidth;
5605
            while (length > 0) {
5606
                int l = qMin(BufferSize, length);
5607
                quint32 *dest = destFetch(buffer, rasterBuffer, i, y + ly, l);
5608
                for (int j=0; j < l; ++j) {
5609
                    const int coverage = map[j + (i - x)];
5610
                    alphamapblend_argb32(dest + j, coverage, srcColor, c, colorProfile);
5611
                }
5612
                if (destStore)
5613
                    destStore(rasterBuffer, i, y + ly, dest, l);
5614
                length -= l;
5615
                i += l;
5616
            }
5617
            map += mapStride;
5618
        }
5619
    } else {
5620
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
5621
5622
        int top = qMax(y, 0);
5623
        map += (top - y) * mapStride;
5624
5625
        const_cast<QClipData *>(clip)->initialize();
5626
        for (int yp = top; yp<bottom; ++yp) {
5627
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
5628
5629
            for (int i=0; i<line.count; ++i) {
5630
                const QT_FT_Span &clip = line.spans[i];
5631
5632
                int start = qMax<int>(x, clip.x);
5633
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
5634
                if (end <= start)
5635
                    continue;
5636
                Q_ASSERT(end - start <= BufferSize);
5637
                quint32 *dest = destFetch(buffer, rasterBuffer, start, clip.y, end - start);
5638
5639
                for (int xp=start; xp<end; ++xp) {
5640
                    const int coverage = map[xp - x];
5641
                    alphamapblend_argb32(dest + xp - x, coverage, srcColor, color, colorProfile);
5642
                }
5643
                if (destStore)
5644
                    destStore(rasterBuffer, start, clip.y, dest, end - start);
5645
            } // for (i -> line.count)
5646
            map += mapStride;
5647
        } // for (yp -> bottom)
5648
    }
5649
}
5650
#endif
5651
5652
static inline void alphamapblend_quint16(int coverage, quint16 *dest, int x, const quint16 srcColor)
5653
0
{
5654
0
    if (coverage == 0) {
5655
        // nothing
5656
0
    } else if (coverage == 255) {
5657
0
        dest[x] = srcColor;
5658
0
    } else {
5659
0
        dest[x] = BYTE_MUL_RGB16(srcColor, coverage)
5660
0
                + BYTE_MUL_RGB16(dest[x], 255 - coverage);
5661
0
    }
5662
0
}
5663
5664
void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
5665
                             int x, int y, const QRgba64 &color,
5666
                             const uchar *map,
5667
                             int mapWidth, int mapHeight, int mapStride,
5668
                             const QClipData *clip, bool useGammaCorrection)
5669
0
{
5670
0
    if (useGammaCorrection || !color.isOpaque()) {
5671
0
        qt_alphamapblit_generic(rasterBuffer, x, y, color, map, mapWidth, mapHeight, mapStride, clip, useGammaCorrection);
5672
0
        return;
5673
0
    }
5674
5675
0
    const quint16 c = color.toRgb16();
5676
5677
0
    if (!clip) {
5678
0
        quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
5679
0
        const int destStride = rasterBuffer->stride<quint16>();
5680
0
        while (--mapHeight >= 0) {
5681
0
            for (int i = 0; i < mapWidth; ++i)
5682
0
                alphamapblend_quint16(map[i], dest, i, c);
5683
0
            dest += destStride;
5684
0
            map += mapStride;
5685
0
        }
5686
0
    } else {
5687
0
        int top = qMax(y, 0);
5688
0
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
5689
0
        map += (top - y) * mapStride;
5690
5691
0
        const_cast<QClipData *>(clip)->initialize();
5692
0
        for (int yp = top; yp<bottom; ++yp) {
5693
0
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
5694
5695
0
            quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(yp));
5696
5697
0
            for (int i=0; i<line.count; ++i) {
5698
0
                const QT_FT_Span &clip = line.spans[i];
5699
5700
0
                int start = qMax<int>(x, clip.x);
5701
0
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
5702
5703
0
                for (int xp=start; xp<end; ++xp)
5704
0
                    alphamapblend_quint16(map[xp - x], dest, xp, c);
5705
0
            } // for (i -> line.count)
5706
0
            map += mapStride;
5707
0
        } // for (yp -> bottom)
5708
0
    }
5709
0
}
5710
5711
static void qt_alphamapblit_argb32_oneline(const uchar *map,
5712
                                           int mapWidth, const QRgba64 &srcColor,
5713
                                           quint32 *dest, const quint32 c,
5714
                                           const QColorTrcLut *colorProfile)
5715
0
{
5716
0
    for (int i = 0; i < mapWidth; ++i)
5717
0
        alphamapblend_argb32(dest + i, map[i], srcColor, c, colorProfile);
5718
0
}
5719
5720
static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer,
5721
                                   int x, int y, const QRgba64 &color,
5722
                                   const uchar *map,
5723
                                   int mapWidth, int mapHeight, int mapStride,
5724
                                   const QClipData *clip, bool useGammaCorrection)
5725
0
{
5726
0
    const quint32 c = color.toArgb32();
5727
0
    const int destStride = rasterBuffer->stride<quint32>();
5728
5729
0
    if (color.isTransparent())
5730
0
        return;
5731
5732
0
    const QColorTrcLut *colorProfile = nullptr;
5733
5734
0
    if (useGammaCorrection)
5735
0
        colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
5736
5737
0
    QRgba64 srcColor = color;
5738
0
    if (colorProfile && color.isOpaque())
5739
0
        srcColor = colorProfile->toLinear(srcColor);
5740
5741
0
    if (!clip) {
5742
0
        quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
5743
0
        while (--mapHeight >= 0) {
5744
0
            qt_alphamapblit_argb32_oneline(map, mapWidth, srcColor, dest, c, colorProfile);
5745
0
            dest += destStride;
5746
0
            map += mapStride;
5747
0
        }
5748
0
    } else {
5749
0
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
5750
5751
0
        int top = qMax(y, 0);
5752
0
        map += (top - y) * mapStride;
5753
5754
0
        const_cast<QClipData *>(clip)->initialize();
5755
0
        for (int yp = top; yp<bottom; ++yp) {
5756
0
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
5757
5758
0
            quint32 *dest = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
5759
5760
0
            for (int i=0; i<line.count; ++i) {
5761
0
                const QT_FT_Span &clip = line.spans[i];
5762
0
                int start = qMax<int>(x, clip.x);
5763
0
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
5764
0
                qt_alphamapblit_argb32_oneline(map + start - x, end - start, srcColor, dest + start, c, colorProfile);
5765
0
            } // for (yp -> bottom)
5766
0
            map += mapStride;
5767
0
        }
5768
0
    }
5769
0
}
5770
5771
#if QT_CONFIG(raster_64bit)
5772
static void qt_alphamapblit_nonpremul_argb32(QRasterBuffer *rasterBuffer,
5773
                                             int x, int y, const QRgba64 &color,
5774
                                             const uchar *map,
5775
                                             int mapWidth, int mapHeight, int mapStride,
5776
                                             const QClipData *clip, bool useGammaCorrection)
5777
0
{
5778
0
    if (clip)
5779
0
        return qt_alphamapblit_generic(rasterBuffer, x, y, color, map, mapWidth, mapHeight,
5780
0
                                       mapStride, clip, useGammaCorrection);
5781
5782
0
    if (color.isTransparent())
5783
0
        return;
5784
5785
0
    const QColorTrcLut *colorProfile = nullptr;
5786
5787
0
    if (useGammaCorrection)
5788
0
        colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
5789
5790
0
    const quint32 c = color.toArgb32();
5791
0
    QRgba64 srcColor = color;
5792
0
    if (colorProfile && color.isOpaque())
5793
0
        srcColor = colorProfile->toLinear(srcColor);
5794
5795
0
    alignas(8) Q_DECL_UNINITIALIZED QRgba64 buffer[BufferSize];
5796
0
    const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
5797
0
    const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format];
5798
5799
0
    for (int ly = 0; ly < mapHeight; ++ly) {
5800
0
        bool dstFullyOpaque = true;
5801
0
        int i = x;
5802
0
        int length = mapWidth;
5803
0
        while (length > 0) {
5804
0
            int l = qMin(BufferSize, length);
5805
0
            quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y + ly)) + i;
5806
0
            for (int j = 0; j < l && dstFullyOpaque; ++j)
5807
0
                dstFullyOpaque = (dest[j] & 0xff000000) == 0xff000000;
5808
0
            if (dstFullyOpaque) {
5809
                // Use RGB/ARGB32PM optimized version
5810
0
                qt_alphamapblit_argb32_oneline(map + i - x, l, srcColor, dest, c, colorProfile);
5811
0
            } else {
5812
                // Use generic version
5813
0
                QRgba64 *dest64 = destFetch64(buffer, rasterBuffer, i, y + ly, l);
5814
0
                qt_alphamapblit_generic_oneline(map + i - x, l,
5815
0
                                                srcColor, dest64, color,
5816
0
                                                colorProfile);
5817
0
                if (destStore64)
5818
0
                    destStore64(rasterBuffer, i, y + ly, dest64, l);
5819
0
            }
5820
0
            length -= l;
5821
0
            i += l;
5822
0
        }
5823
0
        map += mapStride;
5824
0
    }
5825
0
}
5826
#endif
5827
5828
static inline int qRgbAvg(QRgb rgb)
5829
0
{
5830
0
    return (qRed(rgb) * 5 + qGreen(rgb) * 6 + qBlue(rgb) * 5) / 16;
5831
0
}
5832
5833
static inline void rgbBlendPixel(quint32 *dst, int coverage, QRgba64 slinear, const QColorTrcLut *colorProfile)
5834
0
{
5835
    // Do a gammacorrected RGB alphablend...
5836
0
    const QRgba64 dlinear = colorProfile ? colorProfile->toLinear64(*dst) : QRgba64::fromArgb32(*dst);
5837
5838
0
    QRgba64 blend = rgbBlend(dlinear, slinear, coverage);
5839
5840
0
    *dst = colorProfile ? colorProfile->fromLinear64(blend) : toArgb32(blend);
5841
0
}
5842
5843
static inline QRgb rgbBlend(QRgb d, QRgb s, uint rgbAlpha)
5844
0
{
5845
0
#if defined(__SSE2__)
5846
0
    __m128i vd = _mm_cvtsi32_si128(d);
5847
0
    __m128i vs = _mm_cvtsi32_si128(s);
5848
0
    __m128i va = _mm_cvtsi32_si128(rgbAlpha);
5849
0
    const __m128i vz = _mm_setzero_si128();
5850
0
    vd = _mm_unpacklo_epi8(vd, vz);
5851
0
    vs = _mm_unpacklo_epi8(vs, vz);
5852
0
    va = _mm_unpacklo_epi8(va, vz);
5853
0
    __m128i vb = _mm_xor_si128(_mm_set1_epi16(255), va);
5854
0
    vs = _mm_mullo_epi16(vs, va);
5855
0
    vd = _mm_mullo_epi16(vd, vb);
5856
0
    vd = _mm_add_epi16(vd, vs);
5857
0
    vd = _mm_add_epi16(vd, _mm_srli_epi16(vd, 8));
5858
0
    vd = _mm_add_epi16(vd, _mm_set1_epi16(0x80));
5859
0
    vd = _mm_srli_epi16(vd, 8);
5860
0
    vd = _mm_packus_epi16(vd, vd);
5861
0
    return _mm_cvtsi128_si32(vd);
5862
#else
5863
    const int dr = qRed(d);
5864
    const int dg = qGreen(d);
5865
    const int db = qBlue(d);
5866
5867
    const int sr = qRed(s);
5868
    const int sg = qGreen(s);
5869
    const int sb = qBlue(s);
5870
5871
    const int mr = qRed(rgbAlpha);
5872
    const int mg = qGreen(rgbAlpha);
5873
    const int mb = qBlue(rgbAlpha);
5874
5875
    const int nr = qt_div_255(sr * mr + dr * (255 - mr));
5876
    const int ng = qt_div_255(sg * mg + dg * (255 - mg));
5877
    const int nb = qt_div_255(sb * mb + db * (255 - mb));
5878
5879
    return 0xff000000 | (nr << 16) | (ng << 8) | nb;
5880
#endif
5881
0
}
5882
5883
static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorTrcLut *colorProfile)
5884
0
{
5885
0
    if (coverage == 0xff000000) {
5886
        // nothing
5887
0
    } else if (coverage == 0xffffffff && qAlpha(src) == 255) {
5888
0
        blend_pixel(*dst, src);
5889
0
    } else if (*dst < 0xff000000) {
5890
        // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
5891
0
        blend_pixel(*dst, src, qRgbAvg(coverage));
5892
0
    } else if (!colorProfile) {
5893
        // First do naive blend with text-color
5894
0
        QRgb s = *dst;
5895
0
        blend_pixel(s, src);
5896
        // Then a naive blend with glyph shape
5897
0
        *dst = rgbBlend(*dst, s, coverage);
5898
0
    } else if (srcLinear.isOpaque()) {
5899
0
        rgbBlendPixel(dst, coverage, srcLinear, colorProfile);
5900
0
    } else {
5901
        // First do naive blend with text-color
5902
0
        QRgb s = *dst;
5903
0
        blend_pixel(s, src);
5904
        // Then gamma-corrected blend with glyph shape
5905
0
        QRgba64 s64 = colorProfile ? colorProfile->toLinear64(s) : QRgba64::fromArgb32(s);
5906
0
        rgbBlendPixel(dst, coverage, s64, colorProfile);
5907
0
    }
5908
0
}
5909
5910
#if QT_CONFIG(raster_64bit)
5911
static inline void rgbBlendPixel(QRgba64 &dst, int coverage, QRgba64 slinear, const QColorTrcLut *colorProfile)
5912
0
{
5913
    // Do a gammacorrected RGB alphablend...
5914
0
    const QRgba64 dlinear = colorProfile ? colorProfile->toLinear(dst) : dst;
5915
5916
0
    QRgba64 blend = rgbBlend(dlinear, slinear, coverage);
5917
5918
0
    dst = colorProfile ? colorProfile->fromLinear(blend) : blend;
5919
0
}
5920
5921
static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile)
5922
0
{
5923
0
    if (coverage == 0xff000000) {
5924
        // nothing
5925
0
    } else if (coverage == 0xffffffff) {
5926
0
        blend_pixel(dest[x], src);
5927
0
    } else if (!dest[x].isOpaque()) {
5928
        // Do a gray alphablend.
5929
0
        alphamapblend_generic(qRgbAvg(coverage), dest, x, srcLinear, src, colorProfile);
5930
0
    } else if (src.isOpaque()) {
5931
0
        rgbBlendPixel(dest[x], coverage, srcLinear, colorProfile);
5932
0
    } else {
5933
        // First do naive blend with text-color
5934
0
        QRgba64 s = dest[x];
5935
0
        blend_pixel(s, src);
5936
        // Then gamma-corrected blend with glyph shape
5937
0
        if (colorProfile)
5938
0
            s = colorProfile->toLinear(s);
5939
0
        rgbBlendPixel(dest[x], coverage, s, colorProfile);
5940
0
    }
5941
0
}
5942
5943
static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
5944
                                    int x, int y, const QRgba64 &color,
5945
                                    const uint *src, int mapWidth, int mapHeight, int srcStride,
5946
                                    const QClipData *clip, bool useGammaCorrection)
5947
0
{
5948
0
    if (color.isTransparent())
5949
0
        return;
5950
5951
0
    const QColorTrcLut *colorProfile = nullptr;
5952
5953
0
    if (useGammaCorrection)
5954
0
        colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
5955
5956
0
    QRgba64 srcColor = color;
5957
0
    if (colorProfile && color.isOpaque())
5958
0
        srcColor = colorProfile->toLinear(srcColor);
5959
5960
0
    alignas(8) Q_DECL_UNINITIALIZED QRgba64 buffer[BufferSize];
5961
0
    const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
5962
0
    const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format];
5963
5964
0
    if (!clip) {
5965
0
        for (int ly = 0; ly < mapHeight; ++ly) {
5966
0
            int i = x;
5967
0
            int length = mapWidth;
5968
0
            while (length > 0) {
5969
0
                int l = qMin(BufferSize, length);
5970
0
                QRgba64 *dest = destFetch64(buffer, rasterBuffer, i, y + ly, l);
5971
0
                for (int j=0; j < l; ++j) {
5972
0
                    const uint coverage = src[j + (i - x)];
5973
0
                    alphargbblend_generic(coverage, dest, j, srcColor, color, colorProfile);
5974
0
                }
5975
0
                if (destStore64)
5976
0
                    destStore64(rasterBuffer, i, y + ly, dest, l);
5977
0
                length -= l;
5978
0
                i += l;
5979
0
            }
5980
0
            src += srcStride;
5981
0
        }
5982
0
    } else {
5983
0
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
5984
5985
0
        int top = qMax(y, 0);
5986
0
        src += (top - y) * srcStride;
5987
5988
0
        const_cast<QClipData *>(clip)->initialize();
5989
0
        for (int yp = top; yp<bottom; ++yp) {
5990
0
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
5991
5992
0
            for (int i=0; i<line.count; ++i) {
5993
0
                const QT_FT_Span &clip = line.spans[i];
5994
5995
0
                int start = qMax<int>(x, clip.x);
5996
0
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
5997
0
                if (end <= start)
5998
0
                    continue;
5999
0
                Q_ASSERT(end - start <= BufferSize);
6000
0
                QRgba64 *dest = destFetch64(buffer, rasterBuffer, start, clip.y, end - start);
6001
6002
0
                for (int xp=start; xp<end; ++xp) {
6003
0
                    const uint coverage = src[xp - x];
6004
0
                    alphargbblend_generic(coverage, dest, xp - start, srcColor, color, colorProfile);
6005
0
                }
6006
0
                if (destStore64)
6007
0
                    destStore64(rasterBuffer, start, clip.y, dest, end - start);
6008
0
            } // for (i -> line.count)
6009
0
            src += srcStride;
6010
0
        } // for (yp -> bottom)
6011
0
    }
6012
0
}
6013
#else
6014
static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
6015
                                    int x, int y, const QRgba64 &color,
6016
                                    const uint *src, int mapWidth, int mapHeight, int srcStride,
6017
                                    const QClipData *clip, bool useGammaCorrection)
6018
{
6019
    if (color.isTransparent())
6020
        return;
6021
6022
    const quint32 c = color.toArgb32();
6023
6024
    const QColorTrcLut *colorProfile = nullptr;
6025
6026
    if (useGammaCorrection)
6027
        colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
6028
6029
    QRgba64 srcColor = color;
6030
    if (colorProfile && color.isOpaque())
6031
        srcColor = colorProfile->toLinear(srcColor);
6032
6033
    Q_DECL_UNINITIALIZED quint32 buffer[BufferSize];
6034
    const DestFetchProc destFetch = destFetchProc[rasterBuffer->format];
6035
    const DestStoreProc destStore = destStoreProc[rasterBuffer->format];
6036
6037
    if (!clip) {
6038
        for (int ly = 0; ly < mapHeight; ++ly) {
6039
            int i = x;
6040
            int length = mapWidth;
6041
            while (length > 0) {
6042
                int l = qMin(BufferSize, length);
6043
                quint32 *dest = destFetch(buffer, rasterBuffer, i, y + ly, l);
6044
                for (int j=0; j < l; ++j) {
6045
                    const uint coverage = src[j + (i - x)];
6046
                    alphargbblend_argb32(dest + j, coverage, srcColor, c, colorProfile);
6047
                }
6048
                if (destStore)
6049
                    destStore(rasterBuffer, i, y + ly, dest, l);
6050
                length -= l;
6051
                i += l;
6052
            }
6053
            src += srcStride;
6054
        }
6055
    } else {
6056
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
6057
6058
        int top = qMax(y, 0);
6059
        src += (top - y) * srcStride;
6060
6061
        const_cast<QClipData *>(clip)->initialize();
6062
        for (int yp = top; yp<bottom; ++yp) {
6063
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
6064
6065
            for (int i=0; i<line.count; ++i) {
6066
                const QT_FT_Span &clip = line.spans[i];
6067
6068
                int start = qMax<int>(x, clip.x);
6069
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
6070
                if (end <= start)
6071
                    continue;
6072
                Q_ASSERT(end - start <= BufferSize);
6073
                quint32 *dest = destFetch(buffer, rasterBuffer, start, clip.y, end - start);
6074
6075
                for (int xp=start; xp<end; ++xp) {
6076
                    const uint coverage = src[xp - x];
6077
                    alphargbblend_argb32(dest + xp - start, coverage, srcColor, c, colorProfile);
6078
                }
6079
                if (destStore)
6080
                    destStore(rasterBuffer, start, clip.y, dest, end - start);
6081
            } // for (i -> line.count)
6082
            src += srcStride;
6083
        } // for (yp -> bottom)
6084
    }
6085
}
6086
#endif
6087
6088
static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer,
6089
                                   int x, int y, const QRgba64 &color,
6090
                                   const uint *src, int mapWidth, int mapHeight, int srcStride,
6091
                                   const QClipData *clip, bool useGammaCorrection)
6092
0
{
6093
0
    if (color.isTransparent())
6094
0
        return;
6095
6096
0
    const quint32 c = color.toArgb32();
6097
6098
0
    const QColorTrcLut *colorProfile = nullptr;
6099
6100
0
    if (useGammaCorrection)
6101
0
        colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
6102
6103
0
    QRgba64 srcColor = color;
6104
0
    if (colorProfile && color.isOpaque())
6105
0
        srcColor = colorProfile->toLinear(srcColor);
6106
6107
0
    if (!clip) {
6108
0
        quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
6109
0
        const int destStride = rasterBuffer->stride<quint32>();
6110
0
        while (--mapHeight >= 0) {
6111
0
            for (int i = 0; i < mapWidth; ++i) {
6112
0
                const uint coverage = src[i];
6113
0
                alphargbblend_argb32(dst + i, coverage, srcColor, c, colorProfile);
6114
0
            }
6115
6116
0
            dst += destStride;
6117
0
            src += srcStride;
6118
0
        }
6119
0
    } else {
6120
0
        int bottom = qMin(y + mapHeight, rasterBuffer->height());
6121
6122
0
        int top = qMax(y, 0);
6123
0
        src += (top - y) * srcStride;
6124
6125
0
        const_cast<QClipData *>(clip)->initialize();
6126
0
        for (int yp = top; yp<bottom; ++yp) {
6127
0
            const QClipData::ClipLine &line = clip->m_clipLines[yp];
6128
6129
0
            quint32 *dst = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
6130
6131
0
            for (int i=0; i<line.count; ++i) {
6132
0
                const QT_FT_Span &clip = line.spans[i];
6133
6134
0
                int start = qMax<int>(x, clip.x);
6135
0
                int end = qMin<int>(x + mapWidth, clip.x + clip.len);
6136
6137
0
                for (int xp=start; xp<end; ++xp) {
6138
0
                    const uint coverage = src[xp - x];
6139
0
                    alphargbblend_argb32(dst + xp, coverage, srcColor, c, colorProfile);
6140
0
                }
6141
0
            } // for (i -> line.count)
6142
0
            src += srcStride;
6143
0
        } // for (yp -> bottom)
6144
6145
0
    }
6146
0
}
6147
6148
static void qt_rectfill_argb32(QRasterBuffer *rasterBuffer,
6149
                               int x, int y, int width, int height,
6150
                               const QRgba64 &color)
6151
0
{
6152
0
    qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
6153
0
                         color.toArgb32(), x, y, width, height, rasterBuffer->bytesPerLine());
6154
0
}
6155
6156
static void qt_rectfill_quint16(QRasterBuffer *rasterBuffer,
6157
                                int x, int y, int width, int height,
6158
                                const QRgba64 &color)
6159
0
{
6160
0
    const QPixelLayout &layout = qPixelLayouts[rasterBuffer->format];
6161
0
    quint32 c32 = color.toArgb32();
6162
0
    quint16 c16;
6163
0
    layout.storeFromARGB32PM(reinterpret_cast<uchar *>(&c16), &c32, 0, 1, nullptr, nullptr);
6164
0
    qt_rectfill<quint16>(reinterpret_cast<quint16 *>(rasterBuffer->buffer()),
6165
0
                         c16, x, y, width, height, rasterBuffer->bytesPerLine());
6166
0
}
6167
6168
static void qt_rectfill_quint24(QRasterBuffer *rasterBuffer,
6169
                                int x, int y, int width, int height,
6170
                                const QRgba64 &color)
6171
0
{
6172
0
    const QPixelLayout &layout = qPixelLayouts[rasterBuffer->format];
6173
0
    quint32 c32 = color.toArgb32();
6174
0
    quint24 c24;
6175
0
    layout.storeFromARGB32PM(reinterpret_cast<uchar *>(&c24), &c32, 0, 1, nullptr, nullptr);
6176
0
    qt_rectfill<quint24>(reinterpret_cast<quint24 *>(rasterBuffer->buffer()),
6177
0
                         c24, x, y, width, height, rasterBuffer->bytesPerLine());
6178
0
}
6179
6180
static void qt_rectfill_nonpremul_argb32(QRasterBuffer *rasterBuffer,
6181
                                         int x, int y, int width, int height,
6182
                                         const QRgba64 &color)
6183
0
{
6184
0
    qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
6185
0
                         color.unpremultiplied().toArgb32(), x, y, width, height, rasterBuffer->bytesPerLine());
6186
0
}
6187
6188
static void qt_rectfill_rgbx(QRasterBuffer *rasterBuffer,
6189
                             int x, int y, int width, int height,
6190
                             const QRgba64 &color)
6191
0
{
6192
0
    qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
6193
0
                         ARGB2RGBA(color.toArgb32() | 0xff000000), x, y, width, height, rasterBuffer->bytesPerLine());
6194
0
}
6195
6196
static void qt_rectfill_rgba(QRasterBuffer *rasterBuffer,
6197
                             int x, int y, int width, int height,
6198
                             const QRgba64 &color)
6199
0
{
6200
0
    qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
6201
0
                         ARGB2RGBA(color.toArgb32()), x, y, width, height, rasterBuffer->bytesPerLine());
6202
0
}
6203
6204
static void qt_rectfill_nonpremul_rgba(QRasterBuffer *rasterBuffer,
6205
                                       int x, int y, int width, int height,
6206
                                       const QRgba64 &color)
6207
0
{
6208
0
    qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
6209
0
                         ARGB2RGBA(color.unpremultiplied().toArgb32()), x, y, width, height, rasterBuffer->bytesPerLine());
6210
0
}
6211
6212
template<QtPixelOrder PixelOrder>
6213
static void qt_rectfill_rgb30(QRasterBuffer *rasterBuffer,
6214
                              int x, int y, int width, int height,
6215
                              const QRgba64 &color)
6216
0
{
6217
0
    qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
6218
0
                         qConvertRgb64ToRgb30<PixelOrder>(color), x, y, width, height, rasterBuffer->bytesPerLine());
6219
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&)
6220
6221
static void qt_rectfill_alpha(QRasterBuffer *rasterBuffer,
6222
                             int x, int y, int width, int height,
6223
                             const QRgba64 &color)
6224
0
{
6225
0
    qt_rectfill<quint8>(reinterpret_cast<quint8 *>(rasterBuffer->buffer()),
6226
0
                         color.alpha() >> 8, x, y, width, height, rasterBuffer->bytesPerLine());
6227
0
}
6228
6229
static void qt_rectfill_gray(QRasterBuffer *rasterBuffer,
6230
                             int x, int y, int width, int height,
6231
                             const QRgba64 &color)
6232
0
{
6233
0
    qt_rectfill<quint8>(reinterpret_cast<quint8 *>(rasterBuffer->buffer()),
6234
0
                         qGray(color.toArgb32()), x, y, width, height, rasterBuffer->bytesPerLine());
6235
0
}
6236
6237
static void qt_rectfill_quint64(QRasterBuffer *rasterBuffer,
6238
                                int x, int y, int width, int height,
6239
                                const QRgba64 &color)
6240
0
{
6241
0
    const auto store = qStoreFromRGBA64PM[rasterBuffer->format];
6242
0
    quint64 c64;
6243
0
    store(reinterpret_cast<uchar *>(&c64), &color, 0, 1, nullptr, nullptr);
6244
0
    qt_rectfill<quint64>(reinterpret_cast<quint64 *>(rasterBuffer->buffer()),
6245
0
                         c64, x, y, width, height, rasterBuffer->bytesPerLine());
6246
0
}
6247
6248
static void qt_rectfill_fp32x4(QRasterBuffer *rasterBuffer,
6249
                               int x, int y, int width, int height,
6250
                               const QRgba64 &color)
6251
0
{
6252
0
    const auto store = qStoreFromRGBA64PM[rasterBuffer->format];
6253
0
    QRgbaFloat32 c;
6254
0
    store(reinterpret_cast<uchar *>(&c), &color, 0, 1, nullptr, nullptr);
6255
0
    qt_rectfill<QRgbaFloat32>(reinterpret_cast<QRgbaFloat32 *>(rasterBuffer->buffer()),
6256
0
                          c, x, y, width, height, rasterBuffer->bytesPerLine());
6257
0
}
6258
6259
// Map table for destination image format. Contains function pointers
6260
// for blends of various types unto the destination
6261
6262
DrawHelper qDrawHelper[] =
6263
{
6264
    // Format_Invalid,
6265
    { nullptr, nullptr, nullptr, nullptr, nullptr },
6266
    // Format_Mono,
6267
    {
6268
        blend_color_generic,
6269
        nullptr, nullptr, nullptr, nullptr
6270
    },
6271
    // Format_MonoLSB,
6272
    {
6273
        blend_color_generic,
6274
        nullptr, nullptr, nullptr, nullptr
6275
    },
6276
    // Format_Indexed8,
6277
    {
6278
        blend_color_generic,
6279
        nullptr, nullptr, nullptr, nullptr
6280
    },
6281
    // Format_RGB32,
6282
    {
6283
        blend_color_argb,
6284
        qt_bitmapblit_argb32,
6285
        qt_alphamapblit_argb32,
6286
        qt_alphargbblit_argb32,
6287
        qt_rectfill_argb32
6288
    },
6289
    // Format_ARGB32,
6290
    {
6291
        blend_color_generic,
6292
        qt_bitmapblit_argb32,
6293
#if QT_CONFIG(raster_64bit)
6294
        qt_alphamapblit_nonpremul_argb32,
6295
#else
6296
        qt_alphamapblit_generic,
6297
#endif
6298
        qt_alphargbblit_generic,
6299
        qt_rectfill_nonpremul_argb32
6300
    },
6301
    // Format_ARGB32_Premultiplied
6302
    {
6303
        blend_color_argb,
6304
        qt_bitmapblit_argb32,
6305
        qt_alphamapblit_argb32,
6306
        qt_alphargbblit_argb32,
6307
        qt_rectfill_argb32
6308
    },
6309
    // Format_RGB16
6310
    {
6311
        blend_color_generic,
6312
        qt_bitmapblit_quint16,
6313
        qt_alphamapblit_quint16,
6314
        qt_alphargbblit_generic,
6315
        qt_rectfill_quint16
6316
    },
6317
    // Format_ARGB8565_Premultiplied
6318
    {
6319
        blend_color_generic,
6320
        nullptr,
6321
        qt_alphamapblit_generic,
6322
        qt_alphargbblit_generic,
6323
        qt_rectfill_quint24
6324
    },
6325
    // Format_RGB666
6326
    {
6327
        blend_color_generic,
6328
        nullptr,
6329
        qt_alphamapblit_generic,
6330
        qt_alphargbblit_generic,
6331
        qt_rectfill_quint24
6332
    },
6333
    // Format_ARGB6666_Premultiplied
6334
    {
6335
        blend_color_generic,
6336
        nullptr,
6337
        qt_alphamapblit_generic,
6338
        qt_alphargbblit_generic,
6339
        qt_rectfill_quint24
6340
    },
6341
    // Format_RGB555
6342
    {
6343
        blend_color_generic,
6344
        nullptr,
6345
        qt_alphamapblit_generic,
6346
        qt_alphargbblit_generic,
6347
        qt_rectfill_quint16
6348
    },
6349
    // Format_ARGB8555_Premultiplied
6350
    {
6351
        blend_color_generic,
6352
        nullptr,
6353
        qt_alphamapblit_generic,
6354
        qt_alphargbblit_generic,
6355
        qt_rectfill_quint24
6356
    },
6357
    // Format_RGB888
6358
    {
6359
        blend_color_generic,
6360
        nullptr,
6361
        qt_alphamapblit_generic,
6362
        qt_alphargbblit_generic,
6363
        qt_rectfill_quint24
6364
    },
6365
    // Format_RGB444
6366
    {
6367
        blend_color_generic,
6368
        nullptr,
6369
        qt_alphamapblit_generic,
6370
        qt_alphargbblit_generic,
6371
        qt_rectfill_quint16
6372
    },
6373
    // Format_ARGB4444_Premultiplied
6374
    {
6375
        blend_color_generic,
6376
        nullptr,
6377
        qt_alphamapblit_generic,
6378
        qt_alphargbblit_generic,
6379
        qt_rectfill_quint16
6380
    },
6381
    // Format_RGBX8888
6382
    {
6383
        blend_color_generic,
6384
        qt_bitmapblit_rgba8888,
6385
        qt_alphamapblit_generic,
6386
        qt_alphargbblit_generic,
6387
        qt_rectfill_rgbx
6388
    },
6389
    // Format_RGBA8888
6390
    {
6391
        blend_color_generic,
6392
        qt_bitmapblit_rgba8888,
6393
        qt_alphamapblit_generic,
6394
        qt_alphargbblit_generic,
6395
        qt_rectfill_nonpremul_rgba
6396
    },
6397
    // Format_RGB8888_Premultiplied
6398
    {
6399
        blend_color_generic,
6400
        qt_bitmapblit_rgba8888,
6401
        qt_alphamapblit_generic,
6402
        qt_alphargbblit_generic,
6403
        qt_rectfill_rgba
6404
    },
6405
    // Format_BGR30
6406
    {
6407
        blend_color_generic_rgb64,
6408
        qt_bitmapblit_rgb30<PixelOrderBGR>,
6409
        qt_alphamapblit_generic,
6410
        qt_alphargbblit_generic,
6411
        qt_rectfill_rgb30<PixelOrderBGR>
6412
    },
6413
    // Format_A2BGR30_Premultiplied
6414
    {
6415
        blend_color_generic_rgb64,
6416
        qt_bitmapblit_rgb30<PixelOrderBGR>,
6417
        qt_alphamapblit_generic,
6418
        qt_alphargbblit_generic,
6419
        qt_rectfill_rgb30<PixelOrderBGR>
6420
    },
6421
    // Format_RGB30
6422
    {
6423
        blend_color_generic_rgb64,
6424
        qt_bitmapblit_rgb30<PixelOrderRGB>,
6425
        qt_alphamapblit_generic,
6426
        qt_alphargbblit_generic,
6427
        qt_rectfill_rgb30<PixelOrderRGB>
6428
    },
6429
    // Format_A2RGB30_Premultiplied
6430
    {
6431
        blend_color_generic_rgb64,
6432
        qt_bitmapblit_rgb30<PixelOrderRGB>,
6433
        qt_alphamapblit_generic,
6434
        qt_alphargbblit_generic,
6435
        qt_rectfill_rgb30<PixelOrderRGB>
6436
    },
6437
    // Format_Alpha8
6438
    {
6439
        blend_color_generic,
6440
        nullptr,
6441
        qt_alphamapblit_generic,
6442
        qt_alphargbblit_generic,
6443
        qt_rectfill_alpha
6444
    },
6445
    // Format_Grayscale8
6446
    {
6447
        blend_color_generic,
6448
        nullptr,
6449
        qt_alphamapblit_generic,
6450
        qt_alphargbblit_generic,
6451
        qt_rectfill_gray
6452
    },
6453
    // Format_RGBX64
6454
    {
6455
        blend_color_generic_rgb64,
6456
        nullptr,
6457
        qt_alphamapblit_generic,
6458
        qt_alphargbblit_generic,
6459
        qt_rectfill_quint64
6460
    },
6461
    // Format_RGBA64
6462
    {
6463
        blend_color_generic_rgb64,
6464
        nullptr,
6465
        qt_alphamapblit_generic,
6466
        qt_alphargbblit_generic,
6467
        qt_rectfill_quint64
6468
    },
6469
    // Format_RGBA64_Premultiplied
6470
    {
6471
        blend_color_generic_rgb64,
6472
        nullptr,
6473
        qt_alphamapblit_generic,
6474
        qt_alphargbblit_generic,
6475
        qt_rectfill_quint64
6476
    },
6477
    // Format_Grayscale16
6478
    {
6479
        blend_color_generic_rgb64,
6480
        nullptr,
6481
        qt_alphamapblit_generic,
6482
        qt_alphargbblit_generic,
6483
        qt_rectfill_quint16
6484
    },
6485
    // Format_BGR888
6486
    {
6487
        blend_color_generic,
6488
        nullptr,
6489
        qt_alphamapblit_generic,
6490
        qt_alphargbblit_generic,
6491
        qt_rectfill_quint24
6492
    },
6493
    // Format_RGBX16FPx4
6494
    {
6495
        blend_color_generic_fp,
6496
        nullptr,
6497
        qt_alphamapblit_generic,
6498
        qt_alphargbblit_generic,
6499
        qt_rectfill_quint64
6500
    },
6501
    // Format_RGBA16FPx4
6502
    {
6503
        blend_color_generic_fp,
6504
        nullptr,
6505
        qt_alphamapblit_generic,
6506
        qt_alphargbblit_generic,
6507
        qt_rectfill_quint64
6508
    },
6509
    // Format_RGBA16FPx4_Premultiplied
6510
    {
6511
        blend_color_generic_fp,
6512
        nullptr,
6513
        qt_alphamapblit_generic,
6514
        qt_alphargbblit_generic,
6515
        qt_rectfill_quint64
6516
    },
6517
    // Format_RGBX32FPx4
6518
    {
6519
        blend_color_generic_fp,
6520
        nullptr,
6521
        qt_alphamapblit_generic,
6522
        qt_alphargbblit_generic,
6523
        qt_rectfill_fp32x4
6524
    },
6525
    // Format_RGBA32FPx4
6526
    {
6527
        blend_color_generic_fp,
6528
        nullptr,
6529
        qt_alphamapblit_generic,
6530
        qt_alphargbblit_generic,
6531
        qt_rectfill_fp32x4
6532
    },
6533
    // Format_RGBA32FPx4_Premultiplied
6534
    {
6535
        blend_color_generic_fp,
6536
        nullptr,
6537
        qt_alphamapblit_generic,
6538
        qt_alphargbblit_generic,
6539
        qt_rectfill_fp32x4
6540
    },
6541
};
6542
6543
static_assert(std::size(qDrawHelper) == QImage::NImageFormats);
6544
6545
#if !defined(Q_PROCESSOR_X86) && !defined(QT_COMPILER_SUPPORTS_LSX)
6546
void qt_memfill64(quint64 *dest, quint64 color, qsizetype count)
6547
{
6548
    qt_memfill_template<quint64>(dest, color, count);
6549
}
6550
#endif
6551
6552
#if defined(QT_COMPILER_SUPPORTS_SSSE3) && defined(Q_CC_GNU) && !defined(Q_CC_CLANG)
6553
__attribute__((optimize("no-tree-vectorize")))
6554
#endif
6555
void qt_memfill24(quint24 *dest, quint24 color, qsizetype count)
6556
27.5M
{
6557
27.5M
#  ifdef QT_COMPILER_SUPPORTS_SSSE3
6558
27.5M
    extern void qt_memfill24_ssse3(quint24 *, quint24, qsizetype);
6559
27.5M
    if (qCpuHasFeature(SSSE3))
6560
27.5M
        return qt_memfill24_ssse3(dest, color, count);
6561
#  elif defined QT_COMPILER_SUPPORTS_LSX
6562
    extern void qt_memfill24_lsx(quint24 *, quint24, qsizetype);
6563
    if (qCpuHasFeature(LSX))
6564
        return qt_memfill24_lsx(dest, color, count);
6565
#  endif
6566
6567
0
    const quint32 v = color;
6568
0
    quint24 *end = dest + count;
6569
6570
    // prolog: align dest to 32bit
6571
0
    while ((quintptr(dest) & 0x3) && dest < end) {
6572
0
        *dest++ = v;
6573
0
    }
6574
0
    if (dest >= end)
6575
0
        return;
6576
6577
0
    const uint val1 = qFromBigEndian((v <<  8) | (v >> 16));
6578
0
    const uint val2 = qFromBigEndian((v << 16) | (v >>  8));
6579
0
    const uint val3 = qFromBigEndian((v << 24) | (v >>  0));
6580
6581
0
    for ( ; dest <= (end - 4); dest += 4) {
6582
0
       quint32 *dst = reinterpret_cast<quint32 *>(dest);
6583
0
       dst[0] = val1;
6584
0
       dst[1] = val2;
6585
0
       dst[2] = val3;
6586
0
    }
6587
6588
    // less than 4px left
6589
0
    switch (end - dest) {
6590
0
    case 3:
6591
0
        *dest++ = v;
6592
0
        Q_FALLTHROUGH();
6593
0
    case 2:
6594
0
        *dest++ = v;
6595
0
        Q_FALLTHROUGH();
6596
0
    case 1:
6597
0
        *dest++ = v;
6598
0
    }
6599
0
}
6600
6601
void qt_memfill16(quint16 *dest, quint16 value, qsizetype count)
6602
40.8M
{
6603
40.8M
    const int align = quintptr(dest) & 0x3;
6604
40.8M
    if (align) {
6605
0
        *dest++ = value;
6606
0
        --count;
6607
0
    }
6608
6609
40.8M
    if (count & 0x1)
6610
40.8M
        dest[count - 1] = value;
6611
6612
40.8M
    const quint32 value32 = (value << 16) | value;
6613
40.8M
    qt_memfill32(reinterpret_cast<quint32*>(dest), value32, count / 2);
6614
40.8M
}
6615
6616
#if defined(Q_PROCESSOR_X86) || defined(QT_COMPILER_SUPPORTS_LSX)
6617
void (*qt_memfill32)(quint32 *dest, quint32 value, qsizetype count) = nullptr;
6618
void (*qt_memfill64)(quint64 *dest, quint64 value, qsizetype count) = nullptr;
6619
#elif !defined(__ARM_NEON__) && !defined(__MIPS_DSP__)
6620
void qt_memfill32(quint32 *dest, quint32 color, qsizetype count)
6621
{
6622
    qt_memfill_template<quint32>(dest, color, count);
6623
}
6624
#endif
6625
6626
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
6627
template<QtPixelOrder> void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6628
#elif defined(QT_COMPILER_SUPPORTS_LSX)
6629
template<QtPixelOrder> void QT_FASTCALL storeA2RGB30PMFromARGB32PM_lsx(uchar *dest, const uint *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6630
#endif
6631
6632
extern void qInitBlendFunctions();
6633
6634
static void qInitDrawhelperFunctions()
6635
49
{
6636
    // Set up basic blend function tables.
6637
49
    qInitBlendFunctions();
6638
6639
#if defined(Q_PROCESSOR_X86) && !defined(__SSE2__)
6640
    qt_memfill32 = qt_memfill_template<quint32>;
6641
    qt_memfill64 = qt_memfill_template<quint64>;
6642
#elif defined(__SSE2__)
6643
#  ifndef __haswell__
6644
49
    qt_memfill32 = qt_memfill32_sse2;
6645
49
    qt_memfill64 = qt_memfill64_sse2;
6646
49
#  endif
6647
49
    qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2;
6648
49
    qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2;
6649
49
    qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2;
6650
49
    qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse2;
6651
49
    qDrawHelper[QImage::Format_RGBX8888].bitmapBlit = qt_bitmapblit8888_sse2;
6652
49
    qDrawHelper[QImage::Format_RGBA8888].bitmapBlit = qt_bitmapblit8888_sse2;
6653
49
    qDrawHelper[QImage::Format_RGBA8888_Premultiplied].bitmapBlit = qt_bitmapblit8888_sse2;
6654
6655
49
    extern void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
6656
49
                                                     const uchar *srcPixels, int sbpl, int srch,
6657
49
                                                     const QRectF &targetRect,
6658
49
                                                     const QRectF &sourceRect,
6659
49
                                                     const QRect &clip,
6660
49
                                                     int const_alpha);
6661
49
    qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2;
6662
49
    qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2;
6663
49
    qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2;
6664
49
    qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2;
6665
6666
49
    extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
6667
49
                                             const uchar *srcPixels, int sbpl,
6668
49
                                             int w, int h,
6669
49
                                             int const_alpha);
6670
49
    extern void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
6671
49
                                               const uchar *srcPixels, int sbpl,
6672
49
                                               int w, int h,
6673
49
                                               int const_alpha);
6674
6675
49
    qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
6676
49
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
6677
49
    qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
6678
49
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
6679
49
    qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_sse2;
6680
49
    qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_sse2;
6681
49
    qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
6682
49
    qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
6683
6684
49
    extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data,
6685
49
                                                                  int y, int x, int length);
6686
6687
49
    qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2;
6688
6689
49
    extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
6690
49
    extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha);
6691
49
    extern void QT_FASTCALL comp_func_Source_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
6692
49
    extern void QT_FASTCALL comp_func_solid_Source_sse2(uint *destPixels, int length, uint color, uint const_alpha);
6693
49
    extern void QT_FASTCALL comp_func_Plus_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
6694
49
    qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_sse2;
6695
49
    qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_sse2;
6696
49
    qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_sse2;
6697
49
    qt_functionForModeSolid_C[QPainter::CompositionMode_Source] = comp_func_solid_Source_sse2;
6698
49
    qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2;
6699
6700
49
#ifdef QT_COMPILER_SUPPORTS_SSSE3
6701
49
    if (qCpuHasFeature(SSSE3)) {
6702
49
        extern void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl,
6703
49
                                                    const uchar *srcPixels, int sbpl,
6704
49
                                                    int w, int h,
6705
49
                                                    int const_alpha);
6706
6707
49
        extern const uint * QT_FASTCALL qt_fetchUntransformed_888_ssse3(uint *buffer, const Operator *, const QSpanData *data,
6708
49
                                                                        int y, int x, int length);
6709
49
        qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
6710
49
        qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
6711
49
        qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
6712
49
        qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
6713
49
        sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_ssse3;
6714
49
        extern void QT_FASTCALL rbSwap_888_ssse3(uchar *dst, const uchar *src, int count);
6715
49
        qPixelLayouts[QImage::Format_RGB888].rbSwap = rbSwap_888_ssse3;
6716
49
        qPixelLayouts[QImage::Format_BGR888].rbSwap = rbSwap_888_ssse3;
6717
49
    }
6718
49
#endif // SSSE3
6719
6720
49
#if defined(QT_COMPILER_SUPPORTS_SSE4_1)
6721
49
    if (qCpuHasFeature(SSE4_1)) {
6722
49
        extern void QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, int count, const QList<QRgb> *);
6723
49
        extern void QT_FASTCALL convertRGBA8888ToARGB32PM_sse4(uint *buffer, int count, const QList<QRgb> *);
6724
49
        extern const uint *QT_FASTCALL fetchARGB32ToARGB32PM_sse4(uint *buffer, const uchar *src, int index, int count,
6725
49
                                                                  const QList<QRgb> *, QDitherInfo *);
6726
49
        extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_sse4(uint *buffer, const uchar *src, int index, int count,
6727
49
                                                                    const QList<QRgb> *, QDitherInfo *);
6728
49
        extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_sse4(QRgba64 *buffer, const uint *src, int count,
6729
49
                                                                        const QList<QRgb> *, QDitherInfo *);
6730
49
        extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_sse4(QRgba64 *buffer, const uint *src, int count,
6731
49
                                                                          const QList<QRgb> *, QDitherInfo *);
6732
49
        extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_sse4(QRgba64 *buffer, const uchar *src, int index, int count,
6733
49
                                                                     const QList<QRgb> *, QDitherInfo *);
6734
49
        extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_sse4(QRgba64 *buffer, const uchar *src, int index, int count,
6735
49
                                                                       const QList<QRgb> *, QDitherInfo *);
6736
49
        extern void QT_FASTCALL storeARGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
6737
49
                                                                      const QList<QRgb> *, QDitherInfo *);
6738
49
        extern void QT_FASTCALL storeRGBA8888FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
6739
49
                                                                        const QList<QRgb> *, QDitherInfo *);
6740
49
        extern void QT_FASTCALL storeRGBXFromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
6741
49
                                                                    const QList<QRgb> *, QDitherInfo *);
6742
49
        extern void QT_FASTCALL storeARGB32FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
6743
49
                                                             const QList<QRgb> *, QDitherInfo *);
6744
49
        extern void QT_FASTCALL storeRGBA8888FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
6745
49
                                                              const QList<QRgb> *, QDitherInfo *);
6746
49
        extern void QT_FASTCALL storeRGBA64FromRGBA64PM_sse4(uchar *, const QRgba64 *, int, int, const QList<QRgb> *, QDitherInfo *);
6747
49
        extern void QT_FASTCALL storeRGBx64FromRGBA64PM_sse4(uchar *, const QRgba64 *, int, int, const QList<QRgb> *, QDitherInfo *);
6748
49
        extern void QT_FASTCALL destStore64ARGB32_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
6749
49
        extern void QT_FASTCALL destStore64RGBA8888_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
6750
49
#  ifndef __haswell__
6751
49
        qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_sse4;
6752
49
        qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4;
6753
49
        qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_sse4;
6754
49
        qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_sse4;
6755
49
        qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_sse4;
6756
49
        qPixelLayouts[QImage::Format_ARGB32].convertToRGBA64PM = convertARGB32ToRGBA64PM_sse4;
6757
49
        qPixelLayouts[QImage::Format_RGBA8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_sse4;
6758
49
        qPixelLayouts[QImage::Format_RGBA8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_sse4;
6759
49
        qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_sse4;
6760
49
        qPixelLayouts[QImage::Format_RGBX8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_sse4;
6761
49
#  endif
6762
49
        qPixelLayouts[QImage::Format_ARGB32].storeFromARGB32PM = storeARGB32FromARGB32PM_sse4;
6763
49
        qPixelLayouts[QImage::Format_RGBA8888].storeFromARGB32PM = storeRGBA8888FromARGB32PM_sse4;
6764
49
        qPixelLayouts[QImage::Format_RGBX8888].storeFromARGB32PM = storeRGBXFromARGB32PM_sse4;
6765
49
        qPixelLayouts[QImage::Format_A2BGR30_Premultiplied].storeFromARGB32PM = storeA2RGB30PMFromARGB32PM_sse4<PixelOrderBGR>;
6766
49
        qPixelLayouts[QImage::Format_A2RGB30_Premultiplied].storeFromARGB32PM = storeA2RGB30PMFromARGB32PM_sse4<PixelOrderRGB>;
6767
49
        qStoreFromRGBA64PM[QImage::Format_ARGB32] = storeARGB32FromRGBA64PM_sse4;
6768
49
        qStoreFromRGBA64PM[QImage::Format_RGBA8888] = storeRGBA8888FromRGBA64PM_sse4;
6769
49
        qStoreFromRGBA64PM[QImage::Format_RGBX64] = storeRGBx64FromRGBA64PM_sse4;
6770
49
        qStoreFromRGBA64PM[QImage::Format_RGBA64] = storeRGBA64FromRGBA64PM_sse4;
6771
49
#if QT_CONFIG(raster_64bit)
6772
49
        destStoreProc64[QImage::Format_ARGB32] = destStore64ARGB32_sse4;
6773
49
        destStoreProc64[QImage::Format_RGBA8888] = destStore64RGBA8888_sse4;
6774
49
#endif
6775
49
#if QT_CONFIG(raster_fp)
6776
49
        extern const QRgbaFloat32 *QT_FASTCALL fetchRGBA32FToRGBA32F_sse4(QRgbaFloat32 *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6777
49
        extern void QT_FASTCALL storeRGBX32FFromRGBA32F_sse4(uchar *dest, const QRgbaFloat32 *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6778
49
        extern void QT_FASTCALL storeRGBA32FFromRGBA32F_sse4(uchar *dest, const QRgbaFloat32 *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6779
49
        qFetchToRGBA32F[QImage::Format_RGBA32FPx4] = fetchRGBA32FToRGBA32F_sse4;
6780
49
        qStoreFromRGBA32F[QImage::Format_RGBX32FPx4] = storeRGBX32FFromRGBA32F_sse4;
6781
49
        qStoreFromRGBA32F[QImage::Format_RGBA32FPx4] = storeRGBA32FFromRGBA32F_sse4;
6782
49
#endif // QT_CONFIG(raster_fp)
6783
49
    }
6784
49
#endif
6785
6786
49
#if defined(QT_COMPILER_SUPPORTS_AVX2)
6787
49
    if (qCpuHasFeature(ArchHaswell)) {
6788
49
        qt_memfill32 = qt_memfill32_avx2;
6789
49
        qt_memfill64 = qt_memfill64_avx2;
6790
49
        extern void qt_blend_rgb32_on_rgb32_avx2(uchar *destPixels, int dbpl,
6791
49
                                                 const uchar *srcPixels, int sbpl,
6792
49
                                                 int w, int h, int const_alpha);
6793
49
        extern void qt_blend_argb32_on_argb32_avx2(uchar *destPixels, int dbpl,
6794
49
                                                   const uchar *srcPixels, int sbpl,
6795
49
                                                   int w, int h, int const_alpha);
6796
49
        qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_avx2;
6797
49
        qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_avx2;
6798
49
        qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx2;
6799
49
        qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx2;
6800
49
        qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_avx2;
6801
49
        qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_avx2;
6802
49
        qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_avx2;
6803
49
        qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_avx2;
6804
6805
49
        extern void QT_FASTCALL comp_func_Source_avx2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
6806
49
        extern void QT_FASTCALL comp_func_SourceOver_avx2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
6807
49
        extern void QT_FASTCALL comp_func_solid_SourceOver_avx2(uint *destPixels, int length, uint color, uint const_alpha);
6808
49
        qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_avx2;
6809
49
        qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_avx2;
6810
49
        qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_avx2;
6811
49
#if QT_CONFIG(raster_64bit)
6812
49
        extern void QT_FASTCALL comp_func_Source_rgb64_avx2(QRgba64 *destPixels, const QRgba64 *srcPixels, int length, uint const_alpha);
6813
49
        extern void QT_FASTCALL comp_func_SourceOver_rgb64_avx2(QRgba64 *destPixels, const QRgba64 *srcPixels, int length, uint const_alpha);
6814
49
        extern void QT_FASTCALL comp_func_solid_SourceOver_rgb64_avx2(QRgba64 *destPixels, int length, QRgba64 color, uint const_alpha);
6815
49
        qt_functionForMode64_C[QPainter::CompositionMode_Source] = comp_func_Source_rgb64_avx2;
6816
49
        qt_functionForMode64_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_rgb64_avx2;
6817
49
        qt_functionForModeSolid64_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_rgb64_avx2;
6818
49
#endif
6819
49
#if QT_CONFIG(raster_fp)
6820
49
        extern void QT_FASTCALL comp_func_Source_rgbafp_avx2(QRgbaFloat32 *destPixels, const QRgbaFloat32 *srcPixels, int length, uint const_alpha);
6821
49
        extern void QT_FASTCALL comp_func_SourceOver_rgbafp_avx2(QRgbaFloat32 *destPixels, const QRgbaFloat32 *srcPixels, int length, uint const_alpha);
6822
49
        extern void QT_FASTCALL comp_func_solid_Source_rgbafp_avx2(QRgbaFloat32 *destPixels, int length, QRgbaFloat32 color, uint const_alpha);
6823
49
        extern void QT_FASTCALL comp_func_solid_SourceOver_rgbafp_avx2(QRgbaFloat32 *destPixels, int length, QRgbaFloat32 color, uint const_alpha);
6824
49
        qt_functionForModeFP_C[QPainter::CompositionMode_Source] = comp_func_Source_rgbafp_avx2;
6825
49
        qt_functionForModeFP_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_rgbafp_avx2;
6826
49
        qt_functionForModeSolidFP_C[QPainter::CompositionMode_Source] = comp_func_solid_Source_rgbafp_avx2;
6827
49
        qt_functionForModeSolidFP_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_rgbafp_avx2;
6828
49
#endif
6829
6830
49
        extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2(uint *b, uint *end, const QTextureData &image,
6831
49
                                                                                          int &fx, int &fy, int fdx, int /*fdy*/);
6832
49
        extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_downscale_helper_avx2(uint *b, uint *end, const QTextureData &image,
6833
49
                                                                                       int &fx, int &fy, int fdx, int /*fdy*/);
6834
49
        extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2(uint *b, uint *end, const QTextureData &image,
6835
49
                                                                                         int &fx, int &fy, int fdx, int fdy);
6836
6837
49
        bilinearFastTransformHelperARGB32PM[0][SimpleScaleTransform] = fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2;
6838
49
        bilinearFastTransformHelperARGB32PM[0][DownscaleTransform] = fetchTransformedBilinearARGB32PM_downscale_helper_avx2;
6839
49
        bilinearFastTransformHelperARGB32PM[0][FastRotateTransform] = fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2;
6840
6841
49
        extern void QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, int count, const QList<QRgb> *);
6842
49
        extern void QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, int count, const QList<QRgb> *);
6843
49
        extern const uint *QT_FASTCALL fetchARGB32ToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count,
6844
49
                                                                  const QList<QRgb> *, QDitherInfo *);
6845
49
        extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count,
6846
49
                                                                    const QList<QRgb> *, QDitherInfo *);
6847
49
        qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_avx2;
6848
49
        qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_avx2;
6849
49
        qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_avx2;
6850
49
        qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_avx2;
6851
6852
49
        extern const QRgba64 *QT_FASTCALL convertARGB32ToRGBA64PM_avx2(QRgba64 *, const uint *, int, const QList<QRgb> *, QDitherInfo *);
6853
49
        extern const QRgba64 *QT_FASTCALL convertRGBA8888ToRGBA64PM_avx2(QRgba64 *, const uint *, int count, const QList<QRgb> *, QDitherInfo *);
6854
49
        extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_avx2(QRgba64 *, const uchar *, int, int, const QList<QRgb> *, QDitherInfo *);
6855
49
        extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_avx2(QRgba64 *, const uchar *, int, int, const QList<QRgb> *, QDitherInfo *);
6856
49
        extern const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6857
49
        qPixelLayouts[QImage::Format_ARGB32].convertToRGBA64PM = convertARGB32ToRGBA64PM_avx2;
6858
49
        qPixelLayouts[QImage::Format_RGBX8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_avx2;
6859
49
        qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_avx2;
6860
49
        qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_avx2;
6861
49
        qPixelLayouts[QImage::Format_RGBA64].fetchToRGBA64PM = fetchRGBA64ToRGBA64PM_avx2;
6862
6863
49
        extern const uint *QT_FASTCALL fetchRGB16FToRGB32_avx2(uint *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6864
49
        extern const uint *QT_FASTCALL fetchRGBA16FToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6865
49
        extern const QRgba64 *QT_FASTCALL fetchRGBA16FPMToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6866
49
        extern const QRgba64 *QT_FASTCALL fetchRGBA16FToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6867
49
        extern void QT_FASTCALL storeRGB16FFromRGB32_avx2(uchar *dest, const uint *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6868
49
        extern void QT_FASTCALL storeRGBA16FFromARGB32PM_avx2(uchar *dest, const uint *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6869
49
        qPixelLayouts[QImage::Format_RGBX16FPx4].fetchToARGB32PM = fetchRGB16FToRGB32_avx2;
6870
49
        qPixelLayouts[QImage::Format_RGBX16FPx4].fetchToRGBA64PM = fetchRGBA16FPMToRGBA64PM_avx2;
6871
49
        qPixelLayouts[QImage::Format_RGBX16FPx4].storeFromARGB32PM = storeRGB16FFromRGB32_avx2;
6872
49
        qPixelLayouts[QImage::Format_RGBX16FPx4].storeFromRGB32 = storeRGB16FFromRGB32_avx2;
6873
49
        qPixelLayouts[QImage::Format_RGBA16FPx4].fetchToARGB32PM = fetchRGBA16FToARGB32PM_avx2;
6874
49
        qPixelLayouts[QImage::Format_RGBA16FPx4].fetchToRGBA64PM = fetchRGBA16FToRGBA64PM_avx2;
6875
49
        qPixelLayouts[QImage::Format_RGBA16FPx4].storeFromARGB32PM = storeRGBA16FFromARGB32PM_avx2;
6876
49
        qPixelLayouts[QImage::Format_RGBA16FPx4].storeFromRGB32 = storeRGB16FFromRGB32_avx2;
6877
49
        qPixelLayouts[QImage::Format_RGBA16FPx4_Premultiplied].fetchToARGB32PM = fetchRGB16FToRGB32_avx2;
6878
49
        qPixelLayouts[QImage::Format_RGBA16FPx4_Premultiplied].fetchToRGBA64PM = fetchRGBA16FPMToRGBA64PM_avx2;
6879
49
        qPixelLayouts[QImage::Format_RGBA16FPx4_Premultiplied].storeFromARGB32PM = storeRGB16FFromRGB32_avx2;
6880
49
        qPixelLayouts[QImage::Format_RGBA16FPx4_Premultiplied].storeFromRGB32 = storeRGB16FFromRGB32_avx2;
6881
49
#if QT_CONFIG(raster_fp)
6882
49
        extern const QRgbaFloat32 *QT_FASTCALL fetchRGBA16FToRGBA32F_avx2(QRgbaFloat32 *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6883
49
        extern void QT_FASTCALL storeRGBX16FFromRGBA32F_avx2(uchar *dest, const QRgbaFloat32 *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6884
49
        extern void QT_FASTCALL storeRGBA16FFromRGBA32F_avx2(uchar *dest, const QRgbaFloat32 *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
6885
49
        qFetchToRGBA32F[QImage::Format_RGBA16FPx4] = fetchRGBA16FToRGBA32F_avx2;
6886
49
        qStoreFromRGBA32F[QImage::Format_RGBX16FPx4] = storeRGBX16FFromRGBA32F_avx2;
6887
49
        qStoreFromRGBA32F[QImage::Format_RGBA16FPx4] = storeRGBA16FFromRGBA32F_avx2;
6888
49
#endif // QT_CONFIG(raster_fp)
6889
49
    }
6890
6891
49
#endif
6892
6893
49
#endif // SSE2
6894
6895
#if defined(QT_COMPILER_SUPPORTS_LSX)
6896
    if (qCpuHasFeature(LSX)) {
6897
        qt_memfill32 = qt_memfill32_lsx;
6898
        qt_memfill64 = qt_memfill64_lsx;
6899
6900
        qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_lsx;
6901
        qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_lsx;
6902
        qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_lsx;
6903
        qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_lsx;
6904
        qDrawHelper[QImage::Format_RGBX8888].bitmapBlit = qt_bitmapblit8888_lsx;
6905
        qDrawHelper[QImage::Format_RGBA8888].bitmapBlit = qt_bitmapblit8888_lsx;
6906
        qDrawHelper[QImage::Format_RGBA8888_Premultiplied].bitmapBlit = qt_bitmapblit8888_lsx;
6907
6908
        extern void qt_scale_image_argb32_on_argb32_lsx(uchar *destPixels, int dbpl,
6909
                                                        const uchar *srcPixels, int sbpl, int srch,
6910
                                                        const QRectF &targetRect,
6911
                                                        const QRectF &sourceRect,
6912
                                                        const QRect &clip,
6913
                                                        int const_alpha);
6914
6915
        qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_lsx;
6916
        qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_lsx;
6917
        qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_lsx;
6918
        qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_lsx;
6919
6920
        extern void qt_blend_rgb32_on_rgb32_lsx(uchar *destPixels, int dbpl,
6921
                                                const uchar *srcPixels, int sbpl,
6922
                                                int w, int h,
6923
                                                int const_alpha);
6924
6925
        extern void qt_blend_argb32_on_argb32_lsx(uchar *destPixels, int dbpl,
6926
                                                  const uchar *srcPixels, int sbpl,
6927
                                                  int w, int h,
6928
                                                  int const_alpha);
6929
6930
        qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_lsx;
6931
        qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_lsx;
6932
        qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_lsx;
6933
        qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_lsx;
6934
        qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_lsx;
6935
        qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_lsx;
6936
        qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_lsx;
6937
        qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_lsx;
6938
6939
        extern const uint * QT_FASTCALL qt_fetch_radial_gradient_lsx(uint *buffer, const Operator *op, const QSpanData *data,
6940
                                                                     int y, int x, int length);
6941
6942
        qt_fetch_radial_gradient = qt_fetch_radial_gradient_lsx;
6943
6944
        extern void QT_FASTCALL comp_func_SourceOver_lsx(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
6945
        extern void QT_FASTCALL comp_func_solid_SourceOver_lsx(uint *destPixels, int length, uint color, uint const_alpha);
6946
        extern void QT_FASTCALL comp_func_Source_lsx(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
6947
        extern void QT_FASTCALL comp_func_solid_Source_lsx(uint *destPixels, int length, uint color, uint const_alpha);
6948
        extern void QT_FASTCALL comp_func_Plus_lsx(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
6949
        qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_lsx;
6950
        qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_lsx;
6951
        qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_lsx;
6952
        qt_functionForModeSolid_C[QPainter::CompositionMode_Source] = comp_func_solid_Source_lsx;
6953
        qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_lsx;
6954
6955
        extern const uint * QT_FASTCALL qt_fetchUntransformed_888_lsx(uint *buffer, const Operator *, const QSpanData *data,
6956
                                                                      int y, int x, int length);
6957
        sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_lsx;
6958
        extern void QT_FASTCALL rbSwap_888_lsx(uchar *dst, const uchar *src, int count);
6959
        qPixelLayouts[QImage::Format_RGB888].rbSwap = rbSwap_888_lsx;
6960
        qPixelLayouts[QImage::Format_BGR888].rbSwap = rbSwap_888_lsx;
6961
6962
        extern void QT_FASTCALL convertARGB32ToARGB32PM_lsx(uint *buffer, int count, const QList<QRgb> *);
6963
        extern void QT_FASTCALL convertRGBA8888ToARGB32PM_lsx(uint *buffer, int count, const QList<QRgb> *);
6964
        extern const uint *QT_FASTCALL fetchARGB32ToARGB32PM_lsx(uint *buffer, const uchar *src, int index, int count,
6965
                                                                 const QList<QRgb> *, QDitherInfo *);
6966
        extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_lsx(uint *buffer, const uchar *src, int index, int count,
6967
                                                                   const QList<QRgb> *, QDitherInfo *);
6968
        extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_lsx(QRgba64 *buffer, const uint *src, int count,
6969
                                                                       const QList<QRgb> *, QDitherInfo *);
6970
        extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_lsx(QRgba64 *buffer, const uint *src, int count,
6971
                                                                         const QList<QRgb> *, QDitherInfo *);
6972
        extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_lsx(QRgba64 *buffer, const uchar *src, int index, int count,
6973
                                                                    const QList<QRgb> *, QDitherInfo *);
6974
        extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_lsx(QRgba64 *buffer, const uchar *src, int index, int count,
6975
                                                                      const QList<QRgb> *, QDitherInfo *);
6976
        extern void QT_FASTCALL storeARGB32FromARGB32PM_lsx(uchar *dest, const uint *src, int index, int count,
6977
                                                            const QList<QRgb> *, QDitherInfo *);
6978
        extern void QT_FASTCALL storeRGBA8888FromARGB32PM_lsx(uchar *dest, const uint *src, int index, int count,
6979
                                                              const QList<QRgb> *, QDitherInfo *);
6980
        extern void QT_FASTCALL storeRGBXFromARGB32PM_lsx(uchar *dest, const uint *src, int index, int count,
6981
                                                          const QList<QRgb> *, QDitherInfo *);
6982
        extern void QT_FASTCALL storeARGB32FromRGBA64PM_lsx(uchar *dest, const QRgba64 *src, int index, int count,
6983
                                                            const QList<QRgb> *, QDitherInfo *);
6984
        extern void QT_FASTCALL storeRGBA8888FromRGBA64PM_lsx(uchar *dest, const QRgba64 *src, int index, int count,
6985
                                                              const QList<QRgb> *, QDitherInfo *);
6986
        extern void QT_FASTCALL destStore64ARGB32_lsx(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
6987
        extern void QT_FASTCALL destStore64RGBA8888_lsx(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
6988
        extern void QT_FASTCALL storeRGBA64FromRGBA64PM_lsx(uchar *, const QRgba64 *, int, int, const QList<QRgb> *, QDitherInfo *);
6989
        extern void QT_FASTCALL storeRGBx64FromRGBA64PM_lsx(uchar *, const QRgba64 *, int, int, const QList<QRgb> *, QDitherInfo *);
6990
        qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_lsx;
6991
        qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_lsx;
6992
        qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_lsx;
6993
        qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_lsx;
6994
        qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_lsx;
6995
        qPixelLayouts[QImage::Format_ARGB32].convertToRGBA64PM = convertARGB32ToRGBA64PM_lsx;
6996
        qPixelLayouts[QImage::Format_RGBA8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_lsx;
6997
        qPixelLayouts[QImage::Format_RGBA8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_lsx;
6998
        qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_lsx;
6999
        qPixelLayouts[QImage::Format_RGBX8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_lsx;
7000
        qPixelLayouts[QImage::Format_ARGB32].storeFromARGB32PM = storeARGB32FromARGB32PM_lsx;
7001
        qPixelLayouts[QImage::Format_RGBA8888].storeFromARGB32PM = storeRGBA8888FromARGB32PM_lsx;
7002
        qPixelLayouts[QImage::Format_RGBX8888].storeFromARGB32PM = storeRGBXFromARGB32PM_lsx;
7003
        qPixelLayouts[QImage::Format_A2BGR30_Premultiplied].storeFromARGB32PM = storeA2RGB30PMFromARGB32PM_lsx<PixelOrderBGR>;
7004
        qPixelLayouts[QImage::Format_A2RGB30_Premultiplied].storeFromARGB32PM = storeA2RGB30PMFromARGB32PM_lsx<PixelOrderRGB>;
7005
        qStoreFromRGBA64PM[QImage::Format_ARGB32] = storeARGB32FromRGBA64PM_lsx;
7006
        qStoreFromRGBA64PM[QImage::Format_RGBA8888] = storeRGBA8888FromRGBA64PM_lsx;
7007
        qStoreFromRGBA64PM[QImage::Format_RGBX64] = storeRGBx64FromRGBA64PM_lsx;
7008
        qStoreFromRGBA64PM[QImage::Format_RGBA64] = storeRGBA64FromRGBA64PM_lsx;
7009
#if QT_CONFIG(raster_64bit)
7010
        destStoreProc64[QImage::Format_ARGB32] = destStore64ARGB32_lsx;
7011
        destStoreProc64[QImage::Format_RGBA8888] = destStore64RGBA8888_lsx;
7012
#endif
7013
#if QT_CONFIG(raster_fp)
7014
        extern const QRgbaFloat32 *QT_FASTCALL fetchRGBA32FToRGBA32F_lsx(QRgbaFloat32 *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
7015
        extern void QT_FASTCALL storeRGBX32FFromRGBA32F_lsx(uchar *dest, const QRgbaFloat32 *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
7016
        extern void QT_FASTCALL storeRGBA32FFromRGBA32F_lsx(uchar *dest, const QRgbaFloat32 *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
7017
        qFetchToRGBA32F[QImage::Format_RGBA32FPx4] = fetchRGBA32FToRGBA32F_lsx;
7018
        qStoreFromRGBA32F[QImage::Format_RGBX32FPx4] = storeRGBX32FFromRGBA32F_lsx;
7019
        qStoreFromRGBA32F[QImage::Format_RGBA32FPx4] = storeRGBA32FFromRGBA32F_lsx;
7020
#endif // QT_CONFIG(raster_fp)
7021
    }
7022
7023
#if defined(QT_COMPILER_SUPPORTS_LASX)
7024
    if (qCpuHasFeature(LASX)) {
7025
        qt_memfill32 = qt_memfill32_lasx;
7026
        qt_memfill64 = qt_memfill64_lasx;
7027
7028
        extern void qt_blend_rgb32_on_rgb32_lasx(uchar *destPixels, int dbpl,
7029
                                                 const uchar *srcPixels, int sbpl,
7030
                                                 int w, int h, int const_alpha);
7031
        extern void qt_blend_argb32_on_argb32_lasx(uchar *destPixels, int dbpl,
7032
                                                   const uchar *srcPixels, int sbpl,
7033
                                                   int w, int h, int const_alpha);
7034
        qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_lasx;
7035
        qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_lasx;
7036
        qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_lasx;
7037
        qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_lasx;
7038
        qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_lasx;
7039
        qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_lasx;
7040
        qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_lasx;
7041
        qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_lasx;
7042
7043
        extern void QT_FASTCALL comp_func_Source_lasx(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
7044
        extern void QT_FASTCALL comp_func_SourceOver_lasx(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
7045
        extern void QT_FASTCALL comp_func_solid_SourceOver_lasx(uint *destPixels, int length, uint color, uint const_alpha);
7046
        qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_lasx;
7047
        qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_lasx;
7048
        qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_lasx;
7049
#if QT_CONFIG(raster_64bit)
7050
        extern void QT_FASTCALL comp_func_Source_rgb64_lasx(QRgba64 *destPixels, const QRgba64 *srcPixels, int length, uint const_alpha);
7051
        extern void QT_FASTCALL comp_func_solid_SourceOver_rgb64_lasx(QRgba64 *destPixels, int length, QRgba64 color, uint const_alpha);
7052
        qt_functionForMode64_C[QPainter::CompositionMode_Source] = comp_func_Source_rgb64_lasx;
7053
        qt_functionForModeSolid64_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_rgb64_lasx;
7054
#endif
7055
7056
        extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper_lasx(uint *b, uint *end, const QTextureData &image,
7057
                                                                                          int &fx, int &fy, int fdx, int /*fdy*/);
7058
        extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_downscale_helper_lasx(uint *b, uint *end, const QTextureData &image,
7059
                                                                                       int &fx, int &fy, int fdx, int /*fdy*/);
7060
        extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper_lasx(uint *b, uint *end, const QTextureData &image,
7061
                                                                                         int &fx, int &fy, int fdx, int fdy);
7062
7063
        bilinearFastTransformHelperARGB32PM[0][SimpleScaleTransform] = fetchTransformedBilinearARGB32PM_simple_scale_helper_lasx;
7064
        bilinearFastTransformHelperARGB32PM[0][DownscaleTransform] = fetchTransformedBilinearARGB32PM_downscale_helper_lasx;
7065
        bilinearFastTransformHelperARGB32PM[0][FastRotateTransform] = fetchTransformedBilinearARGB32PM_fast_rotate_helper_lasx;
7066
7067
        extern void QT_FASTCALL convertARGB32ToARGB32PM_lasx(uint *buffer, int count, const QList<QRgb> *);
7068
        extern void QT_FASTCALL convertRGBA8888ToARGB32PM_lasx(uint *buffer, int count, const QList<QRgb> *);
7069
        extern const uint *QT_FASTCALL fetchARGB32ToARGB32PM_lasx(uint *buffer, const uchar *src, int index, int count,
7070
                                                                  const QList<QRgb> *, QDitherInfo *);
7071
        extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_lasx(uint *buffer, const uchar *src, int index, int count,
7072
                                                                    const QList<QRgb> *, QDitherInfo *);
7073
        qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_lasx;
7074
        qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_lasx;
7075
        qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_lasx;
7076
        qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_lasx;
7077
7078
        extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_lasx(QRgba64 *, const uint *, int, const QList<QRgb> *, QDitherInfo *);
7079
        extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_lasx(QRgba64 *, const uint *, int count, const QList<QRgb> *, QDitherInfo *);
7080
        extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_lasx(QRgba64 *, const uchar *, int, int, const QList<QRgb> *, QDitherInfo *);
7081
        extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_lasx(QRgba64 *, const uchar *, int, int, const QList<QRgb> *, QDitherInfo *);
7082
        qPixelLayouts[QImage::Format_ARGB32].convertToRGBA64PM = convertARGB32ToRGBA64PM_lasx;
7083
        qPixelLayouts[QImage::Format_RGBX8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_lasx;
7084
        qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_lasx;
7085
        qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_lasx;
7086
    }
7087
#endif  //QT_COMPILER_SUPPORTS_LASX
7088
7089
#endif //QT_COMPILER_SUPPORTS_LSX
7090
7091
#if defined(__ARM_NEON__)
7092
    qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
7093
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
7094
    qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
7095
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
7096
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
7097
    qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_neon;
7098
    qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_neon;
7099
    qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_neon;
7100
    qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_neon;
7101
#endif
7102
7103
    qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_neon;
7104
    qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon;
7105
    qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon;
7106
7107
    extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data,
7108
                                                                  int y, int x, int length);
7109
7110
    qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon;
7111
7112
    sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_neon;
7113
7114
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
7115
    extern void QT_FASTCALL convertARGB32ToARGB32PM_neon(uint *buffer, int count, const QList<QRgb> *);
7116
    extern void QT_FASTCALL convertRGBA8888ToARGB32PM_neon(uint *buffer, int count, const QList<QRgb> *);
7117
    extern const uint *QT_FASTCALL fetchARGB32ToARGB32PM_neon(uint *buffer, const uchar *src, int index, int count,
7118
                                                              const QList<QRgb> *, QDitherInfo *);
7119
    extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_neon(uint *buffer, const uchar *src, int index, int count,
7120
                                                                const QList<QRgb> *, QDitherInfo *);
7121
   extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count,
7122
                                                                   const QList<QRgb> *, QDitherInfo *);
7123
   extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count,
7124
                                                                     const QList<QRgb> *, QDitherInfo *);
7125
   extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_neon(QRgba64 *buffer, const uchar *src, int index, int count,
7126
                                                                const QList<QRgb> *, QDitherInfo *);
7127
   extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_neon(QRgba64 *buffer, const uchar *src, int index, int count,
7128
                                                                  const QList<QRgb> *, QDitherInfo *);
7129
    extern void QT_FASTCALL storeARGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
7130
                                                         const QList<QRgb> *, QDitherInfo *);
7131
    extern void QT_FASTCALL storeRGBA8888FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
7132
                                                           const QList<QRgb> *, QDitherInfo *);
7133
    extern void QT_FASTCALL storeRGBXFromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
7134
                                                       const QList<QRgb> *, QDitherInfo *);
7135
    qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_neon;
7136
    qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_neon;
7137
    qPixelLayouts[QImage::Format_ARGB32].storeFromARGB32PM = storeARGB32FromARGB32PM_neon;
7138
    qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_neon;
7139
    qPixelLayouts[QImage::Format_ARGB32].convertToRGBA64PM = convertARGB32ToRGBA64PM_neon;
7140
    qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_neon;
7141
    qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_neon;
7142
    qPixelLayouts[QImage::Format_RGBA8888].storeFromARGB32PM = storeRGBA8888FromARGB32PM_neon;
7143
    qPixelLayouts[QImage::Format_RGBA8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_neon;
7144
    qPixelLayouts[QImage::Format_RGBA8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_neon;
7145
    qPixelLayouts[QImage::Format_RGBX8888].storeFromARGB32PM = storeRGBXFromARGB32PM_neon;
7146
    qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_neon;
7147
    qPixelLayouts[QImage::Format_RGBX8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_neon;
7148
#endif
7149
7150
#if defined(ENABLE_PIXMAN_DRAWHELPERS)
7151
    // The RGB16 helpers are using Arm32 assemblythat has not been ported to AArch64
7152
    qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon;
7153
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB16] = qt_blend_rgb16_on_argb32_neon;
7154
    qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_neon;
7155
7156
    qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16_neon;
7157
    qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16_neon;
7158
7159
    qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16_neon;
7160
    qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16_neon;
7161
7162
    qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon;
7163
7164
    destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon;
7165
    destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon;
7166
7167
    qMemRotateFunctions[QPixelLayout::BPP16][0] = qt_memrotate90_16_neon;
7168
    qMemRotateFunctions[QPixelLayout::BPP16][2] = qt_memrotate270_16_neon;
7169
#endif
7170
#endif // defined(__ARM_NEON__)
7171
7172
#if defined(__MIPS_DSP__)
7173
    // Composition functions are all DSP r1
7174
    qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_asm_mips_dsp;
7175
    qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_mips_dsp;
7176
    qt_functionForMode_C[QPainter::CompositionMode_DestinationOver] = comp_func_DestinationOver_mips_dsp;
7177
    qt_functionForMode_C[QPainter::CompositionMode_SourceIn] = comp_func_SourceIn_mips_dsp;
7178
    qt_functionForMode_C[QPainter::CompositionMode_DestinationIn] = comp_func_DestinationIn_mips_dsp;
7179
    qt_functionForMode_C[QPainter::CompositionMode_DestinationOut] = comp_func_DestinationOut_mips_dsp;
7180
    qt_functionForMode_C[QPainter::CompositionMode_SourceAtop] = comp_func_SourceAtop_mips_dsp;
7181
    qt_functionForMode_C[QPainter::CompositionMode_DestinationAtop] = comp_func_DestinationAtop_mips_dsp;
7182
    qt_functionForMode_C[QPainter::CompositionMode_Xor] = comp_func_XOR_mips_dsp;
7183
    qt_functionForMode_C[QPainter::CompositionMode_SourceOut] = comp_func_SourceOut_mips_dsp;
7184
7185
    qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_mips_dsp;
7186
    qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationOver] = comp_func_solid_DestinationOver_mips_dsp;
7187
    qt_functionForModeSolid_C[QPainter::CompositionMode_SourceIn] = comp_func_solid_SourceIn_mips_dsp;
7188
    qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationIn] = comp_func_solid_DestinationIn_mips_dsp;
7189
    qt_functionForModeSolid_C[QPainter::CompositionMode_SourceAtop] = comp_func_solid_SourceAtop_mips_dsp;
7190
    qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationAtop] = comp_func_solid_DestinationAtop_mips_dsp;
7191
    qt_functionForModeSolid_C[QPainter::CompositionMode_Xor] = comp_func_solid_XOR_mips_dsp;
7192
    qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOut] = comp_func_solid_SourceOut_mips_dsp;
7193
7194
    qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp;
7195
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp;
7196
    qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mips_dsp;
7197
    qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mips_dsp;
7198
7199
    destFetchProc[QImage::Format_ARGB32] = qt_destFetchARGB32_mips_dsp;
7200
7201
    destStoreProc[QImage::Format_ARGB32] = qt_destStoreARGB32_mips_dsp;
7202
7203
    sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_mips_dsp;
7204
    sourceFetchUntransformed[QImage::Format_RGB444] = qt_fetchUntransformed_444_mips_dsp;
7205
    sourceFetchUntransformed[QImage::Format_ARGB8565_Premultiplied] = qt_fetchUntransformed_argb8565_premultiplied_mips_dsp;
7206
7207
#if defined(__MIPS_DSPR2__)
7208
    qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_mips_dspr2;
7209
    sourceFetchUntransformed[QImage::Format_RGB16] = qt_fetchUntransformedRGB16_mips_dspr2;
7210
#else
7211
    qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_mips_dsp;
7212
#endif // defined(__MIPS_DSPR2__)
7213
#endif // defined(__MIPS_DSP__)
7214
49
}
7215
7216
// Ensure initialization if this object file is linked.
7217
Q_CONSTRUCTOR_FUNCTION(qInitDrawhelperFunctions);
7218
7219
QT_END_NAMESPACE