diff options
Diffstat (limited to 'src/gui/painting/qimagescale.cpp')
-rw-r--r-- | src/gui/painting/qimagescale.cpp | 907 |
1 files changed, 581 insertions, 326 deletions
diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp index 2e2f65b483..a636635fd5 100644 --- a/src/gui/painting/qimagescale.cpp +++ b/src/gui/painting/qimagescale.cpp @@ -1,47 +1,19 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #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 "qrgbafloat.h" + +#if QT_CONFIG(thread) && !defined(Q_OS_WASM) +#include <qsemaphore.h> +#include <qthreadpool.h> +#include <private/qthreadpool_p.h> +#endif QT_BEGIN_NAMESPACE @@ -239,6 +211,8 @@ static QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img, isi = new QImageScaleInfo; if (!isi) return nullptr; + isi->sh = sh; + isi->sw = sw; isi->xup_yup = (qAbs(dw) >= sw) + ((qAbs(dh) >= sh) << 1); @@ -294,6 +268,33 @@ void qt_qimageScaleAARGBA_down_xy_neon(QImageScaleInfo *isi, unsigned int *dest, int dw, int dh, int dow, int sow); #endif +template<typename T> +static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, const T &scaleSection) +{ +#if QT_CONFIG(thread) && !defined(Q_OS_WASM) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); + if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + threadPool->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; + } +#else + Q_UNUSED(isi); +#endif + scaleSection(0, dh); +} + static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest, int dw, int dh, int dow, int sow) { @@ -303,33 +304,36 @@ static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest, int *yapoints = isi->yapoints; /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - /* calculate the source line we'll scan from */ - const unsigned int *sptr = ypoints[y]; - unsigned int *dptr = dest + (y * dow); - const int yap = yapoints[y]; - if (yap > 0) { - for (int x = 0; x < dw; x++) { - const unsigned int *pix = sptr + xpoints[x]; - const int xap = xapoints[x]; - if (xap > 0) - *dptr = interpolate_4_pixels(pix, pix + sow, xap, yap); - else - *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - yap, pix[sow], yap); - dptr++; - } - } else { - for (int x = 0; x < dw; x++) { - const unsigned int *pix = sptr + xpoints[x]; - const int xap = xapoints[x]; - if (xap > 0) - *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap); - else - *dptr = pix[0]; - dptr++; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + /* calculate the source line we'll scan from */ + const unsigned int *sptr = ypoints[y]; + unsigned int *dptr = dest + (y * dow); + const int yap = yapoints[y]; + if (yap > 0) { + for (int x = 0; x < dw; x++) { + const unsigned int *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + if (xap > 0) + *dptr = interpolate_4_pixels(pix, pix + sow, xap, yap); + else + *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - yap, pix[sow], yap); + dptr++; + } + } else { + for (int x = 0; x < dw; x++) { + const unsigned int *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + if (xap > 0) + *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap); + else + *dptr = pix[0]; + dptr++; + } } } - } + }; + multithread_pixels_function(isi, dh, scaleSection); } /* scale by area sampling - with alpha */ @@ -411,33 +415,36 @@ static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int int *yapoints = isi->yapoints; /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - int Cy = yapoints[y] >> 16; - int yap = yapoints[y] & 0xffff; - - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - const unsigned int *sptr = ypoints[y] + xpoints[x]; - int r, g, b, a; - qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, r, g, b, a); - - int xap = xapoints[x]; - if (xap > 0) { - int rr, gg, bb, aa; - qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); - - r = r * (256 - xap); - g = g * (256 - xap); - b = b * (256 - xap); - a = a * (256 - xap); - r = (r + (rr * xap)) >> 8; - g = (g + (gg * xap)) >> 8; - b = (b + (bb * xap)) >> 8; - a = (a + (aa * xap)) >> 8; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = yapoints[y] >> 16; + int yap = yapoints[y] & 0xffff; + + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + const unsigned int *sptr = ypoints[y] + xpoints[x]; + int r, g, b, a; + qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, r, g, b, a); + + int xap = xapoints[x]; + if (xap > 0) { + int rr, gg, bb, aa; + qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); + + r = r * (256 - xap); + g = g * (256 - xap); + b = b * (256 - xap); + a = a * (256 - xap); + r = (r + (rr * xap)) >> 8; + g = (g + (gg * xap)) >> 8; + b = (b + (bb * xap)) >> 8; + a = (a + (aa * xap)) >> 8; + } + *dptr++ = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); } - *dptr++ = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); } - } + }; + multithread_pixels_function(isi, dh, scaleSection); } static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, @@ -449,34 +456,37 @@ static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int int *yapoints = isi->yapoints; /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; - - const unsigned int *sptr = ypoints[y] + xpoints[x]; - int r, g, b, a; - qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, r, g, b, a); - - int yap = yapoints[y]; - if (yap > 0) { - int rr, gg, bb, aa; - qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa); - - r = r * (256 - yap); - g = g * (256 - yap); - b = b * (256 - yap); - a = a * (256 - yap); - r = (r + (rr * yap)) >> 8; - g = (g + (gg * yap)) >> 8; - b = (b + (bb * yap)) >> 8; - a = (a + (aa * yap)) >> 8; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[y] + xpoints[x]; + int r, g, b, a; + qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, r, g, b, a); + + int yap = yapoints[y]; + if (yap > 0) { + int rr, gg, bb, aa; + qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa); + + r = r * (256 - yap); + g = g * (256 - yap); + b = b * (256 - yap); + a = a * (256 - yap); + r = (r + (rr * yap)) >> 8; + g = (g + (gg * yap)) >> 8; + b = (b + (bb * yap)) >> 8; + a = (a + (aa * yap)) >> 8; + } + *dptr = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); + dptr++; } - *dptr = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); - dptr++; } - } + }; + multithread_pixels_function(isi, dh, scaleSection); } static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest, @@ -487,45 +497,48 @@ static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *des int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - int Cy = (yapoints[y]) >> 16; - int yap = (yapoints[y]) & 0xffff; - - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = (yapoints[y]) >> 16; + int yap = (yapoints[y]) & 0xffff; - const unsigned int *sptr = ypoints[y] + xpoints[x]; - int rx, gx, bx, ax; - qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; - int r = ((rx>>4) * yap); - int g = ((gx>>4) * yap); - int b = ((bx>>4) * yap); - int a = ((ax>>4) * yap); + const unsigned int *sptr = ypoints[y] + xpoints[x]; + int rx, gx, bx, ax; + qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); - int j; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + int r = ((rx>>4) * yap); + int g = ((gx>>4) * yap); + int b = ((bx>>4) * yap); + int a = ((ax>>4) * yap); + + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); + r += ((rx>>4) * Cy); + g += ((gx>>4) * Cy); + b += ((bx>>4) * Cy); + a += ((ax>>4) * Cy); + } sptr += sow; qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); - r += ((rx>>4) * Cy); - g += ((gx>>4) * Cy); - b += ((bx>>4) * Cy); - a += ((ax>>4) * Cy); - } - sptr += sow; - qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); - r += ((rx>>4) * j); - g += ((gx>>4) * j); - b += ((bx>>4) * j); - a += ((ax>>4) * j); + r += ((rx>>4) * j); + g += ((gx>>4) * j); + b += ((bx>>4) * j); + a += ((ax>>4) * j); - *dptr = qRgba(r >> 24, g >> 24, b >> 24, a >> 24); - dptr++; + *dptr = qRgba(r >> 24, g >> 24, b >> 24, a >> 24); + dptr++; + } } - } + }; + multithread_pixels_function(isi, dh, scaleSection); } #if QT_CONFIG(raster_64bit) @@ -546,32 +559,35 @@ static void qt_qimageScaleRgba64_up_xy(QImageScaleInfo *isi, QRgba64 *dest, int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - const QRgba64 *sptr = ypoints[y]; - QRgba64 *dptr = dest + (y * dow); - const int yap = yapoints[y]; - if (yap > 0) { - for (int x = 0; x < dw; x++) { - const QRgba64 *pix = sptr + xpoints[x]; - const int xap = xapoints[x]; - if (xap > 0) - *dptr = interpolate_4_pixels_rgb64(pix, pix + sow, xap * 256, yap * 256); - else - *dptr = interpolate256(pix[0], 256 - yap, pix[sow], yap); - dptr++; - } - } else { - for (int x = 0; x < dw; x++) { - const QRgba64 *pix = sptr + xpoints[x]; - const int xap = xapoints[x]; - if (xap > 0) - *dptr = interpolate256(pix[0], 256 - xap, pix[1], xap); - else - *dptr = pix[0]; - dptr++; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + const QRgba64 *sptr = ypoints[y]; + QRgba64 *dptr = dest + (y * dow); + const int yap = yapoints[y]; + if (yap > 0) { + for (int x = 0; x < dw; x++) { + const QRgba64 *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + if (xap > 0) + *dptr = interpolate_4_pixels_rgb64(pix, pix + sow, xap * 256, yap * 256); + else + *dptr = interpolate256(pix[0], 256 - yap, pix[sow], yap); + dptr++; + } + } else { + for (int x = 0; x < dw; x++) { + const QRgba64 *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + if (xap > 0) + *dptr = interpolate256(pix[0], 256 - xap, pix[1], xap); + else + *dptr = pix[0]; + dptr++; + } } } - } + }; + multithread_pixels_function(isi, dh, scaleSection); } void qt_qimageScaleRgba64(QImageScaleInfo *isi, QRgba64 *dest, @@ -616,33 +632,36 @@ static void qt_qimageScaleRgba64_up_x_down_y(QImageScaleInfo *isi, QRgba64 *dest int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - int Cy = (yapoints[y]) >> 16; - int yap = (yapoints[y]) & 0xffff; - - QRgba64 *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - const QRgba64 *sptr = ypoints[y] + xpoints[x]; - qint64 r, g, b, a; - qt_qimageScaleRgba64_helper(sptr, yap, Cy, sow, r, g, b, a); - - int xap = xapoints[x]; - if (xap > 0) { - qint64 rr, gg, bb, aa; - qt_qimageScaleRgba64_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); - - r = r * (256 - xap); - g = g * (256 - xap); - b = b * (256 - xap); - a = a * (256 - xap); - r = (r + (rr * xap)) >> 8; - g = (g + (gg * xap)) >> 8; - b = (b + (bb * xap)) >> 8; - a = (a + (aa * xap)) >> 8; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = (yapoints[y]) >> 16; + int yap = (yapoints[y]) & 0xffff; + + QRgba64 *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + const QRgba64 *sptr = ypoints[y] + xpoints[x]; + qint64 r, g, b, a; + qt_qimageScaleRgba64_helper(sptr, yap, Cy, sow, r, g, b, a); + + int xap = xapoints[x]; + if (xap > 0) { + qint64 rr, gg, bb, aa; + qt_qimageScaleRgba64_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); + + r = r * (256 - xap); + g = g * (256 - xap); + b = b * (256 - xap); + a = a * (256 - xap); + r = (r + (rr * xap)) >> 8; + g = (g + (gg * xap)) >> 8; + b = (b + (bb * xap)) >> 8; + a = (a + (aa * xap)) >> 8; + } + *dptr++ = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14); } - *dptr++ = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14); } - } + }; + multithread_pixels_function(isi, dh, scaleSection); } static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest, @@ -653,34 +672,37 @@ static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - QRgba64 *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; - - const QRgba64 *sptr = ypoints[y] + xpoints[x]; - qint64 r, g, b, a; - qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, r, g, b, a); - - int yap = yapoints[y]; - if (yap > 0) { - qint64 rr, gg, bb, aa; - qt_qimageScaleRgba64_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa); - - r = r * (256 - yap); - g = g * (256 - yap); - b = b * (256 - yap); - a = a * (256 - yap); - r = (r + (rr * yap)) >> 8; - g = (g + (gg * yap)) >> 8; - b = (b + (bb * yap)) >> 8; - a = (a + (aa * yap)) >> 8; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + QRgba64 *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const QRgba64 *sptr = ypoints[y] + xpoints[x]; + qint64 r, g, b, a; + qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, r, g, b, a); + + int yap = yapoints[y]; + if (yap > 0) { + qint64 rr, gg, bb, aa; + qt_qimageScaleRgba64_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa); + + r = r * (256 - yap); + g = g * (256 - yap); + b = b * (256 - yap); + a = a * (256 - yap); + r = (r + (rr * yap)) >> 8; + g = (g + (gg * yap)) >> 8; + b = (b + (bb * yap)) >> 8; + a = (a + (aa * yap)) >> 8; + } + *dptr = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14); + dptr++; } - *dptr = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14); - dptr++; } - } + }; + multithread_pixels_function(isi, dh, scaleSection); } static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest, @@ -691,43 +713,261 @@ static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest, int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - int Cy = (yapoints[y]) >> 16; - int yap = (yapoints[y]) & 0xffff; - - QRgba64 *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; - - const QRgba64 *sptr = ypoints[y] + xpoints[x]; - qint64 rx, gx, bx, ax; - qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); - - qint64 r = rx * yap; - qint64 g = gx * yap; - qint64 b = bx * yap; - qint64 a = ax * yap; - int j; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = (yapoints[y]) >> 16; + int yap = (yapoints[y]) & 0xffff; + + QRgba64 *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const QRgba64 *sptr = ypoints[y] + xpoints[x]; + qint64 rx, gx, bx, ax; + qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); + + qint64 r = rx * yap; + qint64 g = gx * yap; + qint64 b = bx * yap; + qint64 a = ax * yap; + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); + r += rx * Cy; + g += gx * Cy; + b += bx * Cy; + a += ax * Cy; + } sptr += sow; qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); - r += rx * Cy; - g += gx * Cy; - b += bx * Cy; - a += ax * Cy; + r += rx * j; + g += gx * j; + b += bx * j; + a += ax * j; + + *dptr = qRgba64(r >> 28, g >> 28, b >> 28, a >> 28); + dptr++; } - sptr += sow; - qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); - r += rx * j; - g += gx * j; - b += bx * j; - a += ax * j; - - *dptr = qRgba64(r >> 28, g >> 28, b >> 28, a >> 28); - dptr++; } + }; + multithread_pixels_function(isi, dh, scaleSection); +} +#endif + +#if QT_CONFIG(raster_fp) +static void qt_qimageScaleRgbaFP_up_x_down_y(QImageScaleInfo *isi, QRgbaFloat32 *dest, + int dw, int dh, int dow, int sow); + +static void qt_qimageScaleRgbaFP_down_x_up_y(QImageScaleInfo *isi, QRgbaFloat32 *dest, + int dw, int dh, int dow, int sow); + +static void qt_qimageScaleRgbaFP_down_xy(QImageScaleInfo *isi, QRgbaFloat32 *dest, + int dw, int dh, int dow, int sow); + +static void qt_qimageScaleRgbaFP_up_xy(QImageScaleInfo *isi, QRgbaFloat32 *dest, + int dw, int dh, int dow, int sow) +{ + const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)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 QRgbaFloat32 *sptr = ypoints[y]; + QRgbaFloat32 *dptr = dest + (y * dow); + const int yap = yapoints[y]; + if (yap > 0) { + for (int x = 0; x < dw; x++) { + const QRgbaFloat32 *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 QRgbaFloat32 *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, QRgbaFloat32 *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 QRgbaFloat32 *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, QRgbaFloat32 *dest, + int dw, int dh, int dow, int sow) +{ + const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)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; + + QRgbaFloat32 *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + const QRgbaFloat32 *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++ = QRgbaFloat32{r, g, b, a}; + } + } + }; + multithread_pixels_function(isi, dh, scaleSection); +} + +static void qt_qimageScaleRgbaFP_down_x_up_y(QImageScaleInfo *isi, QRgbaFloat32 *dest, + int dw, int dh, int dow, int sow) +{ + const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)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) { + QRgbaFloat32 *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const QRgbaFloat32 *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++ = QRgbaFloat32{r, g, b, a}; + } + } + }; + multithread_pixels_function(isi, dh, scaleSection); +} + +static void qt_qimageScaleRgbaFP_down_xy(QImageScaleInfo *isi, QRgbaFloat32 *dest, + int dw, int dh, int dow, int sow) +{ + const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)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; + + QRgbaFloat32 *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const QRgbaFloat32 *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++ = QRgbaFloat32{r, g, b, a}; + } + } + }; + multithread_pixels_function(isi, dh, scaleSection); } #endif @@ -817,31 +1057,34 @@ static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int * int *yapoints = isi->yapoints; /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - int Cy = yapoints[y] >> 16; - int yap = yapoints[y] & 0xffff; - - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - const unsigned int *sptr = ypoints[y] + xpoints[x]; - int r, g, b; - qt_qimageScaleAARGB_helper(sptr, yap, Cy, sow, r, g, b); - - int xap = xapoints[x]; - if (xap > 0) { - int rr, bb, gg; - qt_qimageScaleAARGB_helper(sptr + 1, yap, Cy, sow, rr, gg, bb); - - r = r * (256 - xap); - g = g * (256 - xap); - b = b * (256 - xap); - r = (r + (rr * xap)) >> 8; - g = (g + (gg * xap)) >> 8; - b = (b + (bb * xap)) >> 8; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = yapoints[y] >> 16; + int yap = yapoints[y] & 0xffff; + + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + const unsigned int *sptr = ypoints[y] + xpoints[x]; + int r, g, b; + qt_qimageScaleAARGB_helper(sptr, yap, Cy, sow, r, g, b); + + int xap = xapoints[x]; + if (xap > 0) { + int rr, bb, gg; + qt_qimageScaleAARGB_helper(sptr + 1, yap, Cy, sow, rr, gg, bb); + + r = r * (256 - xap); + g = g * (256 - xap); + b = b * (256 - xap); + r = (r + (rr * xap)) >> 8; + g = (g + (gg * xap)) >> 8; + b = (b + (bb * xap)) >> 8; + } + *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); } - *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); } - } + }; + multithread_pixels_function(isi, dh, scaleSection); } static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, @@ -853,31 +1096,34 @@ static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int * int *yapoints = isi->yapoints; /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; - - const unsigned int *sptr = ypoints[y] + xpoints[x]; - int r, g, b; - qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, r, g, b); - - int yap = yapoints[y]; - if (yap > 0) { - int rr, bb, gg; - qt_qimageScaleAARGB_helper(sptr + sow, xap, Cx, 1, rr, gg, bb); - - r = r * (256 - yap); - g = g * (256 - yap); - b = b * (256 - yap); - r = (r + (rr * yap)) >> 8; - g = (g + (gg * yap)) >> 8; - b = (b + (bb * yap)) >> 8; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[y] + xpoints[x]; + int r, g, b; + qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, r, g, b); + + int yap = yapoints[y]; + if (yap > 0) { + int rr, bb, gg; + qt_qimageScaleAARGB_helper(sptr + sow, xap, Cx, 1, rr, gg, bb); + + r = r * (256 - yap); + g = g * (256 - yap); + b = b * (256 - yap); + r = (r + (rr * yap)) >> 8; + g = (g + (gg * yap)) >> 8; + b = (b + (bb * yap)) >> 8; + } + *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); } - *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); } - } + }; + multithread_pixels_function(isi, dh, scaleSection); } static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest, @@ -888,43 +1134,46 @@ static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - int Cy = yapoints[y] >> 16; - int yap = yapoints[y] & 0xffff; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = yapoints[y] >> 16; + int yap = yapoints[y] & 0xffff; - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; - const unsigned int *sptr = ypoints[y] + xpoints[x]; - int rx, gx, bx; - qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx); + const unsigned int *sptr = ypoints[y] + xpoints[x]; + int rx, gx, bx; + qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx); - int r = (rx >> 4) * yap; - int g = (gx >> 4) * yap; - int b = (bx >> 4) * yap; + int r = (rx >> 4) * yap; + int g = (gx >> 4) * yap; + int b = (bx >> 4) * yap; - int j; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx); + + r += (rx >> 4) * Cy; + g += (gx >> 4) * Cy; + b += (bx >> 4) * Cy; + } sptr += sow; qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx); - r += (rx >> 4) * Cy; - g += (gx >> 4) * Cy; - b += (bx >> 4) * Cy; - } - sptr += sow; - qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx); - - r += (rx >> 4) * j; - g += (gx >> 4) * j; - b += (bx >> 4) * j; + r += (rx >> 4) * j; + g += (gx >> 4) * j; + b += (bx >> 4) * j; - *dptr = qRgb(r >> 24, g >> 24, b >> 24); - dptr++; + *dptr = qRgb(r >> 24, g >> 24, b >> 24); + dptr++; + } } - } + }; + multithread_pixels_function(isi, dh, scaleSection); } QImage qSmoothScaleImage(const QImage &src, int dw, int dh) @@ -947,6 +1196,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, (QRgbaFloat32 *)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), |