Add special thread pool for Qt Gui

To avoid gui slowdowns due to global pool being blocked.

Fixes: QTBUG-109511
Change-Id: I4e8d91e8fb0bd2e395072a082e992a3c5d3464ad
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
(cherry picked from commit 93047c71e8e6dd4ac28e1e59dcb561df11c759eb)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Allan Sandfeld Jensen 2023-02-24 10:57:56 +01:00 committed by Qt Cherry-pick Bot
parent c1c201025e
commit 61b8e334d2
9 changed files with 50 additions and 20 deletions

View File

@ -31,6 +31,7 @@
#include <private/qthread_p.h> #include <private/qthread_p.h>
#if QT_CONFIG(thread) #if QT_CONFIG(thread)
#include <qthreadpool.h> #include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#endif #endif
#endif #endif
#include <qelapsedtimer.h> #include <qelapsedtimer.h>
@ -907,8 +908,10 @@ 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
} }
@ -916,6 +919,10 @@ 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,6 +474,21 @@ 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 QMutexLocker locker(&theMutex);
if (guiInstance.isNull() && !QCoreApplication::closingDown())
guiInstance = new QThreadPool();
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

@ -134,6 +134,8 @@ 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

@ -35,8 +35,9 @@
#include <private/qfont_p.h> #include <private/qfont_p.h>
#if QT_CONFIG(thread) #if QT_CONFIG(thread)
#include "qsemaphore.h" #include <qsemaphore.h>
#include "qthreadpool.h" #include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#endif #endif
#include <qtgui_tracepoints_p.h> #include <qtgui_tracepoints_p.h>
@ -5119,7 +5120,7 @@ void QImage::applyColorTransform(const QColorTransform &transform)
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(thread) && !defined(Q_OS_WASM)
int segments = (qsizetype(width()) * height()) >> 16; int segments = (qsizetype(width()) * height()) >> 16;
segments = std::min(segments, height()); segments = std::min(segments, height());
QThreadPool *threadPool = QThreadPool::globalInstance(); QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
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

@ -15,6 +15,7 @@
#if QT_CONFIG(thread) #if QT_CONFIG(thread)
#include <qsemaphore.h> #include <qsemaphore.h>
#include <qthreadpool.h> #include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#ifdef Q_OS_WASM #ifdef Q_OS_WASM
// WebAssembly has threads; however we can't block the main thread. // WebAssembly has threads; however we can't block the main thread.
#else #else
@ -203,7 +204,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
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 = QThreadPool::globalInstance(); QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
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);
@ -258,7 +259,7 @@ void convert_generic_over_rgb64(QImageData *dest, const QImageData *src, Qt::Ima
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 = QThreadPool::globalInstance(); QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
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);
@ -312,7 +313,7 @@ void convert_generic_over_rgba32f(QImageData *dest, const QImageData *src, Qt::I
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 = QThreadPool::globalInstance(); QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
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);
@ -419,7 +420,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS #ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
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 = QThreadPool::globalInstance(); QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
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;
@ -513,7 +514,7 @@ bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_for
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS #ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
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 = QThreadPool::globalInstance(); QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
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;
@ -608,7 +609,7 @@ bool convert_generic_inplace_over_rgba32f(QImageData *data, QImage::Format dst_f
#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS #ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
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 = QThreadPool::globalInstance(); QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
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

@ -32,6 +32,7 @@
#if defined(QT_USE_THREAD_PARALLEL_FILLS) #if defined(QT_USE_THREAD_PARALLEL_FILLS)
#include <qsemaphore.h> #include <qsemaphore.h>
#include <qthreadpool.h> #include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#endif #endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -3777,7 +3778,7 @@ static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP b
#if defined(QT_USE_THREAD_PARALLEL_FILLS) #if defined(QT_USE_THREAD_PARALLEL_FILLS)
#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 = QThreadPool::globalInstance(); \ QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); \
if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { \ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { \
QSemaphore semaphore; \ QSemaphore semaphore; \
int c = 0; \ int c = 0; \
@ -3786,7 +3787,7 @@ static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP b
threadPool->start([&, c, cn]() { \ threadPool->start([&, c, cn]() { \
function(c, c + cn); \ function(c, c + cn); \
semaphore.release(1); \ semaphore.release(1); \
}); \ }, 1); \
c += cn; \ c += cn; \
} \ } \
semaphore.acquire(segments); \ semaphore.acquire(segments); \

View File

@ -10,8 +10,9 @@
#include "qrgbafloat.h" #include "qrgbafloat.h"
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(thread) && !defined(Q_OS_WASM)
#include "qsemaphore.h" #include <qsemaphore.h>
#include "qthreadpool.h" #include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#endif #endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -273,7 +274,7 @@ static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, con
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(thread) && !defined(Q_OS_WASM)
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 = QThreadPool::globalInstance(); QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
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/qsimd_p.h> #include <private/qsimd_p.h>
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(thread) && !defined(Q_OS_WASM)
#include "qsemaphore.h" #include <qsemaphore.h>
#include "qthreadpool.h" #include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#endif #endif
#if defined(__ARM_NEON__) #if defined(__ARM_NEON__)
@ -22,7 +23,7 @@ static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, con
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(thread) && !defined(Q_OS_WASM)
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 = QThreadPool::globalInstance(); QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
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

@ -7,8 +7,9 @@
#include <private/qsimd_p.h> #include <private/qsimd_p.h>
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(thread) && !defined(Q_OS_WASM)
#include "qsemaphore.h" #include <qsemaphore.h>
#include "qthreadpool.h" #include <qthreadpool.h>
#include <private/qthreadpool_p.h>
#endif #endif
#if defined(QT_COMPILER_SUPPORTS_SSE4_1) #if defined(QT_COMPILER_SUPPORTS_SSE4_1)
@ -23,7 +24,7 @@ static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, con
#if QT_CONFIG(thread) && !defined(Q_OS_WASM) #if QT_CONFIG(thread) && !defined(Q_OS_WASM)
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 = QThreadPool::globalInstance(); QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
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;