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:
parent
154fe8d803
commit
083e44318c
@ -930,10 +930,8 @@ QCoreApplication::~QCoreApplication()
|
||||
#if QT_CONFIG(thread)
|
||||
// Synchronize and stop the global thread pool threads.
|
||||
QThreadPool *globalThreadPool = nullptr;
|
||||
QThreadPool *guiThreadPool = nullptr;
|
||||
QT_TRY {
|
||||
globalThreadPool = QThreadPool::globalInstance();
|
||||
guiThreadPool = QThreadPoolPrivate::qtGuiInstance();
|
||||
} QT_CATCH (...) {
|
||||
// swallow the exception, since destructors shouldn't throw
|
||||
}
|
||||
@ -941,10 +939,6 @@ QCoreApplication::~QCoreApplication()
|
||||
globalThreadPool->waitForDone();
|
||||
delete globalThreadPool;
|
||||
}
|
||||
if (guiThreadPool) {
|
||||
guiThreadPool->waitForDone();
|
||||
delete guiThreadPool;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef QT_NO_QOBJECT
|
||||
|
@ -474,28 +474,6 @@ QThreadPool *QThreadPool::globalInstance()
|
||||
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
|
||||
make the current thread count exceed maxThreadCount(). In that case,
|
||||
|
@ -133,8 +133,6 @@ public:
|
||||
void stealAndRunRunnable(QRunnable *runnable);
|
||||
void deletePageIfFinished(QueuePage *page);
|
||||
|
||||
static QThreadPool *qtGuiInstance();
|
||||
|
||||
mutable QMutex mutex;
|
||||
QSet<QThreadPoolThread *> allThreads;
|
||||
QQueue<QThreadPoolThread *> waitingThreads;
|
||||
|
@ -1271,6 +1271,14 @@ qt_feature("raster-fp" PRIVATE
|
||||
PURPOSE "Internal painting support for floating point rasterization."
|
||||
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
|
||||
SECTION "Utilities"
|
||||
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 "graphicsframecapture")
|
||||
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_add_summary_section(NAME "Features used by QPA backends")
|
||||
qt_configure_add_summary_entry(ARGS "evdev")
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include <private/qimage_p.h>
|
||||
#include <private/qfont_p.h>
|
||||
|
||||
#if QT_CONFIG(thread)
|
||||
#if QT_CONFIG(qtgui_threadpool)
|
||||
#include <qsemaphore.h>
|
||||
#include <qthreadpool.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
|
||||
if (nonpaintable_scale_xform
|
||||
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
|
||||
#if QT_CONFIG(qtgui_threadpool)
|
||||
|| (ws * hs) >= (1<<20)
|
||||
#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;
|
||||
segments = std::min(segments, height());
|
||||
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
|
||||
QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
|
||||
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
|
||||
QSemaphore semaphore;
|
||||
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;
|
||||
segments = std::min(segments, height());
|
||||
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
|
||||
QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
|
||||
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
|
@ -17,11 +17,6 @@
|
||||
#include <qsemaphore.h>
|
||||
#include <qthreadpool.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
|
||||
|
||||
#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;
|
||||
segments = std::min(segments, src->height);
|
||||
|
||||
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
|
||||
QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
|
||||
if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
|
||||
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;
|
||||
}
|
||||
};
|
||||
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
|
||||
#if QT_CONFIG(qtgui_threadpool)
|
||||
int segments = (qsizetype(src->width) * src->height) >> 16;
|
||||
segments = std::min(segments, src->height);
|
||||
|
||||
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
|
||||
QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
|
||||
if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
|
||||
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;
|
||||
}
|
||||
};
|
||||
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
|
||||
#if QT_CONFIG(qtgui_threadpool)
|
||||
int segments = (qsizetype(src->width) * src->height) >> 16;
|
||||
segments = std::min(segments, src->height);
|
||||
|
||||
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
|
||||
QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
|
||||
if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
|
||||
return convertSegment(0, src->height);
|
||||
|
||||
@ -434,10 +429,10 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
|
||||
destData += params.bytesPerLine;
|
||||
}
|
||||
};
|
||||
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
|
||||
#if QT_CONFIG(qtgui_threadpool)
|
||||
int segments = (qsizetype(data->width) * data->height) >> 16;
|
||||
segments = std::min(segments, data->height);
|
||||
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
|
||||
QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
|
||||
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
@ -527,10 +522,10 @@ bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_for
|
||||
destData += params.bytesPerLine;
|
||||
}
|
||||
};
|
||||
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
|
||||
#if QT_CONFIG(qtgui_threadpool)
|
||||
int segments = (qsizetype(data->width) * data->height) >> 16;
|
||||
segments = std::min(segments, data->height);
|
||||
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
|
||||
QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
|
||||
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
@ -621,10 +616,10 @@ bool convert_generic_inplace_over_rgba32f(QImageData *data, QImage::Format dst_f
|
||||
destData += params.bytesPerLine;
|
||||
}
|
||||
};
|
||||
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
|
||||
#if QT_CONFIG(qtgui_threadpool)
|
||||
int segments = (qsizetype(data->width) * data->height) >> 16;
|
||||
segments = std::min(segments, data->height);
|
||||
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
|
||||
QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
|
||||
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
|
@ -99,6 +99,10 @@
|
||||
#include <private/qvulkandefaultinstance_p.h>
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(thread)
|
||||
#include <QtCore/QThreadPool>
|
||||
#endif
|
||||
|
||||
#include <qtgui_tracepoints_p.h>
|
||||
|
||||
#include <private/qtools_p.h>
|
||||
@ -686,6 +690,20 @@ QGuiApplication::~QGuiApplication()
|
||||
d->cursor_list.clear();
|
||||
#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;
|
||||
QGuiApplicationPrivate::app_icon = nullptr;
|
||||
delete QGuiApplicationPrivate::platform_name;
|
||||
@ -4552,6 +4570,32 @@ QInputDeviceManager *QGuiApplicationPrivate::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
|
||||
|
||||
|
@ -57,6 +57,7 @@ class QActionPrivate;
|
||||
#if QT_CONFIG(shortcut)
|
||||
class QShortcutPrivate;
|
||||
#endif
|
||||
class QThreadPool;
|
||||
|
||||
class Q_GUI_EXPORT QGuiApplicationPrivate : public QCoreApplicationPrivate
|
||||
{
|
||||
@ -337,6 +338,8 @@ public:
|
||||
|
||||
static QEvent::Type contextMenuEventType();
|
||||
|
||||
static QThreadPool *qtGuiThreadPool();
|
||||
|
||||
protected:
|
||||
virtual void handleThemeChanged();
|
||||
|
||||
|
@ -27,11 +27,7 @@
|
||||
#include <qloggingcategory.h>
|
||||
#include <qmath.h>
|
||||
|
||||
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
|
||||
#define QT_USE_THREAD_PARALLEL_FILLS
|
||||
#endif
|
||||
|
||||
#if defined(QT_USE_THREAD_PARALLEL_FILLS)
|
||||
#if QT_CONFIG(qtgui_threadpool)
|
||||
#include <qsemaphore.h>
|
||||
#include <qthreadpool.h>
|
||||
#include <private/qthreadpool_p.h>
|
||||
@ -3963,10 +3959,10 @@ static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP b
|
||||
|
||||
// -------------------- blend methods ---------------------
|
||||
|
||||
#if defined(QT_USE_THREAD_PARALLEL_FILLS)
|
||||
#if QT_CONFIG(qtgui_threadpool)
|
||||
#define QT_THREAD_PARALLEL_FILLS(function) \
|
||||
const int segments = (count + 32) / 64; \
|
||||
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); \
|
||||
QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool(); \
|
||||
if (segments > 1 && qPixelLayouts[data->rasterBuffer->format].bpp >= QPixelLayout::BPP8 \
|
||||
&& threadPool && !threadPool->contains(QThread::currentThread())) { \
|
||||
QSemaphore semaphore; \
|
||||
|
@ -10,9 +10,10 @@
|
||||
#include "qrgba64_p.h"
|
||||
#include "qrgbafloat.h"
|
||||
|
||||
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
|
||||
#if QT_CONFIG(qtgui_threadpool)
|
||||
#include <qsemaphore.h>
|
||||
#include <qthreadpool.h>
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include <private/qthreadpool_p.h>
|
||||
#endif
|
||||
|
||||
@ -284,10 +285,10 @@ void qt_qimageScaleAARGBA_down_xy_neon(QImageScaleInfo *isi, unsigned int *dest,
|
||||
template<typename T>
|
||||
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);
|
||||
segments = std::min(segments, dh);
|
||||
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
|
||||
QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
|
||||
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
|
@ -6,8 +6,9 @@
|
||||
#include <private/qdrawhelper_loongarch64_p.h>
|
||||
#include <private/qsimd_p.h>
|
||||
|
||||
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
|
||||
#if QT_CONFIG(qtgui_threadpool)
|
||||
#include <qsemaphore.h>
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include <private/qthreadpool_p.h>
|
||||
#endif
|
||||
|
||||
@ -20,10 +21,10 @@ using namespace QImageScale;
|
||||
template<typename T>
|
||||
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);
|
||||
segments = std::min(segments, dh);
|
||||
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
|
||||
QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
|
||||
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
|
@ -3,11 +3,13 @@
|
||||
|
||||
#include "qimagescale_p.h"
|
||||
#include "qimage.h"
|
||||
#include <private/qtguiglobal_p.h>
|
||||
#include <private/qsimd_p.h>
|
||||
|
||||
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
|
||||
#if QT_CONFIG(qtgui_threadpool)
|
||||
#include <qsemaphore.h>
|
||||
#include <qthreadpool.h>
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include <private/qthreadpool_p.h>
|
||||
#endif
|
||||
|
||||
@ -20,10 +22,10 @@ using namespace QImageScale;
|
||||
template<typename T>
|
||||
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);
|
||||
segments = std::min(segments, dh);
|
||||
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
|
||||
QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
|
||||
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
|
@ -6,9 +6,10 @@
|
||||
#include <private/qdrawhelper_x86_p.h>
|
||||
#include <private/qsimd_p.h>
|
||||
|
||||
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
|
||||
#if QT_CONFIG(qtgui_threadpool)
|
||||
#include <qsemaphore.h>
|
||||
#include <qthreadpool.h>
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include <private/qthreadpool_p.h>
|
||||
#endif
|
||||
|
||||
@ -21,10 +22,10 @@ using namespace QImageScale;
|
||||
template<typename T>
|
||||
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);
|
||||
segments = std::min(segments, dh);
|
||||
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
|
||||
QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
|
||||
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
|
||||
QSemaphore semaphore;
|
||||
int y = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user