Make multi-threaded image transforms and painter fills configurable

Some users prefer to avoid having this many threads. This also
moves disabling it for WASM from sources to config.

Fixes: QTBUG-129650
Change-Id: Ib4c7903e85ba9cb75a9e013d1032653ea0ab8b84
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
This commit is contained in:
Allan Sandfeld Jensen 2024-11-15 10:44:05 +01:00
parent 154fe8d803
commit 083e44318c
13 changed files with 97 additions and 72 deletions

View File

@ -930,10 +930,8 @@ QCoreApplication::~QCoreApplication()
#if QT_CONFIG(thread) #if QT_CONFIG(thread)
// Synchronize and stop the global thread pool threads. // Synchronize and stop the global thread pool threads.
QThreadPool *globalThreadPool = nullptr; QThreadPool *globalThreadPool = nullptr;
QThreadPool *guiThreadPool = nullptr;
QT_TRY { QT_TRY {
globalThreadPool = QThreadPool::globalInstance(); globalThreadPool = QThreadPool::globalInstance();
guiThreadPool = QThreadPoolPrivate::qtGuiInstance();
} QT_CATCH (...) { } QT_CATCH (...) {
// swallow the exception, since destructors shouldn't throw // swallow the exception, since destructors shouldn't throw
} }
@ -941,10 +939,6 @@ QCoreApplication::~QCoreApplication()
globalThreadPool->waitForDone(); globalThreadPool->waitForDone();
delete globalThreadPool; delete globalThreadPool;
} }
if (guiThreadPool) {
guiThreadPool->waitForDone();
delete guiThreadPool;
}
#endif #endif
#ifndef QT_NO_QOBJECT #ifndef QT_NO_QOBJECT

View File

@ -474,28 +474,6 @@ QThreadPool *QThreadPool::globalInstance()
return theInstance; return theInstance;
} }
/*!
Returns the QThreadPool instance for Qt Gui.
\internal
*/
QThreadPool *QThreadPoolPrivate::qtGuiInstance()
{
Q_CONSTINIT static QPointer<QThreadPool> guiInstance;
Q_CONSTINIT static QBasicMutex theMutex;
const static bool runtime_disable = qEnvironmentVariableIsSet("QT_NO_GUI_THREADPOOL");
if (runtime_disable)
return nullptr;
const QMutexLocker locker(&theMutex);
if (guiInstance.isNull() && !QCoreApplication::closingDown()) {
guiInstance = new QThreadPool();
// Limit max thread to avoid too many parallel threads.
// We are not optimized for much more than 4 or 8 threads.
if (guiInstance && guiInstance->maxThreadCount() > 4)
guiInstance->setMaxThreadCount(qBound(4, guiInstance->maxThreadCount() / 2, 8));
}
return guiInstance;
}
/*! /*!
Reserves a thread and uses it to run \a runnable, unless this thread will Reserves a thread and uses it to run \a runnable, unless this thread will
make the current thread count exceed maxThreadCount(). In that case, make the current thread count exceed maxThreadCount(). In that case,

View File

@ -133,8 +133,6 @@ public:
void stealAndRunRunnable(QRunnable *runnable); void stealAndRunRunnable(QRunnable *runnable);
void deletePageIfFinished(QueuePage *page); void deletePageIfFinished(QueuePage *page);
static QThreadPool *qtGuiInstance();
mutable QMutex mutex; mutable QMutex mutex;
QSet<QThreadPoolThread *> allThreads; QSet<QThreadPoolThread *> allThreads;
QQueue<QThreadPoolThread *> waitingThreads; QQueue<QThreadPoolThread *> waitingThreads;

View File

@ -1271,6 +1271,14 @@ qt_feature("raster-fp" PRIVATE
PURPOSE "Internal painting support for floating point rasterization." PURPOSE "Internal painting support for floating point rasterization."
CONDITION NOT VXWORKS # QTBUG-115777 CONDITION NOT VXWORKS # QTBUG-115777
) )
qt_feature("qtgui-threadpool" PRIVATE
SECTION "Painting"
LABEL "Multi-threaded image and painting helpers"
PURPOSE "Multi-threaded image transforms and QPainter fills."
CONDITION QT_FEATURE_thread AND NOT WASM
)
qt_feature("undocommand" PUBLIC qt_feature("undocommand" PUBLIC
SECTION "Utilities" SECTION "Utilities"
LABEL "QUndoCommand" LABEL "QUndoCommand"
@ -1344,6 +1352,10 @@ qt_configure_add_summary_entry(ARGS "vulkan")
qt_configure_add_summary_entry(ARGS "metal") qt_configure_add_summary_entry(ARGS "metal")
qt_configure_add_summary_entry(ARGS "graphicsframecapture") qt_configure_add_summary_entry(ARGS "graphicsframecapture")
qt_configure_add_summary_entry(ARGS "sessionmanager") qt_configure_add_summary_entry(ARGS "sessionmanager")
qt_configure_add_summary_entry(
ARGS "qtgui-threadpool"
CONDITION QT_FEATURE_thread
)
qt_configure_end_summary_section() # end of "Qt Gui" section qt_configure_end_summary_section() # end of "Qt Gui" section
qt_configure_add_summary_section(NAME "Features used by QPA backends") qt_configure_add_summary_section(NAME "Features used by QPA backends")
qt_configure_add_summary_entry(ARGS "evdev") qt_configure_add_summary_entry(ARGS "evdev")

View File

@ -35,7 +35,7 @@
#include <private/qimage_p.h> #include <private/qimage_p.h>
#include <private/qfont_p.h> #include <private/qfont_p.h>
#if QT_CONFIG(thread) #if QT_CONFIG(qtgui_threadpool)
#include <qsemaphore.h> #include <qsemaphore.h>
#include <qthreadpool.h> #include <qthreadpool.h>
#include <private/qthreadpool_p.h> #include <private/qthreadpool_p.h>
@ -4908,7 +4908,7 @@ QImage Q_TRACE_INSTRUMENT(qtgui) QImage::transformed(const QTransform &matrix, Q
} }
// Otherwise only use it when the scaling factor demands it, or the image is large enough to scale multi-threaded // Otherwise only use it when the scaling factor demands it, or the image is large enough to scale multi-threaded
if (nonpaintable_scale_xform if (nonpaintable_scale_xform
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(qtgui_threadpool)
|| (ws * hs) >= (1<<20) || (ws * hs) >= (1<<20)
#endif #endif
) { ) {
@ -5328,10 +5328,10 @@ void QImage::applyColorTransform(const QColorTransform &transform)
}; };
} }
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(qtgui_threadpool)
int segments = (qsizetype(width()) * height()) >> 16; int segments = (qsizetype(width()) * height()) >> 16;
segments = std::min(segments, height()); segments = std::min(segments, height());
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore; QSemaphore semaphore;
int y = 0; int y = 0;
@ -5818,10 +5818,10 @@ QImage QImage::colorTransformed(const QColorTransform &transform, QImage::Format
} }
} }
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(qtgui_threadpool)
int segments = (qsizetype(width()) * height()) >> 16; int segments = (qsizetype(width()) * height()) >> 16;
segments = std::min(segments, height()); segments = std::min(segments, height());
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore; QSemaphore semaphore;
int y = 0; int y = 0;

View File

@ -17,11 +17,6 @@
#include <qsemaphore.h> #include <qsemaphore.h>
#include <qthreadpool.h> #include <qthreadpool.h>
#include <private/qthreadpool_p.h> #include <private/qthreadpool_p.h>
#ifdef Q_OS_WASM
// WebAssembly has threads; however we can't block the main thread.
#else
#define QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
#endif
#endif #endif
#include <QtCore/q20utility.h> #include <QtCore/q20utility.h>
@ -212,11 +207,11 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
} }
}; };
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS #if QT_CONFIG(qtgui_threadpool)
int segments = (qsizetype(src->width) * src->height) >> 16; int segments = (qsizetype(src->width) * src->height) >> 16;
segments = std::min(segments, src->height); segments = std::min(segments, src->height);
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread())) if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
return convertSegment(0, src->height); return convertSegment(0, src->height);
@ -267,11 +262,11 @@ void convert_generic_over_rgb64(QImageData *dest, const QImageData *src, Qt::Ima
destData += dest->bytes_per_line; destData += dest->bytes_per_line;
} }
}; };
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS #if QT_CONFIG(qtgui_threadpool)
int segments = (qsizetype(src->width) * src->height) >> 16; int segments = (qsizetype(src->width) * src->height) >> 16;
segments = std::min(segments, src->height); segments = std::min(segments, src->height);
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread())) if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
return convertSegment(0, src->height); return convertSegment(0, src->height);
@ -321,11 +316,11 @@ void convert_generic_over_rgba32f(QImageData *dest, const QImageData *src, Qt::I
destData += dest->bytes_per_line; destData += dest->bytes_per_line;
} }
}; };
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS #if QT_CONFIG(qtgui_threadpool)
int segments = (qsizetype(src->width) * src->height) >> 16; int segments = (qsizetype(src->width) * src->height) >> 16;
segments = std::min(segments, src->height); segments = std::min(segments, src->height);
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread())) if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
return convertSegment(0, src->height); return convertSegment(0, src->height);
@ -434,10 +429,10 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
destData += params.bytesPerLine; destData += params.bytesPerLine;
} }
}; };
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS #if QT_CONFIG(qtgui_threadpool)
int segments = (qsizetype(data->width) * data->height) >> 16; int segments = (qsizetype(data->width) * data->height) >> 16;
segments = std::min(segments, data->height); segments = std::min(segments, data->height);
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore; QSemaphore semaphore;
int y = 0; int y = 0;
@ -527,10 +522,10 @@ bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_for
destData += params.bytesPerLine; destData += params.bytesPerLine;
} }
}; };
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS #if QT_CONFIG(qtgui_threadpool)
int segments = (qsizetype(data->width) * data->height) >> 16; int segments = (qsizetype(data->width) * data->height) >> 16;
segments = std::min(segments, data->height); segments = std::min(segments, data->height);
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore; QSemaphore semaphore;
int y = 0; int y = 0;
@ -621,10 +616,10 @@ bool convert_generic_inplace_over_rgba32f(QImageData *data, QImage::Format dst_f
destData += params.bytesPerLine; destData += params.bytesPerLine;
} }
}; };
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS #if QT_CONFIG(qtgui_threadpool)
int segments = (qsizetype(data->width) * data->height) >> 16; int segments = (qsizetype(data->width) * data->height) >> 16;
segments = std::min(segments, data->height); segments = std::min(segments, data->height);
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore; QSemaphore semaphore;
int y = 0; int y = 0;

View File

@ -99,6 +99,10 @@
#include <private/qvulkandefaultinstance_p.h> #include <private/qvulkandefaultinstance_p.h>
#endif #endif
#if QT_CONFIG(thread)
#include <QtCore/QThreadPool>
#endif
#include <qtgui_tracepoints_p.h> #include <qtgui_tracepoints_p.h>
#include <private/qtools_p.h> #include <private/qtools_p.h>
@ -686,6 +690,20 @@ QGuiApplication::~QGuiApplication()
d->cursor_list.clear(); d->cursor_list.clear();
#endif #endif
#if QT_CONFIG(qtgui_threadpool)
// Synchronize and stop the gui thread pool threads.
QThreadPool *guiThreadPool = nullptr;
QT_TRY {
guiThreadPool = QGuiApplicationPrivate::qtGuiThreadPool();
} QT_CATCH (...) {
// swallow the exception, since destructors shouldn't throw
}
if (guiThreadPool) {
guiThreadPool->waitForDone();
delete guiThreadPool;
}
#endif
delete QGuiApplicationPrivate::app_icon; delete QGuiApplicationPrivate::app_icon;
QGuiApplicationPrivate::app_icon = nullptr; QGuiApplicationPrivate::app_icon = nullptr;
delete QGuiApplicationPrivate::platform_name; delete QGuiApplicationPrivate::platform_name;
@ -4552,6 +4570,32 @@ QInputDeviceManager *QGuiApplicationPrivate::inputDeviceManager()
return m_inputDeviceManager; return m_inputDeviceManager;
} }
/*!
Returns the QThreadPool instance for Qt Gui.
\internal
*/
QThreadPool *QGuiApplicationPrivate::qtGuiThreadPool()
{
#if QT_CONFIG(qtgui_threadpool)
Q_CONSTINIT static QPointer<QThreadPool> guiInstance;
Q_CONSTINIT static QBasicMutex theMutex;
const static bool runtime_disable = qEnvironmentVariableIsSet("QT_NO_GUI_THREADPOOL");
if (runtime_disable)
return nullptr;
const QMutexLocker locker(&theMutex);
if (guiInstance.isNull() && !QCoreApplication::closingDown()) {
guiInstance = new QThreadPool();
// Limit max thread to avoid too many parallel threads.
// We are not optimized for much more than 4 or 8 threads.
if (guiInstance && guiInstance->maxThreadCount() > 4)
guiInstance->setMaxThreadCount(qBound(4, guiInstance->maxThreadCount() / 2, 8));
}
return guiInstance;
#else
return nullptr;
#endif
}
/*! /*!
\fn template <typename QNativeInterface> QNativeInterface *QGuiApplication::nativeInterface() const \fn template <typename QNativeInterface> QNativeInterface *QGuiApplication::nativeInterface() const

View File

@ -57,6 +57,7 @@ class QActionPrivate;
#if QT_CONFIG(shortcut) #if QT_CONFIG(shortcut)
class QShortcutPrivate; class QShortcutPrivate;
#endif #endif
class QThreadPool;
class Q_GUI_EXPORT QGuiApplicationPrivate : public QCoreApplicationPrivate class Q_GUI_EXPORT QGuiApplicationPrivate : public QCoreApplicationPrivate
{ {
@ -337,6 +338,8 @@ public:
static QEvent::Type contextMenuEventType(); static QEvent::Type contextMenuEventType();
static QThreadPool *qtGuiThreadPool();
protected: protected:
virtual void handleThemeChanged(); virtual void handleThemeChanged();

View File

@ -27,11 +27,7 @@
#include <qloggingcategory.h> #include <qloggingcategory.h>
#include <qmath.h> #include <qmath.h>
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(qtgui_threadpool)
#define QT_USE_THREAD_PARALLEL_FILLS
#endif
#if defined(QT_USE_THREAD_PARALLEL_FILLS)
#include <qsemaphore.h> #include <qsemaphore.h>
#include <qthreadpool.h> #include <qthreadpool.h>
#include <private/qthreadpool_p.h> #include <private/qthreadpool_p.h>
@ -3963,10 +3959,10 @@ static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP b
// -------------------- blend methods --------------------- // -------------------- blend methods ---------------------
#if defined(QT_USE_THREAD_PARALLEL_FILLS) #if QT_CONFIG(qtgui_threadpool)
#define QT_THREAD_PARALLEL_FILLS(function) \ #define QT_THREAD_PARALLEL_FILLS(function) \
const int segments = (count + 32) / 64; \ const int segments = (count + 32) / 64; \
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); \ QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool(); \
if (segments > 1 && qPixelLayouts[data->rasterBuffer->format].bpp >= QPixelLayout::BPP8 \ if (segments > 1 && qPixelLayouts[data->rasterBuffer->format].bpp >= QPixelLayout::BPP8 \
&& threadPool && !threadPool->contains(QThread::currentThread())) { \ && threadPool && !threadPool->contains(QThread::currentThread())) { \
QSemaphore semaphore; \ QSemaphore semaphore; \

View File

@ -10,9 +10,10 @@
#include "qrgba64_p.h" #include "qrgba64_p.h"
#include "qrgbafloat.h" #include "qrgbafloat.h"
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(qtgui_threadpool)
#include <qsemaphore.h> #include <qsemaphore.h>
#include <qthreadpool.h> #include <qthreadpool.h>
#include <private/qguiapplication_p.h>
#include <private/qthreadpool_p.h> #include <private/qthreadpool_p.h>
#endif #endif
@ -284,10 +285,10 @@ void qt_qimageScaleAARGBA_down_xy_neon(QImageScaleInfo *isi, unsigned int *dest,
template<typename T> template<typename T>
static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, const T &scaleSection) static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, const T &scaleSection)
{ {
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(qtgui_threadpool)
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
segments = std::min(segments, dh); segments = std::min(segments, dh);
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore; QSemaphore semaphore;
int y = 0; int y = 0;

View File

@ -6,8 +6,9 @@
#include <private/qdrawhelper_loongarch64_p.h> #include <private/qdrawhelper_loongarch64_p.h>
#include <private/qsimd_p.h> #include <private/qsimd_p.h>
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(qtgui_threadpool)
#include <qsemaphore.h> #include <qsemaphore.h>
#include <private/qguiapplication_p.h>
#include <private/qthreadpool_p.h> #include <private/qthreadpool_p.h>
#endif #endif
@ -20,10 +21,10 @@ using namespace QImageScale;
template<typename T> template<typename T>
static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, const T &scaleSection) static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, const T &scaleSection)
{ {
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(qtgui_threadpool)
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
segments = std::min(segments, dh); segments = std::min(segments, dh);
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore; QSemaphore semaphore;
int y = 0; int y = 0;

View File

@ -3,11 +3,13 @@
#include "qimagescale_p.h" #include "qimagescale_p.h"
#include "qimage.h" #include "qimage.h"
#include <private/qtguiglobal_p.h>
#include <private/qsimd_p.h> #include <private/qsimd_p.h>
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(qtgui_threadpool)
#include <qsemaphore.h> #include <qsemaphore.h>
#include <qthreadpool.h> #include <qthreadpool.h>
#include <private/qguiapplication_p.h>
#include <private/qthreadpool_p.h> #include <private/qthreadpool_p.h>
#endif #endif
@ -20,10 +22,10 @@ using namespace QImageScale;
template<typename T> template<typename T>
static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, const T &scaleSection) static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, const T &scaleSection)
{ {
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(qtgui_threadpool)
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
segments = std::min(segments, dh); segments = std::min(segments, dh);
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore; QSemaphore semaphore;
int y = 0; int y = 0;

View File

@ -6,9 +6,10 @@
#include <private/qdrawhelper_x86_p.h> #include <private/qdrawhelper_x86_p.h>
#include <private/qsimd_p.h> #include <private/qsimd_p.h>
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(qtgui_threadpool)
#include <qsemaphore.h> #include <qsemaphore.h>
#include <qthreadpool.h> #include <qthreadpool.h>
#include <private/qguiapplication_p.h>
#include <private/qthreadpool_p.h> #include <private/qthreadpool_p.h>
#endif #endif
@ -21,10 +22,10 @@ using namespace QImageScale;
template<typename T> template<typename T>
static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, const T &scaleSection) static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, const T &scaleSection)
{ {
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(qtgui_threadpool)
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
segments = std::min(segments, dh); segments = std::min(segments, dh);
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore; QSemaphore semaphore;
int y = 0; int y = 0;