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>
bb10
Allan Sandfeld Jensen 2018-05-18 17:03:58 +02:00
parent e51831260a
commit 93cd9130d6
26 changed files with 5174 additions and 277 deletions

View File

@ -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

View File

@ -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"

View File

@ -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.",

View File

@ -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);

View File

@ -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

View File

@ -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)) {

View File

@ -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)
{

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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),

View File

@ -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

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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];

135
src/gui/painting/qrgbaf.h Normal file
View File

@ -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

View File

@ -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()
*/

View File

@ -152,6 +152,25 @@ QT_BEGIN_NAMESPACE
#define GL_DEPTH_STENCIL 0x84F9
#endif
#ifndef GL_HALF_FLOAT
#define GL_HALF_FLOAT 0x140B
#endif
#ifndef GL_RGBA32F
#define GL_RGBA32F 0x8814
#endif
#ifndef GL_RGB32F
#define GL_RGB32F 0x8815
#endif
#ifndef GL_RGBA16F
#define GL_RGBA16F 0x881A
#endif
#ifndef GL_RGB16F
#define GL_RGB16F 0x881B
#endif
/*!
@ -554,6 +573,8 @@ void QOpenGLFramebufferObjectPrivate::initTexture(int idx)
pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
else if (color.internalFormat == GL_RGB16 || color.internalFormat == GL_RGBA16)
pixelType = GL_UNSIGNED_SHORT;
else if (color.internalFormat == GL_RGB16F || color.internalFormat == GL_RGBA16F)
pixelType = GL_HALF_FLOAT;
funcs.glTexImage2D(target, 0, color.internalFormat, color.size.width(), color.size.height(), 0,
GL_RGBA, pixelType, nullptr);
@ -1379,6 +1400,21 @@ static inline QImage qt_gl_read_framebuffer_rgba16(const QSize &size, bool inclu
return img;
}
static inline QImage qt_gl_read_framebuffer_rgba16f(const QSize &size, bool include_alpha, QOpenGLContext *context)
{
// We assume OpenGL (ES) 3.0+ here.
QImage img(size, include_alpha ? QImage::Format_RGBA16FPx4_Premultiplied : QImage::Format_RGBX16FPx4);
context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_HALF_FLOAT, img.bits());
return img;
}
static inline QImage qt_gl_read_framebuffer_rgba32f(const QSize &size, bool include_alpha, QOpenGLContext *context)
{
QImage img(size, include_alpha ? QImage::Format_RGBA32FPx4_Premultiplied : QImage::Format_RGBX32FPx4);
context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_FLOAT, img.bits());
return img;
}
static QImage qt_gl_read_framebuffer(const QSize &size, GLenum internal_format, bool include_alpha, bool flip)
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
@ -1400,6 +1436,14 @@ static QImage qt_gl_read_framebuffer(const QSize &size, GLenum internal_format,
return qt_gl_read_framebuffer_rgba16(size, false, ctx).mirrored(false, flip);
case GL_RGBA16:
return qt_gl_read_framebuffer_rgba16(size, include_alpha, ctx).mirrored(false, flip);
case GL_RGB16F:
return qt_gl_read_framebuffer_rgba16f(size, false, ctx).mirrored(false, flip);
case GL_RGBA16F:
return qt_gl_read_framebuffer_rgba16f(size, include_alpha, ctx).mirrored(false, flip);
case GL_RGB32F:
return qt_gl_read_framebuffer_rgba32f(size, false, ctx).mirrored(false, flip);
case GL_RGBA32F:
return qt_gl_read_framebuffer_rgba32f(size, include_alpha, ctx).mirrored(false, flip);
case GL_RGBA:
case GL_RGBA8:
default:

View File

@ -1572,6 +1572,8 @@ void QOpenGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, c
case QImage::Format_RGBA8888:
case QImage::Format_ARGB32:
case QImage::Format_RGBA64:
case QImage::Format_RGBA16FPx4:
case QImage::Format_RGBA32FPx4:
d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::NonPremultipliedImageSrc);
bindOption = { };
break;

View File

@ -45,6 +45,10 @@
#include <private/qopenglcontext_p.h>
#include <private/qopenglextensions_p.h>
#ifndef GL_HALF_FLOAT
#define GL_HALF_FLOAT 0x140B
#endif
#ifndef GL_RED
#define GL_RED 0x1903
#endif
@ -81,6 +85,14 @@
#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
#endif
#ifndef GL_RGBA16F
#define GL_RGBA16F 0x881A
#endif
#ifndef GL_RGBA32F
#define GL_RGBA32F 0x8814
#endif
#ifndef GL_TEXTURE_SWIZZLE_R
#define GL_TEXTURE_SWIZZLE_R 0x8E42
#endif
@ -236,6 +248,25 @@ qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &imag
pixelType = GL_UNSIGNED_SHORT;
targetFormat = image.format();
break;
case QImage::Format_RGBX16FPx4:
case QImage::Format_RGBA16FPx4:
case QImage::Format_RGBA16FPx4_Premultiplied:
if (context->format().majorVersion() >= 3) {
externalFormat = GL_RGBA;
internalFormat = GL_RGBA16F;
pixelType = GL_HALF_FLOAT;
targetFormat = image.format();
}
break;
case QImage::Format_RGBX32FPx4:
case QImage::Format_RGBA32FPx4:
case QImage::Format_RGBA32FPx4_Premultiplied:
externalFormat = internalFormat = GL_RGBA;
if (context->format().majorVersion() >= 3)
internalFormat = GL_RGBA32F;
pixelType = GL_FLOAT;
targetFormat = image.format();
break;
case QImage::Format_Indexed8:
if (sRgbBinding) {
// Always needs conversion
@ -333,6 +364,10 @@ qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &imag
targetFormat = QImage::Format_RGBA8888_Premultiplied;
else if (targetFormat == QImage::Format_RGBA64)
targetFormat = QImage::Format_RGBA64_Premultiplied;
else if (targetFormat == QImage::Format_RGBA16FPx4)
targetFormat = QImage::Format_RGBA16FPx4_Premultiplied;
else if (targetFormat == QImage::Format_RGBA32FPx4)
targetFormat = QImage::Format_RGBA32FPx4_Premultiplied;
} else {
if (targetFormat == QImage::Format_ARGB32_Premultiplied)
targetFormat = QImage::Format_ARGB32;
@ -340,6 +375,10 @@ qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &imag
targetFormat = QImage::Format_RGBA8888;
else if (targetFormat == QImage::Format_RGBA64_Premultiplied)
targetFormat = QImage::Format_RGBA64;
else if (targetFormat == QImage::Format_RGBA16FPx4_Premultiplied)
targetFormat = QImage::Format_RGBA16FPx4;
else if (targetFormat == QImage::Format_RGBA32FPx4_Premultiplied)
targetFormat = QImage::Format_RGBA32FPx4;
}
if (sRgbBinding) {

View File

@ -323,6 +323,18 @@ static QLatin1String formatToString(QImage::Format format)
return QLatin1String("Grayscale16");
case QImage::Format_BGR888:
return QLatin1String("BGR888");
case QImage::Format_RGBX16FPx4:
return QLatin1String("RGBx16FPx4");
case QImage::Format_RGBA16FPx4:
return QLatin1String("RGBA16FPx4");
case QImage::Format_RGBA16FPx4_Premultiplied:
return QLatin1String("RGBA16FPx4pm");
case QImage::Format_RGBX32FPx4:
return QLatin1String("RGBx32FPx4");
case QImage::Format_RGBA32FPx4:
return QLatin1String("RGBA32FPx4");
case QImage::Format_RGBA32FPx4_Premultiplied:
return QLatin1String("RGBA32FPx4pm");
default:
break;
};
@ -1765,7 +1777,17 @@ void tst_QImage::smoothScale2_data()
QTest::addColumn<int>("size");
int sizes[] = { 2, 3, 4, 6, 7, 8, 10, 16, 20, 32, 40, 64, 100, 101, 128, 0 };
QImage::Format formats[] = { QImage::Format_RGB32, QImage::Format_ARGB32_Premultiplied, QImage::Format_RGBX64, QImage::Format_RGBA64_Premultiplied, QImage::Format_Invalid };
QImage::Format formats[] = { QImage::Format_RGB32,
QImage::Format_ARGB32_Premultiplied,
#if QT_CONFIG(raster_64bit)
QImage::Format_RGBX64,
QImage::Format_RGBA64_Premultiplied,
#endif
#if QT_CONFIG(raster_fp)
QImage::Format_RGBX32FPx4,
QImage::Format_RGBA32FPx4_Premultiplied,
#endif
QImage::Format_Invalid };
for (int j = 0; formats[j] != QImage::Format_Invalid; ++j) {
QString formatstr = formatToString(formats[j]);
for (int i = 0; sizes[i] != 0; ++i) {
@ -1780,11 +1802,9 @@ void tst_QImage::smoothScale2()
QFETCH(QImage::Format, format);
QFETCH(int, size);
bool opaque = (format == QImage::Format_RGB32 || format == QImage::Format_RGBX64);
QRgb expected = opaque ? qRgb(63, 127, 255) : qRgba(31, 63, 127, 127);
QImage img(size, size, format);
bool opaque = !img.hasAlphaChannel();
QRgb expected = opaque ? qRgb(63, 127, 255) : qRgba(31, 63, 127, 127);
img.fill(expected);
// scale x down, y down
@ -1929,6 +1949,9 @@ void tst_QImage::smoothScale4_data()
#if QT_CONFIG(raster_64bit)
QTest::newRow("RGBx64") << QImage::Format_RGBX64;
#endif
#if QT_CONFIG(raster_fp)
QTest::newRow("RGBx32FP") << QImage::Format_RGBX32FPx4;
#endif
}
void tst_QImage::smoothScale4()
@ -2356,6 +2379,8 @@ void tst_QImage::fillColor_data()
QImage::Format_RGBA8888_Premultiplied,
QImage::Format_BGR30,
QImage::Format_A2RGB30_Premultiplied,
QImage::Format_RGBX16FPx4,
QImage::Format_RGBA32FPx4_Premultiplied,
};
for (int i=0; names[i] != 0; ++i) {
@ -2678,7 +2703,6 @@ void tst_QImage::inplaceRgbSwapped_data()
void tst_QImage::inplaceRgbSwapped()
{
#if defined(Q_COMPILER_REF_QUALIFIERS)
QFETCH(QImage::Format, format);
QImage image(64, 1, format);
@ -2686,7 +2710,7 @@ void tst_QImage::inplaceRgbSwapped()
QList<QRgb> testColor(image.width());
for (int i = 0; i < image.width(); ++i)
testColor[i] = qRgb(i * 2, i * 3, 255 - i * 4);
testColor[i] = qRgb(i * 2, i * 3, std::min(255 - i * 4, 0));
if (format == QImage::Format_Indexed8) {
for (int i = 0; i < image.width(); ++i) {
@ -2739,7 +2763,6 @@ void tst_QImage::inplaceRgbSwapped()
QCOMPARE(dataSwapped, orig.rgbSwapped());
}
#endif
}
@ -3006,6 +3029,7 @@ void tst_QImage::inplaceRgbConversion_data()
void tst_QImage::inplaceRgbConversion()
{
// Test that conversions between RGB formats of the same bitwidth can be done inplace.
QFETCH(QImage::Format, format);
QFETCH(QImage::Format, dest_format);

View File

@ -1060,6 +1060,7 @@ void tst_QPainter::fillRect_data()
QTest::newRow("argb32pm") << QImage::Format_ARGB32_Premultiplied;
QTest::newRow("rgba8888pm") << QImage::Format_RGBA8888_Premultiplied;
QTest::newRow("rgba64pm") << QImage::Format_RGBA64_Premultiplied;
QTest::newRow("rgbaFP16pm") << QImage::Format_RGBA16FPx4_Premultiplied;
}
void tst_QPainter::fillRect()
@ -1558,6 +1559,8 @@ void tst_QPainter::qimageFormats_data()
QTest::newRow("Qimage::Format_BGR888") << QImage::Format_BGR888;
QTest::newRow("Qimage::Format_A2RGB30_Premultiplied") << QImage::Format_A2RGB30_Premultiplied;
QTest::newRow("Qimage::Format_RGB30") << QImage::Format_RGB30;
QTest::newRow("QImage::Format_RGBX16FPx4") << QImage::Format_RGBX16FPx4;
QTest::newRow("QImage::Format_RGBA32FPx4_Premultiplied") << QImage::Format_RGBA32FPx4_Premultiplied;
}
/*

View File

@ -182,6 +182,14 @@ const char *PaintCommands::imageFormatTable[] = {
"RGBx64",
"RGBA64",
"RGBA64_Premultiplied",
"Grayscale16",
"BGR888",
"RGBx16FPx4",
"RGBA16FPx4",
"RGBA16FPx4_Premultiplied",
"RGBx32FPx4",
"RGBA32FPx4",
"RGBA32FPx4_Premultiplied",
};
int PaintCommands::translateEnum(const char *table[], const QString &pattern, int limit)

View File

@ -90,6 +90,10 @@ private slots:
void testRasterGrayscale8();
void testRasterRGBA64PM_data();
void testRasterRGBA64PM();
void testRasterRGBA16F_data();
void testRasterRGBA16F();
void testRasterRGBA32FPM_data();
void testRasterRGBA32FPM();
#ifndef QT_NO_OPENGL
void testOpenGL_data();
@ -242,6 +246,27 @@ void tst_Lancelot::testRasterRGBA64PM()
}
void tst_Lancelot::testRasterRGBA16F_data()
{
setupTestSuite();
}
void tst_Lancelot::testRasterRGBA16F()
{
runTestSuite(Raster, QImage::Format_RGBA16FPx4);
}
void tst_Lancelot::testRasterRGBA32FPM_data()
{
setupTestSuite();
}
void tst_Lancelot::testRasterRGBA32FPM()
{
runTestSuite(Raster, QImage::Format_RGBA32FPx4_Premultiplied);
}
#ifndef QT_NO_OPENGL
bool tst_Lancelot::checkSystemGLSupport()
{