From 61b8e334d2d81a24e4f4c4605fcd23f9caa1ffa5 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Fri, 24 Feb 2023 10:57:56 +0100 Subject: [PATCH] Add special thread pool for Qt Gui MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid gui slowdowns due to global pool being blocked. Fixes: QTBUG-109511 Change-Id: I4e8d91e8fb0bd2e395072a082e992a3c5d3464ad Reviewed-by: MÃ¥rten Nordheim (cherry picked from commit 93047c71e8e6dd4ac28e1e59dcb561df11c759eb) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/kernel/qcoreapplication.cpp | 7 +++++++ src/corelib/thread/qthreadpool.cpp | 15 +++++++++++++++ src/corelib/thread/qthreadpool_p.h | 2 ++ src/gui/image/qimage.cpp | 7 ++++--- src/gui/image/qimage_conversions.cpp | 13 +++++++------ src/gui/painting/qdrawhelper.cpp | 5 +++-- src/gui/painting/qimagescale.cpp | 7 ++++--- src/gui/painting/qimagescale_neon.cpp | 7 ++++--- src/gui/painting/qimagescale_sse4.cpp | 7 ++++--- 9 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 093f01e5c41..85d19ad5594 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -31,6 +31,7 @@ #include #if QT_CONFIG(thread) #include +#include #endif #endif #include @@ -907,8 +908,10 @@ 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 } @@ -916,6 +919,10 @@ QCoreApplication::~QCoreApplication() globalThreadPool->waitForDone(); delete globalThreadPool; } + if (guiThreadPool) { + guiThreadPool->waitForDone(); + delete guiThreadPool; + } #endif #ifndef QT_NO_QOBJECT diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp index bb7e232f42e..51783321b97 100644 --- a/src/corelib/thread/qthreadpool.cpp +++ b/src/corelib/thread/qthreadpool.cpp @@ -474,6 +474,21 @@ QThreadPool *QThreadPool::globalInstance() return theInstance; } +/*! + Returns the QThreadPool instance for Qt Gui. + \internal +*/ +QThreadPool *QThreadPoolPrivate::qtGuiInstance() +{ + Q_CONSTINIT static QPointer 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 make the current thread count exceed maxThreadCount(). In that case, diff --git a/src/corelib/thread/qthreadpool_p.h b/src/corelib/thread/qthreadpool_p.h index f967880bde5..67c703fabd9 100644 --- a/src/corelib/thread/qthreadpool_p.h +++ b/src/corelib/thread/qthreadpool_p.h @@ -134,6 +134,8 @@ public: void stealAndRunRunnable(QRunnable *runnable); void deletePageIfFinished(QueuePage *page); + static QThreadPool *qtGuiInstance(); + mutable QMutex mutex; QSet allThreads; QQueue waitingThreads; diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 8eea2f1366f..dc2d936fdae 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -35,8 +35,9 @@ #include #if QT_CONFIG(thread) -#include "qsemaphore.h" -#include "qthreadpool.h" +#include +#include +#include #endif #include @@ -5119,7 +5120,7 @@ void QImage::applyColorTransform(const QColorTransform &transform) #if QT_CONFIG(thread) && !defined(Q_OS_WASM) int segments = (qsizetype(width()) * height()) >> 16; segments = std::min(segments, height()); - QThreadPool *threadPool = QThreadPool::globalInstance(); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { QSemaphore semaphore; int y = 0; diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index d13bef71907..2e1eb5e5e40 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -15,6 +15,7 @@ #if QT_CONFIG(thread) #include #include +#include #ifdef Q_OS_WASM // WebAssembly has threads; however we can't block the main thread. #else @@ -203,7 +204,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio int segments = (qsizetype(src->width) * src->height) >> 16; segments = std::min(segments, src->height); - QThreadPool *threadPool = QThreadPool::globalInstance(); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread())) 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; segments = std::min(segments, src->height); - QThreadPool *threadPool = QThreadPool::globalInstance(); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread())) 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; segments = std::min(segments, src->height); - QThreadPool *threadPool = QThreadPool::globalInstance(); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread())) 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 int segments = (qsizetype(data->width) * data->height) >> 16; segments = std::min(segments, data->height); - QThreadPool *threadPool = QThreadPool::globalInstance(); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { QSemaphore semaphore; 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 int segments = (qsizetype(data->width) * data->height) >> 16; segments = std::min(segments, data->height); - QThreadPool *threadPool = QThreadPool::globalInstance(); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { QSemaphore semaphore; 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 int segments = (qsizetype(data->width) * data->height) >> 16; segments = std::min(segments, data->height); - QThreadPool *threadPool = QThreadPool::globalInstance(); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { QSemaphore semaphore; int y = 0; diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 46f75add1b8..3ab54b91678 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -32,6 +32,7 @@ #if defined(QT_USE_THREAD_PARALLEL_FILLS) #include #include +#include #endif QT_BEGIN_NAMESPACE @@ -3777,7 +3778,7 @@ static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP b #if defined(QT_USE_THREAD_PARALLEL_FILLS) #define QT_THREAD_PARALLEL_FILLS(function) \ const int segments = (count + 32) / 64; \ - QThreadPool *threadPool = QThreadPool::globalInstance(); \ + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); \ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { \ QSemaphore semaphore; \ int c = 0; \ @@ -3786,7 +3787,7 @@ static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP b threadPool->start([&, c, cn]() { \ function(c, c + cn); \ semaphore.release(1); \ - }); \ + }, 1); \ c += cn; \ } \ semaphore.acquire(segments); \ diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp index 80d1a67a3f0..a636635fd5d 100644 --- a/src/gui/painting/qimagescale.cpp +++ b/src/gui/painting/qimagescale.cpp @@ -10,8 +10,9 @@ #include "qrgbafloat.h" #if QT_CONFIG(thread) && !defined(Q_OS_WASM) -#include "qsemaphore.h" -#include "qthreadpool.h" +#include +#include +#include #endif 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) int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); segments = std::min(segments, dh); - QThreadPool *threadPool = QThreadPool::globalInstance(); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { QSemaphore semaphore; int y = 0; diff --git a/src/gui/painting/qimagescale_neon.cpp b/src/gui/painting/qimagescale_neon.cpp index c8d364d56c0..074b8198626 100644 --- a/src/gui/painting/qimagescale_neon.cpp +++ b/src/gui/painting/qimagescale_neon.cpp @@ -6,8 +6,9 @@ #include #if QT_CONFIG(thread) && !defined(Q_OS_WASM) -#include "qsemaphore.h" -#include "qthreadpool.h" +#include +#include +#include #endif #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) int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); segments = std::min(segments, dh); - QThreadPool *threadPool = QThreadPool::globalInstance(); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { QSemaphore semaphore; int y = 0; diff --git a/src/gui/painting/qimagescale_sse4.cpp b/src/gui/painting/qimagescale_sse4.cpp index f55290b46cb..982e533a32a 100644 --- a/src/gui/painting/qimagescale_sse4.cpp +++ b/src/gui/painting/qimagescale_sse4.cpp @@ -7,8 +7,9 @@ #include #if QT_CONFIG(thread) && !defined(Q_OS_WASM) -#include "qsemaphore.h" -#include "qthreadpool.h" +#include +#include +#include #endif #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) int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); segments = std::min(segments, dh); - QThreadPool *threadPool = QThreadPool::globalInstance(); + QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { QSemaphore semaphore; int y = 0;