summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-18 17:03:58 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-05-26 18:00:01 +0200
commit93cd9130d6d8d30e901dd3b2f2546dbc63754e2e (patch)
tree3def7382cd1e4edd4ff380587deee775e48a2e4b /src/gui
parente51831260a759b58cb089cac089c202a795fc584 (diff)
Introduce float QImage formats and rendering
Useful for some HDR representations and HDR rendering. Change-Id: If6e8a661faa3d2afdf17b6ed4d8ff5c5b2aeb30e Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/CMakeLists.txt1
-rw-r--r--src/gui/configure.cmake5
-rw-r--r--src/gui/configure.json6
-rw-r--r--src/gui/image/qimage.cpp277
-rw-r--r--src/gui/image/qimage.h8
-rw-r--r--src/gui/image/qimage_conversions.cpp221
-rw-r--r--src/gui/image/qimage_p.h51
-rw-r--r--src/gui/painting/qcompositionfunctions.cpp1250
-rw-r--r--src/gui/painting/qdrawhelper.cpp1319
-rw-r--r--src/gui/painting/qdrawhelper_avx2.cpp385
-rw-r--r--src/gui/painting/qdrawhelper_p.h133
-rw-r--r--src/gui/painting/qdrawhelper_sse4.cpp75
-rw-r--r--src/gui/painting/qimagescale.cpp223
-rw-r--r--src/gui/painting/qmemrotate.cpp66
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp6
-rw-r--r--src/gui/painting/qpixellayout.cpp847
-rw-r--r--src/gui/painting/qpixellayout_p.h32
-rw-r--r--src/gui/painting/qrgbaf.h135
-rw-r--r--src/gui/painting/qrgbaf.qdoc248
19 files changed, 5020 insertions, 268 deletions
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index c46075d3ed..7eb901f778 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -195,6 +195,7 @@ qt_internal_add_module(Gui
painting/qregion.cpp painting/qregion.h
painting/qrgb.h
painting/qrgba64.h painting/qrgba64_p.h
+ painting/qrgbaf.h
painting/qstroker.cpp painting/qstroker_p.h
painting/qtextureglyphcache.cpp painting/qtextureglyphcache_p.h
painting/qtransform.cpp painting/qtransform.h
diff --git a/src/gui/configure.cmake b/src/gui/configure.cmake
index 5650126326..49b4753870 100644
--- a/src/gui/configure.cmake
+++ b/src/gui/configure.cmake
@@ -1154,6 +1154,11 @@ qt_feature("raster-64bit" PRIVATE
LABEL "QPainter - 64 bit raster"
PURPOSE "Internal painting support for 64 bit (16 bpc) rasterization."
)
+qt_feature("raster-fp" PRIVATE
+ SECTION "Painting"
+ LABEL "QPainter - floating point raster"
+ PURPOSE "Internal painting support for floating point rasterization."
+)
qt_feature("undocommand" PUBLIC
SECTION "Utilities"
LABEL "QUndoCommand"
diff --git a/src/gui/configure.json b/src/gui/configure.json
index f8c945fc21..47398c9a4e 100644
--- a/src/gui/configure.json
+++ b/src/gui/configure.json
@@ -1663,6 +1663,12 @@
"section": "Painting",
"output": [ "privateFeature" ]
},
+ "raster-fp": {
+ "label": "QPainter - floating point raster",
+ "purpose": "Internal painting support for floating point rasterization.",
+ "section": "Painting",
+ "output": [ "privateFeature" ]
+ },
"undocommand": {
"label": "QUndoCommand",
"purpose": "Applies (redo or) undo of a single change in a document.",
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 95be9772c8..4ee781a383 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -42,10 +42,12 @@
#include "qbuffer.h"
#include "qdatastream.h"
#include "qcolortransform.h"
+#include "qfloat16.h"
#include "qmap.h"
#include "qtransform.h"
#include "qimagereader.h"
#include "qimagewriter.h"
+#include "qrgbaf.h"
#include "qstringlist.h"
#include "qvariant.h"
#include "qimagepixmapcleanuphooks_p.h"
@@ -293,6 +295,24 @@ bool QImageData::checkForAlphaPixels() const
bits += bytes_per_line;
}
} break;
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied: {
+ uchar *bits = data;
+ for (int y = 0; y < height && !has_alpha_pixels; ++y) {
+ for (int x = 0; x < width; ++x)
+ has_alpha_pixels |= ((qfloat16 *)bits)[x * 4 + 3] < 1.0f;
+ bits += bytes_per_line;
+ }
+ } break;
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied: {
+ uchar *bits = data;
+ for (int y = 0; y < height && !has_alpha_pixels; ++y) {
+ for (int x = 0; x < width; ++x)
+ has_alpha_pixels |= ((float *)bits)[x * 4 + 3] < 1.0f;
+ bits += bytes_per_line;
+ }
+ } break;
case QImage::Format_RGB32:
case QImage::Format_RGB16:
@@ -307,6 +327,8 @@ bool QImageData::checkForAlphaPixels() const
case QImage::Format_Grayscale8:
case QImage::Format_Grayscale16:
case QImage::Format_RGBX64:
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBX32FPx4:
break;
case QImage::Format_Invalid:
case QImage::NImageFormats:
@@ -735,6 +757,16 @@ bool QImageData::checkForAlphaPixels() const
\value Format_RGBA64_Premultiplied The image is stored using a premultiplied 64-bit halfword-ordered
RGBA format (16-16-16-16). (added in Qt 5.12)
\value Format_BGR888 The image is stored using a 24-bit BGR format. (added in Qt 5.14)
+ \value Format_RGBX16FPx4 The image is stored using a 4 16-bit halfword floating point RGBx format (16FP-16FP-16FP-16FP).
+ This is the same as the Format_RGBA16FPx4 except alpha must always be 1.0. (added in Qt 6.2)
+ \value Format_RGBA16FPx4 The image is stored using a 4 16-bit halfword floating point RGBA format (16FP-16FP-16FP-16FP). (added in Qt 6.2)
+ \value Format_RGBA16FPx4_Premultiplied The image is stored using a premultiplied 4 16-bit halfword floating point
+ RGBA format (16FP-16FP-16FP-16FP). (added in Qt 6.2)
+ \value Format_RGBX32FPx4 The image is stored using a 4 32-bit floating point RGBx format (32FP-32FP-32FP-32FP).
+ This is the same as the Format_RGBA32FPx4 except alpha must always be 1.0. (added in Qt 6.2)
+ \value Format_RGBA32FPx4 The image is stored using a 4 32-bit floating point RGBA format (32FP-32FP-32FP-32FP). (added in Qt 6.2)
+ \value Format_RGBA32FPx4_Premultiplied The image is stored using a premultiplied 4 32-bit floating point
+ RGBA format (32FP-32FP-32FP-32FP). (added in Qt 6.2)
\note Drawing into a QImage with QImage::Format_Indexed8 is not
supported.
@@ -1741,11 +1773,29 @@ void QImage::fill(uint pixel)
qt_rectfill<quint24>(reinterpret_cast<quint24*>(d->data), pixel,
0, 0, d->width, d->height, d->bytes_per_line);
return;
- } else if (d->depth == 64) {
+ } else if (d->format >= QImage::Format_RGBX64 && d->format <= QImage::Format_RGBA64_Premultiplied) {
qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), QRgba64::fromArgb32(pixel),
0, 0, d->width, d->height, d->bytes_per_line);
return;
+ } else if (d->format >= QImage::Format_RGBX16FPx4 && d->format <= QImage::Format_RGBA16FPx4_Premultiplied) {
+ quint64 cu;
+ QRgba16F cf = QRgba16F::fromArgb32(pixel);
+ ::memcpy(&cu, &cf, sizeof(quint64));
+ qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), cu,
+ 0, 0, d->width, d->height, d->bytes_per_line);
+ return;
+ } else if (d->format >= QImage::Format_RGBX32FPx4 && d->format <= QImage::Format_RGBA32FPx4_Premultiplied) {
+ QRgba32F cf = QRgba32F::fromArgb32(pixel);
+ uchar *data = d->data;
+ for (int y = 0; y < d->height; ++y) {
+ QRgba32F *line = reinterpret_cast<QRgba32F *>(data);
+ for (int x = 0; x < d->width; ++x)
+ line[x] = cf;
+ data += d->bytes_per_line;
+ }
+ return;
}
+ Q_ASSERT(d->depth == 32);
if (d->format == Format_RGB32)
pixel |= 0xff000000;
@@ -1907,7 +1957,13 @@ void QImage::invertPixels(InvertMode mode)
QImage::Format originalFormat = d->format;
// Inverting premultiplied pixels would produce invalid image data.
if (hasAlphaChannel() && qPixelLayouts[d->format].premultiplied) {
- if (depth() > 32) {
+ if (d->format == QImage::Format_RGBA16FPx4_Premultiplied) {
+ if (!d->convertInPlace(QImage::Format_RGBA16FPx4, { }))
+ *this = convertToFormat(QImage::Format_RGBA16FPx4);
+ } else if (d->format == QImage::Format_RGBA32FPx4_Premultiplied) {
+ if (!d->convertInPlace(QImage::Format_RGBA32FPx4, { }))
+ *this = convertToFormat(QImage::Format_RGBA32FPx4);
+ } else if (depth() > 32) {
if (!d->convertInPlace(QImage::Format_RGBA64, { }))
*this = convertToFormat(QImage::Format_RGBA64);
} else {
@@ -1926,8 +1982,32 @@ void QImage::invertPixels(InvertMode mode)
*sl++ ^= 0xff;
sl += pad;
}
- }
- else if (depth() == 64) {
+ } else if (format() >= QImage::Format_RGBX16FPx4 && format() <= QImage::Format_RGBA16FPx4_Premultiplied) {
+ qfloat16 *p = reinterpret_cast<qfloat16 *>(d->data);
+ qfloat16 *end = reinterpret_cast<qfloat16 *>(d->data + d->nbytes);
+ while (p < end) {
+ p[0] = 1.0f - p[0];
+ p[1] = 1.0f - p[1];
+ p[2] = 1.0f - p[2];
+ if (mode == InvertRgba)
+ p[3] = 1.0f - p[3];
+ p += 4;
+ }
+ } else if (format() >= QImage::Format_RGBX32FPx4 && format() <= QImage::Format_RGBA32FPx4_Premultiplied) {
+ uchar *data = d->data;
+ for (int y = 0; y < d->height; ++y) {
+ float *p = reinterpret_cast<float *>(data);
+ for (int x = 0; x < d->width; ++x) {
+ p[0] = 1.0f - p[0];
+ p[1] = 1.0f - p[1];
+ p[2] = 1.0f - p[2];
+ if (mode == InvertRgba)
+ p[3] = 1.0f - p[3];
+ p += 4;
+ }
+ data += d->bytes_per_line;
+ }
+ } else if (depth() == 64) {
quint16 *p = (quint16*)d->data;
quint16 *end = (quint16*)(d->data + d->nbytes);
quint16 xorbits = 0xffff;
@@ -2085,7 +2165,12 @@ QImage QImage::convertToFormat_helper(Format format, Qt::ImageConversionFlags fl
if (!converter && format > QImage::Format_Indexed8 && d->format > QImage::Format_Indexed8) {
if (qt_highColorPrecision(d->format, !destLayout->hasAlphaChannel)
&& qt_highColorPrecision(format, !hasAlphaChannel())) {
- converter = convert_generic_over_rgb64;
+#if QT_CONFIG(raster_fp)
+ if (qt_fpColorPrecision(d->format) && qt_fpColorPrecision(format))
+ converter = convert_generic_over_rgba32f;
+ else
+#endif
+ converter = convert_generic_over_rgb64;
} else
converter = convert_generic;
}
@@ -2418,6 +2503,14 @@ QRgb QImage::pixel(int x, int y) const
case Format_RGBA64: // Match ARGB32 behavior.
case Format_RGBA64_Premultiplied:
return reinterpret_cast<const QRgba64 *>(s)[x].toArgb32();
+ case Format_RGBX16FPx4:
+ case Format_RGBA16FPx4: // Match ARGB32 behavior.
+ case Format_RGBA16FPx4_Premultiplied:
+ return reinterpret_cast<const QRgba16F *>(s)[x].toArgb32();
+ case Format_RGBX32FPx4:
+ case Format_RGBA32FPx4: // Match ARGB32 behavior.
+ case Format_RGBA32FPx4_Premultiplied:
+ return reinterpret_cast<const QRgba32F *>(s)[x].toArgb32();
default:
break;
}
@@ -2519,6 +2612,20 @@ void QImage::setPixel(int x, int y, uint index_or_rgb)
case Format_RGBA64_Premultiplied:
((QRgba64 *)s)[x] = QRgba64::fromArgb32(index_or_rgb);
return;
+ case Format_RGBX16FPx4:
+ ((QRgba16F *)s)[x] = QRgba16F::fromArgb32(index_or_rgb | 0xff000000);
+ return;
+ case Format_RGBA16FPx4:
+ case Format_RGBA16FPx4_Premultiplied:
+ ((QRgba16F *)s)[x] = QRgba16F::fromArgb32(index_or_rgb);
+ return;
+ case Format_RGBX32FPx4:
+ ((QRgba32F *)s)[x] = QRgba32F::fromArgb32(index_or_rgb | 0xff000000);
+ return;
+ case Format_RGBA32FPx4:
+ case Format_RGBA32FPx4_Premultiplied:
+ ((QRgba32F *)s)[x] = QRgba32F::fromArgb32(index_or_rgb);
+ return;
case Format_Invalid:
case NImageFormats:
Q_ASSERT(false);
@@ -2583,6 +2690,26 @@ QColor QImage::pixelColor(int x, int y) const
quint16 v = reinterpret_cast<const quint16 *>(s)[x];
return QColor(qRgba64(v, v, v, 0xffff));
}
+ case Format_RGBX16FPx4:
+ case Format_RGBA16FPx4:
+ case Format_RGBA16FPx4_Premultiplied: {
+ QRgba16F p = reinterpret_cast<const QRgba16F *>(s)[x];
+ if (d->format == Format_RGBA16FPx4_Premultiplied)
+ p = p.unpremultiplied();
+ QColor color;
+ color.setRgbF(p.red(), p.green(), p.blue(), p.alpha());
+ return color;
+ }
+ case Format_RGBX32FPx4:
+ case Format_RGBA32FPx4:
+ case Format_RGBA32FPx4_Premultiplied: {
+ QRgba32F p = reinterpret_cast<const QRgba32F *>(s)[x];
+ if (d->format == Format_RGBA32FPx4_Premultiplied)
+ p = p.unpremultiplied();
+ QColor color;
+ color.setRgbF(p.red(), p.green(), p.blue(), p.alpha());
+ return color;
+ }
default:
c = QRgba64::fromArgb32(pixel(x, y));
break;
@@ -2658,6 +2785,32 @@ void QImage::setPixelColor(int x, int y, const QColor &color)
case Format_RGBA64_Premultiplied:
((QRgba64 *)s)[x] = c;
return;
+ case Format_RGBX16FPx4:
+ case Format_RGBA16FPx4:
+ case Format_RGBA16FPx4_Premultiplied: {
+ float r, g, b, a;
+ color.getRgbF(&r, &g, &b, &a);
+ if (d->format == Format_RGBX16FPx4)
+ a = 1.0f;
+ QRgba16F c16f{r, g, b, a};
+ if (d->format == Format_RGBA16FPx4_Premultiplied)
+ c16f = c16f.premultiplied();
+ ((QRgba16F *)s)[x] = c16f;
+ return;
+ }
+ case Format_RGBX32FPx4:
+ case Format_RGBA32FPx4:
+ case Format_RGBA32FPx4_Premultiplied: {
+ float r, g, b, a;
+ color.getRgbF(&r, &g, &b, &a);
+ if (d->format == Format_RGBX32FPx4)
+ a = 1.0f;
+ QRgba32F c32f{r, g, b, a};
+ if (d->format == Format_RGBA32FPx4_Premultiplied)
+ c32f = c32f.premultiplied();
+ ((QRgba32F *)s)[x] = c32f;
+ return;
+ }
default:
setPixel(x, y, c.toArgb32());
return;
@@ -3218,6 +3371,9 @@ inline void do_mirror(QImageData *dst, QImageData *src, bool horizontal, bool ve
}
switch (depth) {
+ case 128:
+ do_mirror_data<QRgba32F>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
+ break;
case 64:
do_mirror_data<quint64>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
break;
@@ -4409,8 +4565,12 @@ int QImage::bitPlaneCount() const
bpc = 12;
break;
case QImage::Format_RGBX64:
+ case QImage::Format_RGBX16FPx4:
bpc = 48;
break;
+ case QImage::Format_RGBX32FPx4:
+ bpc = 96;
+ break;
default:
bpc = qt_depthForFormat(d->format);
break;
@@ -4429,7 +4589,8 @@ int QImage::bitPlaneCount() const
if necessary. To avoid unnecessary conversion the result is returned in the format
internally used, and not in the original format.
*/
-QImage QImage::smoothScaled(int w, int h) const {
+QImage QImage::smoothScaled(int w, int h) const
+{
QImage src = *this;
switch (src.format()) {
case QImage::Format_RGB32:
@@ -4443,14 +4604,28 @@ QImage QImage::smoothScaled(int w, int h) const {
case QImage::Format_RGBA64_Premultiplied:
break;
case QImage::Format_RGBA64:
- src = src.convertToFormat(QImage::Format_RGBA64_Premultiplied);
+ case QImage::Format_Grayscale16:
+ src.convertTo(QImage::Format_RGBA64_Premultiplied);
+ break;
+#endif
+#if QT_CONFIG(raster_fp)
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+ break;
+ case QImage::Format_RGBX16FPx4:
+ src.convertTo(QImage::Format_RGBX32FPx4);
+ break;
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBA32FPx4:
+ src.convertTo(QImage::Format_RGBA32FPx4_Premultiplied);
break;
#endif
default:
if (src.hasAlphaChannel())
- src = src.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ src.convertTo(QImage::Format_ARGB32_Premultiplied);
else
- src = src.convertToFormat(QImage::Format_RGB32);
+ src.convertTo(QImage::Format_RGB32);
}
src = qSmoothScaleImage(src, w, h);
if (!src.isNull())
@@ -4903,6 +5078,10 @@ bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFla
// any direct ones are probably better even if not inplace.
if (qt_highColorPrecision(newFormat, !qPixelLayouts[newFormat].hasAlphaChannel)
&& qt_highColorPrecision(format, !qPixelLayouts[format].hasAlphaChannel)) {
+#if QT_CONFIG(raster_fp)
+ if (qt_fpColorPrecision(format) && qt_fpColorPrecision(newFormat))
+ return convert_generic_inplace_over_rgba32f(this, newFormat, flags);
+#endif
return convert_generic_inplace_over_rgb64(this, newFormat, flags);
}
return convert_generic_inplace(this, newFormat, flags);
@@ -5328,6 +5507,84 @@ static constexpr QPixelFormat pixelformats[] = {
/*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
/*INTERPRETATION*/ QPixelFormat::UnsignedByte,
/*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
+ //QImage::Format_RGBX16FPx4:
+ QPixelFormat(QPixelFormat::RGB,
+ /*RED*/ 16,
+ /*GREEN*/ 16,
+ /*BLUE*/ 16,
+ /*FOURTH*/ 0,
+ /*FIFTH*/ 0,
+ /*ALPHA*/ 16,
+ /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
+ /*ALPHA POSITION*/ QPixelFormat::AtEnd,
+ /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
+ /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
+ /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
+ //QImage::Format_RGBA16FPx4:
+ QPixelFormat(QPixelFormat::RGB,
+ /*RED*/ 16,
+ /*GREEN*/ 16,
+ /*BLUE*/ 16,
+ /*FOURTH*/ 0,
+ /*FIFTH*/ 0,
+ /*ALPHA*/ 16,
+ /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
+ /*ALPHA POSITION*/ QPixelFormat::AtEnd,
+ /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
+ /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
+ /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
+ //QImage::Format_RGBA16FPx4_Premultiplied:
+ QPixelFormat(QPixelFormat::RGB,
+ /*RED*/ 16,
+ /*GREEN*/ 16,
+ /*BLUE*/ 16,
+ /*FOURTH*/ 0,
+ /*FIFTH*/ 0,
+ /*ALPHA*/ 16,
+ /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
+ /*ALPHA POSITION*/ QPixelFormat::AtEnd,
+ /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
+ /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
+ /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
+ //QImage::Format_RGBX32FPx4:
+ QPixelFormat(QPixelFormat::RGB,
+ /*RED*/ 32,
+ /*GREEN*/ 32,
+ /*BLUE*/ 32,
+ /*FOURTH*/ 0,
+ /*FIFTH*/ 0,
+ /*ALPHA*/ 32,
+ /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
+ /*ALPHA POSITION*/ QPixelFormat::AtEnd,
+ /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
+ /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
+ /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
+ //QImage::Format_RGBA32FPx4:
+ QPixelFormat(QPixelFormat::RGB,
+ /*RED*/ 32,
+ /*GREEN*/ 32,
+ /*BLUE*/ 32,
+ /*FOURTH*/ 0,
+ /*FIFTH*/ 0,
+ /*ALPHA*/ 32,
+ /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
+ /*ALPHA POSITION*/ QPixelFormat::AtEnd,
+ /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
+ /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
+ /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
+ //QImage::Format_RGBA32FPx4_Premultiplied:
+ QPixelFormat(QPixelFormat::RGB,
+ /*RED*/ 32,
+ /*GREEN*/ 32,
+ /*BLUE*/ 32,
+ /*FOURTH*/ 0,
+ /*FIFTH*/ 0,
+ /*ALPHA*/ 32,
+ /*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
+ /*ALPHA POSITION*/ QPixelFormat::AtEnd,
+ /*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
+ /*INTERPRETATION*/ QPixelFormat::FloatingPoint,
+ /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
};
static_assert(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats);
diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h
index ecb38af172..885c804457 100644
--- a/src/gui/image/qimage.h
+++ b/src/gui/image/qimage.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -104,6 +104,12 @@ public:
Format_RGBA64_Premultiplied,
Format_Grayscale16,
Format_BGR888,
+ Format_RGBX16FPx4,
+ Format_RGBA16FPx4,
+ Format_RGBA16FPx4_Premultiplied,
+ Format_RGBX32FPx4,
+ Format_RGBA32FPx4,
+ Format_RGBA32FPx4_Premultiplied,
#ifndef Q_QDOC
NImageFormats
#endif
diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp
index 7415c86b9b..5825397a21 100644
--- a/src/gui/image/qimage_conversions.cpp
+++ b/src/gui/image/qimage_conversions.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -47,6 +47,7 @@
#include <private/qimage_p.h>
#include <qendian.h>
+#include <qrgbaf.h>
#if QT_CONFIG(thread)
#include <qsemaphore.h>
#include <qthreadpool.h>
@@ -313,6 +314,61 @@ void convert_generic_over_rgb64(QImageData *dest, const QImageData *src, Qt::Ima
#endif
}
+#if QT_CONFIG(raster_fp)
+void convert_generic_over_rgba32f(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(dest->format >= QImage::Format_RGBX16FPx4);
+ Q_ASSERT(src->format >= QImage::Format_RGBX16FPx4);
+
+ const FetchAndConvertPixelsFuncFP fetch = qFetchToRGBA32F[src->format];
+ const ConvertAndStorePixelsFuncFP store = qStoreFromRGBA32F[dest->format];
+
+ auto convertSegment = [=](int yStart, int yEnd) {
+ QRgba32F buf[BufferSize];
+ QRgba32F *buffer = buf;
+ const uchar *srcData = src->data + yStart * src->bytes_per_line;
+ uchar *destData = dest->data + yStart * dest->bytes_per_line;
+ for (int y = yStart; y < yEnd; ++y) {
+ int x = 0;
+ while (x < src->width) {
+ int l = src->width - x;
+ if (dest->depth == 128)
+ buffer = reinterpret_cast<QRgba32F *>(destData) + x;
+ else
+ l = qMin(l, BufferSize);
+ const QRgba32F *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr);
+ store(destData, ptr, x, l, nullptr, nullptr);
+ x += l;
+ }
+ srcData += src->bytes_per_line;
+ destData += dest->bytes_per_line;
+ }
+ };
+#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
+ int segments = (qsizetype(src->width) * src->height) >> 16;
+ segments = std::min(segments, src->height);
+
+ QThreadPool *threadPool = QThreadPool::globalInstance();
+ if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
+ return convertSegment(0, src->height);
+
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (src->height - y) / (segments - i);
+ threadPool->start([&, y, yn]() {
+ convertSegment(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+#else
+ convertSegment(0, src->height);
+#endif
+}
+#endif
+
bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags flags)
{
// Cannot be used with indexed formats or between formats with different pixel depths.
@@ -337,7 +393,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
return false;
}
- Q_ASSERT(destLayout->bpp != QPixelLayout::BPP64);
+ Q_ASSERT(destLayout->bpp < QPixelLayout::BPP64);
FetchAndConvertPixelsFunc fetch = srcLayout->fetchToARGB32PM;
ConvertAndStorePixelsFunc store = destLayout->storeFromARGB32PM;
if (!srcLayout->hasAlphaChannel && destLayout->storeFromRGB32) {
@@ -535,6 +591,102 @@ bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_for
return true;
}
+#if QT_CONFIG(raster_fp)
+bool convert_generic_inplace_over_rgba32f(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(data->format >= QImage::Format_RGBX16FPx4);
+ Q_ASSERT(dst_format >= QImage::Format_RGBX16FPx4);
+ const int destDepth = qt_depthForFormat(dst_format);
+ if (data->depth < destDepth)
+ return false;
+
+ const QPixelLayout *srcLayout = &qPixelLayouts[data->format];
+ const QPixelLayout *destLayout = &qPixelLayouts[dst_format];
+
+ QImageData::ImageSizeParameters params = { data->bytes_per_line, data->nbytes };
+ if (data->depth != destDepth) {
+ params = QImageData::calculateImageParameters(data->width, data->height, destDepth);
+ if (!params.isValid())
+ return false;
+ }
+
+ FetchAndConvertPixelsFuncFP fetch = qFetchToRGBA32F[data->format];
+ ConvertAndStorePixelsFuncFP store = qStoreFromRGBA32F[dst_format];
+ if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied &&
+ destLayout->hasAlphaChannel && !destLayout->premultiplied) {
+ // Avoid unnecessary premultiply and unpremultiply when converting between two unpremultiplied formats.
+ // This abuses the fact unpremultiplied formats are always before their premultiplied counterparts.
+ fetch = qFetchToRGBA32F[data->format + 1];
+ store = qStoreFromRGBA32F[dst_format + 1];
+ }
+
+ auto convertSegment = [=](int yStart, int yEnd) {
+ QRgba32F buf[BufferSize];
+ QRgba32F *buffer = buf;
+ uchar *srcData = data->data + yStart * data->bytes_per_line;
+ uchar *destData = srcData;
+ for (int y = yStart; y < yEnd; ++y) {
+ int x = 0;
+ while (x < data->width) {
+ int l = data->width - x;
+ if (srcLayout->bpp == QPixelLayout::BPP32FPx4)
+ buffer = reinterpret_cast<QRgba32F *>(srcData) + x;
+ else
+ l = qMin(l, BufferSize);
+ const QRgba32F *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr);
+ store(destData, ptr, x, l, nullptr, nullptr);
+ x += l;
+ }
+ srcData += data->bytes_per_line;
+ destData += params.bytesPerLine;
+ }
+ };
+#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
+ int segments = (qsizetype(data->width) * data->height) >> 16;
+ segments = std::min(segments, data->height);
+ QThreadPool *threadPool = QThreadPool::globalInstance();
+ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (data->height - y) / (segments - i);
+ threadPool->start([&, y, yn]() {
+ convertSegment(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ if (data->bytes_per_line != params.bytesPerLine) {
+ // Compress segments to a continuous block
+ y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (data->height - y) / (segments - i);
+ uchar *srcData = data->data + data->bytes_per_line * y;
+ uchar *destData = data->data + params.bytesPerLine * y;
+ if (srcData != destData)
+ memmove(destData, srcData, params.bytesPerLine * yn);
+ y += yn;
+ }
+ }
+ } else
+#endif
+ convertSegment(0, data->height);
+ if (params.totalSize != data->nbytes) {
+ Q_ASSERT(params.totalSize < data->nbytes);
+ void *newData = realloc(data->data, params.totalSize);
+ if (newData) {
+ data->data = (uchar *)newData;
+ data->nbytes = params.totalSize;
+ }
+ data->bytes_per_line = params.bytesPerLine;
+ }
+ data->depth = destDepth;
+ data->format = dst_format;
+ return true;
+}
+#endif
+
static void convert_passthrough(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(src->width == dest->width);
@@ -1424,6 +1576,55 @@ static void convert_RGBA64_to_gray16(QImageData *dest, const QImageData *src, Qt
}
}
+template<bool MaskAlpha>
+static void convert_RGBA16FPM_to_RGBA16F(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_RGBA16FPx4_Premultiplied);
+ Q_ASSERT(dest->format == QImage::Format_RGBA16FPx4 || dest->format == QImage::Format_RGBX16FPx4);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ const int src_pad = (src->bytes_per_line >> 3) - src->width;
+ const int dest_pad = (dest->bytes_per_line >> 3) - dest->width;
+ const QRgba16F *src_data = reinterpret_cast<const QRgba16F *>(src->data);
+ QRgba16F *dest_data = reinterpret_cast<QRgba16F *>(dest->data);
+
+ for (int i = 0; i < src->height; ++i) {
+ const QRgba16F *end = src_data + src->width;
+ while (src_data < end) {
+ *dest_data = src_data->unpremultiplied();
+ if (MaskAlpha)
+ dest_data->setAlpha(1.0f);
+ ++src_data;
+ ++dest_data;
+ }
+ src_data += src_pad;
+ dest_data += dest_pad;
+ }
+}
+
+template<bool MaskAlpha>
+static bool convert_RGBA16FPM_to_RGBA16F_inplace(QImageData *data, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(data->format == QImage::Format_RGBA16FPx4_Premultiplied);
+
+ const int pad = (data->bytes_per_line >> 3) - data->width;
+ QRgba16F *rgb_data = reinterpret_cast<QRgba16F *>(data->data);
+
+ for (int i = 0; i < data->height; ++i) {
+ const QRgba16F *end = rgb_data + data->width;
+ while (rgb_data < end) {
+ *rgb_data = rgb_data->unpremultiplied();
+ if (MaskAlpha)
+ rgb_data->setAlpha(1.0f);
+ ++rgb_data;
+ }
+ rgb_data += pad;
+ }
+ data->format = MaskAlpha ? QImage::Format_RGBX16FPx4 : QImage::Format_RGBA16FPx4;
+ return true;
+}
+
static QList<QRgb> fix_color_table(const QList<QRgb> &ctbl, QImage::Format format)
{
QList<QRgb> colorTable = ctbl;
@@ -2421,6 +2622,12 @@ static void qInitImageConversions()
qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888_Premultiplied] = convert_RGB888_to_RGB<false>;
#endif
+ qimage_converter_map[QImage::Format_RGBX16FPx4][QImage::Format_RGBA16FPx4] = convert_passthrough;
+ qimage_converter_map[QImage::Format_RGBX16FPx4][QImage::Format_RGBA16FPx4_Premultiplied] = convert_passthrough;
+
+ qimage_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4] = convert_passthrough;
+ qimage_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4_Premultiplied] = convert_passthrough;
+
// Inline converters:
qimage_inplace_converter_map[QImage::Format_Indexed8][QImage::Format_Grayscale8] =
convert_Indexed8_to_Grayscale8_inplace;
@@ -2526,6 +2733,16 @@ static void qInitImageConversions()
qimage_inplace_converter_map[QImage::Format_BGR888][QImage::Format_RGB888] =
convert_rgbswap_generic_inplace;
+ qimage_inplace_converter_map[QImage::Format_RGBX16FPx4][QImage::Format_RGBA16FPx4] =
+ convert_passthrough_inplace<QImage::Format_RGBA16FPx4>;
+ qimage_inplace_converter_map[QImage::Format_RGBX16FPx4][QImage::Format_RGBA16FPx4_Premultiplied] =
+ convert_passthrough_inplace<QImage::Format_RGBA16FPx4_Premultiplied>;
+
+ qimage_inplace_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4] =
+ convert_passthrough_inplace<QImage::Format_RGBA32FPx4>;
+ qimage_inplace_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4_Premultiplied] =
+ convert_passthrough_inplace<QImage::Format_RGBA32FPx4_Premultiplied>;
+
// Now architecture specific conversions:
#if defined(__SSE2__) && defined(QT_COMPILER_SUPPORTS_SSSE3)
if (qCpuHasFeature(SSSE3)) {
diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h
index 64f5be9e76..a2c50adc43 100644
--- a/src/gui/image/qimage_p.h
+++ b/src/gui/image/qimage_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -161,6 +161,10 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
void convert_generic_over_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags);
bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags);
+#if QT_CONFIG(raster_fp)
+void convert_generic_over_rgba32f(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
+bool convert_generic_inplace_over_rgba32f(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags);
+#endif
void dither_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags, bool fromalpha);
@@ -216,8 +220,16 @@ inline int qt_depthForFormat(QImage::Format format)
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
depth = 64;
break;
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+ depth = 128;
+ break;
}
return depth;
}
@@ -247,6 +259,12 @@ inline QImage::Format qt_opaqueVersion(QImage::Format format)
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
return QImage::Format_RGBX64;
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ return QImage::Format_RGBX16FPx4;
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+ return QImage::Format_RGBX32FPx4;
case QImage::Format_ARGB32_Premultiplied:
case QImage::Format_ARGB32:
return QImage::Format_RGB32;
@@ -261,6 +279,8 @@ inline QImage::Format qt_opaqueVersion(QImage::Format format)
case QImage::Format_BGR30:
case QImage::Format_RGB30:
case QImage::Format_RGBX64:
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBX32FPx4:
case QImage::Format_Grayscale8:
case QImage::Format_Grayscale16:
return format;
@@ -300,6 +320,12 @@ inline QImage::Format qt_alphaVersion(QImage::Format format)
case QImage::Format_RGBA64:
case QImage::Format_Grayscale16:
return QImage::Format_RGBA64_Premultiplied;
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBA16FPx4:
+ return QImage::Format_RGBA16FPx4_Premultiplied;
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ return QImage::Format_RGBA32FPx4_Premultiplied;
case QImage::Format_ARGB32_Premultiplied:
case QImage::Format_ARGB8565_Premultiplied:
case QImage::Format_ARGB8555_Premultiplied:
@@ -309,6 +335,8 @@ inline QImage::Format qt_alphaVersion(QImage::Format format)
case QImage::Format_A2BGR30_Premultiplied:
case QImage::Format_A2RGB30_Premultiplied:
case QImage::Format_RGBA64_Premultiplied:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
return format;
case QImage::Format_Mono:
case QImage::Format_MonoLSB:
@@ -339,6 +367,12 @@ inline bool qt_highColorPrecision(QImage::Format format, bool opaque = false)
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
case QImage::Format_Grayscale16:
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
return true;
default:
break;
@@ -346,6 +380,21 @@ inline bool qt_highColorPrecision(QImage::Format format, bool opaque = false)
return false;
}
+inline bool qt_fpColorPrecision(QImage::Format format)
+{
+ switch (format) {
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
inline QImage::Format qt_maybeAlphaVersionWithSameDepth(QImage::Format format)
{
diff --git a/src/gui/painting/qcompositionfunctions.cpp b/src/gui/painting/qcompositionfunctions.cpp
index 65b03a1e12..3fc9aa3e4e 100644
--- a/src/gui/painting/qcompositionfunctions.cpp
+++ b/src/gui/painting/qcompositionfunctions.cpp
@@ -38,8 +38,10 @@
****************************************************************************/
#include <qglobal.h>
+
#include "qdrawhelper_p.h"
#include "qrgba64_p.h"
+#include "qrgbaf.h"
QT_BEGIN_NAMESPACE
@@ -117,6 +119,8 @@ struct Argb32OperationsC
const Argb32OperationsC::Type Argb32OperationsC::clear = 0;
+typedef Argb32OperationsC Argb32Operations;
+
struct Rgba64OperationsBase
{
typedef QRgba64 Type;
@@ -319,9 +323,188 @@ typedef Rgba64OperationsNEON Rgba64Operations;
#else
typedef Rgba64OperationsC Rgba64Operations;
#endif
+
#endif // QT_CONFIG(raster_64bit)
-typedef Argb32OperationsC Argb32Operations;
+#if QT_CONFIG(raster_fp)
+
+static inline QRgba32F qRgba32f(float r, float g, float b, float a)
+{
+ return QRgba32F{r, g, b, a};
+}
+
+struct RgbaFPOperationsBase
+{
+ typedef QRgba32F Type;
+ typedef float Scalar;
+
+ static inline constexpr Type clear = { 0, 0, 0, 0 };
+
+ static bool isOpaque(Type val)
+ { return val.a >= 1.0f; }
+ static bool isTransparent(Type val)
+ { return val.a <= 0.0f; }
+ static Scalar scalarFrom8bit(uint8_t a)
+ { return a * (1.0f / 255.0f); }
+
+ static void memfill(Type *ptr, Type value, qsizetype len)
+ {
+ for (qsizetype i = 0; i < len; ++i)
+ ptr[i] = value;
+ }
+ static void memcpy(Type *Q_DECL_RESTRICT dest, const Type *Q_DECL_RESTRICT src, qsizetype len)
+ { ::memcpy(dest, src, len * sizeof(Type)); }
+};
+
+struct RgbaFPOperationsC : RgbaFPOperationsBase
+{
+ typedef QRgba32F OptimalType;
+ typedef float OptimalScalar;
+
+ static OptimalType load(const Type *ptr)
+ {
+ return QRgba32F { ptr->r, ptr->g, ptr->b, ptr->a };
+ }
+ static OptimalType convert(const Type &val)
+ {
+ return QRgba32F { val.r, val.g, val.b, val.a };
+ }
+ static void store(Type *ptr, OptimalType value)
+ {
+ ptr->r = value.r;
+ ptr->g = value.g;
+ ptr->b = value.b;
+ ptr->a = value.a;
+ }
+ static OptimalType add(OptimalType a, OptimalType b)
+ {
+ a.r += b.r;
+ a.g += b.g;
+ a.b += b.b;
+ a.a += b.a;
+ return a;
+ }
+ static OptimalScalar add(OptimalScalar a, OptimalScalar b)
+ { return a + b; }
+ static OptimalType plus(OptimalType a, OptimalType b)
+ {
+ a = add(a, b); // no saturation on color values
+ if (a.a < 0.0f) a.a = 0.0f;
+ else if (a.a > 1.0f) a.a = 1.0f;
+ return a;
+ }
+ static OptimalScalar alpha(OptimalType val)
+ { return val.a; }
+ static OptimalScalar invAlpha(OptimalScalar c)
+ { return 1.0f - c; }
+ static OptimalScalar invAlpha(OptimalType val)
+ { return 1.0f - val.a; }
+ static OptimalScalar scalar(Scalar v)
+ { return v; }
+ static OptimalType multiplyAlpha(OptimalType val, OptimalScalar a)
+ {
+ val.r *= a;
+ val.g *= a;
+ val.b *= a;
+ val.a *= a;
+ return val;
+ }
+ static OptimalScalar multiplyAlpha8bit(OptimalScalar val, uint8_t a)
+ {
+ return val * a * (1.0f / 255.0f);
+ }
+ static OptimalType interpolate(OptimalType x, OptimalScalar a1, OptimalType y, OptimalScalar a2)
+ {
+ return add(multiplyAlpha(x, a1), multiplyAlpha(y, a2));
+ }
+ static OptimalType multiplyAlpha8bit(OptimalType val, uint8_t a)
+ {
+ return multiplyAlpha(val, a * (1.0f / 255.0f));
+ }
+ static OptimalType interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2)
+ {
+ return add(multiplyAlpha8bit(x, a1), multiplyAlpha8bit(y, a2));
+ }
+};
+
+#if defined(__SSE2__)
+struct RgbaFPOperationsSSE2 : public RgbaFPOperationsBase
+{
+ typedef __m128 OptimalType;
+ typedef __m128 OptimalScalar;
+
+ static OptimalType load(const Type *ptr)
+ {
+ return _mm_load_ps(reinterpret_cast<const float *>(ptr));
+ }
+ static OptimalType convert(const Type &value)
+ {
+ return load(&value);
+ }
+ static void store(Type *ptr, OptimalType value)
+ {
+ _mm_store_ps(reinterpret_cast<float *>(ptr), value);
+ }
+ static OptimalType add(OptimalType a, OptimalType b)
+ {
+ return _mm_add_ps(a, b);
+ }
+// same as above:
+// static OptimalScalar add(OptimalScalar a, OptimalScalar b)
+ static OptimalType plus(OptimalType a, OptimalType b)
+ {
+ a = _mm_add_ps(a, b);
+ __m128 aa = _mm_min_ps(a, _mm_set1_ps(1.0f));
+ aa = _mm_max_ps(aa, _mm_set1_ps(0.0f));
+ // An indirect insert using only SSE2:
+ aa = _mm_shuffle_ps(aa, a, _MM_SHUFFLE(2, 2, 3, 3));
+ a = _mm_shuffle_ps(a, aa, _MM_SHUFFLE(0, 2, 1, 0));
+ return a;
+ }
+ static OptimalScalar alpha(OptimalType c)
+ {
+ return _mm_shuffle_ps(c, c, _MM_SHUFFLE(3, 3, 3, 3));
+ }
+ static OptimalScalar invAlpha(Scalar c)
+ {
+ return _mm_set1_ps(1.0f - float(c));
+ }
+ static OptimalScalar invAlpha(OptimalType c)
+ {
+ return _mm_sub_ps(_mm_set1_ps(1.0f), alpha(c));
+ }
+ static OptimalScalar scalar(Scalar n)
+ {
+ return _mm_set1_ps(float(n));
+ }
+ static OptimalType multiplyAlpha(OptimalType val, OptimalScalar a)
+ {
+ return _mm_mul_ps(val, a);
+ }
+ static OptimalType interpolate(OptimalType x, OptimalScalar a1, OptimalType y, OptimalScalar a2)
+ {
+ return add(multiplyAlpha(x, a1), multiplyAlpha(y, a2));
+ }
+ static OptimalType multiplyAlpha8bit(OptimalType val, uint8_t a)
+ {
+ return multiplyAlpha(val, _mm_set1_ps(a * (1.0f / 255.0f)));
+ }
+// same as above:
+// static OptimalScalar multiplyAlpha8bit(OptimalScalar a, uint8_t a)
+ static OptimalType interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2)
+ {
+ return add(multiplyAlpha8bit(x, a1), multiplyAlpha8bit(y, a2));
+ }
+};
+#endif
+
+#if defined(__SSE2__)
+typedef RgbaFPOperationsSSE2 RgbaFPOperations;
+#else
+typedef RgbaFPOperationsC RgbaFPOperations;
+#endif
+
+#endif // QT_CONFIG(raster_fp)
/*
result = 0
@@ -362,6 +545,17 @@ void QT_FASTCALL comp_func_Clear_rgb64(QRgba64 *dest, const QRgba64 *, int lengt
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_Clear_rgbafp(QRgba32F *dest, int length, QRgba32F, uint const_alpha)
+{
+ comp_func_Clear_template<RgbaFPOperations>(dest, length, const_alpha);
+}
+
+void QT_FASTCALL comp_func_Clear_rgbafp(QRgba32F *dest, const QRgba32F *, int length, uint const_alpha)
+{
+ comp_func_Clear_template<RgbaFPOperations>(dest, length, const_alpha);
+}
+#endif
/*
result = s
@@ -421,6 +615,18 @@ void QT_FASTCALL comp_func_Source_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRg
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_Source_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ comp_func_solid_Source_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_Source_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_Source_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint)
{
}
@@ -439,6 +645,16 @@ void QT_FASTCALL comp_func_Destination_rgb64(QRgba64 *, const QRgba64 *, int, ui
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_Destination_rgbafp(QRgba32F *, int, QRgba32F, uint)
+{
+}
+
+void QT_FASTCALL comp_func_Destination_rgbafp(QRgba32F *, const QRgba32F *, int, uint)
+{
+}
+#endif
+
/*
result = s + d * sia
dest = (s + d * sia) * ca + d * cia
@@ -509,6 +725,19 @@ void QT_FASTCALL comp_func_SourceOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_SourceOver_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ comp_func_solid_SourceOver_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+
+void QT_FASTCALL comp_func_SourceOver_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_SourceOver_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = d + s * dia
dest = (d + s * dia) * ca + d * cia
@@ -570,6 +799,18 @@ void QT_FASTCALL comp_func_DestinationOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest,
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_DestinationOver_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ comp_func_solid_DestinationOver_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_DestinationOver_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_DestinationOver_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = s * da
dest = s * da * ca + d * cia
@@ -636,6 +877,18 @@ void QT_FASTCALL comp_func_SourceIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const Q
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_SourceIn_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ comp_func_solid_SourceIn_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_SourceIn_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_SourceIn_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = d * sa
dest = d * sa * ca + d * cia
@@ -697,6 +950,18 @@ void QT_FASTCALL comp_func_DestinationIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, co
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_DestinationIn_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ comp_func_solid_DestinationIn_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_DestinationIn_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_DestinationIn_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = s * dia
dest = s * dia * ca + d * cia
@@ -761,6 +1026,18 @@ void QT_FASTCALL comp_func_SourceOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_SourceOut_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ comp_func_solid_SourceOut_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_SourceOut_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_SourceOut_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = d * sia
dest = d * sia * ca + d * cia
@@ -822,6 +1099,18 @@ void QT_FASTCALL comp_func_DestinationOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, c
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_DestinationOut_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ comp_func_solid_DestinationOut_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_DestinationOut_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_DestinationOut_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = s*da + d*sia
dest = s*da*ca + d*sia*ca + d *cia
@@ -883,6 +1172,18 @@ void QT_FASTCALL comp_func_SourceAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_SourceAtop_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ comp_func_solid_SourceAtop_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_SourceAtop_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_SourceAtop_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = d*sa + s*dia
dest = d*sa*ca + s*dia*ca + d *cia
@@ -949,6 +1250,18 @@ void QT_FASTCALL comp_func_DestinationAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest,
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_DestinationAtop_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ comp_func_solid_DestinationAtop_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_DestinationAtop_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_DestinationAtop_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = d*sia + s*dia
dest = d*sia*ca + s*dia*ca + d *cia
@@ -1011,15 +1324,35 @@ void QT_FASTCALL comp_func_XOR_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba6
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_XOR_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ comp_func_solid_XOR_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_XOR_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_XOR_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
struct QFullCoverage {
inline void store(uint *dest, const uint src) const
{
*dest = src;
}
+#if QT_CONFIG(raster_64bit)
inline void store(QRgba64 *dest, const QRgba64 src) const
{
*dest = src;
}
+#endif
+#if QT_CONFIG(raster_fp)
+ inline void store(QRgba32F *dest, const QRgba32F src) const
+ {
+ *dest = src;
+ }
+#endif
};
struct QPartialCoverage {
@@ -1029,14 +1362,27 @@ struct QPartialCoverage {
{
}
+ template<typename Op>
+ inline void store_template(typename Op::Type *dest, const typename Op::Type src) const
+ {
+ Op::store(dest, Op::interpolate8bit(Op::convert(src), ca, Op::load(dest), ica));
+ }
inline void store(uint *dest, const uint src) const
{
- *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica);
+ store_template<Argb32Operations>(dest, src);
}
+#if QT_CONFIG(raster_64bit)
inline void store(QRgba64 *dest, const QRgba64 src) const
{
- *dest = interpolate255(src, ca, *dest, ica);
+ store_template<Rgba64Operations>(dest, src);
}
+#endif
+#if QT_CONFIG(raster_fp)
+ inline void store(QRgba32F *dest, const QRgba32F src) const
+ {
+ store_template<RgbaFPOperations>(dest, src);
+ }
+#endif
private:
const uint ca;
@@ -1048,10 +1394,19 @@ static inline int mix_alpha(int da, int sa)
return 255 - ((255 - sa) * (255 - da) >> 8);
}
+#if QT_CONFIG(raster_64bit)
static inline uint mix_alpha_rgb64(uint da, uint sa)
{
return 65535U - ((65535U - sa) * (65535U - da) >> 16);
}
+#endif
+
+#if QT_CONFIG(raster_fp)
+static inline float mix_alpha_rgbafp(float da, float sa)
+{
+ return 1.0f - (1.0f - sa) * (1.0f - da);
+}
+#endif
/*
Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -1122,6 +1477,18 @@ void QT_FASTCALL comp_func_Plus_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_Plus_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ comp_func_solid_Plus_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_Plus_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_Plus_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
*/
@@ -1199,6 +1566,45 @@ void QT_FASTCALL comp_func_solid_Multiply_rgb64(QRgba64 *dest, int length, QRgba
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float multiply_op_rgbafp(float dst, float src, float da, float sa)
+{
+ return src * dst + src * (1.0f - da) + dst * (1.0f - sa);
+}
+
+template <typename T>
+static inline void comp_func_solid_Multiply_impl(QRgba32F *dest, int length, QRgba32F color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) multiply_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Multiply_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
+
template <typename T>
static inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1259,6 +1665,37 @@ void QT_FASTCALL comp_func_Multiply_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const Q
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Multiply_impl(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ QRgba32F s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) multiply_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Multiply_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Multiply_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
= Sca + Dca - Sca.Dca
@@ -1327,6 +1764,39 @@ void QT_FASTCALL comp_func_solid_Screen_rgb64(QRgba64 *dest, int length, QRgba64
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_solid_Screen_impl(QRgba32F *dest, int length, QRgba32F color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) (1.0f - ((1.0f - a) * (1.0f - b)))
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Screen_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Screen_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1387,6 +1857,37 @@ void QT_FASTCALL comp_func_Screen_rgb64(QRgba64 *dest, const QRgba64 *src, int l
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Screen_impl(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ QRgba32F s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) (1.0f - ((1.0f - a) * (1.0f - b)))
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Screen_rgbafp(QRgba32F *dest, const QRgba32F *src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Screen_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
if 2.Dca < Da
Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -1475,6 +1976,48 @@ void QT_FASTCALL comp_func_solid_Overlay_rgb64(QRgba64 *dest, int length, QRgba6
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float overlay_op_rgbafp(float dst, float src, float da, float sa)
+{
+ const float temp = src * (1.0f - da) + dst * (1.0f - sa);
+ if (2 * dst < da)
+ return 2 * src * dst + temp;
+ else
+ return sa * da - 2 * (da - dst) * (sa - src) + temp;
+}
+
+template <typename T>
+static inline void comp_func_solid_Overlay_impl(QRgba32F *dest, int length, QRgba32F color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) overlay_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Overlay_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1535,6 +2078,37 @@ void QT_FASTCALL comp_func_Overlay_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QR
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Overlay_impl(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ QRgba32F s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) overlay_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Overlay_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Overlay_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
Da' = Sa + Da - Sa.Da
@@ -1613,6 +2187,44 @@ void QT_FASTCALL comp_func_solid_Darken_rgb64(QRgba64 *dest, int length, QRgba64
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float darken_op_rgbafp(float dst, float src, float da, float sa)
+{
+ return qMin(src * da, dst * sa) + src * (1.0f - da) + dst * (1.0f - sa);
+}
+
+template <typename T>
+static inline void comp_func_solid_Darken_impl(QRgba32F *dest, int length, QRgba32F color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) darken_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Darken_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Darken_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1673,6 +2285,37 @@ void QT_FASTCALL comp_func_Darken_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRg
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Darken_impl(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ QRgba32F s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) darken_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Darken_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Darken_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
Da' = Sa + Da - Sa.Da
@@ -1752,6 +2395,44 @@ void QT_FASTCALL comp_func_solid_Lighten_rgb64(QRgba64 *dest, int length, QRgba6
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float lighten_op_rgbafp(float dst, float src, float da, float sa)
+{
+ return qMax(src * da, dst * sa) + src * (1.0f - da) + dst * (1.0f - sa);
+}
+
+template <typename T>
+static inline void comp_func_solid_Lighten_impl(QRgba32F *dest, int length, QRgba32F color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) lighten_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Lighten_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1812,6 +2493,37 @@ void QT_FASTCALL comp_func_Lighten_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QR
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Lighten_impl(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ QRgba32F s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) lighten_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Lighten_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Lighten_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
if Sca.Da + Dca.Sa > Sa.Da
Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -1914,6 +2626,54 @@ void QT_FASTCALL comp_func_solid_ColorDodge_rgb64(QRgba64 *dest, int length, QRg
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float color_dodge_op_rgbafp(float dst, float src, float da, float sa)
+{
+ const float sa_da = sa * da;
+ const float dst_sa = dst * sa;
+ const float src_da = src * da;
+
+ const float temp = src * (1.0f - da) + dst * (1.0f - sa);
+ if (src_da + dst_sa > sa_da)
+ return sa_da + temp;
+ else if (src == sa || sa == 0.0f)
+ return temp;
+ else
+ return dst_sa / (1.0f - src / sa) + temp;
+}
+
+template <typename T>
+static inline void comp_func_solid_ColorDodge_impl(QRgba32F *dest, int length, QRgba32F color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ float da = d.alpha();
+
+#define OP(a,b) color_dodge_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_ColorDodge_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1974,6 +2734,37 @@ void QT_FASTCALL comp_func_ColorDodge_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_ColorDodge_impl(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ QRgba32F s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) color_dodge_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_ColorDodge_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_ColorDodge_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
if Sca.Da + Dca.Sa < Sa.Da
Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
@@ -2076,6 +2867,54 @@ void QT_FASTCALL comp_func_solid_ColorBurn_rgb64(QRgba64 *dest, int length, QRgb
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float color_burn_op_rgbafp(float dst, float src, float da, float sa)
+{
+ const float src_da = src * da;
+ const float dst_sa = dst * sa;
+ const float sa_da = sa * da;
+
+ const float temp = src * (1.0f - da) + dst * (1.0f - sa);
+
+ if (src_da + dst_sa < sa_da)
+ return temp;
+ else if (src == 0)
+ return dst_sa + temp;
+ return sa * (src_da + dst_sa - sa_da) / src + temp;
+}
+
+template <typename T>
+static inline void comp_func_solid_ColorBurn_impl(QRgba32F *dest, int length, QRgba32F color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) color_burn_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_ColorBurn_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -2136,6 +2975,37 @@ void QT_FASTCALL comp_func_ColorBurn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_ColorBurn_impl(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ QRgba32F s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) color_burn_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_ColorBurn_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_ColorBurn_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
if 2.Sca < Sa
Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -2226,6 +3096,49 @@ void QT_FASTCALL comp_func_solid_HardLight_rgb64(QRgba64 *dest, int length, QRgb
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float hardlight_op_rgbafp(float dst, float src, float da, float sa)
+{
+ const float temp = src * (1.0f - da) + dst * (1.0f - sa);
+
+ if (2 * src < sa)
+ return 2 * src * dst + temp;
+ else
+ return sa * da - 2 * (da - dst) * (sa - src) + temp;
+}
+
+template <typename T>
+static inline void comp_func_solid_HardLight_impl(QRgba32F *dest, int length, QRgba32F color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) hardlight_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_HardLight_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -2286,6 +3199,37 @@ void QT_FASTCALL comp_func_HardLight_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_HardLight_impl(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ QRgba32F s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) hardlight_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_HardLight_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_HardLight_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
if 2.Sca <= Sa
Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -2332,6 +3276,14 @@ static inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint c
}
}
+void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
#if QT_CONFIG(raster_64bit)
static inline uint soft_light_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa)
{
@@ -2371,15 +3323,64 @@ static inline void comp_func_solid_SoftLight_impl(QRgba64 *dest, int length, QRg
coverage.store(&dest[i], qRgba64(r, g, b, a));
}
}
+
+void QT_FASTCALL comp_func_solid_SoftLight_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
#endif
-void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
+#if QT_CONFIG(raster_fp)
+static inline float soft_light_op_rgbafp(float dst, float src, float da, float sa)
+{
+ const float src2 = src * 2;
+ const float dst_np = da != 0.0f ? (dst / da) : 0.0f;
+ const float temp = src * (1.0f - da) + dst * (1.0f - sa);
+
+ if (src2 < sa)
+ return dst * (sa + (src2 - sa) * (1.0f - dst_np)) + temp;
+ else if (4 * dst <= da)
+ return dst * sa + da * (src2 - sa) * (((16 * dst_np - 12) * dst_np + 3) * dst_np) + temp;
+ else {
+ return dst * sa + da * (src2 - sa) * (qSqrt(qreal(dst_np)) - dst_np) + temp;
+ }
+}
+
+template <typename T>
+static inline void comp_func_solid_SoftLight_impl(QRgba32F *dest, int length, QRgba32F color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) soft_light_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_SoftLight_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
{
if (const_alpha == 255)
comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
else
comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
}
+#endif
template <typename T>
static inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
@@ -2411,14 +3412,6 @@ void QT_FASTCALL comp_func_SoftLight(uint *Q_DECL_RESTRICT dest, const uint *Q_D
}
#if QT_CONFIG(raster_64bit)
-void QT_FASTCALL comp_func_solid_SoftLight_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
-{
- if (const_alpha == 255)
- comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
- else
- comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
-}
-
template <typename T>
static inline void comp_func_SoftLight_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -2449,6 +3442,37 @@ void QT_FASTCALL comp_func_SoftLight_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_SoftLight_impl(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ QRgba32F s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) soft_light_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_SoftLight_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_SoftLight_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
= Sca + Dca - 2.min(Sca.Da, Dca.Sa)
@@ -2527,6 +3551,44 @@ void QT_FASTCALL comp_func_solid_Difference_rgb64(QRgba64 *dest, int length, QRg
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float difference_op_rgbafp(float dst, float src, float da, float sa)
+{
+ return src + dst - (2 * qMin(src * da, dst * sa));
+}
+
+template <typename T>
+static inline void comp_func_solid_Difference_impl(QRgba32F *dest, int length, QRgba32F color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) difference_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Difference_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Difference_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -2587,6 +3649,37 @@ void QT_FASTCALL comp_func_Difference_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Difference_impl(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ QRgba32F s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) difference_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Difference_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Difference_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
*/
@@ -2645,7 +3738,6 @@ static inline void QT_FASTCALL comp_func_solid_Exclusion_impl(QRgba64 *dest, int
}
}
-
void QT_FASTCALL comp_func_solid_Exclusion_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
{
if (const_alpha == 255)
@@ -2655,6 +3747,39 @@ void QT_FASTCALL comp_func_solid_Exclusion_rgb64(QRgba64 *dest, int length, QRgb
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void QT_FASTCALL comp_func_solid_Exclusion_impl(QRgba32F *dest, int length, QRgba32F color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) (a + b - (2.0f * a * b))
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Exclusion_rgbafp(QRgba32F *dest, int length, QRgba32F color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_Exclusion_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -2715,6 +3840,37 @@ void QT_FASTCALL comp_func_Exclusion_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Exclusion_impl(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba32F d = dest[i];
+ QRgba32F s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) (a + b - (2.0f * a * b))
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba32f(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Exclusion_rgbafp(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Exclusion_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest,
int length,
uint color,
@@ -3097,6 +4253,40 @@ CompositionFunctionSolid64 qt_functionForModeSolid64_C[] = {
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
};
+CompositionFunctionSolidFP qt_functionForModeSolidFP_C[] = {
+#if QT_CONFIG(raster_fp)
+ comp_func_solid_SourceOver_rgbafp,
+ comp_func_solid_DestinationOver_rgbafp,
+ comp_func_solid_Clear_rgbafp,
+ comp_func_solid_Source_rgbafp,
+ comp_func_solid_Destination_rgbafp,
+ comp_func_solid_SourceIn_rgbafp,
+ comp_func_solid_DestinationIn_rgbafp,
+ comp_func_solid_SourceOut_rgbafp,
+ comp_func_solid_DestinationOut_rgbafp,
+ comp_func_solid_SourceAtop_rgbafp,
+ comp_func_solid_DestinationAtop_rgbafp,
+ comp_func_solid_XOR_rgbafp,
+ comp_func_solid_Plus_rgbafp,
+ comp_func_solid_Multiply_rgbafp,
+ comp_func_solid_Screen_rgbafp,
+ comp_func_solid_Overlay_rgbafp,
+ comp_func_solid_Darken_rgbafp,
+ comp_func_solid_Lighten_rgbafp,
+ comp_func_solid_ColorDodge_rgbafp,
+ comp_func_solid_ColorBurn_rgbafp,
+ comp_func_solid_HardLight_rgbafp,
+ comp_func_solid_SoftLight_rgbafp,
+ comp_func_solid_Difference_rgbafp,
+ comp_func_solid_Exclusion_rgbafp,
+#else
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#endif
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
CompositionFunction qt_functionForMode_C[] = {
comp_func_SourceOver,
comp_func_DestinationOver,
@@ -3173,4 +4363,38 @@ CompositionFunction64 qt_functionForMode64_C[] = {
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
};
+CompositionFunctionFP qt_functionForModeFP_C[] = {
+#if QT_CONFIG(raster_fp)
+ comp_func_SourceOver_rgbafp,
+ comp_func_DestinationOver_rgbafp,
+ comp_func_Clear_rgbafp,
+ comp_func_Source_rgbafp,
+ comp_func_Destination_rgbafp,
+ comp_func_SourceIn_rgbafp,
+ comp_func_DestinationIn_rgbafp,
+ comp_func_SourceOut_rgbafp,
+ comp_func_DestinationOut_rgbafp,
+ comp_func_SourceAtop_rgbafp,
+ comp_func_DestinationAtop_rgbafp,
+ comp_func_XOR_rgbafp,
+ comp_func_Plus_rgbafp,
+ comp_func_Multiply_rgbafp,
+ comp_func_Screen_rgbafp,
+ comp_func_Overlay_rgbafp,
+ comp_func_Darken_rgbafp,
+ comp_func_Lighten_rgbafp,
+ comp_func_ColorDodge_rgbafp,
+ comp_func_ColorBurn_rgbafp,
+ comp_func_HardLight_rgbafp,
+ comp_func_SoftLight_rgbafp,
+ comp_func_Difference_rgbafp,
+ comp_func_Exclusion_rgbafp,
+#else
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#endif
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 161eebb300..eb01487743 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2018 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
@@ -38,7 +38,7 @@
**
****************************************************************************/
-#include <qglobal.h>
+#include "qdrawhelper_p.h"
#include <qstylehints.h>
#include <qguiapplication.h>
@@ -76,16 +76,255 @@ enum {
half_point = 1 << 15
};
+template <QPixelLayout::BPP bpp> static
+inline uint QT_FASTCALL fetch1Pixel(const uchar *, int)
+{
+ Q_UNREACHABLE();
+ return 0;
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP1LSB>(const uchar *src, int index)
+{
+ return (src[index >> 3] >> (index & 7)) & 1;
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP1MSB>(const uchar *src, int index)
+{
+ return (src[index >> 3] >> (~index & 7)) & 1;
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP8>(const uchar *src, int index)
+{
+ return src[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP16>(const uchar *src, int index)
+{
+ return reinterpret_cast<const quint16 *>(src)[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP24>(const uchar *src, int index)
+{
+ return reinterpret_cast<const quint24 *>(src)[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP32>(const uchar *src, int index)
+{
+ return reinterpret_cast<const uint *>(src)[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP64>(const uchar *src, int index)
+{
+ // We have to do the conversion in fetch to fit into a 32bit uint
+ QRgba64 c = reinterpret_cast<const QRgba64 *>(src)[index];
+ return c.toArgb32();
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP16FPx4>(const uchar *src, int index)
+{
+ // We have to do the conversion in fetch to fit into a 32bit uint
+ QRgba16F c = reinterpret_cast<const QRgba16F *>(src)[index];
+ return c.toArgb32();
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP32FPx4>(const uchar *src, int index)
+{
+ // We have to do the conversion in fetch to fit into a 32bit uint
+ QRgba32F c = reinterpret_cast<const QRgba32F *>(src)[index];
+ return c.toArgb32();
+}
+
+typedef uint (QT_FASTCALL *Fetch1PixelFunc)(const uchar *src, int index);
+
+constexpr Fetch1PixelFunc fetch1PixelTable[QPixelLayout::BPPCount] = {
+ nullptr, // BPPNone
+ fetch1Pixel<QPixelLayout::BPP1MSB>,
+ fetch1Pixel<QPixelLayout::BPP1LSB>,
+ fetch1Pixel<QPixelLayout::BPP8>,
+ fetch1Pixel<QPixelLayout::BPP16>,
+ fetch1Pixel<QPixelLayout::BPP24>,
+ fetch1Pixel<QPixelLayout::BPP32>,
+ fetch1Pixel<QPixelLayout::BPP64>,
+ fetch1Pixel<QPixelLayout::BPP16FPx4>,
+ fetch1Pixel<QPixelLayout::BPP32FPx4>,
+};
+
#if QT_CONFIG(raster_64bit)
-static void convertRGBA64ToRGBA64PM(QRgba64 *buffer, int count)
+static void QT_FASTCALL convertRGBA64ToRGBA64PM(QRgba64 *buffer, int count)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = buffer[i].premultiplied();
+}
+
+static void QT_FASTCALL convertRGBA64PMToRGBA64PM(QRgba64 *, int)
+{
+}
+
+static void QT_FASTCALL convertRGBA16FToRGBA64PM(QRgba64 *buffer, int count)
+{
+ const QRgba16F *in = reinterpret_cast<const QRgba16F *>(buffer);
+ for (int i = 0; i < count; ++i) {
+ QRgba16F c = in[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16()).premultiplied();
+ }
+}
+
+static void QT_FASTCALL convertRGBA16FPMToRGBA64PM(QRgba64 *buffer, int count)
+{
+ const QRgba16F *in = reinterpret_cast<const QRgba16F *>(buffer);
+ for (int i = 0; i < count; ++i) {
+ QRgba16F c = in[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
+ }
+}
+
+static void QT_FASTCALL convertRGBA32FToRGBA64PM(QRgba64 *buffer, int count)
+{
+ const QRgba32F *in = reinterpret_cast<const QRgba32F *>(buffer);
+ for (int i = 0; i < count; ++i) {
+ QRgba32F c = in[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16()).premultiplied();
+ }
+}
+
+static void QT_FASTCALL convertRGBA32FPMToRGBA64PM(QRgba64 *buffer, int count)
+{
+ const QRgba32F *in = reinterpret_cast<const QRgba32F *>(buffer);
+ for (int i = 0; i < count; ++i) {
+ QRgba32F c = in[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
+ }
+}
+
+static Convert64Func convert64ToRGBA64PM[QImage::NImageFormats] = {
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ convertRGBA64PMToRGBA64PM,
+ convertRGBA64ToRGBA64PM,
+ convertRGBA64PMToRGBA64PM,
+ nullptr,
+ nullptr,
+ convertRGBA16FPMToRGBA64PM,
+ convertRGBA16FToRGBA64PM,
+ convertRGBA16FPMToRGBA64PM,
+ convertRGBA32FPMToRGBA64PM,
+ convertRGBA32FToRGBA64PM,
+ convertRGBA32FPMToRGBA64PM,
+};
+#endif
+
+#if QT_CONFIG(raster_fp)
+static void QT_FASTCALL convertRGBA64PMToRGBA32F(QRgba32F *buffer, const quint64 *src, int count)
+{
+ const auto *in = reinterpret_cast<const QRgba64 *>(src);
+ for (int i = 0; i < count; ++i) {
+ auto c = in[i];
+ buffer[i] = QRgba32F::fromRgba64(c.red(), c.green(), c.blue(), c.alpha()).premultiplied();
+ }
+}
+
+static void QT_FASTCALL convertRGBA64ToRGBA32F(QRgba32F *buffer, const quint64 *src, int count)
+{
+ const auto *in = reinterpret_cast<const QRgba64 *>(src);
+ for (int i = 0; i < count; ++i) {
+ auto c = in[i];
+ buffer[i] = QRgba32F::fromRgba64(c.red(), c.green(), c.blue(), c.alpha());
+ }
+}
+
+static void QT_FASTCALL convertRGBA16FPMToRGBA32F(QRgba32F *buffer, const quint64 *src, int count)
+{
+ qFloatFromFloat16((float *)buffer, (const qfloat16 *)src, count * 4);
+ for (int i = 0; i < count; ++i)
+ buffer[i] = buffer[i].premultiplied();
+}
+
+static void QT_FASTCALL convertRGBA16FToRGBA32F(QRgba32F *buffer, const quint64 *src, int count)
+{
+ qFloatFromFloat16((float *)buffer, (const qfloat16 *)src, count * 4);
+}
+
+static Convert64ToFPFunc convert64ToRGBA32F[QImage::NImageFormats] = {
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ convertRGBA64ToRGBA32F,
+ convertRGBA64PMToRGBA32F,
+ convertRGBA64ToRGBA32F,
+ nullptr,
+ nullptr,
+ convertRGBA16FToRGBA32F,
+ convertRGBA16FPMToRGBA32F,
+ convertRGBA16FToRGBA32F,
+ nullptr,
+ nullptr,
+ nullptr,
+};
+
+static void convertRGBA32FToRGBA32FPM(QRgba32F *buffer, int count)
{
for (int i = 0; i < count; ++i)
buffer[i] = buffer[i].premultiplied();
}
-static void convertRGBA64PMToRGBA64PM(QRgba64 *, int)
+static void convertRGBA32FToRGBA32F(QRgba32F *, int)
{
}
+
#endif
/*
@@ -175,6 +414,12 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] =
destFetch, // Format_RGBA64_Premultiplied
destFetch, // Format_Grayscale16
destFetch, // Format_BGR888
+ destFetch, // Format_RGBX16FPx4
+ destFetch, // Format_RGBA16FPx4
+ destFetch, // Format_RGBA16FPx4_Premultiplied
+ destFetch, // Format_RGBX32FPx4
+ destFetch, // Format_RGBA32FPx4
+ destFetch, // Format_RGBA32FPx4_Premultiplied
};
#if QT_CONFIG(raster_64bit)
@@ -226,9 +471,27 @@ static DestFetchProc64 destFetchProc64[QImage::NImageFormats] =
destFetchRGB64, // Format_RGBA64_Premultiplied
destFetch64, // Format_Grayscale16
destFetch64, // Format_BGR888
+ destFetch64, // Format_RGBX16FPx4
+ destFetch64, // Format_RGBA16FPx4
+ destFetch64, // Format_RGBA16FPx4_Premultiplied
+ destFetch64, // Format_RGBX32FPx4
+ destFetch64, // Format_RGBA32FPx4
+ destFetch64, // Format_RGBA32FPx4_Premultiplied
};
#endif
+#if QT_CONFIG(raster_fp)
+static QRgba32F *QT_FASTCALL destFetchFP(QRgba32F *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
+{
+ return const_cast<QRgba32F *>(qFetchToRGBA32F[rasterBuffer->format](buffer, rasterBuffer->scanLine(y), x, length, nullptr, nullptr));
+}
+
+static QRgba32F *QT_FASTCALL destFetchFPUndefined(QRgba32F *buffer, QRasterBuffer *, int, int, int)
+{
+ return buffer;
+}
+#endif
+
/*
Returns the color in the mono destination color table
that is the "nearest" to /color/.
@@ -412,6 +675,12 @@ static DestStoreProc destStoreProc[QImage::NImageFormats] =
destStore, // Format_RGBA64_Premultiplied
destStoreGray16, // Format_Grayscale16
destStore, // Format_BGR888
+ destStore, // Format_RGBX16FPx4
+ destStore, // Format_RGBA16FPx4
+ destStore, // Format_RGBA16FPx4_Premultiplied
+ destStore, // Format_RGBX32FPx4
+ destStore, // Format_RGBA32FPx4
+ destStore, // Format_RGBA32FPx4_Premultiplied
};
#if QT_CONFIG(raster_64bit)
@@ -506,9 +775,24 @@ static DestStoreProc64 destStoreProc64[QImage::NImageFormats] =
nullptr, // Format_RGBA64_Premultiplied
destStore64Gray16, // Format_Grayscale16
destStore64, // Format_BGR888
+ destStore64, // Format_RGBX16FPx4
+ destStore64, // Format_RGBA16FPx4
+ destStore64, // Format_RGBA16FPx4_Premultiplied
+ destStore64, // Format_RGBX32FPx4
+ destStore64, // Format_RGBA32FPx4
+ destStore64, // Format_RGBA32FPx4_Premultiplied
};
#endif
+#if QT_CONFIG(raster_fp)
+static void QT_FASTCALL destStoreFP(QRasterBuffer *rasterBuffer, int x, int y, const QRgba32F *buffer, int length)
+{
+ auto store = qStoreFromRGBA32F[rasterBuffer->format];
+ uchar *dest = rasterBuffer->scanLine(y);
+ store(dest, buffer, x, length, nullptr, nullptr);
+}
+#endif
+
/*
Source fetches
@@ -574,6 +858,15 @@ static const QRgba64 *QT_FASTCALL fetchUntransformedRGBA64PM(QRgba64 *, const Op
}
#endif
+#if QT_CONFIG(raster_fp)
+static const QRgba32F *QT_FASTCALL fetchUntransformedFP(QRgba32F *buffer, const Operator *,
+ const QSpanData *data, int y, int x, int length)
+{
+ const auto fetch = qFetchToRGBA32F[data->texture.format];
+ return fetch(buffer, data->texture.scanLine(y), x, length, data->texture.colorTable, nullptr);
+}
+#endif
+
template<TextureBlendType blendType>
inline void fetchTransformed_pixelBounds(int max, int l1, int l2, int &v)
{
@@ -618,9 +911,9 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
constexpr bool useFetch = (bpp < QPixelLayout::BPP32) && sizeof(T) == sizeof(uint);
const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
if (!useFetch)
- Q_ASSERT(layout->bpp == bpp);
+ Q_ASSERT(layout->bpp == bpp || (layout->bpp == QPixelLayout::BPP16FPx4 && bpp == QPixelLayout::BPP64));
// When templated 'fetch' should be inlined at compile time:
- const FetchPixelFunc fetch = (bpp == QPixelLayout::BPPNone) ? qFetchPixelTable[layout->bpp] : FetchPixelFunc(qFetchPixel<bpp>);
+ const Fetch1PixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? fetch1PixelTable[layout->bpp] : Fetch1PixelFunc(fetch1Pixel<bpp>);
if (canUseFastMatrixPath(cx, cy, length, data)) {
// The increment pr x in the scanline
@@ -651,8 +944,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
fetchTransformed_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1);
if (x1 == x2)
break;
- if (useFetch)
- buffer[i] = fetch(src, x1);
+ if constexpr (useFetch)
+ buffer[i] = fetch1(src, x1);
else
buffer[i] = reinterpret_cast<const T*>(src)[x1];
fx += fdx;
@@ -660,8 +953,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
for (; i < fastLen; ++i) {
int px = (fx >> 16);
- if (useFetch)
- buffer[i] = fetch(src, px);
+ if constexpr (useFetch)
+ buffer[i] = fetch1(src, px);
else
buffer[i] = reinterpret_cast<const T*>(src)[px];
fx += fdx;
@@ -671,8 +964,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
for (; i < length; ++i) {
int px = (fx >> 16);
fetchTransformed_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, px);
- if (useFetch)
- buffer[i] = fetch(src, px);
+ if constexpr (useFetch)
+ buffer[i] = fetch1(src, px);
else
buffer[i] = reinterpret_cast<const T*>(src)[px];
fx += fdx;
@@ -699,8 +992,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
fetchTransformed_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1);
if (x1 == x2 && y1 == y2)
break;
- if (useFetch)
- buffer[i] = fetch(image.scanLine(y1), x1);
+ if constexpr (useFetch)
+ buffer[i] = fetch1(image.scanLine(y1), x1);
else
buffer[i] = reinterpret_cast<const T*>(image.scanLine(y1))[x1];
fx += fdx;
@@ -710,8 +1003,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
for (; i < fastLen; ++i) {
int px = (fx >> 16);
int py = (fy >> 16);
- if (useFetch)
- buffer[i] = fetch(image.scanLine(py), px);
+ if constexpr (useFetch)
+ buffer[i] = fetch1(image.scanLine(py), px);
else
buffer[i] = reinterpret_cast<const T*>(image.scanLine(py))[px];
fx += fdx;
@@ -724,8 +1017,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
int py = (fy >> 16);
fetchTransformed_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, px);
fetchTransformed_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, py);
- if (useFetch)
- buffer[i] = fetch(image.scanLine(py), px);
+ if constexpr (useFetch)
+ buffer[i] = fetch1(image.scanLine(py), px);
else
buffer[i] = reinterpret_cast<const T*>(image.scanLine(py))[px];
fx += fdx;
@@ -752,8 +1045,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
fetchTransformed_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, py);
fetchTransformed_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, px);
- if (useFetch)
- *b = fetch(image.scanLine(py), px);
+ if constexpr (useFetch)
+ *b = fetch1(image.scanLine(py), px);
else
*b = reinterpret_cast<const T*>(image.scanLine(py))[px];
@@ -786,7 +1079,7 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper
int y, int x, int length)
{
const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
- if (layout->bpp != QPixelLayout::BPP64) {
+ if (layout->bpp < QPixelLayout::BPP64) {
uint buffer32[BufferSize];
Q_ASSERT(length <= BufferSize);
if (layout->bpp == QPixelLayout::BPP32)
@@ -796,9 +1089,37 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper
return layout->convertToRGBA64PM(buffer, buffer32, length, data->texture.colorTable, nullptr);
}
- fetchTransformed_fetcher<blendType, QPixelLayout::BPP64, QRgba64>(buffer, data, y, x, length);
- if (data->texture.format == QImage::Format_RGBA64)
- convertRGBA64ToRGBA64PM(buffer, length);
+ fetchTransformed_fetcher<blendType, QPixelLayout::BPP64, quint64>(reinterpret_cast<quint64*>(buffer), data, y, x, length);
+ if (auto convert = convert64ToRGBA64PM[data->texture.format])
+ convert(buffer, length);
+ return buffer;
+}
+#endif
+
+#if QT_CONFIG(raster_fp)
+template<TextureBlendType blendType> /* either BlendTransformed or BlendTransformedTiled */
+static const QRgba32F *QT_FASTCALL fetchTransformedFP(QRgba32F *buffer, const Operator *, const QSpanData *data,
+ int y, int x, int length)
+{
+ const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
+ if (layout->bpp < QPixelLayout::BPP64) {
+ uint buffer32[BufferSize];
+ Q_ASSERT(length <= BufferSize);
+ if (layout->bpp == QPixelLayout::BPP32)
+ fetchTransformed_fetcher<blendType, QPixelLayout::BPP32, uint>(buffer32, data, y, x, length);
+ else
+ fetchTransformed_fetcher<blendType, QPixelLayout::BPPNone, uint>(buffer32, data, y, x, length);
+ qConvertToRGBA32F[data->texture.format](buffer, buffer32, length, data->texture.colorTable, nullptr);
+ } else if (layout->bpp < QPixelLayout::BPP32FPx4) {
+ quint64 buffer64[BufferSize];
+ fetchTransformed_fetcher<blendType, QPixelLayout::BPP64, quint64>(buffer64, data, y, x, length);
+ convert64ToRGBA32F[data->texture.format](buffer, buffer64, length);
+ } else {
+ fetchTransformed_fetcher<blendType, QPixelLayout::BPP32FPx4, QRgba32F>(buffer, data, y, x, length);
+ if (data->texture.format == QImage::Format_RGBA32FPx4)
+ convertRGBA32FToRGBA32FPM(buffer, length);
+ return buffer;
+ }
return buffer;
}
#endif
@@ -1771,8 +2092,8 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
if (useFetch)
Q_ASSERT(sizeof(T) == sizeof(uint));
else
- Q_ASSERT(layout.bpp == bpp);
- const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixelTable[layout.bpp] : qFetchPixel<bpp>;
+ Q_ASSERT(layout.bpp == bpp || (layout.bpp == QPixelLayout::BPP16FPx4 && bpp == QPixelLayout::BPP64));
+ const Fetch1PixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? fetch1PixelTable[layout.bpp] : fetch1Pixel<bpp>;
if (fdy == 0) {
int y1 = (fy >> 16);
int y2;
@@ -1788,7 +2109,7 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
if (x1 != x2)
break;
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = buf1[i * 2 + 1] = fetch1(s1, x1);
buf2[i * 2 + 0] = buf2[i * 2 + 1] = fetch1(s2, x1);
} else {
@@ -1805,7 +2126,7 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
for (; i < fastLen; ++i) {
int x = (fx >> 16);
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = fetch1(s1, x);
buf1[i * 2 + 1] = fetch1(s1, x + 1);
buf2[i * 2 + 0] = fetch1(s2, x);
@@ -1824,7 +2145,7 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
int x1 = (fx >> 16);
int x2;
fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = fetch1(s1, x1);
buf1[i * 2 + 1] = fetch1(s1, x2);
buf2[i * 2 + 0] = fetch1(s2, x1);
@@ -1851,7 +2172,7 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
break;
const uchar *s1 = image.scanLine(y1);
const uchar *s2 = image.scanLine(y2);
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = fetch1(s1, x1);
buf1[i * 2 + 1] = fetch1(s1, x2);
buf2[i * 2 + 0] = fetch1(s2, x1);
@@ -1880,7 +2201,7 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
int y = (fy >> 16);
const uchar *s1 = image.scanLine(y);
const uchar *s2 = s1 + image.bytesPerLine;
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = fetch1(s1, x);
buf1[i * 2 + 1] = fetch1(s1, x + 1);
buf2[i * 2 + 0] = fetch1(s2, x);
@@ -1906,7 +2227,7 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
const uchar *s1 = image.scanLine(y1);
const uchar *s2 = image.scanLine(y2);
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = fetch1(s1, x1);
buf1[i * 2 + 1] = fetch1(s1, x2);
buf2[i * 2 + 0] = fetch1(s2, x1);
@@ -1936,7 +2257,7 @@ static void QT_FASTCALL fetchTransformedBilinear_slow_fetcher(T *buf1, T *buf2,
else
Q_ASSERT(layout.bpp == bpp);
- const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixelTable[layout.bpp] : qFetchPixel<bpp>;
+ const Fetch1PixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? fetch1PixelTable[layout.bpp] : fetch1Pixel<bpp>;
for (int i = 0; i < len; ++i) {
const qreal iw = fw == 0 ? 16384 : 1 / fw;
@@ -1956,7 +2277,7 @@ static void QT_FASTCALL fetchTransformedBilinear_slow_fetcher(T *buf1, T *buf2,
const uchar *s1 = image.scanLine(y1);
const uchar *s2 = image.scanLine(y2);
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = fetch1(s1, x1);
buf1[i * 2 + 1] = fetch1(s1, x2);
buf2[i * 2 + 0] = fetch1(s2, x1);
@@ -2128,7 +2449,8 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf
int y, int x, int length)
{
const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
- const QList<QRgb> *clut = data->texture.colorTable;
+ const auto *clut = data->texture.colorTable;
+ const auto convert = layout->convertToRGBA64PM;
const qreal cx = x + qreal(0.5);
const qreal cy = y + qreal(0.5);
@@ -2137,7 +2459,6 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf
uint sbuf2[BufferSize];
alignas(8) QRgba64 buf1[BufferSize];
alignas(8) QRgba64 buf2[BufferSize];
- QRgba64 *end = buffer + length;
QRgba64 *b = buffer;
if (canUseFastMatrixPath(cx, cy, length, data)) {
@@ -2158,20 +2479,20 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf
if (fdy == 0) { //simple scale, no rotation
while (length) {
- int len = qMin(length, BufferSize / 2);
- int disty = (fy & 0x0000ffff);
+ const int len = qMin(length, BufferSize / 2);
+ const int disty = (fy & 0x0000ffff);
#if defined(__SSE2__)
const __m128i vdy = _mm_set1_epi16(disty);
const __m128i vidy = _mm_set1_epi16(0x10000 - disty);
#endif
fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
- layout->convertToRGBA64PM(buf1, sbuf1, len * 2, clut, nullptr);
+ convert(buf1, sbuf1, len * 2, clut, nullptr);
if (disty)
- layout->convertToRGBA64PM(buf2, sbuf2, len * 2, clut, nullptr);
+ convert(buf2, sbuf2, len * 2, clut, nullptr);
for (int i = 0; i < len; ++i) {
- int distx = (fx & 0x0000ffff);
+ const int distx = (fx & 0x0000ffff);
#if defined(__SSE2__)
__m128i vt = _mm_loadu_si128((const __m128i*)(buf1 + i*2));
if (disty) {
@@ -2196,17 +2517,17 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf
b += len;
}
} else { // rotation or shear
- while (b < end) {
- int len = qMin(length, BufferSize / 2);
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
- layout->convertToRGBA64PM(buf1, sbuf1, len * 2, clut, nullptr);
- layout->convertToRGBA64PM(buf2, sbuf2, len * 2, clut, nullptr);
+ convert(buf1, sbuf1, len * 2, clut, nullptr);
+ convert(buf2, sbuf2, len * 2, clut, nullptr);
for (int i = 0; i < len; ++i) {
- int distx = (fx & 0x0000ffff);
- int disty = (fy & 0x0000ffff);
+ const int distx = (fx & 0x0000ffff);
+ const int disty = (fy & 0x0000ffff);
b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty);
fx += fdx;
fy += fdy;
@@ -2237,8 +2558,8 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf
const int len = qMin(length, BufferSize / 2);
fetcher(sbuf1, sbuf2, distxs, distys, len, data->texture, fx, fy, fw, fdx, fdy, fdw);
- layout->convertToRGBA64PM(buf1, sbuf1, len * 2, clut, nullptr);
- layout->convertToRGBA64PM(buf2, sbuf2, len * 2, clut, nullptr);
+ convert(buf1, sbuf1, len * 2, clut, nullptr);
+ convert(buf2, sbuf2, len * 2, clut, nullptr);
for (int i = 0; i < len; ++i) {
const int distx = distxs[i];
@@ -2257,8 +2578,7 @@ template<TextureBlendType blendType>
static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint64(QRgba64 *buffer, const QSpanData *data,
int y, int x, int length)
{
- Q_ASSERT(qPixelLayouts[data->texture.format].bpp == QPixelLayout::BPP64);
- const auto convert = (data->texture.format == QImage::Format_RGBA64) ? convertRGBA64ToRGBA64PM : convertRGBA64PMToRGBA64PM;
+ const auto convert = convert64ToRGBA64PM[data->texture.format];
const qreal cx = x + qreal(0.5);
const qreal cy = y + qreal(0.5);
@@ -2375,15 +2695,366 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint64(QRgba64 *buf
}
template<TextureBlendType blendType>
+static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_f32x4(QRgba64 *buffer, const QSpanData *data,
+ int y, int x, int length)
+{
+ const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
+ const auto *clut = data->texture.colorTable;
+ const auto convert = layout->fetchToRGBA64PM;
+
+ const qreal cx = x + qreal(0.5);
+ const qreal cy = y + qreal(0.5);
+
+ QRgba32F sbuf1[BufferSize];
+ QRgba32F sbuf2[BufferSize];
+ alignas(8) QRgba64 buf1[BufferSize];
+ alignas(8) QRgba64 buf2[BufferSize];
+ QRgba64 *b = buffer;
+
+ if (canUseFastMatrixPath(cx, cy, length, data)) {
+ // The increment pr x in the scanline
+ const int fdx = (int)(data->m11 * fixed_scale);
+ const int fdy = (int)(data->m12 * fixed_scale);
+
+ int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
+ int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
+
+ fx -= half_point;
+ fy -= half_point;
+
+ const auto fetcher = fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPP32FPx4, QRgba32F>;
+
+ const bool skipsecond = (fdy == 0) && ((fy & 0x0000ffff) == 0);
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+
+ fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
+
+ convert(buf1, (const uchar *)sbuf1, 0, len * 2, clut, nullptr);
+ if (!skipsecond)
+ convert(buf2, (const uchar *)sbuf2, 0, len * 2, clut, nullptr);
+
+ for (int i = 0; i < len; ++i) {
+ const int distx = (fx & 0x0000ffff);
+ const int disty = (fy & 0x0000ffff);
+ b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty);
+ fx += fdx;
+ fy += fdy;
+ }
+
+ length -= len;
+ b += len;
+ }
+ } else { // !(data->fast_matrix)
+ const auto fetcher = fetchTransformedBilinear_slow_fetcher<blendType, QPixelLayout::BPP32FPx4, QRgba32F>;
+
+ const qreal fdx = data->m11;
+ const qreal fdy = data->m12;
+ const qreal fdw = data->m13;
+
+ qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
+ qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
+ qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
+
+ ushort distxs[BufferSize / 2];
+ ushort distys[BufferSize / 2];
+
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(sbuf1, sbuf2, distxs, distys, len, data->texture, fx, fy, fw, fdx, fdy, fdw);
+
+ convert(buf1, (const uchar *)sbuf1, 0, len * 2, clut, nullptr);
+ convert(buf2, (const uchar *)sbuf2, 0, len * 2, clut, nullptr);
+
+ for (int i = 0; i < len; ++i) {
+ const int distx = distxs[i];
+ const int disty = distys[i];
+ b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty);
+ }
+
+ length -= len;
+ b += len;
+ }
+ }
+ return buffer;
+}
+
+template<TextureBlendType blendType>
static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, const Operator *,
const QSpanData *data, int y, int x, int length)
{
- if (qPixelLayouts[data->texture.format].bpp == QPixelLayout::BPP64)
+ switch (qPixelLayouts[data->texture.format].bpp) {
+ case QPixelLayout::BPP64:
+ case QPixelLayout::BPP16FPx4:
return fetchTransformedBilinear64_uint64<blendType>(buffer, data, y, x, length);
- return fetchTransformedBilinear64_uint32<blendType>(buffer, data, y, x, length);
+ case QPixelLayout::BPP32FPx4:
+ return fetchTransformedBilinear64_f32x4<blendType>(buffer, data, y, x, length);
+ default:
+ return fetchTransformedBilinear64_uint32<blendType>(buffer, data, y, x, length);
+ }
}
#endif
+#if QT_CONFIG(raster_fp)
+static void interpolate_simple_rgba32f(QRgba32F *b, const QRgba32F *buf1, const QRgba32F *buf2, int len,
+ int &fx, int fdx,
+ int &fy, int fdy)
+{
+ for (int i = 0; i < len; ++i) {
+ const int distx = (fx & 0x0000ffff);
+ const int disty = (fy & 0x0000ffff);
+ b[i] = interpolate_4_pixels_rgba32f(buf1 + i*2, buf2 + i*2, distx, disty);
+ fx += fdx;
+ fy += fdy;
+ }
+}
+
+static void interpolate_perspective_rgba32f(QRgba32F *b, const QRgba32F *buf1, const QRgba32F *buf2, int len,
+ unsigned short *distxs,
+ unsigned short *distys)
+{
+ for (int i = 0; i < len; ++i) {
+ const int dx = distxs[i];
+ const int dy = distys[i];
+ b[i] = interpolate_4_pixels_rgba32f(buf1 + i*2, buf2 + i*2, dx, dy);
+ }
+}
+
+template<TextureBlendType blendType>
+static const QRgba32F *QT_FASTCALL fetchTransformedBilinearFP_uint32(QRgba32F *buffer, const QSpanData *data,
+ int y, int x, int length)
+{
+ const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
+ const auto *clut = data->texture.colorTable;
+ const auto convert = qConvertToRGBA32F[data->texture.format];
+
+ const qreal cx = x + qreal(0.5);
+ const qreal cy = y + qreal(0.5);
+
+ uint sbuf1[BufferSize];
+ uint sbuf2[BufferSize];
+ QRgba32F buf1[BufferSize];
+ QRgba32F buf2[BufferSize];
+ QRgba32F *b = buffer;
+
+ if (canUseFastMatrixPath(cx, cy, length, data)) {
+ // The increment pr x in the scanline
+ const int fdx = (int)(data->m11 * fixed_scale);
+ const int fdy = (int)(data->m12 * fixed_scale);
+
+ int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
+ int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
+
+ fx -= half_point;
+ fy -= half_point;
+
+ const auto fetcher =
+ (layout->bpp == QPixelLayout::BPP32)
+ ? fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPP32, uint>
+ : fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPPNone, uint>;
+
+ const bool skipsecond = (fdy == 0) && ((fy & 0x0000ffff) == 0);
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
+
+ convert(buf1, sbuf1, len * 2, clut, nullptr);
+ if (!skipsecond)
+ convert(buf2, sbuf2, len * 2, clut, nullptr);
+
+ interpolate_simple_rgba32f(b, buf1, buf2, len, fx, fdx, fy, fdy);
+
+ length -= len;
+ b += len;
+ }
+ } else { // !(data->fast_matrix)
+ const auto fetcher =
+ (layout->bpp == QPixelLayout::BPP32)
+ ? fetchTransformedBilinear_slow_fetcher<blendType, QPixelLayout::BPP32, uint>
+ : fetchTransformedBilinear_slow_fetcher<blendType, QPixelLayout::BPPNone, uint>;
+
+ const qreal fdx = data->m11;
+ const qreal fdy = data->m12;
+ const qreal fdw = data->m13;
+ qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
+ qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
+ qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
+ ushort distxs[BufferSize / 2];
+ ushort distys[BufferSize / 2];
+
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(sbuf1, sbuf2, distxs, distys, len, data->texture, fx, fy, fw, fdx, fdy, fdw);
+
+ convert(buf1, sbuf1, len * 2, clut, nullptr);
+ convert(buf2, sbuf2, len * 2, clut, nullptr);
+
+ interpolate_perspective_rgba32f(b, buf1, buf2, len, distxs, distys);
+
+ length -= len;
+ b += len;
+ }
+ }
+ return buffer;
+}
+
+template<TextureBlendType blendType>
+static const QRgba32F *QT_FASTCALL fetchTransformedBilinearFP_uint64(QRgba32F *buffer, const QSpanData *data,
+ int y, int x, int length)
+{
+ const auto convert = convert64ToRGBA32F[data->texture.format];
+
+ const qreal cx = x + qreal(0.5);
+ const qreal cy = y + qreal(0.5);
+
+ quint64 sbuf1[BufferSize];
+ quint64 sbuf2[BufferSize];
+ QRgba32F buf1[BufferSize];
+ QRgba32F buf2[BufferSize];
+ QRgba32F *b = buffer;
+
+ if (canUseFastMatrixPath(cx, cy, length, data)) {
+ // The increment pr x in the scanline
+ const int fdx = (int)(data->m11 * fixed_scale);
+ const int fdy = (int)(data->m12 * fixed_scale);
+
+ int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
+ int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
+
+ fx -= half_point;
+ fy -= half_point;
+ const auto fetcher = fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPP64, quint64>;
+
+ const bool skipsecond = (fdy == 0) && ((fy & 0x0000ffff) == 0);
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
+
+ convert(buf1, sbuf1, len * 2);
+ if (!skipsecond)
+ convert(buf2, sbuf2, len * 2);
+
+ interpolate_simple_rgba32f(b, buf1, buf2, len, fx, fdx, fy, fdy);
+
+ length -= len;
+ b += len;
+ }
+ } else { // !(data->fast_matrix)
+ const auto fetcher = fetchTransformedBilinear_slow_fetcher<blendType, QPixelLayout::BPP64, quint64>;
+
+ const qreal fdx = data->m11;
+ const qreal fdy = data->m12;
+ const qreal fdw = data->m13;
+
+ qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
+ qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
+ qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
+
+ ushort distxs[BufferSize / 2];
+ ushort distys[BufferSize / 2];
+
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(sbuf1, sbuf2, distxs, distys, len, data->texture, fx, fy, fw, fdx, fdy, fdw);
+
+ convert(buf1, sbuf1, len * 2);
+ convert(buf2, sbuf2, len * 2);
+
+ interpolate_perspective_rgba32f(b, buf1, buf2, len, distxs, distys);
+
+ length -= len;
+ b += len;
+ }
+ }
+ return buffer;
+}
+
+template<TextureBlendType blendType>
+static const QRgba32F *QT_FASTCALL fetchTransformedBilinearFP(QRgba32F *buffer, const QSpanData *data,
+ int y, int x, int length)
+{
+ const auto convert = data->rasterBuffer->format == QImage::Format_RGBA32FPx4 ? convertRGBA32FToRGBA32FPM
+ : convertRGBA32FToRGBA32F;
+
+ const qreal cx = x + qreal(0.5);
+ const qreal cy = y + qreal(0.5);
+
+ QRgba32F buf1[BufferSize];
+ QRgba32F buf2[BufferSize];
+ QRgba32F *b = buffer;
+
+ if (canUseFastMatrixPath(cx, cy, length, data)) {
+ // The increment pr x in the scanline
+ const int fdx = (int)(data->m11 * fixed_scale);
+ const int fdy = (int)(data->m12 * fixed_scale);
+
+ int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
+ int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
+
+ fx -= half_point;
+ fy -= half_point;
+ const auto fetcher = fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPP32FPx4, QRgba32F>;
+
+ const bool skipsecond = (fdy == 0) && ((fy & 0x0000ffff) == 0);
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, fdy);
+
+ convert(buf1, len * 2);
+ if (!skipsecond)
+ convert(buf2, len * 2);
+
+ interpolate_simple_rgba32f(b, buf1, buf2, len, fx, fdx, fy, fdy);
+
+ length -= len;
+ b += len;
+ }
+ } else { // !(data->fast_matrix)
+ const auto fetcher = fetchTransformedBilinear_slow_fetcher<blendType, QPixelLayout::BPP32FPx4, QRgba32F>;
+
+ const qreal fdx = data->m11;
+ const qreal fdy = data->m12;
+ const qreal fdw = data->m13;
+
+ qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
+ qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
+ qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
+
+ ushort distxs[BufferSize / 2];
+ ushort distys[BufferSize / 2];
+
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(buf1, buf2, distxs, distys, len, data->texture, fx, fy, fw, fdx, fdy, fdw);
+
+ convert(buf1, len * 2);
+ convert(buf2, len * 2);
+
+ interpolate_perspective_rgba32f(b, buf1, buf2, len, distxs, distys);
+
+ length -= len;
+ b += len;
+ }
+ }
+ return buffer;
+}
+
+template<TextureBlendType blendType>
+static const QRgba32F *QT_FASTCALL fetchTransformedBilinearFP(QRgba32F *buffer, const Operator *,
+ const QSpanData *data, int y, int x, int length)
+{
+ switch (qPixelLayouts[data->texture.format].bpp) {
+ case QPixelLayout::BPP64:
+ case QPixelLayout::BPP16FPx4:
+ return fetchTransformedBilinearFP_uint64<blendType>(buffer, data, y, x, length);
+ case QPixelLayout::BPP32FPx4:
+ return fetchTransformedBilinearFP<blendType>(buffer, data, y, x, length);
+ default:
+ return fetchTransformedBilinearFP_uint32<blendType>(buffer, data, y, x, length);
+ }
+}
+#endif // QT_CONFIG(raster_fp)
+
// FetchUntransformed can have more specialized methods added depending on SIMD features.
static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = {
nullptr, // Invalid
@@ -2416,6 +3087,12 @@ static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = {
fetchUntransformed, // RGBA64_Premultiplied
fetchUntransformed, // Grayscale16
fetchUntransformed, // BGR888
+ fetchUntransformed, // RGBX16FPx4
+ fetchUntransformed, // RGBA16FPx4
+ fetchUntransformed, // RGBA16FPx4_Premultiplied
+ fetchUntransformed, // RGBX32Px4
+ fetchUntransformed, // RGBA32FPx4
+ fetchUntransformed, // RGBA32FPx4_Premultiplied
};
static const SourceFetchProc sourceFetchGeneric[NBlendTypes] = {
@@ -2494,6 +3171,21 @@ static inline SourceFetchProc64 getSourceFetch64(TextureBlendType blendType, QIm
}
#endif
+#if QT_CONFIG(raster_fp)
+static const SourceFetchProcFP sourceFetchGenericFP[NBlendTypes] = {
+ fetchUntransformedFP, // Untransformed
+ fetchUntransformedFP, // Tiled
+ fetchTransformedFP<BlendTransformed>, // Transformed
+ fetchTransformedFP<BlendTransformedTiled>, // TransformedTiled
+ fetchTransformedBilinearFP<BlendTransformedBilinear>, // Bilinear
+ fetchTransformedBilinearFP<BlendTransformedBilinearTiled> // BilinearTiled
+};
+
+static inline SourceFetchProcFP getSourceFetchFP(TextureBlendType blendType, QImage::Format /*format*/)
+{
+ return sourceFetchGenericFP[blendType];
+}
+#endif
#define FIXPT_BITS 8
#define FIXPT_SIZE (1<<FIXPT_BITS)
@@ -2513,6 +3205,22 @@ static const QRgba64& qt_gradient_pixel64_fixed(const QGradientData *data, int f
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline QRgba32F qt_gradient_pixelFP(const QGradientData *data, qreal pos)
+{
+ int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5));
+ QRgba64 rgb64 = data->colorTable64[qt_gradient_clamp(data, ipos)];
+ return QRgba32F::fromRgba64(rgb64.red(),rgb64.green(), rgb64.blue(), rgb64.alpha());
+}
+
+static inline QRgba32F qt_gradient_pixelFP_fixed(const QGradientData *data, int fixed_pos)
+{
+ int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
+ QRgba64 rgb64 = data->colorTable64[qt_gradient_clamp(data, ipos)];
+ return QRgba32F::fromRgba64(rgb64.red(), rgb64.green(), rgb64.blue(), rgb64.alpha());
+}
+#endif
+
static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
{
v->dx = data->gradient.linear.end.x - data->gradient.linear.origin.x;
@@ -2566,6 +3274,29 @@ public:
};
#endif
+#if QT_CONFIG(raster_fp)
+class GradientBaseFP
+{
+public:
+ typedef QRgba32F Type;
+ static Type null() { return QRgba32F::fromRgba64(0,0,0,0); }
+ static Type fetchSingle(const QGradientData& gradient, qreal v)
+ {
+ return qt_gradient_pixelFP(&gradient, v);
+ }
+ static Type fetchSingle(const QGradientData& gradient, int v)
+ {
+ return qt_gradient_pixelFP_fixed(&gradient, v);
+ }
+ static void memfill(Type *buffer, Type fill, int length)
+ {
+ quint64 fillCopy;
+ memcpy(&fillCopy, &fill, sizeof(quint64));
+ qt_memfill64((quint64*)buffer, fillCopy, length);
+ }
+};
+#endif
+
template<class GradientBase, typename BlendType>
static inline const BlendType * QT_FASTCALL qt_fetch_linear_gradient_template(
BlendType *buffer, const Operator *op, const QSpanData *data,
@@ -2651,6 +3382,13 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe
return qt_fetch_linear_gradient_template<GradientBase64, QRgba64>(buffer, op, data, y, x, length);
}
#endif
+#if QT_CONFIG(raster_fp)
+static const QRgba32F * QT_FASTCALL qt_fetch_linear_gradient_rgbfp(QRgba32F *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_linear_gradient_template<GradientBaseFP, QRgba32F>(buffer, op, data, y, x, length);
+}
+#endif
static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data)
{
@@ -2720,6 +3458,14 @@ const QRgba64 * QT_FASTCALL qt_fetch_radial_gradient_rgb64(QRgba64 *buffer, cons
}
#endif
+#if QT_CONFIG(raster_fp)
+static const QRgba32F * QT_FASTCALL qt_fetch_radial_gradient_rgbfp(QRgba32F *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_radial_gradient_template<RadialFetchPlain<GradientBaseFP>, QRgba32F>(buffer, op, data, y, x, length);
+}
+#endif
+
template <class GradientBase, typename BlendType>
static inline const BlendType * QT_FASTCALL qt_fetch_conical_gradient_template(
BlendType *buffer, const QSpanData *data,
@@ -2785,21 +3531,37 @@ static const QRgba64 * QT_FASTCALL qt_fetch_conical_gradient_rgb64(QRgba64 *buff
}
#endif
+#if QT_CONFIG(raster_fp)
+static const QRgba32F * QT_FASTCALL qt_fetch_conical_gradient_rgbfp(QRgba32F *buffer, const Operator *, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_conical_gradient_template<GradientBaseFP, QRgba32F>(buffer, data, y, x, length);
+}
+#endif
+
extern CompositionFunctionSolid qt_functionForModeSolid_C[];
extern CompositionFunctionSolid64 qt_functionForModeSolid64_C[];
+extern CompositionFunctionSolidFP qt_functionForModeSolidFP_C[];
static const CompositionFunctionSolid *functionForModeSolid = qt_functionForModeSolid_C;
#if QT_CONFIG(raster_64bit)
static const CompositionFunctionSolid64 *functionForModeSolid64 = qt_functionForModeSolid64_C;
#endif
+#if QT_CONFIG(raster_fp)
+static const CompositionFunctionSolidFP *functionForModeSolidFP = qt_functionForModeSolidFP_C;
+#endif
extern CompositionFunction qt_functionForMode_C[];
extern CompositionFunction64 qt_functionForMode64_C[];
+extern CompositionFunctionFP qt_functionForModeFP_C[];
static const CompositionFunction *functionForMode = qt_functionForMode_C;
#if QT_CONFIG(raster_64bit)
static const CompositionFunction64 *functionForMode64 = qt_functionForMode64_C;
#endif
+#if QT_CONFIG(raster_fp)
+static const CompositionFunctionFP *functionForModeFP = qt_functionForModeFP_C;
+#endif
static TextureBlendType getBlendType(const QSpanData *data)
{
@@ -2833,9 +3595,8 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
case QSpanData::Solid:
solidSource = data->solidColor.isOpaque();
op.srcFetch = nullptr;
-#if QT_CONFIG(raster_64bit)
op.srcFetch64 = nullptr;
-#endif
+ op.srcFetchFP = nullptr;
break;
case QSpanData::LinearGradient:
solidSource = !data->gradient.alphaColor;
@@ -2844,6 +3605,9 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
#if QT_CONFIG(raster_64bit)
op.srcFetch64 = qt_fetch_linear_gradient_rgb64;
#endif
+#if QT_CONFIG(raster_fp)
+ op.srcFetchFP = qt_fetch_linear_gradient_rgbfp;
+#endif
break;
case QSpanData::RadialGradient:
solidSource = !data->gradient.alphaColor;
@@ -2852,6 +3616,9 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
#if QT_CONFIG(raster_64bit)
op.srcFetch64 = qt_fetch_radial_gradient_rgb64;
#endif
+#if QT_CONFIG(raster_fp)
+ op.srcFetchFP = qt_fetch_radial_gradient_rgbfp;
+#endif
break;
case QSpanData::ConicalGradient:
solidSource = !data->gradient.alphaColor;
@@ -2859,6 +3626,9 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
#if QT_CONFIG(raster_64bit)
op.srcFetch64 = qt_fetch_conical_gradient_rgb64;
#endif
+#if QT_CONFIG(raster_fp)
+ op.srcFetchFP = qt_fetch_conical_gradient_rgbfp;
+#endif
break;
case QSpanData::Texture:
solidSource = !data->texture.hasAlpha;
@@ -2866,13 +3636,19 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
#if QT_CONFIG(raster_64bit)
op.srcFetch64 = getSourceFetch64(getBlendType(data), data->texture.format);;
#endif
+#if QT_CONFIG(raster_fp)
+ op.srcFetchFP = getSourceFetchFP(getBlendType(data), data->texture.format);
+#endif
break;
default:
Q_UNREACHABLE();
break;
}
#if !QT_CONFIG(raster_64bit)
- op.srcFetch64 = 0;
+ op.srcFetch64 = nullptr;
+#endif
+#if !QT_CONFIG(raster_fp)
+ op.srcFetchFP = nullptr;
#endif
op.mode = data->rasterBuffer->compositionMode;
@@ -2883,8 +3659,14 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
#if QT_CONFIG(raster_64bit)
op.destFetch64 = destFetchProc64[data->rasterBuffer->format];
#else
- op.destFetch64 = 0;
+ op.destFetch64 = nullptr;
#endif
+#if QT_CONFIG(raster_fp)
+ if (data->rasterBuffer->format > QImage::Format_Indexed8)
+ op.destFetchFP = destFetchFP;
+ else
+#endif
+ op.destFetchFP = nullptr;
if (op.mode == QPainter::CompositionMode_Source &&
(data->type != QSpanData::Texture || data->texture.const_alpha == 256)) {
const QSpan *lastSpan = spans + spanCount;
@@ -2905,6 +3687,9 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
if (op.destFetch64 != destFetchRGB64)
op.destFetch64 = destFetch64Undefined;
#endif
+#if QT_CONFIG(raster_fp)
+ op.destFetchFP = destFetchFPUndefined;
+#endif
}
}
@@ -2916,9 +3701,18 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
op.funcSolid64 = functionForModeSolid64[op.mode];
op.func64 = functionForMode64[op.mode];
#else
- op.destStore64 = 0;
- op.funcSolid64 = 0;
- op.func64 = 0;
+ op.destStore64 = nullptr;
+ op.funcSolid64 = nullptr;
+ op.func64 = nullptr;
+#endif
+#if QT_CONFIG(raster_fp)
+ op.destStoreFP = destStoreFP;
+ op.funcSolidFP = functionForModeSolidFP[op.mode];
+ op.funcFP = functionForModeFP[op.mode];
+#else
+ op.destStoreFP = nullptr;
+ op.funcSolidFP = nullptr;
+ op.funcFP = nullptr;
#endif
return op;
@@ -2927,6 +3721,12 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP bpp, int x, int y, int length)
{
switch (bpp) {
+ case QPixelLayout::BPP32FPx4: {
+ QRgba32F *dest = reinterpret_cast<QRgba32F *>(rasterBuffer->scanLine(y)) + x;
+ qt_memfill_template(dest + 1, dest[0], length - 1);
+ break;
+ }
+ case QPixelLayout::BPP16FPx4:
case QPixelLayout::BPP64: {
quint64 *dest = reinterpret_cast<quint64 *>(rasterBuffer->scanLine(y)) + x;
qt_memfill_template(dest + 1, dest[0], length - 1);
@@ -3027,7 +3827,7 @@ static void blend_color_argb(int count, const QSpan *spans, void *userData)
}
}
-void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData)
+static void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData)
{
#if QT_CONFIG(raster_64bit)
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
@@ -3068,6 +3868,47 @@ void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData)
#endif
}
+static void blend_color_generic_fp(int count, const QSpan *spans, void *userData)
+{
+#if QT_CONFIG(raster_fp)
+ QSpanData *data = reinterpret_cast<QSpanData *>(userData);
+ Operator op = getOperator(data, nullptr, 0);
+ if (!op.funcSolidFP || !op.destFetchFP) {
+ qCDebug(lcQtGuiDrawHelper, "blend_color_generic_fp: unsupported 4xF16 blend attempted, falling back to 32-bit");
+ return blend_color_generic(count, spans, userData);
+ }
+
+ QRgba32F buffer[BufferSize];
+ const QRgba32F color = qConvertRgb64ToRgbaF32(data->solidColor);
+ const bool solidFill = op.mode == QPainter::CompositionMode_Source;
+ QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
+
+ while (count--) {
+ int x = spans->x;
+ int length = spans->len;
+ if (solidFill && bpp >= QPixelLayout::BPP8 && spans->coverage == 255 && length && op.destStoreFP) {
+ // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels
+ op.destStoreFP(data->rasterBuffer, x, spans->y, &color, 1);
+ spanfill_from_first(data->rasterBuffer, bpp, x, spans->y, length);
+ length = 0;
+ }
+
+ while (length) {
+ int l = qMin(BufferSize, length);
+ QRgba32F *dest = op.destFetchFP(buffer, data->rasterBuffer, x, spans->y, l);
+ op.funcSolidFP(dest, l, color, spans->coverage);
+ if (op.destStoreFP)
+ op.destStoreFP(data->rasterBuffer, x, spans->y, dest, l);
+ length -= l;
+ x += l;
+ }
+ ++spans;
+ }
+#else
+ blend_color_generic(count, spans, userData);
+#endif
+}
+
template <typename T>
void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handler)
{
@@ -3098,7 +3939,7 @@ void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handle
int process_length = l;
int process_x = x;
- const typename T::BlendType *src = handler.fetch(process_x, y, process_length);
+ const auto *src = handler.fetch(process_x, y, process_length);
int offset = 0;
while (l > 0) {
if (x == spans->x) // new span?
@@ -3123,31 +3964,20 @@ void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handle
}
}
-template<typename T>
struct QBlendBase
{
- typedef T BlendType;
- QBlendBase(QSpanData *d, const Operator &o)
- : data(d)
- , op(o)
- , dest(nullptr)
- {
- }
-
QSpanData *data;
Operator op;
-
- BlendType *dest;
-
- alignas(8) BlendType buffer[BufferSize];
- alignas(8) BlendType src_buffer[BufferSize];
};
-class BlendSrcGeneric : public QBlendBase<uint>
+class BlendSrcGeneric : public QBlendBase
{
public:
+ uint *dest = nullptr;
+ alignas(16) uint buffer[BufferSize];
+ alignas(16) uint src_buffer[BufferSize];
BlendSrcGeneric(QSpanData *d, const Operator &o)
- : QBlendBase<uint>(d, o)
+ : QBlendBase{d, o}
{
}
@@ -3170,11 +4000,14 @@ public:
};
#if QT_CONFIG(raster_64bit)
-class BlendSrcGenericRGB64 : public QBlendBase<QRgba64>
+class BlendSrcGenericRGB64 : public QBlendBase
{
public:
+ QRgba64 *dest = nullptr;
+ alignas(16) QRgba64 buffer[BufferSize];
+ alignas(16) QRgba64 src_buffer[BufferSize];
BlendSrcGenericRGB64(QSpanData *d, const Operator &o)
- : QBlendBase<QRgba64>(d, o)
+ : QBlendBase{d, o}
{
}
@@ -3202,6 +4035,42 @@ public:
};
#endif
+#if QT_CONFIG(raster_fp)
+class BlendSrcGenericRGBFP : public QBlendBase
+{
+public:
+ QRgba32F *dest = nullptr;
+ alignas(16) QRgba32F buffer[BufferSize];
+ alignas(16) QRgba32F src_buffer[BufferSize];
+ BlendSrcGenericRGBFP(QSpanData *d, const Operator &o)
+ : QBlendBase{d, o}
+ {
+ }
+
+ bool isSupported() const
+ {
+ return op.funcFP && op.destFetchFP && op.srcFetchFP;
+ }
+
+ const QRgba32F *fetch(int x, int y, int len)
+ {
+ dest = op.destFetchFP(buffer, data->rasterBuffer, x, y, len);
+ return op.srcFetchFP(src_buffer, &op, data, y, x, len);
+ }
+
+ void process(int, int, int len, int coverage, const QRgba32F *src, int offset)
+ {
+ op.funcFP(dest + offset, src + offset, len, coverage);
+ }
+
+ void store(int x, int y, int len)
+ {
+ if (op.destStoreFP)
+ op.destStoreFP(data->rasterBuffer, x, y, dest, len);
+ }
+};
+#endif
+
static void blend_src_generic(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
@@ -3225,6 +4094,22 @@ static void blend_src_generic_rgb64(int count, const QSpan *spans, void *userDat
}
#endif
+#if QT_CONFIG(raster_fp)
+static void blend_src_generic_fp(int count, const QSpan *spans, void *userData)
+{
+ QSpanData *data = reinterpret_cast<QSpanData *>(userData);
+ Operator op = getOperator(data, spans, count);
+ BlendSrcGenericRGBFP blendFP(data, op);
+ if (blendFP.isSupported())
+ handleSpans(count, spans, data, blendFP);
+ else {
+ qCDebug(lcQtGuiDrawHelper, "blend_src_generic_fp: unsupported 4xFP blend attempted, falling back to 32-bit");
+ BlendSrcGeneric blend32(data, op);
+ handleSpans(count, spans, data, blend32);
+ }
+}
+#endif
+
static void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
@@ -3323,6 +4208,58 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi
}
#endif
+#if QT_CONFIG(raster_fp)
+static void blend_untransformed_generic_fp(int count, const QSpan *spans, void *userData)
+{
+ QSpanData *data = reinterpret_cast<QSpanData *>(userData);
+
+ Operator op = getOperator(data, spans, count);
+ if (!op.funcFP) {
+ qCDebug(lcQtGuiDrawHelper, "blend_untransformed_generic_rgbaf16: unsupported 4xFP16 blend attempted, falling back to 32-bit");
+ return blend_untransformed_generic(count, spans, userData);
+ }
+ QRgba32F buffer[BufferSize];
+ QRgba32F src_buffer[BufferSize];
+
+ const int image_width = data->texture.width;
+ const int image_height = data->texture.height;
+ int xoff = -qRound(-data->dx);
+ int yoff = -qRound(-data->dy);
+
+ for (; count--; spans++) {
+ if (!spans->len)
+ continue;
+ int x = spans->x;
+ int length = spans->len;
+ int sx = xoff + x;
+ int sy = yoff + spans->y;
+ if (sy >= 0 && sy < image_height && sx < image_width) {
+ if (sx < 0) {
+ x -= sx;
+ length += sx;
+ sx = 0;
+ }
+ if (sx + length > image_width)
+ length = image_width - sx;
+ if (length > 0) {
+ const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
+ while (length) {
+ int l = qMin(BufferSize, length);
+ const QRgba32F *src = op.srcFetchFP(src_buffer, &op, data, sy, sx, l);
+ QRgba32F *dest = op.destFetchFP(buffer, data->rasterBuffer, x, spans->y, l);
+ op.funcFP(dest, src, l, coverage);
+ if (op.destStoreFP)
+ op.destStoreFP(data->rasterBuffer, x, spans->y, dest, l);
+ x += l;
+ sx += l;
+ length -= l;
+ }
+ }
+ }
+ }
+}
+#endif
+
static void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
@@ -3626,6 +4563,62 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD
}
#endif
+#if QT_CONFIG(raster_fp)
+static void blend_tiled_generic_fp(int count, const QSpan *spans, void *userData)
+{
+ QSpanData *data = reinterpret_cast<QSpanData *>(userData);
+
+ Operator op = getOperator(data, spans, count);
+ if (!op.funcFP) {
+ qCDebug(lcQtGuiDrawHelper, "blend_tiled_generic_fp: unsupported 4xFP blend attempted, falling back to 32-bit");
+ return blend_tiled_generic(count, spans, userData);
+ }
+ QRgba32F buffer[BufferSize];
+ QRgba32F src_buffer[BufferSize];
+
+ const int image_width = data->texture.width;
+ const int image_height = data->texture.height;
+ int xoff = -qRound(-data->dx) % image_width;
+ int yoff = -qRound(-data->dy) % image_height;
+
+ if (xoff < 0)
+ xoff += image_width;
+ if (yoff < 0)
+ yoff += image_height;
+
+ // Consider tiling optimizing like the other versions.
+
+ while (count--) {
+ int x = spans->x;
+ int length = spans->len;
+ int sx = (xoff + spans->x) % image_width;
+ int sy = (spans->y + yoff) % image_height;
+ if (sx < 0)
+ sx += image_width;
+ if (sy < 0)
+ sy += image_height;
+
+ const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
+ while (length) {
+ int l = qMin(image_width - sx, length);
+ if (BufferSize < l)
+ l = BufferSize;
+ const QRgba32F *src = op.srcFetchFP(src_buffer, &op, data, sy, sx, l);
+ QRgba32F *dest = op.destFetchFP(buffer, data->rasterBuffer, x, spans->y, l);
+ op.funcFP(dest, src, l, coverage);
+ if (op.destStoreFP)
+ op.destStoreFP(data->rasterBuffer, x, spans->y, dest, l);
+ x += l;
+ sx += l;
+ length -= l;
+ if (sx >= image_width)
+ sx = 0;
+ }
+ ++spans;
+ }
+}
+#endif
+
static void blend_tiled_argb(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
@@ -3812,19 +4805,31 @@ static const ProcessSpans processTextureSpansGeneric64[NBlendTypes] = {
};
#endif
+#if QT_CONFIG(raster_fp)
+static const ProcessSpans processTextureSpansGenericFP[NBlendTypes] = {
+ blend_untransformed_generic_fp, // Untransformed
+ blend_tiled_generic_fp, // Tiled
+ blend_src_generic_fp, // Transformed
+ blend_src_generic_fp, // TransformedTiled
+ blend_src_generic_fp, // TransformedBilinear
+ blend_src_generic_fp // TransformedBilinearTiled
+};
+#endif
void qBlendTexture(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
TextureBlendType blendType = getBlendType(data);
ProcessSpans proc;
switch (data->rasterBuffer->format) {
+ case QImage::Format_Invalid:
+ Q_UNREACHABLE();
+ return;
case QImage::Format_ARGB32_Premultiplied:
proc = processTextureSpansARGB32PM[blendType];
break;
case QImage::Format_RGB16:
proc = processTextureSpansRGB16[blendType];
break;
-#if QT_CONFIG(raster_64bit)
#if defined(__SSE2__) || defined(__ARM_NEON__) || (Q_PROCESSOR_WORDSIZE == 8)
case QImage::Format_ARGB32:
case QImage::Format_RGBA8888:
@@ -3837,12 +4842,28 @@ void qBlendTexture(int count, const QSpan *spans, void *userData)
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
case QImage::Format_Grayscale16:
+#if !QT_CONFIG(raster_fp)
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+#endif
+#if QT_CONFIG(raster_64bit)
proc = processTextureSpansGeneric64[blendType];
break;
#endif // QT_CONFIG(raster_64bit)
- case QImage::Format_Invalid:
- Q_UNREACHABLE();
- return;
+#if QT_CONFIG(raster_fp)
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+ proc = processTextureSpansGenericFP[blendType];
+ break;
+#endif
default:
proc = processTextureSpansGeneric[blendType];
break;
@@ -3925,12 +4946,13 @@ void qBlendGradient(int count, const QSpan *spans, void *userData)
data->type == QSpanData::LinearGradient &&
data->gradient.linear.end.x == data->gradient.linear.origin.x;
switch (data->rasterBuffer->format) {
+ case QImage::Format_Invalid:
+ break;
case QImage::Format_RGB32:
case QImage::Format_ARGB32_Premultiplied:
if (isVerticalGradient)
return blend_vertical_gradient_argb(count, spans, userData);
return blend_src_generic(count, spans, userData);
-#if QT_CONFIG(raster_64bit)
#if defined(__SSE2__) || defined(__ARM_NEON__) || (Q_PROCESSOR_WORDSIZE == 8)
case QImage::Format_ARGB32:
case QImage::Format_RGBA8888:
@@ -3942,12 +4964,30 @@ void qBlendGradient(int count, const QSpan *spans, void *userData)
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
+#if !QT_CONFIG(raster_fp)
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+#endif
+#if QT_CONFIG(raster_64bit)
if (isVerticalGradient)
return blend_vertical_gradient<blend_color_generic_rgb64>(count, spans, userData);
return blend_src_generic_rgb64(count, spans, userData);
#endif // QT_CONFIG(raster_64bit)
- case QImage::Format_Invalid:
- break;
+#if QT_CONFIG(raster_fp)
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+ if (isVerticalGradient)
+ return blend_vertical_gradient<blend_color_generic_fp>(count, spans, userData);
+ return blend_src_generic_fp(count, spans, userData);
+#endif
default:
if (isVerticalGradient)
return blend_vertical_gradient<blend_color_generic>(count, spans, userData);
@@ -4806,6 +5846,17 @@ static void qt_rectfill_quint64(QRasterBuffer *rasterBuffer,
c64, x, y, width, height, rasterBuffer->bytesPerLine());
}
+static void qt_rectfill_fp32x4(QRasterBuffer *rasterBuffer,
+ int x, int y, int width, int height,
+ const QRgba64 &color)
+{
+ const auto store = qStoreFromRGBA64PM[rasterBuffer->format];
+ QRgba32F c;
+ store(reinterpret_cast<uchar *>(&c), &color, 0, 1, nullptr, nullptr);
+ qt_rectfill<QRgba32F>(reinterpret_cast<QRgba32F *>(rasterBuffer->buffer()),
+ c, x, y, width, height, rasterBuffer->bytesPerLine());
+}
+
// Map table for destination image format. Contains function pointers
// for blends of various types unto the destination
@@ -5036,6 +6087,54 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
qt_alphargbblit_generic,
qt_rectfill_quint24
},
+ // Format_RGBX16FPx4
+ {
+ blend_color_generic_fp,
+ nullptr,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ qt_rectfill_quint64
+ },
+ // Format_RGBA16FPx4
+ {
+ blend_color_generic_fp,
+ nullptr,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ qt_rectfill_quint64
+ },
+ // Format_RGBA16FPx4_Premultiplied
+ {
+ blend_color_generic_fp,
+ nullptr,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ qt_rectfill_quint64
+ },
+ // Format_RGBX32FPx4
+ {
+ blend_color_generic_fp,
+ nullptr,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ qt_rectfill_fp32x4
+ },
+ // Format_RGBA32FPx4
+ {
+ blend_color_generic_fp,
+ nullptr,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ qt_rectfill_fp32x4
+ },
+ // Format_RGBA32FPx4_Premultiplied
+ {
+ blend_color_generic_fp,
+ nullptr,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ qt_rectfill_fp32x4
+ },
};
#if !defined(__SSE2__)
@@ -5260,6 +6359,14 @@ static void qInitDrawhelperFunctions()
destStoreProc64[QImage::Format_ARGB32] = destStore64ARGB32_sse4;
destStoreProc64[QImage::Format_RGBA8888] = destStore64RGBA8888_sse4;
#endif
+#if QT_CONFIG(raster_fp)
+ extern const QRgba32F *QT_FASTCALL fetchRGBA32FToRGBA32F_sse4(QRgba32F *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGBX32FFromRGBA32F_sse4(uchar *dest, const QRgba32F *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGBA32FFromRGBA32F_sse4(uchar *dest, const QRgba32F *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ qFetchToRGBA32F[QImage::Format_RGBA32FPx4] = fetchRGBA32FToRGBA32F_sse4;
+ qStoreFromRGBA32F[QImage::Format_RGBX32FPx4] = storeRGBX32FFromRGBA32F_sse4;
+ qStoreFromRGBA32F[QImage::Format_RGBA32FPx4] = storeRGBA32FFromRGBA32F_sse4;
+#endif // QT_CONFIG(raster_fp)
}
#endif
@@ -5296,6 +6403,16 @@ static void qInitDrawhelperFunctions()
qt_functionForMode64_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_rgb64_avx2;
qt_functionForModeSolid64_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_rgb64_avx2;
#endif
+#if QT_CONFIG(raster_fp)
+ extern void QT_FASTCALL comp_func_Source_rgbafp_avx2(QRgba32F *destPixels, const QRgba32F *srcPixels, int length, uint const_alpha);
+ extern void QT_FASTCALL comp_func_SourceOver_rgbafp_avx2(QRgba32F *destPixels, const QRgba32F *srcPixels, int length, uint const_alpha);
+ extern void QT_FASTCALL comp_func_solid_Source_rgbafp_avx2(QRgba32F *destPixels, int length, QRgba32F color, uint const_alpha);
+ extern void QT_FASTCALL comp_func_solid_SourceOver_rgbafp_avx2(QRgba32F *destPixels, int length, QRgba32F color, uint const_alpha);
+ qt_functionForModeFP_C[QPainter::CompositionMode_Source] = comp_func_Source_rgbafp_avx2;
+ qt_functionForModeFP_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_rgbafp_avx2;
+ qt_functionForModeSolidFP_C[QPainter::CompositionMode_Source] = comp_func_solid_Source_rgbafp_avx2;
+ qt_functionForModeSolidFP_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_rgbafp_avx2;
+#endif
extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2(uint *b, uint *end, const QTextureData &image,
int &fx, int &fy, int fdx, int /*fdy*/);
@@ -5329,7 +6446,35 @@ static void qInitDrawhelperFunctions()
qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_avx2;
qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_avx2;
qPixelLayouts[QImage::Format_RGBA64].fetchToRGBA64PM = fetchRGBA64ToRGBA64PM_avx2;
+
+ extern const uint *QT_FASTCALL fetchRGB16FToRGB32_avx2(uint *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern const uint *QT_FASTCALL fetchRGBA16FToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern const QRgba64 *QT_FASTCALL fetchRGBA16FPMToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern const QRgba64 *QT_FASTCALL fetchRGBA16FToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGB16FFromRGB32_avx2(uchar *dest, const uint *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGBA16FFromARGB32PM_avx2(uchar *dest, const uint *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ qPixelLayouts[QImage::Format_RGBX16FPx4].fetchToARGB32PM = fetchRGB16FToRGB32_avx2;
+ qPixelLayouts[QImage::Format_RGBX16FPx4].fetchToRGBA64PM = fetchRGBA16FPMToRGBA64PM_avx2;
+ qPixelLayouts[QImage::Format_RGBX16FPx4].storeFromARGB32PM = storeRGB16FFromRGB32_avx2;
+ qPixelLayouts[QImage::Format_RGBX16FPx4].storeFromRGB32 = storeRGB16FFromRGB32_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4].fetchToARGB32PM = fetchRGBA16FToARGB32PM_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4].fetchToRGBA64PM = fetchRGBA16FToRGBA64PM_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4].storeFromARGB32PM = storeRGBA16FFromARGB32PM_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4].storeFromRGB32 = storeRGB16FFromRGB32_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4_Premultiplied].fetchToARGB32PM = fetchRGB16FToRGB32_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4_Premultiplied].fetchToRGBA64PM = fetchRGBA16FPMToRGBA64PM_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4_Premultiplied].storeFromARGB32PM = storeRGB16FFromRGB32_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4_Premultiplied].storeFromRGB32 = storeRGB16FFromRGB32_avx2;
+#if QT_CONFIG(raster_fp)
+ extern const QRgba32F *QT_FASTCALL fetchRGBA16FToRGBA32F_avx2(QRgba32F *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGBX16FFromRGBA32F_avx2(uchar *dest, const QRgba32F *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGBA16FFromRGBA32F_avx2(uchar *dest, const QRgba32F *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ qFetchToRGBA32F[QImage::Format_RGBA16FPx4] = fetchRGBA16FToRGBA32F_avx2;
+ qStoreFromRGBA32F[QImage::Format_RGBX16FPx4] = storeRGBX16FFromRGBA32F_avx2;
+ qStoreFromRGBA32F[QImage::Format_RGBA16FPx4] = storeRGBA16FFromRGBA32F_avx2;
+#endif // QT_CONFIG(raster_fp)
}
+
#endif
#endif // SSE2
diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp
index e401a1463f..3e7743e980 100644
--- a/src/gui/painting/qdrawhelper_avx2.cpp
+++ b/src/gui/painting/qdrawhelper_avx2.cpp
@@ -143,7 +143,6 @@ INTERPOLATE_PIXEL_RGB64_AVX2(__m256i srcVector, __m256i &dstVector, __m256i alph
dstVector = _mm256_or_si256(finalAG, finalRB);
}
-
// See BLEND_SOURCE_OVER_ARGB32_SSE2 for details.
inline static void Q_DECL_VECTORCALL BLEND_SOURCE_OVER_ARGB32_AVX2(quint32 *dst, const quint32 *src, const int length)
{
@@ -457,6 +456,40 @@ void QT_FASTCALL comp_func_SourceOver_rgb64_avx2(QRgba64 *dst, const QRgba64 *sr
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_SourceOver_rgbafp_avx2(QRgba32F *dst, const QRgba32F *src, int length, uint const_alpha)
+{
+ Q_ASSERT(const_alpha < 256); // const_alpha is in [0-255]
+
+ const float a = const_alpha / 255.0f;
+ const __m128 one = _mm_set1_ps(1.0f);
+ const __m128 constAlphaVector = _mm_set1_ps(a);
+ const __m256 one256 = _mm256_set1_ps(1.0f);
+ const __m256 constAlphaVector256 = _mm256_set1_ps(a);
+ int x = 0;
+ for (; x < length - 1; x += 2) {
+ __m256 srcVector = _mm256_loadu_ps((const float *)&src[x]);
+ __m256 dstVector = _mm256_loadu_ps((const float *)&dst[x]);
+ srcVector = _mm256_mul_ps(srcVector, constAlphaVector256);
+ __m256 alphaChannel = _mm256_permute_ps(srcVector, _MM_SHUFFLE(3, 3, 3, 3));
+ alphaChannel = _mm256_sub_ps(one256, alphaChannel);
+ dstVector = _mm256_mul_ps(dstVector, alphaChannel);
+ dstVector = _mm256_add_ps(dstVector, srcVector);
+ _mm256_storeu_ps((float *)(dst + x), dstVector);
+ }
+ if (x < length) {
+ __m128 srcVector = _mm_load_ps((float *)(src + x));
+ __m128 dstVector = _mm_load_ps((const float *)(dst + x));
+ srcVector = _mm_mul_ps(srcVector, constAlphaVector);
+ __m128 alphaChannel = _mm_permute_ps(srcVector, _MM_SHUFFLE(3, 3, 3, 3));
+ alphaChannel = _mm_sub_ps(one, alphaChannel);
+ dstVector = _mm_mul_ps(dstVector, alphaChannel);
+ dstVector = _mm_add_ps(dstVector, srcVector);
+ _mm_store_ps((float *)(dst + x), dstVector);
+ }
+}
+#endif
+
void QT_FASTCALL comp_func_Source_avx2(uint *dst, const uint *src, int length, uint const_alpha)
{
if (const_alpha == 255) {
@@ -523,6 +556,41 @@ void QT_FASTCALL comp_func_Source_rgb64_avx2(QRgba64 *dst, const QRgba64 *src, i
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_Source_rgbafp_avx2(QRgba32F *dst, const QRgba32F *src, int length, uint const_alpha)
+{
+ Q_ASSERT(const_alpha < 256); // const_alpha is in [0-255]
+ if (const_alpha == 255) {
+ ::memcpy(dst, src, length * sizeof(QRgba32F));
+ } else {
+ const float ca = const_alpha / 255.f;
+ const float cia = 1.0f - ca;
+
+ const __m128 constAlphaVector = _mm_set1_ps(ca);
+ const __m128 oneMinusConstAlpha = _mm_set1_ps(cia);
+ const __m256 constAlphaVector256 = _mm256_set1_ps(ca);
+ const __m256 oneMinusConstAlpha256 = _mm256_set1_ps(cia);
+ int x = 0;
+ for (; x < length - 1; x += 2) {
+ __m256 srcVector = _mm256_loadu_ps((const float *)&src[x]);
+ __m256 dstVector = _mm256_loadu_ps((const float *)&dst[x]);
+ srcVector = _mm256_mul_ps(srcVector, constAlphaVector256);
+ dstVector = _mm256_mul_ps(dstVector, oneMinusConstAlpha256);
+ dstVector = _mm256_add_ps(dstVector, srcVector);
+ _mm256_storeu_ps((float *)&dst[x], dstVector);
+ }
+ if (x < length) {
+ __m128 srcVector = _mm_load_ps((const float *)&src[x]);
+ __m128 dstVector = _mm_load_ps((const float *)&dst[x]);
+ srcVector = _mm_mul_ps(srcVector, constAlphaVector);
+ dstVector = _mm_mul_ps(dstVector, oneMinusConstAlpha);
+ dstVector = _mm_add_ps(dstVector, srcVector);
+ _mm_store_ps((float *)&dst[x], dstVector);
+ }
+ }
+}
+#endif
+
void QT_FASTCALL comp_func_solid_SourceOver_avx2(uint *destPixels, int length, uint color, uint const_alpha)
{
if ((const_alpha & qAlpha(color)) == 255) {
@@ -587,6 +655,69 @@ void QT_FASTCALL comp_func_solid_SourceOver_rgb64_avx2(QRgba64 *destPixels, int
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_Source_rgbafp_avx2(QRgba32F *dst, int length, QRgba32F color, uint const_alpha)
+{
+ Q_ASSERT(const_alpha < 256); // const_alpha is in [0-255]
+ if (const_alpha == 255) {
+ for (int i = 0; i < length; ++i)
+ dst[i] = color;
+ } else {
+ const float a = const_alpha / 255.0f;
+ const __m128 alphaVector = _mm_set1_ps(a);
+ const __m128 minusAlphaVector = _mm_set1_ps(1.0f - a);
+ __m128 colorVector = _mm_load_ps((const float *)&color);
+ colorVector = _mm_mul_ps(colorVector, alphaVector);
+ const __m256 colorVector256 = _mm256_insertf128_ps(_mm256_castps128_ps256(colorVector), colorVector, 1);
+ const __m256 minusAlphaVector256 = _mm256_set1_ps(1.0f - a);
+ int x = 0;
+ for (; x < length - 1; x += 2) {
+ __m256 dstVector = _mm256_loadu_ps((const float *)&dst[x]);
+ dstVector = _mm256_mul_ps(dstVector, minusAlphaVector256);
+ dstVector = _mm256_add_ps(dstVector, colorVector256);
+ _mm256_storeu_ps((float *)&dst[x], dstVector);
+ }
+ if (x < length) {
+ __m128 dstVector = _mm_load_ps((const float *)&dst[x]);
+ dstVector = _mm_mul_ps(dstVector, minusAlphaVector);
+ dstVector = _mm_add_ps(dstVector, colorVector);
+ _mm_store_ps((float *)&dst[x], dstVector);
+ }
+ }
+}
+
+void QT_FASTCALL comp_func_solid_SourceOver_rgbafp_avx2(QRgba32F *dst, int length, QRgba32F color, uint const_alpha)
+{
+ Q_ASSERT(const_alpha < 256); // const_alpha is in [0-255]
+ if (const_alpha == 255 && color.a >= 1.0f) {
+ for (int i = 0; i < length; ++i)
+ dst[i] = color;
+ } else {
+ __m128 colorVector = _mm_load_ps((const float *)&color);
+ if (const_alpha != 255)
+ colorVector = _mm_mul_ps(colorVector, _mm_set1_ps(const_alpha / 255.f));
+ __m128 minusAlphaOfColorVector =
+ _mm_sub_ps(_mm_set1_ps(1.0f), _mm_permute_ps(colorVector, _MM_SHUFFLE(3, 3, 3, 3)));
+ const __m256 colorVector256 = _mm256_insertf128_ps(_mm256_castps128_ps256(colorVector), colorVector, 1);
+ const __m256 minusAlphaVector256 = _mm256_insertf128_ps(_mm256_castps128_ps256(minusAlphaOfColorVector),
+ minusAlphaOfColorVector, 1);
+ int x = 0;
+ for (; x < length - 1; x += 2) {
+ __m256 dstVector = _mm256_loadu_ps((const float *)&dst[x]);
+ dstVector = _mm256_mul_ps(dstVector, minusAlphaVector256);
+ dstVector = _mm256_add_ps(dstVector, colorVector256);
+ _mm256_storeu_ps((float *)&dst[x], dstVector);
+ }
+ if (x < length) {
+ __m128 dstVector = _mm_load_ps((const float *)&dst[x]);
+ dstVector = _mm_mul_ps(dstVector, minusAlphaOfColorVector);
+ dstVector = _mm_add_ps(dstVector, colorVector);
+ _mm_store_ps((float *)&dst[x], dstVector);
+ }
+ }
+}
+#endif
+
#define interpolate_4_pixels_16_avx2(tlr1, tlr2, blr1, blr2, distx, disty, colorMask, v_256, b) \
{ \
/* Correct for later unpack */ \
@@ -1261,6 +1392,258 @@ const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM_avx2(QRgba64 *buffer, const uch
return buffer;
}
+const uint *QT_FASTCALL fetchRGB16FToRGB32_avx2(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const quint64 *s = reinterpret_cast<const quint64 *>(src) + index;
+ const __m256 vf = _mm256_set1_ps(255.0f);
+ const __m256 vh = _mm256_set1_ps(0.5f);
+ int i = 0;
+ for (; i + 1 < count; i += 2) {
+ __m256 vsf = _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(s + i)));
+ vsf = _mm256_mul_ps(vsf, vf);
+ vsf = _mm256_add_ps(vsf, vh);
+ __m256i vsi = _mm256_cvttps_epi32(vsf);
+ vsi = _mm256_packs_epi32(vsi, vsi);
+ vsi = _mm256_shufflelo_epi16(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ vsi = _mm256_permute4x64_epi64(vsi, _MM_SHUFFLE(3, 1, 2, 0));
+ __m128i vsi128 = _mm256_castsi256_si128(vsi);
+ vsi128 = _mm_packus_epi16(vsi128, vsi128);
+ _mm_storel_epi64((__m128i *)(buffer + i), vsi128);
+ }
+ if (i < count) {
+ __m128 vsf = _mm_cvtph_ps(_mm_loadl_epi64((const __m128i *)(s + i)));
+ vsf = _mm_mul_ps(vsf, _mm_set1_ps(255.0f));
+ vsf = _mm_add_ps(vsf, _mm_set1_ps(0.5f));
+ __m128i vsi = _mm_cvttps_epi32(vsf);
+ vsi = _mm_packs_epi32(vsi, vsi);
+ vsi = _mm_shufflelo_epi16(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ vsi = _mm_packus_epi16(vsi, vsi);
+ buffer[i] = _mm_cvtsi128_si32(vsi);
+ }
+ return buffer;
+}
+
+const uint *QT_FASTCALL fetchRGBA16FToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const quint64 *s = reinterpret_cast<const quint64 *>(src) + index;
+ const __m256 vf = _mm256_set1_ps(255.0f);
+ const __m256 vh = _mm256_set1_ps(0.5f);
+ int i = 0;
+ for (; i + 1 < count; i += 2) {
+ __m256 vsf = _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(s + i)));
+ __m256 vsa = _mm256_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm256_mul_ps(vsf, vsa);
+ vsf = _mm256_blend_ps(vsf, vsa, 0x88);
+ vsf = _mm256_mul_ps(vsf, vf);
+ vsf = _mm256_add_ps(vsf, vh);
+ __m256i vsi = _mm256_cvttps_epi32(vsf);
+ vsi = _mm256_packus_epi32(vsi, vsi);
+ vsi = _mm256_shufflelo_epi16(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ vsi = _mm256_permute4x64_epi64(vsi, _MM_SHUFFLE(3, 1, 2, 0));
+ __m128i vsi128 = _mm256_castsi256_si128(vsi);
+ vsi128 = _mm_packus_epi16(vsi128, vsi128);
+ _mm_storel_epi64((__m128i *)(buffer + i), vsi128);
+ }
+ if (i < count) {
+ __m128 vsf = _mm_cvtph_ps(_mm_loadl_epi64((const __m128i *)(s + i)));
+ __m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm_mul_ps(vsf, vsa);
+ vsf = _mm_insert_ps(vsf, vsa, 0x30);
+ vsf = _mm_mul_ps(vsf, _mm_set1_ps(255.0f));
+ vsf = _mm_add_ps(vsf, _mm_set1_ps(0.5f));
+ __m128i vsi = _mm_cvttps_epi32(vsf);
+ vsi = _mm_packus_epi32(vsi, vsi);
+ vsi = _mm_shufflelo_epi16(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ vsi = _mm_packus_epi16(vsi, vsi);
+ buffer[i] = _mm_cvtsi128_si32(vsi);
+ }
+ return buffer;
+}
+
+const QRgba64 *QT_FASTCALL fetchRGBA16FPMToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const quint64 *s = reinterpret_cast<const quint64 *>(src) + index;
+ const __m256 vf = _mm256_set1_ps(65535.0f);
+ const __m256 vh = _mm256_set1_ps(0.5f);
+ int i = 0;
+ for (; i + 1 < count; i += 2) {
+ __m256 vsf = _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(s + i)));
+ vsf = _mm256_mul_ps(vsf, vf);
+ vsf = _mm256_add_ps(vsf, vh);
+ __m256i vsi = _mm256_cvttps_epi32(vsf);
+ vsi = _mm256_packus_epi32(vsi, vsi);
+ vsi = _mm256_permute4x64_epi64(vsi, _MM_SHUFFLE(3, 1, 2, 0));
+ _mm_storeu_si128((__m128i *)(buffer + i), _mm256_castsi256_si128(vsi));
+ }
+ if (i < count) {
+ __m128 vsf = _mm_cvtph_ps(_mm_loadl_epi64((const __m128i *)(s + i)));
+ vsf = _mm_mul_ps(vsf, _mm_set1_ps(65535.0f));
+ vsf = _mm_add_ps(vsf, _mm_set1_ps(0.5f));
+ __m128i vsi = _mm_cvttps_epi32(vsf);
+ vsi = _mm_packus_epi32(vsi, vsi);
+ _mm_storel_epi64((__m128i *)(buffer + i), vsi);
+ }
+ return buffer;
+}
+
+const QRgba64 *QT_FASTCALL fetchRGBA16FToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const quint64 *s = reinterpret_cast<const quint64 *>(src) + index;
+ const __m256 vf = _mm256_set1_ps(65535.0f);
+ const __m256 vh = _mm256_set1_ps(0.5f);
+ int i = 0;
+ for (; i + 1 < count; i += 2) {
+ __m256 vsf = _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(s + i)));
+ __m256 vsa = _mm256_shuffle_ps(vsf, vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm256_mul_ps(vsf, vsa);
+ vsf = _mm256_blend_ps(vsf, vsa, 0x88);
+ vsf = _mm256_mul_ps(vsf, vf);
+ vsf = _mm256_add_ps(vsf, vh);
+ __m256i vsi = _mm256_cvttps_epi32(vsf);
+ vsi = _mm256_packus_epi32(vsi, vsi);
+ vsi = _mm256_permute4x64_epi64(vsi, _MM_SHUFFLE(3, 1, 2, 0));
+ _mm_storeu_si128((__m128i *)(buffer + i), _mm256_castsi256_si128(vsi));
+ }
+ if (i < count) {
+ __m128 vsf = _mm_cvtph_ps(_mm_loadl_epi64((const __m128i *)(s + i)));
+ __m128 vsa = _mm_shuffle_ps(vsf, vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm_mul_ps(vsf, vsa);
+ vsf = _mm_insert_ps(vsf, vsa, 0x30);
+ vsf = _mm_mul_ps(vsf, _mm_set1_ps(65535.0f));
+ vsf = _mm_add_ps(vsf, _mm_set1_ps(0.5f));
+ __m128i vsi = _mm_cvttps_epi32(vsf);
+ vsi = _mm_packus_epi32(vsi, vsi);
+ _mm_storel_epi64((__m128i *)(buffer + i), vsi);
+ }
+ return buffer;
+}
+
+void QT_FASTCALL storeRGB16FFromRGB32_avx2(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ quint64 *d = reinterpret_cast<quint64 *>(dest) + index;
+ const __m256 vf = _mm256_set1_ps(1.0f / 255.0f);
+ int i = 0;
+ for (; i + 1 < count; i += 2) {
+ __m256i vsi = _mm256_cvtepu8_epi32(_mm_loadl_epi64((const __m128i *)(src + i)));
+ vsi = _mm256_shuffle_epi32(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ __m256 vsf = _mm256_cvtepi32_ps(vsi);
+ vsf = _mm256_mul_ps(vsf, vf);
+ _mm_storeu_si128((__m128i *)(d + i), _mm256_cvtps_ph(vsf, 0));
+ }
+ if (i < count) {
+ __m128i vsi = _mm_cvtsi32_si128(src[i]);
+ vsi = _mm_cvtepu8_epi32(vsi);
+ vsi = _mm_shuffle_epi32(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ __m128 vsf = _mm_cvtepi32_ps(vsi);
+ vsf = _mm_mul_ps(vsf, _mm_set1_ps(1.0f / 255.0f));
+ _mm_storel_epi64((__m128i *)(d + i), _mm_cvtps_ph(vsf, 0));
+ }
+}
+
+void QT_FASTCALL storeRGBA16FFromARGB32PM_avx2(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ quint64 *d = reinterpret_cast<quint64 *>(dest) + index;
+ const __m128 vf = _mm_set1_ps(1.0f / 255.0f);
+ for (int i = 0; i < count; ++i) {
+ const uint s = src[i];
+ __m128i vsi = _mm_cvtsi32_si128(s);
+ vsi = _mm_cvtepu8_epi32(vsi);
+ vsi = _mm_shuffle_epi32(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ __m128 vsf = _mm_cvtepi32_ps(vsi);
+ const uint8_t a = (s >> 24);
+ if (a == 255)
+ vsf = _mm_mul_ps(vsf, vf);
+ else if (a == 0)
+ vsf = _mm_set1_ps(0.0f);
+ else {
+ const __m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ __m128 vsr = _mm_rcp_ps(vsa);
+ vsr = _mm_sub_ps(_mm_add_ps(vsr, vsr), _mm_mul_ps(vsr, _mm_mul_ps(vsr, vsa)));
+ vsr = _mm_insert_ps(vsr, _mm_set_ss(1.0f), 0x30);
+ vsf = _mm_mul_ps(vsf, vsr);
+ }
+ _mm_storel_epi64((__m128i *)(d + i), _mm_cvtps_ph(vsf, 0));
+ }
+}
+
+#if QT_CONFIG(raster_fp)
+const QRgba32F *QT_FASTCALL fetchRGBA16FToRGBA32F_avx2(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const quint64 *s = reinterpret_cast<const quint64 *>(src) + index;
+ int i = 0;
+ for (; i + 1 < count; i += 2) {
+ __m256 vsf = _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(s + i)));
+ __m256 vsa = _mm256_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm256_mul_ps(vsf, vsa);
+ vsf = _mm256_blend_ps(vsf, vsa, 0x88);
+ _mm256_storeu_ps((float *)(buffer + i), vsf);
+ }
+ if (i < count) {
+ __m128 vsf = _mm_cvtph_ps(_mm_loadl_epi64((const __m128i *)(s + i)));
+ __m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm_mul_ps(vsf, vsa);
+ vsf = _mm_insert_ps(vsf, vsa, 0x30);
+ _mm_store_ps((float *)(buffer + i), vsf);
+ }
+ return buffer;
+}
+
+void QT_FASTCALL storeRGBX16FFromRGBA32F_avx2(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ quint64 *d = reinterpret_cast<quint64 *>(dest) + index;
+ const __m128 *s = reinterpret_cast<const __m128 *>(src);
+ const __m128 zero = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f);
+ for (int i = 0; i < count; ++i) {
+ __m128 vsf = _mm_load_ps(reinterpret_cast<const float *>(s + i));
+ const __m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ const float a = _mm_cvtss_f32(vsa);
+ if (a == 1.0f)
+ { }
+ else if (a == 0.0f)
+ vsf = zero;
+ else {
+ __m128 vsr = _mm_rcp_ps(vsa);
+ vsr = _mm_sub_ps(_mm_add_ps(vsr, vsr), _mm_mul_ps(vsr, _mm_mul_ps(vsr, vsa)));
+ vsf = _mm_mul_ps(vsf, vsr);
+ vsf = _mm_insert_ps(vsf, _mm_set_ss(1.0f), 0x30);
+ }
+ _mm_storel_epi64((__m128i *)(d + i), _mm_cvtps_ph(vsf, 0));
+ }
+}
+
+void QT_FASTCALL storeRGBA16FFromRGBA32F_avx2(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ quint64 *d = reinterpret_cast<quint64 *>(dest) + index;
+ const __m128 *s = reinterpret_cast<const __m128 *>(src);
+ const __m128 zero = _mm_set1_ps(0.0f);
+ for (int i = 0; i < count; ++i) {
+ __m128 vsf = _mm_load_ps(reinterpret_cast<const float *>(s + i));
+ const __m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ const float a = _mm_cvtss_f32(vsa);
+ if (a == 1.0f)
+ { }
+ else if (a == 0.0f)
+ vsf = zero;
+ else {
+ __m128 vsr = _mm_rcp_ps(vsa);
+ vsr = _mm_sub_ps(_mm_add_ps(vsr, vsr), _mm_mul_ps(vsr, _mm_mul_ps(vsr, vsa)));
+ vsr = _mm_insert_ps(vsr, _mm_set_ss(1.0f), 0x30);
+ vsf = _mm_mul_ps(vsf, vsr);
+ }
+ _mm_storel_epi64((__m128i *)(d + i), _mm_cvtps_ph(vsf, 0));
+ }
+}
+#endif
+
QT_END_NAMESPACE
#endif
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index 08826bca2f..89db63725f 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -108,6 +108,9 @@ class QRasterBuffer;
class QClipData;
class QRasterPaintEngineState;
+template<typename F> class QRgbaF;
+typedef QRgbaF<float> QRgba32F;
+
typedef QT_FT_SpanFunc ProcessSpans;
typedef void (*BitmapBlitFunc)(QRasterBuffer *rasterBuffer,
int x, int y, const QRgba64 &color,
@@ -194,8 +197,10 @@ extern void qt_memfill16(quint16 *dest, quint16 value, qsizetype count);
typedef void (QT_FASTCALL *CompositionFunction)(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha);
typedef void (QT_FASTCALL *CompositionFunction64)(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha);
+typedef void (QT_FASTCALL *CompositionFunctionFP)(QRgba32F *Q_DECL_RESTRICT dest, const QRgba32F *Q_DECL_RESTRICT src, int length, uint const_alpha);
typedef void (QT_FASTCALL *CompositionFunctionSolid)(uint *dest, int length, uint color, uint const_alpha);
typedef void (QT_FASTCALL *CompositionFunctionSolid64)(QRgba64 *dest, int length, QRgba64 color, uint const_alpha);
+typedef void (QT_FASTCALL *CompositionFunctionSolidFP)(QRgba32F *dest, int length, QRgba32F color, uint const_alpha);
struct LinearGradientValues
{
@@ -219,10 +224,13 @@ struct RadialGradientValues
struct Operator;
typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length);
typedef QRgba64* (QT_FASTCALL *DestFetchProc64)(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length);
+typedef QRgba32F* (QT_FASTCALL *DestFetchProcFP)(QRgba32F *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length);
typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length);
typedef void (QT_FASTCALL *DestStoreProc64)(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
+typedef void (QT_FASTCALL *DestStoreProcFP)(QRasterBuffer *rasterBuffer, int x, int y, const QRgba32F *buffer, int length);
typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length);
typedef const QRgba64* (QT_FASTCALL *SourceFetchProc64)(QRgba64 *buffer, const Operator *o, const QSpanData *data, int y, int x, int length);
+typedef const QRgba32F* (QT_FASTCALL *SourceFetchProcFP)(QRgba32F *buffer, const Operator *o, const QSpanData *data, int y, int x, int length);
struct Operator
{
@@ -239,6 +247,12 @@ struct Operator
CompositionFunctionSolid64 funcSolid64;
CompositionFunction64 func64;
+ DestFetchProcFP destFetchFP;
+ DestStoreProcFP destStoreFP;
+ SourceFetchProcFP srcFetchFP;
+ CompositionFunctionSolidFP funcSolidFP;
+ CompositionFunctionFP funcFP;
+
union {
LinearGradientValues linear;
RadialGradientValues radial;
@@ -295,7 +309,7 @@ struct QGradientData
#define GRADIENT_STOPTABLE_SIZE 1024
#define GRADIENT_STOPTABLE_SIZE_SHIFT 10
-#if QT_CONFIG(raster_64bit)
+#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
const QRgba64 *colorTable64; //[GRADIENT_STOPTABLE_SIZE];
#endif
const QRgb *colorTable32; //[GRADIENT_STOPTABLE_SIZE];
@@ -473,7 +487,7 @@ const BlendType * QT_FASTCALL qt_fetch_radial_gradient_template(BlendType *buffe
while (buffer < end) {
if (rw == 0) {
- *buffer = 0;
+ *buffer = RadialFetchFunc::null();
} else {
qreal invRw = 1 / rw;
qreal gx = rx * invRw - data->gradient.radial.focal.x;
@@ -845,6 +859,57 @@ static inline QRgba64 interpolate_4_pixels_rgb64(const QRgba64 t[], const QRgba6
}
#endif // __SSE2__
+#if QT_CONFIG(raster_fp)
+static inline QRgba32F multiplyAlpha_rgba32f(QRgba32F c, float a)
+{
+ return QRgba32F { c.r * a, c.g * a, c.b * a, c.a * a };
+}
+
+static inline QRgba32F interpolate_rgba32f(QRgba32F x, float alpha1, QRgba32F y, float alpha2)
+{
+ x = multiplyAlpha_rgba32f(x, alpha1);
+ y = multiplyAlpha_rgba32f(y, alpha2);
+ return QRgba32F { x.r + y.r, x.g + y.g, x.b + y.b, x.a + y.a };
+}
+#ifdef __SSE2__
+static inline __m128 Q_DECL_VECTORCALL interpolate_rgba32f(__m128 x, __m128 alpha1, __m128 y, __m128 alpha2)
+{
+ return _mm_add_ps(_mm_mul_ps(x, alpha1), _mm_mul_ps(y, alpha2));
+}
+#endif
+
+static inline QRgba32F interpolate_4_pixels_rgba32f(const QRgba32F t[], const QRgba32F b[], uint distx, uint disty)
+{
+ constexpr float f = 1.0f / 65536.0f;
+ const float dx = distx * f;
+ const float dy = disty * f;
+ const float idx = 1.0f - dx;
+ const float idy = 1.0f - dy;
+#ifdef __SSE2__
+ const __m128 vtl = _mm_load_ps((const float *)&t[0]);
+ const __m128 vtr = _mm_load_ps((const float *)&t[1]);
+ const __m128 vbl = _mm_load_ps((const float *)&b[0]);
+ const __m128 vbr = _mm_load_ps((const float *)&b[1]);
+
+ const __m128 vdx = _mm_set1_ps(dx);
+ const __m128 vidx = _mm_set1_ps(idx);
+ __m128 vt = interpolate_rgba32f(vtl, vidx, vtr, vdx);
+ __m128 vb = interpolate_rgba32f(vbl, vidx, vbr, vdx);
+ const __m128 vdy = _mm_set1_ps(dy);
+ const __m128 vidy = _mm_set1_ps(idy);
+ vt = interpolate_rgba32f(vt, vidy, vb, vdy);
+ QRgba32F res;
+ _mm_store_ps((float*)&res, vt);
+ return res;
+#else
+ QRgba32F xtop = interpolate_rgba32f(t[0], idx, t[1], dx);
+ QRgba32F xbot = interpolate_rgba32f(b[0], idx, b[1], dx);
+ xtop = interpolate_rgba32f(xtop, idy, xbot, dy);
+ return xtop;
+#endif
+}
+#endif // QT_CONFIG(raster_fp)
+
static inline uint BYTE_MUL_RGB16(uint x, uint a) {
a += 1;
uint t = (((x & 0x07e0)*a) >> 8) & 0x07e0;
@@ -1024,70 +1089,6 @@ struct IntermediateBuffer
quint32 buffer_ag[BufferSize+2];
};
-template <QPixelLayout::BPP bpp>
-inline uint QT_FASTCALL qFetchPixel(const uchar *, int)
-{
- Q_UNREACHABLE();
- return 0;
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP1LSB>(const uchar *src, int index)
-{
- return (src[index >> 3] >> (index & 7)) & 1;
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP1MSB>(const uchar *src, int index)
-{
- return (src[index >> 3] >> (~index & 7)) & 1;
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP8>(const uchar *src, int index)
-{
- return src[index];
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP16>(const uchar *src, int index)
-{
- return reinterpret_cast<const quint16 *>(src)[index];
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP24>(const uchar *src, int index)
-{
- return reinterpret_cast<const quint24 *>(src)[index];
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP32>(const uchar *src, int index)
-{
- return reinterpret_cast<const uint *>(src)[index];
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP64>(const uchar *src, int index)
-{
- // We have to do the conversion in fetch to fit into a 32bit uint
- QRgba64 c = reinterpret_cast<const QRgba64 *>(src)[index];
- return c.toArgb32();
-}
-
-typedef uint (QT_FASTCALL *FetchPixelFunc)(const uchar *src, int index);
-
-constexpr FetchPixelFunc qFetchPixelTable[QPixelLayout::BPPCount] = {
- nullptr, // BPPNone
- qFetchPixel<QPixelLayout::BPP1MSB>,
- qFetchPixel<QPixelLayout::BPP1LSB>,
- qFetchPixel<QPixelLayout::BPP8>,
- qFetchPixel<QPixelLayout::BPP16>,
- qFetchPixel<QPixelLayout::BPP24>,
- qFetchPixel<QPixelLayout::BPP32>,
- qFetchPixel<QPixelLayout::BPP64>,
-};
-
QT_END_NAMESPACE
#endif // QDRAWHELPER_P_H
diff --git a/src/gui/painting/qdrawhelper_sse4.cpp b/src/gui/painting/qdrawhelper_sse4.cpp
index dc9755e414..f6ec19c718 100644
--- a/src/gui/painting/qdrawhelper_sse4.cpp
+++ b/src/gui/painting/qdrawhelper_sse4.cpp
@@ -502,6 +502,13 @@ void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4(uchar *dest, const uint *src, i
d[i] = qConvertArgb32ToA2rgb30_sse4<PixelOrder>(src[i]);
}
+template
+void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4<PixelOrderBGR>(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *);
+template
+void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4<PixelOrderRGB>(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *);
+
#if QT_CONFIG(raster_64bit)
void QT_FASTCALL destStore64ARGB32_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length)
{
@@ -544,12 +551,68 @@ void QT_FASTCALL storeRGBx64FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, i
convertRGBA64FromRGBA64PM_sse4<true>(d, src, count);
}
-template
-void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4<PixelOrderBGR>(uchar *dest, const uint *src, int index, int count,
- const QList<QRgb> *, QDitherInfo *);
-template
-void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4<PixelOrderRGB>(uchar *dest, const uint *src, int index, int count,
- const QList<QRgb> *, QDitherInfo *);
+#if QT_CONFIG(raster_fp)
+const QRgba32F *QT_FASTCALL fetchRGBA32FToRGBA32F_sse4(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba32F *s = reinterpret_cast<const QRgba32F *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ __m128 vsf = _mm_load_ps(reinterpret_cast<const float *>(s + i));
+ __m128 vsa = _mm_shuffle_ps(vsf, vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm_mul_ps(vsf, vsa);
+ vsf = _mm_insert_ps(vsf, vsa, 0x30);
+ _mm_store_ps(reinterpret_cast<float *>(buffer + i), vsf);
+ }
+ return buffer;
+}
+
+void QT_FASTCALL storeRGBX32FFromRGBA32F_sse4(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba32F *d = reinterpret_cast<QRgba32F *>(dest) + index;
+ const __m128 zero = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f);
+ for (int i = 0; i < count; ++i) {
+ __m128 vsf = _mm_load_ps(reinterpret_cast<const float *>(src + i));
+ const __m128 vsa = _mm_shuffle_ps(vsf, vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ const float a = _mm_cvtss_f32(vsa);
+ if (a == 1.0f)
+ { }
+ else if (a == 0.0f)
+ vsf = zero;
+ else {
+ __m128 vsr = _mm_rcp_ps(vsa);
+ vsr = _mm_sub_ps(_mm_add_ps(vsr, vsr), _mm_mul_ps(vsr, _mm_mul_ps(vsr, vsa)));
+ vsf = _mm_mul_ps(vsf, vsr);
+ vsf = _mm_insert_ps(vsf, _mm_set_ss(1.0f), 0x30);
+ }
+ _mm_store_ps(reinterpret_cast<float *>(d + i), vsf);
+ }
+}
+
+void QT_FASTCALL storeRGBA32FFromRGBA32F_sse4(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba32F *d = reinterpret_cast<QRgba32F *>(dest) + index;
+ const __m128 zero = _mm_set1_ps(0.0f);
+ for (int i = 0; i < count; ++i) {
+ __m128 vsf = _mm_load_ps(reinterpret_cast<const float *>(src + i));
+ const __m128 vsa = _mm_shuffle_ps(vsf, vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ const float a = _mm_cvtss_f32(vsa);
+ if (a == 1.0f)
+ { }
+ else if (a == 0.0f)
+ vsf = zero;
+ else {
+ __m128 vsr = _mm_rcp_ps(vsa);
+ vsr = _mm_sub_ps(_mm_add_ps(vsr, vsr), _mm_mul_ps(vsr, _mm_mul_ps(vsr, vsa)));
+ vsr = _mm_insert_ps(vsr, _mm_set_ss(1.0f), 0x30);
+ vsf = _mm_mul_ps(vsf, vsr);
+ }
+ _mm_store_ps(reinterpret_cast<float *>(d + i), vsf);
+ }
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp
index 28691fa89b..ae44ca6297 100644
--- a/src/gui/painting/qimagescale.cpp
+++ b/src/gui/painting/qimagescale.cpp
@@ -38,10 +38,12 @@
****************************************************************************/
#include <private/qimagescale_p.h>
#include <private/qdrawhelper_p.h>
+#include <private/qimage_p.h>
#include "qimage.h"
#include "qcolor.h"
#include "qrgba64_p.h"
+#include "qrgbaf.h"
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
#include "qsemaphore.h"
@@ -789,6 +791,221 @@ static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest,
}
#endif
+#if QT_CONFIG(raster_fp)
+static void qt_qimageScaleRgbaFP_up_x_down_y(QImageScaleInfo *isi, QRgba32F *dest,
+ int dw, int dh, int dow, int sow);
+
+static void qt_qimageScaleRgbaFP_down_x_up_y(QImageScaleInfo *isi, QRgba32F *dest,
+ int dw, int dh, int dow, int sow);
+
+static void qt_qimageScaleRgbaFP_down_xy(QImageScaleInfo *isi, QRgba32F *dest,
+ int dw, int dh, int dow, int sow);
+
+static void qt_qimageScaleRgbaFP_up_xy(QImageScaleInfo *isi, QRgba32F *dest,
+ int dw, int dh, int dow, int sow)
+{
+ const QRgba32F **ypoints = (const QRgba32F **)isi->ypoints;
+ int *xpoints = isi->xpoints;
+ int *xapoints = isi->xapoints;
+ int *yapoints = isi->yapoints;
+
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QRgba32F *sptr = ypoints[y];
+ QRgba32F *dptr = dest + (y * dow);
+ const int yap = yapoints[y];
+ if (yap > 0) {
+ for (int x = 0; x < dw; x++) {
+ const QRgba32F *pix = sptr + xpoints[x];
+ const int xap = xapoints[x];
+ if (xap > 0)
+ *dptr = interpolate_4_pixels_rgba32f(pix, pix + sow, xap * 256, yap * 256);
+ else
+ *dptr = interpolate_rgba32f(pix[0], 256 - yap, pix[sow], yap);
+ dptr++;
+ }
+ } else {
+ for (int x = 0; x < dw; x++) {
+ const QRgba32F *pix = sptr + xpoints[x];
+ const int xap = xapoints[x];
+ if (xap > 0)
+ *dptr = interpolate_rgba32f(pix[0], 256 - xap, pix[1], xap);
+ else
+ *dptr = pix[0];
+ dptr++;
+ }
+ }
+ }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
+}
+
+void qt_qimageScaleRgbaFP(QImageScaleInfo *isi, QRgba32F *dest,
+ int dw, int dh, int dow, int sow)
+{
+ if (isi->xup_yup == 3)
+ qt_qimageScaleRgbaFP_up_xy(isi, dest, dw, dh, dow, sow);
+ else if (isi->xup_yup == 1)
+ qt_qimageScaleRgbaFP_up_x_down_y(isi, dest, dw, dh, dow, sow);
+ else if (isi->xup_yup == 2)
+ qt_qimageScaleRgbaFP_down_x_up_y(isi, dest, dw, dh, dow, sow);
+ else
+ qt_qimageScaleRgbaFP_down_xy(isi, dest, dw, dh, dow, sow);
+}
+
+inline static void qt_qimageScaleRgbaFP_helper(const QRgba32F *pix, int xyap, int Cxy, int step, float &r, float &g, float &b, float &a)
+{
+ constexpr float f = (1.0f / float(1<<14));
+ const float xyapf = xyap * f;
+ const float Cxyf = Cxy * f;
+ r = pix->red() * xyapf;
+ g = pix->green() * xyapf;
+ b = pix->blue() * xyapf;
+ a = pix->alpha() * xyapf;
+ int j;
+ for (j = (1 << 14) - xyap; j > Cxy; j -= Cxy ){
+ pix += step;
+ r += pix->red() * Cxyf;
+ g += pix->green() * Cxyf;
+ b += pix->blue() * Cxyf;
+ a += pix->alpha() * Cxyf;
+ }
+ pix += step;
+ const float jf = j * f;
+ r += pix->red() * jf;
+ g += pix->green() * jf;
+ b += pix->blue() * jf;
+ a += pix->alpha() * jf;
+}
+
+static void qt_qimageScaleRgbaFP_up_x_down_y(QImageScaleInfo *isi, QRgba32F *dest,
+ int dw, int dh, int dow, int sow)
+{
+ const QRgba32F **ypoints = (const QRgba32F **)isi->ypoints;
+ int *xpoints = isi->xpoints;
+ int *xapoints = isi->xapoints;
+ int *yapoints = isi->yapoints;
+
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = (yapoints[y]) >> 16;
+ int yap = (yapoints[y]) & 0xffff;
+
+ QRgba32F *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const QRgba32F *sptr = ypoints[y] + xpoints[x];
+ float r, g, b, a;
+ qt_qimageScaleRgbaFP_helper(sptr, yap, Cy, sow, r, g, b, a);
+
+ int xap = xapoints[x];
+ float xapf = xap * (1.f / 256.f);
+ if (xap > 0) {
+ float rr, gg, bb, aa;
+ qt_qimageScaleRgbaFP_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa);
+
+ r = (r * (1.0f - xapf) + (rr * xapf));
+ g = (g * (1.0f - xapf) + (gg * xapf));
+ b = (b * (1.0f - xapf) + (bb * xapf));
+ a = (a * (1.0f - xapf) + (aa * xapf));
+ }
+ *dptr++ = QRgba32F{r, g, b, a};
+ }
+ }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
+}
+
+static void qt_qimageScaleRgbaFP_down_x_up_y(QImageScaleInfo *isi, QRgba32F *dest,
+ int dw, int dh, int dow, int sow)
+{
+ const QRgba32F **ypoints = (const QRgba32F **)isi->ypoints;
+ int *xpoints = isi->xpoints;
+ int *xapoints = isi->xapoints;
+ int *yapoints = isi->yapoints;
+
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ QRgba32F *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const QRgba32F *sptr = ypoints[y] + xpoints[x];
+ float r, g, b, a;
+ qt_qimageScaleRgbaFP_helper(sptr, xap, Cx, 1, r, g, b, a);
+
+ int yap = yapoints[y];
+ float yapf = yap * (1.f / 256.f);
+ if (yap > 0) {
+ float rr, gg, bb, aa;
+ qt_qimageScaleRgbaFP_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa);
+
+ r = (r * (1.0f - yapf) + (rr * yapf));
+ g = (g * (1.0f - yapf) + (gg * yapf));
+ b = (b * (1.0f - yapf) + (bb * yapf));
+ a = (a * (1.0f - yapf) + (aa * yapf));
+ }
+ *dptr++ = QRgba32F{r, g, b, a};
+ }
+ }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
+}
+
+static void qt_qimageScaleRgbaFP_down_xy(QImageScaleInfo *isi, QRgba32F *dest,
+ int dw, int dh, int dow, int sow)
+{
+ const QRgba32F **ypoints = (const QRgba32F **)isi->ypoints;
+ int *xpoints = isi->xpoints;
+ int *xapoints = isi->xapoints;
+ int *yapoints = isi->yapoints;
+
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ constexpr float f = 1.f / float(1 << 14);
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = (yapoints[y]) >> 16;
+ int yap = (yapoints[y]) & 0xffff;
+
+ QRgba32F *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const QRgba32F *sptr = ypoints[y] + xpoints[x];
+ float rx, gx, bx, ax;
+ qt_qimageScaleRgbaFP_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+
+ const float yapf = yap * f;
+ const float Cyf = Cy * f;
+ float r = rx * yapf;
+ float g = gx * yapf;
+ float b = bx * yapf;
+ float a = ax * yapf;
+ int j;
+ for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ sptr += sow;
+ qt_qimageScaleRgbaFP_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+ r += rx * Cyf;
+ g += gx * Cyf;
+ b += bx * Cyf;
+ a += ax * Cyf;
+ }
+ sptr += sow;
+ qt_qimageScaleRgbaFP_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+ const float jf = j * f;
+ r += rx * jf;
+ g += gx * jf;
+ b += bx * jf;
+ a += ax * jf;
+
+ *dptr++ = QRgba32F{r, g, b, a};
+ }
+ }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
+}
+#endif
+
static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest,
int dw, int dh, int dow, int sow);
@@ -1014,6 +1231,12 @@ QImage qSmoothScaleImage(const QImage &src, int dw, int dh)
return QImage();
}
+#if QT_CONFIG(raster_fp)
+ if (qt_fpColorPrecision(src.format()))
+ qt_qimageScaleRgbaFP(scaleinfo, (QRgba32F *)buffer.scanLine(0),
+ dw, dh, dw, src.bytesPerLine() / 16);
+ else
+#endif
#if QT_CONFIG(raster_64bit)
if (src.depth() > 32)
qt_qimageScaleRgba64(scaleinfo, (QRgba64 *)buffer.scanLine(0),
diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp
index b3bee9e5e7..c58ead6b84 100644
--- a/src/gui/painting/qmemrotate.cpp
+++ b/src/gui/painting/qmemrotate.cpp
@@ -224,24 +224,11 @@ inline void qt_memrotate90_template(const T *src, int srcWidth, int srcHeight, i
{
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
// packed algorithm assumes little endian and that sizeof(quint32)/sizeof(T) is an integer
- if (sizeof(quint32) % sizeof(T) == 0)
- qt_memrotate90_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
- else
-#endif
+ static_assert(sizeof(quint32) % sizeof(T) == 0);
+ qt_memrotate90_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
+#else
qt_memrotate90_tiled_unpacked<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
-}
-
-template <>
-inline void qt_memrotate90_template<quint32>(const quint32 *src, int w, int h, int sstride, quint32 *dest, int dstride)
-{
- // packed algorithm doesn't have any benefit for quint32
- qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride);
-}
-
-template <>
-inline void qt_memrotate90_template<quint64>(const quint64 *src, int w, int h, int sstride, quint64 *dest, int dstride)
-{
- qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride);
+#endif
}
template<class T>
@@ -268,24 +255,11 @@ inline void qt_memrotate270_template(const T *src, int srcWidth, int srcHeight,
{
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
// packed algorithm assumes little endian and that sizeof(quint32)/sizeof(T) is an integer
- if (sizeof(quint32) % sizeof(T) == 0)
- qt_memrotate270_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
- else
-#endif
+ static_assert(sizeof(quint32) % sizeof(T) == 0);
+ qt_memrotate270_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
+#else
qt_memrotate270_tiled_unpacked<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
-}
-
-template <>
-inline void qt_memrotate270_template<quint32>(const quint32 *src, int w, int h, int sstride, quint32 *dest, int dstride)
-{
- // packed algorithm doesn't have any benefit for quint32
- qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride);
-}
-
-template <>
-inline void qt_memrotate270_template<quint64>(const quint64 *src, int w, int h, int sstride, quint64 *dest, int dstride)
-{
- qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride);
+#endif
}
#define QT_IMPL_MEMROTATE(type) \
@@ -322,10 +296,11 @@ Q_GUI_EXPORT void qt_memrotate270(const type *src, int w, int h, int sstride, \
qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride); \
}
-QT_IMPL_MEMROTATE(quint64)
-QT_IMPL_MEMROTATE(quint32)
+QT_IMPL_SIMPLE_MEMROTATE(QRgba32F)
+QT_IMPL_SIMPLE_MEMROTATE(quint64)
+QT_IMPL_SIMPLE_MEMROTATE(quint32)
+QT_IMPL_SIMPLE_MEMROTATE(quint24)
QT_IMPL_MEMROTATE(quint16)
-QT_IMPL_MEMROTATE(quint24)
QT_IMPL_MEMROTATE(quint8)
void qt_memrotate90_8(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
@@ -404,6 +379,21 @@ void qt_memrotate270_64(const uchar *srcPixels, int w, int h, int sbpl, uchar *d
qt_memrotate270((const quint64 *)srcPixels, w, h, sbpl, (quint64 *)destPixels, dbpl);
}
+void qt_memrotate90_128(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate90((const QRgba32F *)srcPixels, w, h, sbpl, (QRgba32F *)destPixels, dbpl);
+}
+
+void qt_memrotate180_128(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate180((const QRgba32F *)srcPixels, w, h, sbpl, (QRgba32F *)destPixels, dbpl);
+}
+
+void qt_memrotate270_128(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate270((const QRgba32F *)srcPixels, w, h, sbpl, (QRgba32F *)destPixels, dbpl);
+}
+
MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3] =
// 90, 180, 270
{
@@ -415,6 +405,8 @@ MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3] =
{ qt_memrotate90_24, qt_memrotate180_24, qt_memrotate270_24 }, // BPP24
{ qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // BPP32
{ qt_memrotate90_64, qt_memrotate180_64, qt_memrotate270_64 }, // BPP64
+ { qt_memrotate90_64, qt_memrotate180_64, qt_memrotate270_64 }, // BPP16FPx4
+ { qt_memrotate90_128, qt_memrotate180_128, qt_memrotate270_128 }, // BPP32FPx4
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index bae8695e33..68ea3239f9 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -4517,7 +4517,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
gradient.colorTable32 = cacheInfo->buffer32;
-#if QT_CONFIG(raster_64bit)
+#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
gradient.colorTable64 = cacheInfo->buffer64;
#endif
cachedGradient = std::move(cacheInfo);
@@ -4541,7 +4541,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
gradient.colorTable32 = cacheInfo->buffer32;
-#if QT_CONFIG(raster_64bit)
+#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
gradient.colorTable64 = cacheInfo->buffer64;
#endif
cachedGradient = std::move(cacheInfo);
@@ -4569,7 +4569,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
gradient.colorTable32 = cacheInfo->buffer32;
-#if QT_CONFIG(raster_64bit)
+#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
gradient.colorTable64 = cacheInfo->buffer64;
#endif
cachedGradient = std::move(cacheInfo);
diff --git a/src/gui/painting/qpixellayout.cpp b/src/gui/painting/qpixellayout.cpp
index ca6bca344f..e32d4e124a 100644
--- a/src/gui/painting/qpixellayout.cpp
+++ b/src/gui/painting/qpixellayout.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -55,6 +55,9 @@ template<QImage::Format> constexpr uint blueShift();
template<QImage::Format> constexpr uint alphaWidth();
template<QImage::Format> constexpr uint alphaShift();
+template<> constexpr uint redWidth<QImage::Format_RGB32>() { return 8; }
+template<> constexpr uint redWidth<QImage::Format_ARGB32>() { return 8; }
+template<> constexpr uint redWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
template<> constexpr uint redWidth<QImage::Format_RGB16>() { return 5; }
template<> constexpr uint redWidth<QImage::Format_RGB444>() { return 4; }
template<> constexpr uint redWidth<QImage::Format_RGB555>() { return 5; }
@@ -69,6 +72,9 @@ template<> constexpr uint redWidth<QImage::Format_RGBX8888>() { return 8; }
template<> constexpr uint redWidth<QImage::Format_RGBA8888>() { return 8; }
template<> constexpr uint redWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
+template<> constexpr uint redShift<QImage::Format_RGB32>() { return 16; }
+template<> constexpr uint redShift<QImage::Format_ARGB32>() { return 16; }
+template<> constexpr uint redShift<QImage::Format_ARGB32_Premultiplied>() { return 16; }
template<> constexpr uint redShift<QImage::Format_RGB16>() { return 11; }
template<> constexpr uint redShift<QImage::Format_RGB444>() { return 8; }
template<> constexpr uint redShift<QImage::Format_RGB555>() { return 10; }
@@ -88,6 +94,9 @@ template<> constexpr uint redShift<QImage::Format_RGBX8888>() { return 0; }
template<> constexpr uint redShift<QImage::Format_RGBA8888>() { return 0; }
template<> constexpr uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; }
#endif
+template<> constexpr uint greenWidth<QImage::Format_RGB32>() { return 8; }
+template<> constexpr uint greenWidth<QImage::Format_ARGB32>() { return 8; }
+template<> constexpr uint greenWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
template<> constexpr uint greenWidth<QImage::Format_RGB16>() { return 6; }
template<> constexpr uint greenWidth<QImage::Format_RGB444>() { return 4; }
template<> constexpr uint greenWidth<QImage::Format_RGB555>() { return 5; }
@@ -102,6 +111,9 @@ template<> constexpr uint greenWidth<QImage::Format_RGBX8888>() { return 8; }
template<> constexpr uint greenWidth<QImage::Format_RGBA8888>() { return 8; }
template<> constexpr uint greenWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
+template<> constexpr uint greenShift<QImage::Format_RGB32>() { return 8; }
+template<> constexpr uint greenShift<QImage::Format_ARGB32>() { return 8; }
+template<> constexpr uint greenShift<QImage::Format_ARGB32_Premultiplied>() { return 8; }
template<> constexpr uint greenShift<QImage::Format_RGB16>() { return 5; }
template<> constexpr uint greenShift<QImage::Format_RGB444>() { return 4; }
template<> constexpr uint greenShift<QImage::Format_RGB555>() { return 5; }
@@ -121,6 +133,9 @@ template<> constexpr uint greenShift<QImage::Format_RGBX8888>() { return 8; }
template<> constexpr uint greenShift<QImage::Format_RGBA8888>() { return 8; }
template<> constexpr uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
#endif
+template<> constexpr uint blueWidth<QImage::Format_RGB32>() { return 8; }
+template<> constexpr uint blueWidth<QImage::Format_ARGB32>() { return 8; }
+template<> constexpr uint blueWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
template<> constexpr uint blueWidth<QImage::Format_RGB16>() { return 5; }
template<> constexpr uint blueWidth<QImage::Format_RGB444>() { return 4; }
template<> constexpr uint blueWidth<QImage::Format_RGB555>() { return 5; }
@@ -135,6 +150,9 @@ template<> constexpr uint blueWidth<QImage::Format_RGBX8888>() { return 8; }
template<> constexpr uint blueWidth<QImage::Format_RGBA8888>() { return 8; }
template<> constexpr uint blueWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
+template<> constexpr uint blueShift<QImage::Format_RGB32>() { return 0; }
+template<> constexpr uint blueShift<QImage::Format_ARGB32>() { return 0; }
+template<> constexpr uint blueShift<QImage::Format_ARGB32_Premultiplied>() { return 0; }
template<> constexpr uint blueShift<QImage::Format_RGB16>() { return 0; }
template<> constexpr uint blueShift<QImage::Format_RGB444>() { return 0; }
template<> constexpr uint blueShift<QImage::Format_RGB555>() { return 0; }
@@ -154,6 +172,9 @@ template<> constexpr uint blueShift<QImage::Format_RGBX8888>() { return 16; }
template<> constexpr uint blueShift<QImage::Format_RGBA8888>() { return 16; }
template<> constexpr uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; }
#endif
+template<> constexpr uint alphaWidth<QImage::Format_RGB32>() { return 0; }
+template<> constexpr uint alphaWidth<QImage::Format_ARGB32>() { return 8; }
+template<> constexpr uint alphaWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
template<> constexpr uint alphaWidth<QImage::Format_RGB16>() { return 0; }
template<> constexpr uint alphaWidth<QImage::Format_RGB444>() { return 0; }
template<> constexpr uint alphaWidth<QImage::Format_RGB555>() { return 0; }
@@ -168,6 +189,9 @@ template<> constexpr uint alphaWidth<QImage::Format_RGBX8888>() { return 0; }
template<> constexpr uint alphaWidth<QImage::Format_RGBA8888>() { return 8; }
template<> constexpr uint alphaWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
+template<> constexpr uint alphaShift<QImage::Format_RGB32>() { return 24; }
+template<> constexpr uint alphaShift<QImage::Format_ARGB32>() { return 24; }
+template<> constexpr uint alphaShift<QImage::Format_ARGB32_Premultiplied>() { return 24; }
template<> constexpr uint alphaShift<QImage::Format_RGB16>() { return 0; }
template<> constexpr uint alphaShift<QImage::Format_RGB444>() { return 0; }
template<> constexpr uint alphaShift<QImage::Format_RGB555>() { return 0; }
@@ -189,6 +213,9 @@ template<> constexpr uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() {
#endif
template<QImage::Format> constexpr QPixelLayout::BPP bitsPerPixel();
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB32>() { return QPixelLayout::BPP32; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB32>() { return QPixelLayout::BPP32; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB32_Premultiplied>() { return QPixelLayout::BPP32; }
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB16>() { return QPixelLayout::BPP16; }
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB444>() { return QPixelLayout::BPP16; }
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB555>() { return QPixelLayout::BPP16; }
@@ -218,6 +245,73 @@ inline void QT_FASTCALL storePixel<QPixelLayout::BPP24>(uchar *dest, int index,
reinterpret_cast<quint24 *>(dest)[index] = quint24(pixel);
}
+template <QPixelLayout::BPP bpp> static
+inline uint QT_FASTCALL fetchPixel(const uchar *, int)
+{
+ Q_UNREACHABLE();
+ return 0;
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP1LSB>(const uchar *src, int index)
+{
+ return (src[index >> 3] >> (index & 7)) & 1;
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP1MSB>(const uchar *src, int index)
+{
+ return (src[index >> 3] >> (~index & 7)) & 1;
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP8>(const uchar *src, int index)
+{
+ return src[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP16>(const uchar *src, int index)
+{
+ return reinterpret_cast<const quint16 *>(src)[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP24>(const uchar *src, int index)
+{
+ return reinterpret_cast<const quint24 *>(src)[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP32>(const uchar *src, int index)
+{
+ return reinterpret_cast<const uint *>(src)[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP64>(const uchar *src, int index)
+{
+ // We have to do the conversion in fetch to fit into a 32bit uint
+ QRgba64 c = reinterpret_cast<const QRgba64 *>(src)[index];
+ return c.toArgb32();
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP16FPx4>(const uchar *src, int index)
+{
+ // We have to do the conversion in fetch to fit into a 32bit uint
+ QRgba16F c = reinterpret_cast<const QRgba16F *>(src)[index];
+ return c.toArgb32();
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP32FPx4>(const uchar *src, int index)
+{
+ // We have to do the conversion in fetch to fit into a 32bit uint
+ QRgba32F c = reinterpret_cast<const QRgba32F *>(src)[index];
+ return c.toArgb32();
+}
+
template<QImage::Format Format>
static inline uint convertPixelToRGB32(uint s)
{
@@ -269,7 +363,7 @@ static const uint *QT_FASTCALL fetchRGBToRGB32(uint *buffer, const uchar *src, i
}
#endif
for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToRGB32<Format>(qFetchPixel<BPP>(src, index + i));
+ buffer[i] = convertPixelToRGB32<Format>(fetchPixel<BPP>(src, index + i));
return buffer;
}
@@ -293,7 +387,22 @@ static const QRgba64 *QT_FASTCALL fetchRGBToRGB64(QRgba64 *buffer, const uchar *
const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToRGB64<Format>(qFetchPixel<bitsPerPixel<Format>()>(src, index + i));
+ buffer[i] = convertPixelToRGB64<Format>(fetchPixel<bitsPerPixel<Format>()>(src, index + i));
+ return buffer;
+}
+
+template<QImage::Format Format>
+static Q_ALWAYS_INLINE QRgba32F convertPixelToRGB32F(uint s)
+{
+ return QRgba32F::fromArgb32(convertPixelToRGB32<Format>(s));
+}
+
+template<QImage::Format Format>
+static const QRgba32F *QT_FASTCALL fetchRGBToRGB32F(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = convertPixelToRGB32F<Format>(fetchPixel<bitsPerPixel<Format>()>(src, index + i));
return buffer;
}
@@ -360,7 +469,7 @@ static const uint *QT_FASTCALL fetchARGBPMToARGB32PM(uint *buffer, const uchar *
}
#endif
for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToARGB32PM<Format>(qFetchPixel<BPP>(src, index + i));
+ buffer[i] = convertPixelToARGB32PM<Format>(fetchPixel<BPP>(src, index + i));
return buffer;
}
@@ -385,7 +494,33 @@ static const QRgba64 *QT_FASTCALL fetchARGBPMToRGBA64PM(QRgba64 *buffer, const u
{
constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToRGBA64PM<Format>(qFetchPixel<bpp>(src, index + i));
+ buffer[i] = convertPixelToRGBA64PM<Format>(fetchPixel<bpp>(src, index + i));
+ return buffer;
+}
+
+template<QImage::Format Format>
+static Q_ALWAYS_INLINE QRgba32F convertPixelToRGBA32F(uint s)
+{
+ return QRgba32F::fromArgb32(convertPixelToARGB32PM<Format>(s));
+}
+
+template<QImage::Format Format>
+static const QRgba32F *QT_FASTCALL fetchARGBPMToRGBA32F(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
+ for (int i = 0; i < count; ++i)
+ buffer[i] = convertPixelToRGBA32F<Format>(fetchPixel<bpp>(src, index + i));
+ return buffer;
+}
+
+template<QImage::Format Format>
+static const QRgba32F *QT_FASTCALL fetchARGBToRGBA32F(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
+ for (int i = 0; i < count; ++i)
+ buffer[i] = convertPixelToRGBA32F<Format>(fetchPixel<bpp>(src, index + i)).premultiplied();
return buffer;
}
@@ -518,7 +653,7 @@ static void QT_FASTCALL rbSwap(uchar *dst, const uchar *src, int count)
constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
for (int i = 0; i < count; ++i) {
- const uint c = qFetchPixel<bpp>(src, i);
+ const uint c = fetchPixel<bpp>(src, i);
const uint r = (c >> rShift) & redBlueMask;
const uint b = (c >> bShift) & redBlueMask;
const uint t = (c & alphaGreenMask)
@@ -589,6 +724,27 @@ static void QT_FASTCALL rbSwap_4x16(uchar *d, const uchar *s, int count)
}
}
+static void QT_FASTCALL rbSwap_4x32(uchar *d, const uchar *s, int count)
+{
+ const uint *src = reinterpret_cast<const uint *>(s);
+ uint *dest = reinterpret_cast<uint *>(d);
+ if (src != dest) {
+ for (int i = 0; i < count; ++i) {
+ dest[i * 4 + 0] = src[i * 4 + 2];
+ dest[i * 4 + 1] = src[i * 4 + 1];
+ dest[i * 4 + 2] = src[i * 4 + 0];
+ dest[i * 4 + 3] = src[i * 4 + 3];
+ }
+ } else {
+ for (int i = 0; i < count; ++i) {
+ const uint r = src[i * 4 + 0];
+ const uint b = src[i * 4 + 2];
+ dest[i * 4 + 0] = b;
+ dest[i * 4 + 2] = r;
+ }
+ }
+}
+
template<QImage::Format Format> constexpr static inline QPixelLayout pixelLayoutRGB()
{
return QPixelLayout{
@@ -632,7 +788,7 @@ static const uint *QT_FASTCALL fetchIndexedToARGB32PM(uint *buffer, const uchar
const QList<QRgb> *clut, QDitherInfo *)
{
for (int i = 0; i < count; ++i) {
- const uint s = qFetchPixel<BPP>(src, index + i);
+ const uint s = fetchPixel<BPP>(src, index + i);
buffer[i] = qPremultiply(clut->at(s));
}
return buffer;
@@ -643,17 +799,29 @@ static const QRgba64 *QT_FASTCALL fetchIndexedToRGBA64PM(QRgba64 *buffer, const
const QList<QRgb> *clut, QDitherInfo *)
{
for (int i = 0; i < count; ++i) {
- const uint s = qFetchPixel<BPP>(src, index + i);
+ const uint s = fetchPixel<BPP>(src, index + i);
buffer[i] = QRgba64::fromArgb32(clut->at(s)).premultiplied();
}
return buffer;
}
-static const QRgba64 *QT_FASTCALL convertIndexedToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
- const QList<QRgb> *clut, QDitherInfo *)
+template<QPixelLayout::BPP BPP>
+static const QRgba32F *QT_FASTCALL fetchIndexedToRGBA32F(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *clut, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i) {
+ const uint s = fetchPixel<BPP>(src, index + i);
+ buffer[i] = QRgba32F::fromArgb32(clut->at(s)).premultiplied();
+ }
+ return buffer;
+}
+
+template<typename QRgba>
+static const QRgba *QT_FASTCALL convertIndexedTo(QRgba *buffer, const uint *src, int count,
+ const QList<QRgb> *clut, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromArgb32(clut->at(src[i])).premultiplied();
+ buffer[i] = QRgba::fromArgb32(clut->at(src[i])).premultiplied();
return buffer;
}
@@ -731,18 +899,21 @@ static const uint *QT_FASTCALL fetchAlpha8ToRGB32(uint *buffer, const uchar *src
return buffer;
}
-static const QRgba64 *QT_FASTCALL convertAlpha8ToRGB64(QRgba64 *buffer, const uint *src, int count,
- const QList<QRgb> *, QDitherInfo *)
+template<typename QRgba>
+static const QRgba *QT_FASTCALL convertAlpha8To(QRgba *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromRgba(0, 0, 0, src[i]);
+ buffer[i] = QRgba::fromRgba(0, 0, 0, src[i]);
return buffer;
}
-static const QRgba64 *QT_FASTCALL fetchAlpha8ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
- const QList<QRgb> *, QDitherInfo *)
+
+template<typename QRgba>
+static const QRgba *QT_FASTCALL fetchAlpha8To(QRgba *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromRgba(0, 0, 0, src[index + i]);
+ buffer[i] = QRgba::fromRgba(0, 0, 0, src[index + i]);
return buffer;
}
@@ -764,20 +935,22 @@ static const uint *QT_FASTCALL fetchGrayscale8ToRGB32(uint *buffer, const uchar
return buffer;
}
-static const QRgba64 *QT_FASTCALL convertGrayscale8ToRGB64(QRgba64 *buffer, const uint *src, int count,
- const QList<QRgb> *, QDitherInfo *)
+template<typename QRgba>
+static const QRgba *QT_FASTCALL convertGrayscale8To(QRgba *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromRgba(src[i], src[i], src[i], 255);
+ buffer[i] = QRgba::fromRgba(src[i], src[i], src[i], 255);
return buffer;
}
-static const QRgba64 *QT_FASTCALL fetchGrayscale8ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
- const QList<QRgb> *, QDitherInfo *)
+template<typename QRgba>
+static const QRgba *QT_FASTCALL fetchGrayscale8To(QRgba *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i) {
const uint s = src[index + i];
- buffer[i] = QRgba64::fromRgba(s, s, s, 255);
+ buffer[i] = QRgba::fromRgba(s, s, s, 255);
}
return buffer;
}
@@ -789,7 +962,6 @@ static void QT_FASTCALL convertGrayscale16ToRGB32(uint *buffer, int count, const
buffer[i] = qRgb(x, x, x);
}
}
-
static const uint *QT_FASTCALL fetchGrayscale16ToRGB32(uint *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
@@ -801,20 +973,22 @@ static const uint *QT_FASTCALL fetchGrayscale16ToRGB32(uint *buffer, const uchar
return buffer;
}
-static const QRgba64 *QT_FASTCALL convertGrayscale16ToRGBA64(QRgba64 *buffer, const uint *src, int count,
- const QList<QRgb> *, QDitherInfo *)
+template<typename QRgba>
+static const QRgba *QT_FASTCALL convertGrayscale16To(QRgba *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromRgba64(src[i], src[i], src[i], 65535);
+ buffer[i] = QRgba::fromRgba64(src[i], src[i], src[i], 65535);
return buffer;
}
-static const QRgba64 *QT_FASTCALL fetchGrayscale16ToRGBA64(QRgba64 *buffer, const uchar *src, int index, int count,
- const QList<QRgb> *, QDitherInfo *)
+template<typename QRgba>
+static const QRgba *QT_FASTCALL fetchGrayscale16To(QRgba *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
{
const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index;
for (int i = 0; i < count; ++i) {
- buffer[i] = QRgba64::fromRgba64(s[i], s[i], s[i], 65535);
+ buffer[i] = QRgba::fromRgba64(s[i], s[i], s[i], 65535);
}
return buffer;
}
@@ -1212,6 +1386,44 @@ static const QRgba64 *QT_FASTCALL fetchA2RGB30PMToRGBA64PM(QRgba64 *buffer, cons
return convertA2RGB30PMToRGBA64PM<PixelOrder>(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
}
+template<enum QtPixelOrder> inline QRgba32F qConvertA2rgb30ToRgbaFP(uint rgb);
+
+template<>
+inline QRgba32F qConvertA2rgb30ToRgbaFP<PixelOrderBGR>(uint rgb)
+{
+ float alpha = (rgb >> 30) * (1.f/3.f);
+ float blue = ((rgb >> 20) & 0x3ff) * (1.f/1023.f);
+ float green = ((rgb >> 10) & 0x3ff) * (1.f/1023.f);
+ float red = (rgb & 0x3ff) * (1.f/1023.f);
+ return QRgba32F{ red, green, blue, alpha };
+}
+
+template<>
+inline QRgba32F qConvertA2rgb30ToRgbaFP<PixelOrderRGB>(uint rgb)
+{
+ float alpha = (rgb >> 30) * (1.f/3.f);
+ float red = ((rgb >> 20) & 0x3ff) * (1.f/1023.f);
+ float green = ((rgb >> 10) & 0x3ff) * (1.f/1023.f);
+ float blue = (rgb & 0x3ff) * (1.f/1023.f);
+ return QRgba32F{ red, green, blue, alpha };
+}
+
+template<QtPixelOrder PixelOrder>
+static const QRgba32F *QT_FASTCALL convertA2RGB30PMToRGBA32F(QRgba32F *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = qConvertA2rgb30ToRgbaFP<PixelOrder>(src[i]);
+ return buffer;
+}
+
+template<QtPixelOrder PixelOrder>
+static const QRgba32F *QT_FASTCALL fetchRGB30ToRGBA32F(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ return convertA2RGB30PMToRGBA32F<PixelOrder>(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
+}
+
template<QtPixelOrder PixelOrder>
static void QT_FASTCALL storeA2RGB30PMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
@@ -1365,6 +1577,118 @@ static void QT_FASTCALL storeRGBA64FromARGB32(uchar *dest, const uint *src, int
d[i] = QRgba64::fromArgb32(src[i]);
}
+static const uint *QT_FASTCALL fetchRGB16FToRGB32(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba16F *s = reinterpret_cast<const QRgba16F *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = s[i].toArgb32();
+ return buffer;
+}
+
+static void QT_FASTCALL storeRGB16FFromRGB32(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba16F *d = reinterpret_cast<QRgba16F *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = QRgba16F::fromArgb32(src[i]);
+}
+
+static const uint *QT_FASTCALL fetchRGBA16FToARGB32PM(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba16F *s = reinterpret_cast<const QRgba16F *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = s[i].premultiplied().toArgb32();
+ return buffer;
+}
+
+static const QRgba64 *QT_FASTCALL fetchRGBA16FToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba16F *s = reinterpret_cast<const QRgba16F *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ QRgba16F c = s[i].premultiplied();
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
+ }
+ return buffer;
+}
+
+static void QT_FASTCALL storeRGBA16FFromARGB32PM(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba16F *d = reinterpret_cast<QRgba16F *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = QRgba16F::fromArgb32(src[i]).unpremultiplied();
+}
+
+static const QRgba64 *QT_FASTCALL fetchRGBA16FPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba16F *s = reinterpret_cast<const QRgba16F *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ QRgba16F c = s[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
+ }
+ return buffer;
+}
+
+static const uint *QT_FASTCALL fetchRGB32FToRGB32(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba32F *s = reinterpret_cast<const QRgba32F *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = s[i].toArgb32();
+ return buffer;
+}
+
+static void QT_FASTCALL storeRGB32FFromRGB32(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba32F *d = reinterpret_cast<QRgba32F *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = QRgba32F::fromArgb32(src[i]);
+}
+
+static const uint *QT_FASTCALL fetchRGBA32FToARGB32PM(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba32F *s = reinterpret_cast<const QRgba32F *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = s[i].premultiplied().toArgb32();
+ return buffer;
+}
+
+static const QRgba64 *QT_FASTCALL fetchRGBA32FToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba32F *s = reinterpret_cast<const QRgba32F *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ QRgba32F c = s[i].premultiplied();
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
+ }
+ return buffer;
+}
+
+static void QT_FASTCALL storeRGBA32FFromARGB32PM(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba32F *d = reinterpret_cast<QRgba32F *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = QRgba32F::fromArgb32(src[i]).unpremultiplied();
+}
+
+static const QRgba64 *QT_FASTCALL fetchRGBA32FPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba32F *s = reinterpret_cast<const QRgba32F *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ QRgba32F c = s[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
+ }
+ return buffer;
+}
+
// Note:
// convertToArgb32() assumes that no color channel is less than 4 bits.
// storeRGBFromARGB32PM() assumes that no color channel is more than 8 bits.
@@ -1372,15 +1696,15 @@ static void QT_FASTCALL storeRGBA64FromARGB32(uchar *dest, const uint *src, int
QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
{ false, false, QPixelLayout::BPPNone, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }, // Format_Invalid
{ false, false, QPixelLayout::BPP1MSB, nullptr,
- convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
+ convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
fetchIndexedToARGB32PM<QPixelLayout::BPP1MSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1MSB>,
nullptr, nullptr }, // Format_Mono
{ false, false, QPixelLayout::BPP1LSB, nullptr,
- convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
+ convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
fetchIndexedToARGB32PM<QPixelLayout::BPP1LSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1LSB>,
nullptr, nullptr }, // Format_MonoLSB
{ false, false, QPixelLayout::BPP8, nullptr,
- convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
+ convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
fetchIndexedToARGB32PM<QPixelLayout::BPP8>, fetchIndexedToRGBA64PM<QPixelLayout::BPP8>,
nullptr, nullptr }, // Format_Indexed8
// Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong,
@@ -1439,12 +1763,12 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
storeRGB30FromRGB32<PixelOrderRGB>
}, // Format_A2RGB30_Premultiplied
{ true, true, QPixelLayout::BPP8, nullptr,
- convertAlpha8ToRGB32, convertAlpha8ToRGB64,
- fetchAlpha8ToRGB32, fetchAlpha8ToRGB64,
+ convertAlpha8ToRGB32, convertAlpha8To<QRgba64>,
+ fetchAlpha8ToRGB32, fetchAlpha8To<QRgba64>,
storeAlpha8FromARGB32PM, nullptr }, // Format_Alpha8
{ false, false, QPixelLayout::BPP8, nullptr,
- convertGrayscale8ToRGB32, convertGrayscale8ToRGB64,
- fetchGrayscale8ToRGB32, fetchGrayscale8ToRGB64,
+ convertGrayscale8ToRGB32, convertGrayscale8To<QRgba64>,
+ fetchGrayscale8ToRGB32, fetchGrayscale8To<QRgba64>,
storeGrayscale8FromARGB32PM, storeGrayscale8FromRGB32 }, // Format_Grayscale8
{ false, false, QPixelLayout::BPP64, rbSwap_4x16,
convertPassThrough, nullptr,
@@ -1459,10 +1783,34 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
fetchRGB64ToRGB32, fetchPassThrough64,
storeRGBA64FromARGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied
{ false, false, QPixelLayout::BPP16, nullptr,
- convertGrayscale16ToRGB32, convertGrayscale16ToRGBA64,
- fetchGrayscale16ToRGB32, fetchGrayscale16ToRGBA64,
+ convertGrayscale16ToRGB32, convertGrayscale16To<QRgba64>,
+ fetchGrayscale16ToRGB32, fetchGrayscale16To<QRgba64>,
storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 }, // Format_Grayscale16
pixelLayoutRGB<QImage::Format_BGR888>(),
+ { false, false, QPixelLayout::BPP16FPx4, rbSwap_4x16,
+ convertPassThrough, nullptr,
+ fetchRGB16FToRGB32, fetchRGBA16FPMToRGBA64PM,
+ storeRGB16FFromRGB32, storeRGB16FFromRGB32 }, // Format_RGBX16FPx4
+ { true, false, QPixelLayout::BPP16FPx4, rbSwap_4x16,
+ convertARGB32ToARGB32PM, nullptr,
+ fetchRGBA16FToARGB32PM, fetchRGBA16FToRGBA64PM,
+ storeRGBA16FFromARGB32PM, storeRGB16FFromRGB32 }, // Format_RGBA16FPx4
+ { true, true, QPixelLayout::BPP16FPx4, rbSwap_4x16,
+ convertPassThrough, nullptr,
+ fetchRGB16FToRGB32, fetchRGBA16FPMToRGBA64PM,
+ storeRGB16FFromRGB32, storeRGB16FFromRGB32 }, // Format_RGBA16FPx4_Premultiplied
+ { false, false, QPixelLayout::BPP32FPx4, rbSwap_4x32,
+ convertPassThrough, nullptr,
+ fetchRGB32FToRGB32, fetchRGBA32FPMToRGBA64PM,
+ storeRGB32FFromRGB32, storeRGB32FFromRGB32 }, // Format_RGBX32FPx4
+ { true, false, QPixelLayout::BPP32FPx4, rbSwap_4x32,
+ convertARGB32ToARGB32PM, nullptr,
+ fetchRGBA32FToARGB32PM, fetchRGBA32FToRGBA64PM,
+ storeRGBA32FFromARGB32PM, storeRGB32FFromRGB32 }, // Format_RGBA32FPx4
+ { true, true, QPixelLayout::BPP32FPx4, rbSwap_4x32,
+ convertPassThrough, nullptr,
+ fetchRGB32FToRGB32, fetchRGBA32FPMToRGBA64PM,
+ storeRGB32FFromRGB32, storeRGB32FFromRGB32 }, // Format_RGBA32FPx4_Premultiplied
};
static_assert(sizeof(qPixelLayouts) / sizeof(*qPixelLayouts) == QImage::NImageFormats);
@@ -1548,6 +1896,58 @@ static void QT_FASTCALL storeGray16FromRGBA64PM(uchar *dest, const QRgba64 *src,
}
}
+static void QT_FASTCALL storeRGBX16FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba16F *d = reinterpret_cast<QRgba16F *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ d[i] = qConvertRgb64ToRgbaF16(src[i]).unpremultiplied();
+ d[i].setAlpha(1.0);
+ }
+}
+
+static void QT_FASTCALL storeRGBA16FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba16F *d = reinterpret_cast<QRgba16F *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = qConvertRgb64ToRgbaF16(src[i]).unpremultiplied();
+}
+
+static void QT_FASTCALL storeRGBA16FPMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba16F *d = reinterpret_cast<QRgba16F *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = qConvertRgb64ToRgbaF16(src[i]);
+}
+
+static void QT_FASTCALL storeRGBX32FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba32F *d = reinterpret_cast<QRgba32F *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ d[i] = qConvertRgb64ToRgbaF32(src[i]).unpremultiplied();
+ d[i].setAlpha(1.0);
+ }
+}
+
+static void QT_FASTCALL storeRGBA32FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba32F *d = reinterpret_cast<QRgba32F *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = qConvertRgb64ToRgbaF32(src[i]).unpremultiplied();
+}
+
+static void QT_FASTCALL storeRGBA32FPMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba32F *d = reinterpret_cast<QRgba32F *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = qConvertRgb64ToRgbaF32(src[i]);
+}
+
ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats] = {
nullptr,
nullptr,
@@ -1579,6 +1979,375 @@ ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats] = {
storeRGBA64PMFromRGBA64PM,
storeGray16FromRGBA64PM,
storeGenericFromRGBA64PM<QImage::Format_BGR888>,
+ storeRGBX16FFromRGBA64PM,
+ storeRGBA16FFromRGBA64PM,
+ storeRGBA16FPMFromRGBA64PM,
+ storeRGBX32FFromRGBA64PM,
+ storeRGBA32FFromRGBA64PM,
+ storeRGBA32FPMFromRGBA64PM,
+};
+
+#if QT_CONFIG(raster_fp)
+static void QT_FASTCALL convertToRgbaF32(QRgba32F *dest, const uint *src, int length)
+{
+ for (int i = 0; i < length; ++i)
+ dest[i] = QRgba32F::fromArgb32(src[i]);
+}
+
+template<QImage::Format format>
+static const QRgba32F * QT_FASTCALL convertGenericToRGBA32F(QRgba32F *buffer, const uint *src, int count,
+ const QList<QRgb> *clut, QDitherInfo *)
+{
+ uint buffer32[BufferSize];
+ memcpy(buffer32, src, count * sizeof(uint));
+ qPixelLayouts[format].convertToARGB32PM(buffer32, count, clut);
+ convertToRgbaF32(buffer, buffer32, count);
+ return buffer;
+}
+
+static const QRgba32F * QT_FASTCALL convertARGB32ToRGBA32F(QRgba32F *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgba32F::fromArgb32(src[i]).premultiplied();
+ return buffer;
+}
+
+static const QRgba32F * QT_FASTCALL convertRGBA8888ToRGBA32F(QRgba32F *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgba32F::fromArgb32(RGBA2ARGB(src[i])).premultiplied();
+ return buffer;
+}
+
+template<QtPixelOrder PixelOrder>
+static const QRgba32F * QT_FASTCALL convertRGB30ToRGBA32F(QRgba32F *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i) {
+ QRgba64 s = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]);
+ buffer[i] = QRgba32F::fromRgba64(s.red(), s.green(), s.blue(), s.alpha());
+ }
+ return buffer;
+}
+
+ConvertToFPFunc qConvertToRGBA32F[QImage::NImageFormats] = {
+ nullptr,
+ convertIndexedTo<QRgba32F>,
+ convertIndexedTo<QRgba32F>,
+ convertIndexedTo<QRgba32F>,
+ convertGenericToRGBA32F<QImage::Format_RGB32>,
+ convertARGB32ToRGBA32F,
+ convertGenericToRGBA32F<QImage::Format_ARGB32_Premultiplied>,
+ convertGenericToRGBA32F<QImage::Format_RGB16>,
+ convertGenericToRGBA32F<QImage::Format_ARGB8565_Premultiplied>,
+ convertGenericToRGBA32F<QImage::Format_RGB666>,
+ convertGenericToRGBA32F<QImage::Format_ARGB6666_Premultiplied>,
+ convertGenericToRGBA32F<QImage::Format_RGB555>,
+ convertGenericToRGBA32F<QImage::Format_ARGB8555_Premultiplied>,
+ convertGenericToRGBA32F<QImage::Format_RGB888>,
+ convertGenericToRGBA32F<QImage::Format_RGB444>,
+ convertGenericToRGBA32F<QImage::Format_ARGB4444_Premultiplied>,
+ convertGenericToRGBA32F<QImage::Format_RGBX8888>,
+ convertRGBA8888ToRGBA32F,
+ convertGenericToRGBA32F<QImage::Format_RGBA8888_Premultiplied>,
+ convertRGB30ToRGBA32F<PixelOrderBGR>,
+ convertRGB30ToRGBA32F<PixelOrderBGR>,
+ convertRGB30ToRGBA32F<PixelOrderRGB>,
+ convertRGB30ToRGBA32F<PixelOrderRGB>,
+ convertAlpha8To<QRgba32F>,
+ convertGrayscale8To<QRgba32F>,
+ nullptr,
+ nullptr,
+ nullptr,
+ convertGrayscale16To<QRgba32F>,
+ convertGenericToRGBA32F<QImage::Format_BGR888>,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+};
+
+static const QRgba32F *QT_FASTCALL fetchRGBX64ToRGBA32F(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ QRgba64 c = s[i];
+ buffer[i] = QRgba32F::fromRgba64(c.red(), c.green(), c.blue(), 65535);
+ }
+ return buffer;
+}
+
+static const QRgba32F *QT_FASTCALL fetchRGBA64ToRGBA32F(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = qConvertRgb64ToRgbaF32(s[i]).premultiplied();
+ return buffer;
+}
+
+static const QRgba32F *QT_FASTCALL fetchRGBA64PMToRGBA32F(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = qConvertRgb64ToRgbaF32(s[i]);
+ return buffer;
+}
+
+static const QRgba32F *QT_FASTCALL fetchRGBA16FToRGBA32F(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba16F *s = reinterpret_cast<const QRgba16F *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ auto c = s[i].premultiplied();
+ buffer[i] = QRgba32F { c.r, c.g, c.b, c.a};
+ }
+ return buffer;
+}
+
+static const QRgba32F *QT_FASTCALL fetchRGBA16F(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba16F *s = reinterpret_cast<const QRgba16F *>(src) + index;
+ qFloatFromFloat16((float *)buffer, (const qfloat16 *)s, count * 4);
+ return buffer;
+}
+
+static const QRgba32F *QT_FASTCALL fetchRGBA32FToRGBA32F(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba32F *s = reinterpret_cast<const QRgba32F *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = s[i].premultiplied();
+ return buffer;
+}
+
+static const QRgba32F *QT_FASTCALL fetchRGBA32F(QRgba32F *, const uchar *src, int index, int,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba32F *s = reinterpret_cast<const QRgba32F *>(src) + index;
+ return s;
+}
+
+FetchAndConvertPixelsFuncFP qFetchToRGBA32F[QImage::NImageFormats] = {
+ nullptr,
+ fetchIndexedToRGBA32F<QPixelLayout::BPP1MSB>,
+ fetchIndexedToRGBA32F<QPixelLayout::BPP1LSB>,
+ fetchIndexedToRGBA32F<QPixelLayout::BPP8>,
+ fetchRGBToRGB32F<QImage::Format_RGB32>,
+ fetchARGBToRGBA32F<QImage::Format_ARGB32>,
+ fetchARGBPMToRGBA32F<QImage::Format_ARGB32_Premultiplied>,
+ fetchRGBToRGB32F<QImage::Format_RGB16>,
+ fetchARGBToRGBA32F<QImage::Format_ARGB8565_Premultiplied>,
+ fetchRGBToRGB32F<QImage::Format_RGB666>,
+ fetchARGBToRGBA32F<QImage::Format_ARGB6666_Premultiplied>,
+ fetchRGBToRGB32F<QImage::Format_RGB555>,
+ fetchARGBToRGBA32F<QImage::Format_ARGB8555_Premultiplied>,
+ fetchRGBToRGB32F<QImage::Format_RGB888>,
+ fetchRGBToRGB32F<QImage::Format_RGB444>,
+ fetchARGBToRGBA32F<QImage::Format_ARGB4444_Premultiplied>,
+ fetchRGBToRGB32F<QImage::Format_RGBX8888>,
+ fetchARGBToRGBA32F<QImage::Format_RGBA8888>,
+ fetchARGBPMToRGBA32F<QImage::Format_RGBA8888_Premultiplied>,
+ fetchRGB30ToRGBA32F<PixelOrderBGR>,
+ fetchRGB30ToRGBA32F<PixelOrderBGR>,
+ fetchRGB30ToRGBA32F<PixelOrderRGB>,
+ fetchRGB30ToRGBA32F<PixelOrderRGB>,
+ fetchAlpha8To<QRgba32F>,
+ fetchGrayscale8To<QRgba32F>,
+ fetchRGBX64ToRGBA32F,
+ fetchRGBA64ToRGBA32F,
+ fetchRGBA64PMToRGBA32F,
+ fetchGrayscale16To<QRgba32F>,
+ fetchRGBToRGB32F<QImage::Format_BGR888>,
+ fetchRGBA16F,
+ fetchRGBA16FToRGBA32F,
+ fetchRGBA16F,
+ fetchRGBA32F,
+ fetchRGBA32FToRGBA32F,
+ fetchRGBA32F,
+};
+
+static void QT_FASTCALL convertFromRgba32f(uint *dest, const QRgba32F *src, int length)
+{
+ for (int i = 0; i < length; ++i)
+ dest[i] = src[i].toArgb32();
+}
+
+template<QImage::Format format>
+static void QT_FASTCALL storeGenericFromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *clut, QDitherInfo *dither)
+{
+ uint buffer[BufferSize];
+ convertFromRgba32f(buffer, src, count);
+ qPixelLayouts[format].storeFromARGB32PM(dest, buffer, index, count, clut, dither);
+}
+
+static void QT_FASTCALL storeARGB32FromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = (uint*)dest + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = src[i].unpremultiplied().toArgb32();
+}
+
+static void QT_FASTCALL storeRGBA8888FromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = (uint*)dest + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = ARGB2RGBA(src[i].unpremultiplied().toArgb32());
+}
+
+template<QtPixelOrder PixelOrder>
+static void QT_FASTCALL storeRGB30FromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = (uint*)dest + index;
+ for (int i = 0; i < count; ++i) {
+ const auto s = src[i];
+ d[i] = qConvertRgb64ToRgb30<PixelOrder>(QRgba64::fromRgba64(s.red16(), s.green16(), s.blue16(), s.alpha16()));
+ }
+}
+
+static void QT_FASTCALL storeRGBX64FromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ const auto s = src[i].unpremultiplied();
+ d[i] = QRgba64::fromRgba64(s.red16(), s.green16(), s.blue16(), 65535);
+ }
+}
+
+static void QT_FASTCALL storeRGBA64FromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ const auto s = src[i].unpremultiplied();
+ d[i] = QRgba64::fromRgba64(s.red16(), s.green16(), s.blue16(), s.alpha16());
+ }
+}
+
+static void QT_FASTCALL storeRGBA64PMFromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = QRgba64::fromRgba64(src[i].red16(), src[i].green16(), src[i].blue16(), src[i].alpha16());
+}
+
+static void QT_FASTCALL storeGray16FromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ quint16 *d = reinterpret_cast<quint16 *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ auto s = src[i].unpremultiplied();
+ d[i] = qGray(s.red16(), s.green16(), s.blue16());
+ }
+}
+
+static void QT_FASTCALL storeRGBX16FFromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba16F *d = reinterpret_cast<QRgba16F *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ auto s = src[i].unpremultiplied();
+ d[i] = QRgba16F{ s.r, s.g, s.b, 1.0f };
+ }
+}
+
+static void QT_FASTCALL storeRGBA16FFromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba16F *d = reinterpret_cast<QRgba16F *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ auto s = src[i].unpremultiplied();
+ d[i] = QRgba16F{ s.r, s.g, s.b, s.a };
+ }
+}
+
+static void QT_FASTCALL storeRGBA16FPMFromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba16F *d = reinterpret_cast<QRgba16F *>(dest) + index;
+ qFloatToFloat16((qfloat16 *)d, (const float *)src, count * 4);
+}
+
+static void QT_FASTCALL storeRGBX32FFromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba32F *d = reinterpret_cast<QRgba32F *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ auto s = src[i].unpremultiplied();
+ s.a = 1.0f;
+ d[i] = s;
+ }
+}
+
+static void QT_FASTCALL storeRGBA32FFromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba32F *d = reinterpret_cast<QRgba32F *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = src[i].unpremultiplied();
+}
+
+static void QT_FASTCALL storeRGBA32FPMFromRGBA32F(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba32F *d = reinterpret_cast<QRgba32F *>(dest) + index;
+ if (d != src) {
+ for (int i = 0; i < count; ++i)
+ d[i] = src[i];
+ }
+}
+
+ConvertAndStorePixelsFuncFP qStoreFromRGBA32F[QImage::NImageFormats] = {
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ storeGenericFromRGBA32F<QImage::Format_RGB32>,
+ storeARGB32FromRGBA32F,
+ storeGenericFromRGBA32F<QImage::Format_ARGB32_Premultiplied>,
+ storeGenericFromRGBA32F<QImage::Format_RGB16>,
+ storeGenericFromRGBA32F<QImage::Format_ARGB8565_Premultiplied>,
+ storeGenericFromRGBA32F<QImage::Format_RGB666>,
+ storeGenericFromRGBA32F<QImage::Format_ARGB6666_Premultiplied>,
+ storeGenericFromRGBA32F<QImage::Format_RGB555>,
+ storeGenericFromRGBA32F<QImage::Format_ARGB8555_Premultiplied>,
+ storeGenericFromRGBA32F<QImage::Format_RGB888>,
+ storeGenericFromRGBA32F<QImage::Format_RGB444>,
+ storeGenericFromRGBA32F<QImage::Format_ARGB4444_Premultiplied>,
+ storeGenericFromRGBA32F<QImage::Format_RGBX8888>,
+ storeRGBA8888FromRGBA32F,
+ storeGenericFromRGBA32F<QImage::Format_RGBA8888_Premultiplied>,
+ storeRGB30FromRGBA32F<PixelOrderBGR>,
+ storeRGB30FromRGBA32F<PixelOrderBGR>,
+ storeRGB30FromRGBA32F<PixelOrderRGB>,
+ storeRGB30FromRGBA32F<PixelOrderRGB>,
+ storeGenericFromRGBA32F<QImage::Format_Alpha8>,
+ storeGenericFromRGBA32F<QImage::Format_Grayscale8>,
+ storeRGBX64FromRGBA32F,
+ storeRGBA64FromRGBA32F,
+ storeRGBA64PMFromRGBA32F,
+ storeGray16FromRGBA32F,
+ storeGenericFromRGBA32F<QImage::Format_BGR888>,
+ storeRGBX16FFromRGBA32F,
+ storeRGBA16FFromRGBA32F,
+ storeRGBA16FPMFromRGBA32F,
+ storeRGBX32FFromRGBA32F,
+ storeRGBA32FFromRGBA32F,
+ storeRGBA32FPMFromRGBA32F,
};
+#endif // QT_CONFIG(raster_fp)
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpixellayout_p.h b/src/gui/painting/qpixellayout_p.h
index 6d20131efe..bf0bac3b09 100644
--- a/src/gui/painting/qpixellayout_p.h
+++ b/src/gui/painting/qpixellayout_p.h
@@ -54,6 +54,7 @@
#include <QtCore/qlist.h>
#include <QtGui/qimage.h>
#include <QtGui/qrgba64.h>
+#include <QtGui/qrgbaf.h>
QT_BEGIN_NAMESPACE
@@ -217,6 +218,16 @@ inline unsigned int qConvertRgb64ToRgb30<PixelOrderRGB>(QRgba64 c)
return (a << 30) | (r << 20) | (g << 10) | b;
}
+inline constexpr QRgba16F qConvertRgb64ToRgbaF16(QRgba64 c)
+{
+ return QRgba16F::fromRgba64(c.red(), c.green(), c.blue(), c.alpha());
+}
+
+inline constexpr QRgba32F qConvertRgb64ToRgbaF32(QRgba64 c)
+{
+ return QRgba32F::fromRgba64(c.red(), c.green(), c.blue(), c.alpha());
+}
+
inline uint qRgbSwapRgb30(uint c)
{
const uint ag = c & 0xc00ffc00;
@@ -296,10 +307,19 @@ typedef void(QT_FASTCALL *ConvertAndStorePixelsFunc64)(uchar *dest, const QRgba6
int count, const QList<QRgb> *clut,
QDitherInfo *dither);
-typedef void(QT_FASTCALL *ConvertFunc)(uint *buffer, int count, const QList<QRgb> *clut);
-typedef void(QT_FASTCALL *Convert64Func)(quint64 *buffer, int count, const QList<QRgb> *clut);
+typedef const QRgba32F *(QT_FASTCALL *FetchAndConvertPixelsFuncFP)(QRgba32F *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *clut, QDitherInfo *dither);
+typedef void (QT_FASTCALL *ConvertAndStorePixelsFuncFP)(uchar *dest, const QRgba32F *src, int index, int count,
+ const QList<QRgb> *clut, QDitherInfo *dither);
+typedef void (QT_FASTCALL *ConvertFunc)(uint *buffer, int count, const QList<QRgb> *clut);
+typedef void (QT_FASTCALL *Convert64Func)(QRgba64 *buffer, int count);
+typedef void (QT_FASTCALL *ConvertFPFunc)(QRgba32F *buffer, int count);
+typedef void (QT_FASTCALL *Convert64ToFPFunc)(QRgba32F *buffer, const quint64 *src, int count);
+
typedef const QRgba64 *(QT_FASTCALL *ConvertTo64Func)(QRgba64 *buffer, const uint *src, int count,
const QList<QRgb> *clut, QDitherInfo *dither);
+typedef const QRgba32F *(QT_FASTCALL *ConvertToFPFunc)(QRgba32F *buffer, const uint *src, int count,
+ const QList<QRgb> *clut, QDitherInfo *dither);
typedef void (QT_FASTCALL *RbSwapFunc)(uchar *dst, const uchar *src, int count);
typedef void (*MemRotateFunc)(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl);
@@ -316,6 +336,8 @@ struct QPixelLayout
BPP24,
BPP32,
BPP64,
+ BPP16FPx4,
+ BPP32FPx4,
BPPCount
};
@@ -333,6 +355,12 @@ struct QPixelLayout
extern ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats];
+#if QT_CONFIG(raster_fp)
+extern ConvertToFPFunc qConvertToRGBA32F[QImage::NImageFormats];
+extern FetchAndConvertPixelsFuncFP qFetchToRGBA32F[QImage::NImageFormats];
+extern ConvertAndStorePixelsFuncFP qStoreFromRGBA32F[QImage::NImageFormats];
+#endif
+
extern QPixelLayout qPixelLayouts[QImage::NImageFormats];
extern MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3];
diff --git a/src/gui/painting/qrgbaf.h b/src/gui/painting/qrgbaf.h
new file mode 100644
index 0000000000..da6d0a3646
--- /dev/null
+++ b/src/gui/painting/qrgbaf.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QRGBAF_H
+#define QRGBAF_H
+
+#include <QtGui/qtguiglobal.h>
+#include <QtCore/qfloat16.h>
+
+#include <algorithm>
+#include <cmath>
+
+QT_BEGIN_NAMESPACE
+
+template<typename F>
+class alignas(sizeof(F) * 4) QRgbaF {
+public:
+ F r;
+ F g;
+ F b;
+ F a;
+
+ static constexpr
+ QRgbaF fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha)
+ {
+ return QRgbaF{
+ red * (1.0f / 65535.0f),
+ green * (1.0f / 65535.0f),
+ blue * (1.0f / 65535.0f),
+ alpha * (1.0f / 65535.0f) };
+ }
+
+ static constexpr
+ QRgbaF fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha)
+ {
+ return QRgbaF{
+ red * (1.0f / 255.0f),
+ green * (1.0f / 255.0f),
+ blue * (1.0f / 255.0f),
+ alpha * (1.0f / 255.0f) };
+ }
+ static constexpr
+ QRgbaF fromArgb32(uint rgb)
+ {
+ return fromRgba(quint8(rgb >> 16), quint8(rgb >> 8), quint8(rgb), quint8(rgb >> 24));
+ }
+
+ constexpr bool isOpaque() const { return a >= 1.0f; }
+ constexpr bool isTransparent() const { return a <= 0.0f; }
+
+ constexpr float red() const { return r; }
+ constexpr float green() const { return g; }
+ constexpr float blue() const { return b; }
+ constexpr float alpha() const { return a; }
+ void setRed(float _red) { r = _red; }
+ void setGreen(float _green) { g = _green; }
+ void setBlue(float _blue) { b = _blue; }
+ void setAlpha(float _alpha) { a = _alpha; }
+
+ constexpr float redNormalized() const { return std::clamp(static_cast<float>(r), 0.0f, 1.0f); }
+ constexpr float greenNormalized() const { return std::clamp(static_cast<float>(g), 0.0f, 1.0f); }
+ constexpr float blueNormalized() const { return std::clamp(static_cast<float>(b), 0.0f, 1.0f); }
+ constexpr float alphaNormalized() const { return std::clamp(static_cast<float>(a), 0.0f, 1.0f); }
+
+ constexpr quint8 red8() const { return std::lround(redNormalized() * 255.0f); }
+ constexpr quint8 green8() const { return std::lround(greenNormalized() * 255.0f); }
+ constexpr quint8 blue8() const { return std::lround(blueNormalized() * 255.0f); }
+ constexpr quint8 alpha8() const { return std::lround(alphaNormalized() * 255.0f); }
+ constexpr uint toArgb32() const
+ {
+ return uint((alpha8() << 24) | (red8() << 16) | (green8() << 8) | blue8());
+ }
+
+ constexpr quint16 red16() const { return std::lround(redNormalized() * 65535.0f); }
+ constexpr quint16 green16() const { return std::lround(greenNormalized() * 65535.0f); }
+ constexpr quint16 blue16() const { return std::lround(blueNormalized() * 65535.0f); }
+ constexpr quint16 alpha16() const { return std::lround(alphaNormalized() * 65535.0f); }
+
+ constexpr Q_ALWAYS_INLINE QRgbaF premultiplied() const
+ {
+ return QRgbaF{r * a, g * a, b * a, a};
+ }
+ constexpr Q_ALWAYS_INLINE QRgbaF unpremultiplied() const
+ {
+ if (a <= 0.0f)
+ return QRgbaF{0.0f, 0.0f, 0.0f, 0.0f};
+ if (a >= 1.0f)
+ return *this;
+ const float ia = 1.0f / a;
+ return QRgbaF{r * ia, g * ia, b * ia, a};
+ }
+};
+
+typedef QRgbaF<float> QRgba32F;
+typedef QRgbaF<qfloat16> QRgba16F;
+
+QT_END_NAMESPACE
+
+#endif // QRGBAF_H
diff --git a/src/gui/painting/qrgbaf.qdoc b/src/gui/painting/qrgbaf.qdoc
new file mode 100644
index 0000000000..f503e597ee
--- /dev/null
+++ b/src/gui/painting/qrgbaf.qdoc
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QRgbaF
+ \brief The QRgbaF struct contains a four part RGBA floating-point color.
+ \since 6.2
+
+ \ingroup painting
+ \inmodule QtGui
+
+ QRgba16F is a 64-bit data-structure containing four 16-bit floating point color channels: Red, green, blue and alpha.
+ QRgba32F is a 128-bit data-structure containing four 32-bit floating point color channels: Red, green, blue and alpha.
+
+ \sa QRgb, QRgba64, QColor
+*/
+
+/*!
+ \fn static QRgbaF QRgbaF::fromRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
+
+ Constructs a QRgbaF value from the four 16-bit integer color channels \a red, \a green, \a blue and \a alpha.
+
+ \sa fromRgba()
+*/
+
+/*!
+ \fn static QRgbaF QRgbaF::fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha)
+
+ Constructs a QRgbaF value from the four 8-bit color channels \a red, \a green, \a blue and \a alpha.
+
+ \sa fromArgb32()
+*/
+
+/*!
+ \fn static QRgbaF QRgbaF::fromArgb32(uint rgb)
+
+ Constructs a QRgbaF value from the 32bit ARGB value \a rgb.
+
+ \sa fromRgba(), toArgb32()
+*/
+
+/*!
+ \fn bool QRgbaF::isOpaque() const
+
+ Returns whether the color is fully opaque.
+
+ \sa isTransparent(), alpha()
+*/
+
+/*!
+ \fn bool QRgbaF::isTransparent() const
+
+ Returns whether the color is fully transparent.
+
+ \sa isOpaque(), alpha()
+*/
+
+/*!
+ \fn float QRgbaF::red() const
+
+ Returns the red color component.
+
+ \sa setRed()
+*/
+
+/*!
+ \fn void QRgbaF::setRed(float red)
+
+ Sets the red color component of this color to \a red.
+
+ \sa red()
+*/
+
+/*!
+ \fn float QRgbaF::green() const
+
+ Returns the green color component.
+
+ \sa setGreen()
+*/
+
+/*!
+ \fn void QRgbaF::setGreen(float green)
+
+ Sets the green color component of this color to \a green.
+
+ \sa green()
+*/
+
+/*!
+ \fn float QRgbaF::blue() const
+
+ Returns the blue color component.
+
+ \sa setBlue()
+*/
+
+/*!
+ \fn void QRgbaF::setBlue(float blue)
+
+ Sets the blue color component of this color to \a blue.
+
+ \sa blue()
+*/
+
+/*!
+ \fn float QRgbaF::alpha() const
+
+ Returns the alpha channel.
+
+ \sa setAlpha()
+*/
+
+/*!
+ \fn void QRgbaF::setAlpha(float alpha)
+
+ Sets the alpha of this color to \a alpha.
+
+ \sa alpha()
+*/
+
+/*!
+ \fn float QRgbaF::redNormalized() const
+
+ Returns the red color component normalized to values between \c 0.0f and \c 1.0f.
+
+ \sa setRed()
+*/
+
+/*!
+ \fn float QRgbaF::greenNormalized() const
+
+ Returns the green color component normalized to values between \c 0.0f and \c 1.0f.
+
+ \sa setGreen()
+*/
+
+/*!
+ \fn float QRgbaF::blueNormalized() const
+
+ Returns the blue color component normalized to values between \c 0.0f and \c 1.0f.
+
+ \sa setBlue()
+*/
+
+/*!
+ \fn float QRgbaF::alphaNormalized() const
+
+ Returns the alpha channel normalized to values between \c 0.0f and \c 1.0f.
+
+ \sa alpha()
+*/
+
+/*!
+ \fn quint8 QRgbaF::red8() const
+
+ Returns the red color component as an 8-bit.
+*/
+
+/*!
+ \fn quint8 QRgbaF::green8() const
+
+ Returns the green color component as an 8-bit.
+*/
+
+/*!
+ \fn quint8 QRgbaF::blue8() const
+
+ Returns the blue color component as an 8-bit.
+*/
+
+/*!
+ \fn quint8 QRgbaF::alpha8() const
+
+ Returns the alpha channel as an 8-bit.
+*/
+
+/*!
+ \fn uint QRgbaF::toArgb32() const
+
+ Returns the color as a 32-bit ARGB value.
+
+ \sa fromArgb32()
+*/
+
+/*!
+ \fn quint16 QRgbaF::red16() const
+
+ Returns the red color component as a 16-bit integer.
+*/
+
+/*!
+ \fn quint16 QRgbaF::green16() const
+
+ Returns the green color component as a 16-bit integer.
+*/
+
+/*!
+ \fn quint16 QRgbaF::blue16() const
+
+ Returns the blue color component as a 16-bit integer.
+*/
+
+/*!
+ \fn quint16 QRgbaF::alpha16() const
+
+ Returns the alpha channel as a 16-bit integer.
+*/
+
+/*!
+ \fn QRgbaF QRgbaF::premultiplied() const
+
+ Returns the color with the alpha premultiplied.
+
+ \sa unpremultiplied()
+*/
+
+/*!
+ \fn QRgbaF QRgbaF::unpremultiplied() const
+
+ Returns the color with the alpha unpremultiplied.
+
+ \sa premultiplied()
+*/