Multithread some QImage routines
Use QThreadPool to process QImage smooth-scaling, format conversions, and colorspace transforms multithreaded. Change-Id: Ic142b1fa899f56e7e5099d36ca713701a47b681b Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
parent
cc59f0de55
commit
332816779c
@ -69,6 +69,11 @@
|
||||
#include <private/qimage_p.h>
|
||||
#include <private/qfont_p.h>
|
||||
|
||||
#if QT_CONFIG(thread)
|
||||
#include "qsemaphore.h"
|
||||
#include "qthreadpool.h"
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
static inline bool isLocked(QImageData *data)
|
||||
@ -5024,18 +5029,43 @@ void QImage::applyColorTransform(const QColorTransform &transform)
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
std::function<void(int,int)> transformSegment;
|
||||
|
||||
if (depth() > 32) {
|
||||
for (int i = 0; i < height(); ++i) {
|
||||
QRgba64 *scanline = reinterpret_cast<QRgba64 *>(scanLine(i));
|
||||
transform.d->apply(scanline, scanline, width(), flags);
|
||||
}
|
||||
transformSegment = [&](int yStart, int yEnd) {
|
||||
for (int y = yStart; y < yEnd; ++y) {
|
||||
QRgba64 *scanline = reinterpret_cast<QRgba64 *>(scanLine(y));
|
||||
transform.d->apply(scanline, scanline, width(), flags);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
for (int i = 0; i < height(); ++i) {
|
||||
QRgb *scanline = reinterpret_cast<QRgb *>(scanLine(i));
|
||||
transform.d->apply(scanline, scanline, width(), flags);
|
||||
}
|
||||
transformSegment = [&](int yStart, int yEnd) {
|
||||
for (int y = yStart; y < yEnd; ++y) {
|
||||
QRgb *scanline = reinterpret_cast<QRgb *>(scanLine(y));
|
||||
transform.d->apply(scanline, scanline, width(), flags);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = sizeInBytes() / (1<<16);
|
||||
segments = std::min(segments, height());
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (height() - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
transformSegment(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
} else
|
||||
#endif
|
||||
transformSegment(0, height());
|
||||
|
||||
if (oldFormat != format())
|
||||
*this = std::move(*this).convertToFormat(oldFormat);
|
||||
}
|
||||
|
@ -43,7 +43,12 @@
|
||||
#include <private/qendian_p.h>
|
||||
#include <private/qsimd_p.h>
|
||||
#include <private/qimage_p.h>
|
||||
|
||||
#include <qendian.h>
|
||||
#if QT_CONFIG(thread)
|
||||
#include <qsemaphore.h>
|
||||
#include <qthreadpool.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -159,12 +164,8 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
|
||||
// Cannot be used with indexed formats.
|
||||
Q_ASSERT(dest->format > QImage::Format_Indexed8);
|
||||
Q_ASSERT(src->format > QImage::Format_Indexed8);
|
||||
uint buf[BufferSize];
|
||||
uint *buffer = buf;
|
||||
const QPixelLayout *srcLayout = &qPixelLayouts[src->format];
|
||||
const QPixelLayout *destLayout = &qPixelLayouts[dest->format];
|
||||
const uchar *srcData = src->data;
|
||||
uchar *destData = dest->data;
|
||||
|
||||
FetchAndConvertPixelsFunc fetch = srcLayout->fetchToARGB32PM;
|
||||
ConvertAndStorePixelsFunc store = destLayout->storeFromARGB32PM;
|
||||
@ -197,59 +198,110 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
|
||||
else
|
||||
store = destLayout->storeFromRGB32;
|
||||
}
|
||||
QDitherInfo dither;
|
||||
QDitherInfo *ditherPtr = nullptr;
|
||||
if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither)
|
||||
ditherPtr = &dither;
|
||||
|
||||
for (int y = 0; y < src->height; ++y) {
|
||||
dither.y = y;
|
||||
int x = 0;
|
||||
while (x < src->width) {
|
||||
dither.x = x;
|
||||
int l = src->width - x;
|
||||
if (destLayout->bpp == QPixelLayout::BPP32)
|
||||
buffer = reinterpret_cast<uint *>(destData) + x;
|
||||
else
|
||||
l = qMin(l, BufferSize);
|
||||
const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr);
|
||||
store(destData, ptr, x, l, nullptr, ditherPtr);
|
||||
x += l;
|
||||
auto convertSegment = [=](int yStart, int yEnd) {
|
||||
uint buf[BufferSize];
|
||||
uint *buffer = buf;
|
||||
const uchar *srcData = src->data + src->bytes_per_line * yStart;
|
||||
uchar *destData = dest->data + dest->bytes_per_line * yStart;
|
||||
QDitherInfo dither;
|
||||
QDitherInfo *ditherPtr = nullptr;
|
||||
if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither)
|
||||
ditherPtr = &dither;
|
||||
for (int y = yStart; y < yEnd; ++y) {
|
||||
dither.y = y;
|
||||
int x = 0;
|
||||
while (x < src->width) {
|
||||
dither.x = x;
|
||||
int l = src->width - x;
|
||||
if (destLayout->bpp == QPixelLayout::BPP32)
|
||||
buffer = reinterpret_cast<uint *>(destData) + x;
|
||||
else
|
||||
l = qMin(l, BufferSize);
|
||||
const uint *ptr = fetch(buffer, srcData, x, l, 0, ditherPtr);
|
||||
store(destData, ptr, x, l, 0, ditherPtr);
|
||||
x += l;
|
||||
}
|
||||
srcData += src->bytes_per_line;
|
||||
destData += dest->bytes_per_line;
|
||||
}
|
||||
srcData += src->bytes_per_line;
|
||||
destData += dest->bytes_per_line;
|
||||
};
|
||||
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = src->nbytes / (1<<16);
|
||||
segments = std::min(segments, src->height);
|
||||
|
||||
if (segments <= 1)
|
||||
return convertSegment(0, src->height);
|
||||
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (src->height - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
convertSegment(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
#else
|
||||
convertSegment(0, src->height);
|
||||
#endif
|
||||
}
|
||||
|
||||
void convert_generic_to_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
|
||||
{
|
||||
Q_ASSERT(dest->format > QImage::Format_Indexed8);
|
||||
Q_ASSERT(src->format > QImage::Format_Indexed8);
|
||||
QRgba64 buf[BufferSize];
|
||||
QRgba64 *buffer = buf;
|
||||
const QPixelLayout *srcLayout = &qPixelLayouts[src->format];
|
||||
const QPixelLayout *destLayout = &qPixelLayouts[dest->format];
|
||||
const uchar *srcData = src->data;
|
||||
uchar *destData = dest->data;
|
||||
|
||||
const FetchAndConvertPixelsFunc64 fetch = srcLayout->fetchToRGBA64PM;
|
||||
const ConvertAndStorePixelsFunc64 store = qStoreFromRGBA64PM[dest->format];
|
||||
|
||||
for (int y = 0; y < src->height; ++y) {
|
||||
int x = 0;
|
||||
while (x < src->width) {
|
||||
int l = src->width - x;
|
||||
if (destLayout->bpp == QPixelLayout::BPP64)
|
||||
buffer = reinterpret_cast<QRgba64 *>(destData) + x;
|
||||
else
|
||||
l = qMin(l, BufferSize);
|
||||
const QRgba64 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr);
|
||||
store(destData, ptr, x, l, nullptr, nullptr);
|
||||
x += l;
|
||||
auto convertSegment = [=](int yStart, int yEnd) {
|
||||
QRgba64 buf[BufferSize];
|
||||
QRgba64 *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 (destLayout->bpp == QPixelLayout::BPP64)
|
||||
buffer = reinterpret_cast<QRgba64 *>(destData) + x;
|
||||
else
|
||||
l = qMin(l, BufferSize);
|
||||
const QRgba64 *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;
|
||||
}
|
||||
srcData += src->bytes_per_line;
|
||||
destData += dest->bytes_per_line;
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = src->nbytes / (1<<16);
|
||||
segments = std::min(segments, src->height);
|
||||
|
||||
if (segments <= 1)
|
||||
return convertSegment(0, src->height);
|
||||
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (src->height - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
convertSegment(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
#else
|
||||
convertSegment(0, src->height);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags flags)
|
||||
@ -270,11 +322,6 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
|
||||
&& qt_highColorPrecision(dst_format, !srcLayout->hasAlphaChannel))
|
||||
return false;
|
||||
|
||||
uint buf[BufferSize];
|
||||
uint *buffer = buf;
|
||||
uchar *srcData = data->data;
|
||||
uchar *destData = data->data;
|
||||
|
||||
QImageData::ImageSizeParameters params = { data->bytes_per_line, data->nbytes };
|
||||
if (data->depth != destDepth) {
|
||||
params = QImageData::calculateImageParameters(data->width, data->height, destDepth);
|
||||
@ -313,28 +360,52 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
|
||||
else
|
||||
store = destLayout->storeFromRGB32;
|
||||
}
|
||||
QDitherInfo dither;
|
||||
QDitherInfo *ditherPtr = nullptr;
|
||||
if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither)
|
||||
ditherPtr = &dither;
|
||||
|
||||
for (int y = 0; y < data->height; ++y) {
|
||||
dither.y = y;
|
||||
int x = 0;
|
||||
while (x < data->width) {
|
||||
dither.x = x;
|
||||
int l = data->width - x;
|
||||
if (srcLayout->bpp == QPixelLayout::BPP32)
|
||||
buffer = reinterpret_cast<uint *>(srcData) + x;
|
||||
else
|
||||
l = qMin(l, BufferSize);
|
||||
const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr);
|
||||
store(destData, ptr, x, l, nullptr, ditherPtr);
|
||||
x += l;
|
||||
auto convertSegment = [=](int yStart, int yEnd) {
|
||||
uint buf[BufferSize];
|
||||
uint *buffer = buf;
|
||||
uchar *srcData = data->data + data->bytes_per_line * yStart;
|
||||
uchar *destData = srcData;
|
||||
QDitherInfo dither;
|
||||
QDitherInfo *ditherPtr = nullptr;
|
||||
if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither)
|
||||
ditherPtr = &dither;
|
||||
for (int y = yStart; y < yEnd; ++y) {
|
||||
dither.y = y;
|
||||
int x = 0;
|
||||
while (x < data->width) {
|
||||
dither.x = x;
|
||||
int l = data->width - x;
|
||||
if (srcLayout->bpp == QPixelLayout::BPP32)
|
||||
buffer = reinterpret_cast<uint *>(srcData) + x;
|
||||
else
|
||||
l = qMin(l, BufferSize);
|
||||
const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr);
|
||||
store(destData, ptr, x, l, nullptr, ditherPtr);
|
||||
x += l;
|
||||
}
|
||||
srcData += data->bytes_per_line;
|
||||
destData += params.bytesPerLine;
|
||||
}
|
||||
srcData += data->bytes_per_line;
|
||||
destData += params.bytesPerLine;
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = data->nbytes / (1<<16);
|
||||
segments = std::min(segments, data->height);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (data->height - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
convertSegment(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
} else
|
||||
#endif
|
||||
convertSegment(0, data->height);
|
||||
if (params.totalSize != data->nbytes) {
|
||||
Q_ASSERT(params.totalSize < data->nbytes);
|
||||
void *newData = realloc(data->data, params.totalSize);
|
||||
|
@ -43,6 +43,11 @@
|
||||
#include "qcolor.h"
|
||||
#include "qrgba64_p.h"
|
||||
|
||||
#if QT_CONFIG(thread)
|
||||
#include "qsemaphore.h"
|
||||
#include "qthreadpool.h"
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*
|
||||
@ -239,6 +244,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);
|
||||
|
||||
@ -303,33 +310,54 @@ 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
/* scale by area sampling - with alpha */
|
||||
@ -411,33 +439,54 @@ 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;
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest,
|
||||
@ -449,34 +498,55 @@ 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;
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
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++;
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest,
|
||||
@ -487,45 +557,66 @@ 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;
|
||||
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, ax;
|
||||
qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
|
||||
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 r = ((rx>>4) * yap);
|
||||
int g = ((gx>>4) * yap);
|
||||
int b = ((bx>>4) * yap);
|
||||
int a = ((ax>>4) * yap);
|
||||
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) {
|
||||
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);
|
||||
|
||||
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++;
|
||||
}
|
||||
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);
|
||||
|
||||
*dptr = qRgba(r >> 24, g >> 24, b >> 24, a >> 24);
|
||||
dptr++;
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(raster_64bit)
|
||||
@ -546,32 +637,53 @@ 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
void qt_qimageScaleRgba64(QImageScaleInfo *isi, QRgba64 *dest,
|
||||
@ -616,33 +728,54 @@ 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;
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest,
|
||||
@ -653,34 +786,55 @@ 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;
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
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++;
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest,
|
||||
@ -691,43 +845,64 @@ 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;
|
||||
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;
|
||||
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);
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
r += rx * j;
|
||||
g += gx * j;
|
||||
b += bx * j;
|
||||
a += ax * j;
|
||||
|
||||
*dptr = qRgba64(r >> 28, g >> 28, b >> 28, a >> 28);
|
||||
dptr++;
|
||||
*dptr = qRgba64(r >> 28, g >> 28, b >> 28, a >> 28);
|
||||
dptr++;
|
||||
}
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -817,31 +992,52 @@ 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;
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest,
|
||||
@ -853,31 +1049,52 @@ 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;
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest,
|
||||
@ -888,43 +1105,64 @@ 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;
|
||||
r += (rx >> 4) * j;
|
||||
g += (gx >> 4) * j;
|
||||
b += (bx >> 4) * j;
|
||||
|
||||
*dptr = qRgb(r >> 24, g >> 24, b >> 24);
|
||||
dptr++;
|
||||
}
|
||||
sptr += sow;
|
||||
qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
|
||||
|
||||
r += (rx >> 4) * j;
|
||||
g += (gx >> 4) * j;
|
||||
b += (bx >> 4) * j;
|
||||
|
||||
*dptr = qRgb(r >> 24, g >> 24, b >> 24);
|
||||
dptr++;
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
QImage qSmoothScaleImage(const QImage &src, int dw, int dh)
|
||||
|
@ -41,6 +41,11 @@
|
||||
#include "qimage.h"
|
||||
#include <private/qsimd_p.h>
|
||||
|
||||
#if QT_CONFIG(thread)
|
||||
#include "qsemaphore.h"
|
||||
#include "qthreadpool.h"
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_NEON__)
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@ -76,33 +81,54 @@ void qt_qimageScaleAARGBA_up_x_down_y_neon(QImageScaleInfo *isi, unsigned int *d
|
||||
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;
|
||||
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];
|
||||
uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow);
|
||||
unsigned int *dptr = dest + (y * dow);
|
||||
for (int x = 0; x < dw; x++) {
|
||||
const unsigned int *sptr = ypoints[y] + xpoints[x];
|
||||
uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow);
|
||||
|
||||
int xap = xapoints[x];
|
||||
if (xap > 0) {
|
||||
uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow);
|
||||
int xap = xapoints[x];
|
||||
if (xap > 0) {
|
||||
uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow);
|
||||
|
||||
vx = vmulq_n_u32(vx, 256 - xap);
|
||||
vr = vmulq_n_u32(vr, xap);
|
||||
vx = vaddq_u32(vx, vr);
|
||||
vx = vshrq_n_u32(vx, 8);
|
||||
vx = vmulq_n_u32(vx, 256 - xap);
|
||||
vr = vmulq_n_u32(vr, xap);
|
||||
vx = vaddq_u32(vx, vr);
|
||||
vx = vshrq_n_u32(vx, 8);
|
||||
}
|
||||
vx = vshrq_n_u32(vx, 14);
|
||||
const uint16x4_t vx16 = vmovn_u32(vx);
|
||||
const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
|
||||
*dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
|
||||
if (RGB)
|
||||
*dptr |= 0xff000000;
|
||||
dptr++;
|
||||
}
|
||||
vx = vshrq_n_u32(vx, 14);
|
||||
const uint16x4_t vx16 = vmovn_u32(vx);
|
||||
const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
|
||||
*dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
|
||||
if (RGB)
|
||||
*dptr |= 0xff000000;
|
||||
dptr++;
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
template<bool RGB>
|
||||
@ -115,33 +141,54 @@ void qt_qimageScaleAARGBA_down_x_up_y_neon(QImageScaleInfo *isi, unsigned int *d
|
||||
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;
|
||||
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];
|
||||
uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
|
||||
const unsigned int *sptr = ypoints[y] + xpoints[x];
|
||||
uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
|
||||
|
||||
int yap = yapoints[y];
|
||||
if (yap > 0) {
|
||||
uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1);
|
||||
int yap = yapoints[y];
|
||||
if (yap > 0) {
|
||||
uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1);
|
||||
|
||||
vx = vmulq_n_u32(vx, 256 - yap);
|
||||
vr = vmulq_n_u32(vr, yap);
|
||||
vx = vaddq_u32(vx, vr);
|
||||
vx = vshrq_n_u32(vx, 8);
|
||||
vx = vmulq_n_u32(vx, 256 - yap);
|
||||
vr = vmulq_n_u32(vr, yap);
|
||||
vx = vaddq_u32(vx, vr);
|
||||
vx = vshrq_n_u32(vx, 8);
|
||||
}
|
||||
vx = vshrq_n_u32(vx, 14);
|
||||
const uint16x4_t vx16 = vmovn_u32(vx);
|
||||
const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
|
||||
*dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
|
||||
if (RGB)
|
||||
*dptr |= 0xff000000;
|
||||
dptr++;
|
||||
}
|
||||
vx = vshrq_n_u32(vx, 14);
|
||||
const uint16x4_t vx16 = vmovn_u32(vx);
|
||||
const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
|
||||
*dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
|
||||
if (RGB)
|
||||
*dptr |= 0xff000000;
|
||||
dptr++;
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
template<bool RGB>
|
||||
@ -153,43 +200,64 @@ void qt_qimageScaleAARGBA_down_xy_neon(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++) {
|
||||
const int Cx = xapoints[x] >> 16;
|
||||
const int xap = xapoints[x] & 0xffff;
|
||||
unsigned int *dptr = dest + (y * dow);
|
||||
for (int x = 0; x < dw; x++) {
|
||||
const int Cx = xapoints[x] >> 16;
|
||||
const int xap = xapoints[x] & 0xffff;
|
||||
|
||||
const unsigned int *sptr = ypoints[y] + xpoints[x];
|
||||
uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
|
||||
vx = vshrq_n_u32(vx, 4);
|
||||
uint32x4_t vr = vmulq_n_u32(vx, yap);
|
||||
const unsigned int *sptr = ypoints[y] + xpoints[x];
|
||||
uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
|
||||
vx = vshrq_n_u32(vx, 4);
|
||||
uint32x4_t vr = vmulq_n_u32(vx, 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;
|
||||
vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
|
||||
vx = vshrq_n_u32(vx, 4);
|
||||
vx = vmulq_n_u32(vx, Cy);
|
||||
vr = vaddq_u32(vr, vx);
|
||||
}
|
||||
sptr += sow;
|
||||
vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
|
||||
vx = vshrq_n_u32(vx, 4);
|
||||
vx = vmulq_n_u32(vx, Cy);
|
||||
vx = vmulq_n_u32(vx, j);
|
||||
vr = vaddq_u32(vr, vx);
|
||||
}
|
||||
sptr += sow;
|
||||
vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
|
||||
vx = vshrq_n_u32(vx, 4);
|
||||
vx = vmulq_n_u32(vx, j);
|
||||
vr = vaddq_u32(vr, vx);
|
||||
|
||||
vx = vshrq_n_u32(vr, 24);
|
||||
const uint16x4_t vx16 = vmovn_u32(vx);
|
||||
const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
|
||||
*dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
|
||||
if (RGB)
|
||||
*dptr |= 0xff000000;
|
||||
dptr++;
|
||||
vx = vshrq_n_u32(vr, 24);
|
||||
const uint16x4_t vx16 = vmovn_u32(vx);
|
||||
const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
|
||||
*dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
|
||||
if (RGB)
|
||||
*dptr |= 0xff000000;
|
||||
dptr++;
|
||||
}
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
template void qt_qimageScaleAARGBA_up_x_down_y_neon<false>(QImageScaleInfo *isi, unsigned int *dest,
|
||||
|
@ -66,6 +66,8 @@ namespace QImageScale {
|
||||
int *xapoints{nullptr};
|
||||
int *yapoints{nullptr};
|
||||
int xup_yup{0};
|
||||
int sh = 0;
|
||||
int sw = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,11 @@
|
||||
#include <private/qdrawhelper_x86_p.h>
|
||||
#include <private/qsimd_p.h>
|
||||
|
||||
#if QT_CONFIG(thread)
|
||||
#include "qsemaphore.h"
|
||||
#include "qthreadpool.h"
|
||||
#endif
|
||||
|
||||
#if defined(QT_COMPILER_SUPPORTS_SSE4_1)
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@ -70,44 +75,65 @@ void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *d
|
||||
int dw, int dh, int dow, int sow)
|
||||
{
|
||||
const unsigned int **ypoints = isi->ypoints;
|
||||
int *xpoints = isi->xpoints;
|
||||
int *xapoints = isi->xapoints;
|
||||
int *yapoints = isi->yapoints;
|
||||
const int *xpoints = isi->xpoints;
|
||||
const int *xapoints = isi->xapoints;
|
||||
const int *yapoints = isi->yapoints;
|
||||
|
||||
const __m128i v256 = _mm_set1_epi32(256);
|
||||
|
||||
/* 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;
|
||||
const __m128i vCy = _mm_set1_epi32(Cy);
|
||||
const __m128i vyap = _mm_set1_epi32(yap);
|
||||
auto scaleSection = [&] (int yStart, int yEnd) {
|
||||
for (int y = yStart; y < yEnd; ++y) {
|
||||
const int Cy = yapoints[y] >> 16;
|
||||
const int yap = yapoints[y] & 0xffff;
|
||||
const __m128i vCy = _mm_set1_epi32(Cy);
|
||||
const __m128i vyap = _mm_set1_epi32(yap);
|
||||
|
||||
unsigned int *dptr = dest + (y * dow);
|
||||
for (int x = 0; x < dw; x++) {
|
||||
const unsigned int *sptr = ypoints[y] + xpoints[x];
|
||||
__m128i vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, vyap, vCy);
|
||||
unsigned int *dptr = dest + (y * dow);
|
||||
for (int x = 0; x < dw; x++) {
|
||||
const unsigned int *sptr = ypoints[y] + xpoints[x];
|
||||
__m128i vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, vyap, vCy);
|
||||
|
||||
int xap = xapoints[x];
|
||||
if (xap > 0) {
|
||||
const __m128i vxap = _mm_set1_epi32(xap);
|
||||
const __m128i vinvxap = _mm_sub_epi32(v256, vxap);
|
||||
__m128i vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, vyap, vCy);
|
||||
const int xap = xapoints[x];
|
||||
if (xap > 0) {
|
||||
const __m128i vxap = _mm_set1_epi32(xap);
|
||||
const __m128i vinvxap = _mm_sub_epi32(v256, vxap);
|
||||
__m128i vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, vyap, vCy);
|
||||
|
||||
vx = _mm_mullo_epi32(vx, vinvxap);
|
||||
vr = _mm_mullo_epi32(vr, vxap);
|
||||
vx = _mm_add_epi32(vx, vr);
|
||||
vx = _mm_srli_epi32(vx, 8);
|
||||
vx = _mm_mullo_epi32(vx, vinvxap);
|
||||
vr = _mm_mullo_epi32(vr, vxap);
|
||||
vx = _mm_add_epi32(vx, vr);
|
||||
vx = _mm_srli_epi32(vx, 8);
|
||||
}
|
||||
vx = _mm_srli_epi32(vx, 14);
|
||||
vx = _mm_packus_epi32(vx, vx);
|
||||
vx = _mm_packus_epi16(vx, vx);
|
||||
*dptr = _mm_cvtsi128_si32(vx);
|
||||
if (RGB)
|
||||
*dptr |= 0xff000000;
|
||||
dptr++;
|
||||
}
|
||||
vx = _mm_srli_epi32(vx, 14);
|
||||
vx = _mm_packus_epi32(vx, _mm_setzero_si128());
|
||||
vx = _mm_packus_epi16(vx, _mm_setzero_si128());
|
||||
*dptr = _mm_cvtsi128_si32(vx);
|
||||
if (RGB)
|
||||
*dptr |= 0xff000000;
|
||||
dptr++;
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
template<bool RGB>
|
||||
@ -122,37 +148,58 @@ void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *d
|
||||
const __m128i v256 = _mm_set1_epi32(256);
|
||||
|
||||
/* 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 __m128i vCx = _mm_set1_epi32(Cx);
|
||||
const __m128i vxap = _mm_set1_epi32(xap);
|
||||
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 __m128i vCx = _mm_set1_epi32(Cx);
|
||||
const __m128i vxap = _mm_set1_epi32(xap);
|
||||
|
||||
const unsigned int *sptr = ypoints[y] + xpoints[x];
|
||||
__m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
|
||||
const unsigned int *sptr = ypoints[y] + xpoints[x];
|
||||
__m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
|
||||
|
||||
int yap = yapoints[y];
|
||||
if (yap > 0) {
|
||||
const __m128i vyap = _mm_set1_epi32(yap);
|
||||
const __m128i vinvyap = _mm_sub_epi32(v256, vyap);
|
||||
__m128i vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, vxap, vCx);
|
||||
int yap = yapoints[y];
|
||||
if (yap > 0) {
|
||||
const __m128i vyap = _mm_set1_epi32(yap);
|
||||
const __m128i vinvyap = _mm_sub_epi32(v256, vyap);
|
||||
__m128i vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, vxap, vCx);
|
||||
|
||||
vx = _mm_mullo_epi32(vx, vinvyap);
|
||||
vr = _mm_mullo_epi32(vr, vyap);
|
||||
vx = _mm_add_epi32(vx, vr);
|
||||
vx = _mm_srli_epi32(vx, 8);
|
||||
vx = _mm_mullo_epi32(vx, vinvyap);
|
||||
vr = _mm_mullo_epi32(vr, vyap);
|
||||
vx = _mm_add_epi32(vx, vr);
|
||||
vx = _mm_srli_epi32(vx, 8);
|
||||
}
|
||||
vx = _mm_srli_epi32(vx, 14);
|
||||
vx = _mm_packus_epi32(vx, vx);
|
||||
vx = _mm_packus_epi16(vx, vx);
|
||||
*dptr = _mm_cvtsi128_si32(vx);
|
||||
if (RGB)
|
||||
*dptr |= 0xff000000;
|
||||
dptr++;
|
||||
}
|
||||
vx = _mm_srli_epi32(vx, 14);
|
||||
vx = _mm_packus_epi32(vx, _mm_setzero_si128());
|
||||
vx = _mm_packus_epi16(vx, _mm_setzero_si128());
|
||||
*dptr = _mm_cvtsi128_si32(vx);
|
||||
if (RGB)
|
||||
*dptr |= 0xff000000;
|
||||
dptr++;
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
template<bool RGB>
|
||||
@ -164,42 +211,63 @@ void qt_qimageScaleAARGBA_down_xy_sse4(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;
|
||||
const __m128i vCy = _mm_set1_epi32(Cy);
|
||||
const __m128i vyap = _mm_set1_epi32(yap);
|
||||
auto scaleSection = [&] (int yStart, int yEnd) {
|
||||
for (int y = yStart; y < yEnd; ++y) {
|
||||
int Cy = yapoints[y] >> 16;
|
||||
int yap = yapoints[y] & 0xffff;
|
||||
const __m128i vCy = _mm_set1_epi32(Cy);
|
||||
const __m128i vyap = _mm_set1_epi32(yap);
|
||||
|
||||
unsigned int *dptr = dest + (y * dow);
|
||||
for (int x = 0; x < dw; x++) {
|
||||
const int Cx = xapoints[x] >> 16;
|
||||
const int xap = xapoints[x] & 0xffff;
|
||||
const __m128i vCx = _mm_set1_epi32(Cx);
|
||||
const __m128i vxap = _mm_set1_epi32(xap);
|
||||
unsigned int *dptr = dest + (y * dow);
|
||||
for (int x = 0; x < dw; x++) {
|
||||
const int Cx = xapoints[x] >> 16;
|
||||
const int xap = xapoints[x] & 0xffff;
|
||||
const __m128i vCx = _mm_set1_epi32(Cx);
|
||||
const __m128i vxap = _mm_set1_epi32(xap);
|
||||
|
||||
const unsigned int *sptr = ypoints[y] + xpoints[x];
|
||||
__m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
|
||||
__m128i vr = _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vyap);
|
||||
const unsigned int *sptr = ypoints[y] + xpoints[x];
|
||||
__m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
|
||||
__m128i vr = _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vyap);
|
||||
|
||||
int j;
|
||||
for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
|
||||
int j;
|
||||
for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
|
||||
sptr += sow;
|
||||
vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
|
||||
vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vCy));
|
||||
}
|
||||
sptr += sow;
|
||||
vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
|
||||
vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vCy));
|
||||
}
|
||||
sptr += sow;
|
||||
vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
|
||||
vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), _mm_set1_epi32(j)));
|
||||
vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), _mm_set1_epi32(j)));
|
||||
|
||||
vr = _mm_srli_epi32(vr, 24);
|
||||
vr = _mm_packus_epi32(vr, _mm_setzero_si128());
|
||||
vr = _mm_packus_epi16(vr, _mm_setzero_si128());
|
||||
*dptr = _mm_cvtsi128_si32(vr);
|
||||
if (RGB)
|
||||
*dptr |= 0xff000000;
|
||||
dptr++;
|
||||
vr = _mm_srli_epi32(vr, 24);
|
||||
vr = _mm_packus_epi32(vr, _mm_setzero_si128());
|
||||
vr = _mm_packus_epi16(vr, _mm_setzero_si128());
|
||||
*dptr = _mm_cvtsi128_si32(vr);
|
||||
if (RGB)
|
||||
*dptr |= 0xff000000;
|
||||
dptr++;
|
||||
}
|
||||
}
|
||||
};
|
||||
#if QT_CONFIG(thread)
|
||||
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
|
||||
segments = std::min(segments, dh);
|
||||
if (segments > 1) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
int yn = (dh - y) / (segments - i);
|
||||
QThreadPool::globalInstance()->start([&, y, yn]() {
|
||||
scaleSection(y, y + yn);
|
||||
semaphore.release(1);
|
||||
});
|
||||
y += yn;
|
||||
}
|
||||
semaphore.acquire(segments);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
scaleSection(0, dh);
|
||||
}
|
||||
|
||||
template void qt_qimageScaleAARGBA_up_x_down_y_sse4<false>(QImageScaleInfo *isi, unsigned int *dest,
|
||||
|
Loading…
Reference in New Issue
Block a user