diff options
-rw-r--r-- | src/corelib/kernel/qcoreapplication.cpp | 6 | ||||
-rw-r--r-- | src/corelib/thread/qthreadpool.cpp | 22 | ||||
-rw-r--r-- | src/corelib/thread/qthreadpool_p.h | 2 | ||||
-rw-r--r-- | src/gui/configure.cmake | 12 | ||||
-rw-r--r-- | src/gui/image/qimage.cpp | 12 | ||||
-rw-r--r-- | src/gui/image/qimage_conversions.cpp | 29 | ||||
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 44 | ||||
-rw-r--r-- | src/gui/kernel/qguiapplication_p.h | 3 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper.cpp | 10 | ||||
-rw-r--r-- | src/gui/painting/qimagescale.cpp | 7 | ||||
-rw-r--r-- | src/gui/painting/qimagescale_lsx.cpp | 7 | ||||
-rw-r--r-- | src/gui/painting/qimagescale_neon.cpp | 8 | ||||
-rw-r--r-- | src/gui/painting/qimagescale_sse4.cpp | 7 |
13 files changed, 97 insertions, 72 deletions
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 0f1de6b97cd..2bff9468824 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -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 diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp index 62e3773af95..f326ed21229 100644 --- a/src/corelib/thread/qthreadpool.cpp +++ b/src/corelib/thread/qthreadpool.cpp @@ -475,28 +475,6 @@ QThreadPool *QThreadPool::globalInstance() } /*! - 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, \a runnable is added to a run queue instead. The \a priority argument can diff --git a/src/corelib/thread/qthreadpool_p.h b/src/corelib/thread/qthreadpool_p.h index 284cf21e4fd..eac078cad88 100644 --- a/src/corelib/thread/qthreadpool_p.h +++ b/src/corelib/thread/qthreadpool_p.h @@ -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; diff --git a/src/gui/configure.cmake b/src/gui/configure.cmake index 7889445976b..b7eb37e8a8c 100644 --- a/src/gui/configure.cmake +++ b/src/gui/configure.cmake @@ -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") diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index b18952fc12f..06ae65e3f63 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -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; diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 5f300afd5f5..c1a700fddfb 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -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; diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 2a5a4933907..1e44ac83361 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -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; @@ -4553,6 +4571,32 @@ QInputDeviceManager *QGuiApplicationPrivate::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 Returns a native interface of the given type for the application. diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index 45eac1c2654..2bdbc2463be 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -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(); diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 8beb299fab4..92d3ad8d821 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -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; \ diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp index 1b1f2e8b8c8..1bbfcf07a0a 100644 --- a/src/gui/painting/qimagescale.cpp +++ b/src/gui/painting/qimagescale.cpp @@ -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; diff --git a/src/gui/painting/qimagescale_lsx.cpp b/src/gui/painting/qimagescale_lsx.cpp index c128b014b8c..6ec856c6f3b 100644 --- a/src/gui/painting/qimagescale_lsx.cpp +++ b/src/gui/painting/qimagescale_lsx.cpp @@ -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; diff --git a/src/gui/painting/qimagescale_neon.cpp b/src/gui/painting/qimagescale_neon.cpp index 074b8198626..1fc1070dc0d 100644 --- a/src/gui/painting/qimagescale_neon.cpp +++ b/src/gui/painting/qimagescale_neon.cpp @@ -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; diff --git a/src/gui/painting/qimagescale_sse4.cpp b/src/gui/painting/qimagescale_sse4.cpp index 982e533a32a..5d4c3a4e7c2 100644 --- a/src/gui/painting/qimagescale_sse4.cpp +++ b/src/gui/painting/qimagescale_sse4.cpp @@ -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; |