From cf50127ee37ed9976d505bf25261f69b70ea5bf2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pasi=20Pet=C3=A4j=C3=A4j=C3=A4rvi?= <pasi.petajajarvi@qt.io>
Date: Fri, 27 Sep 2024 12:24:53 +0300
Subject: [PATCH 1/2] Gui: Add opt-out env variable to control usage of threads

---
 src/gui/image/qimage_conversions.cpp | 213 ++++++++++++++-------------
 1 file changed, 111 insertions(+), 102 deletions(-)

diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp
index 8d9e0b87e2..8b7acc38a8 100644
--- a/src/gui/image/qimage_conversions.cpp
+++ b/src/gui/image/qimage_conversions.cpp
@@ -26,6 +26,16 @@
 
 QT_BEGIN_NAMESPACE
 
+bool useParallelImageConversions()
+{
+    static int use = -1;
+#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
+    if (use < 0)
+        use = !qEnvironmentVariableIsSet("QT_NO_THREAD_PARALLEL_IMAGE_CONVERSIONS") ? 1 : 0;
+#endif
+    return bool(use);
+}
+
 struct QDefaultColorTables
 {
     QDefaultColorTables()
@@ -201,28 +211,28 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
         }
     };
 
-#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
-    int segments = (qsizetype(src->width) * src->height) >> 16;
-    segments = std::min(segments, src->height);
+    if (useParallelImageConversions()) {
+        int segments = (qsizetype(src->width) * src->height) >> 16;
+        segments = std::min(segments, src->height);
 
-    QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
-    if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
-        return convertSegment(0, src->height);
-
-    QSemaphore semaphore;
-    int y = 0;
-    for (int i = 0; i < segments; ++i) {
-        int yn = (src->height - y) / (segments - i);
-        threadPool->start([&, y, yn]() {
-            convertSegment(y, y + yn);
-            semaphore.release(1);
-        });
-        y += yn;
-    }
-    semaphore.acquire(segments);
-#else
-    convertSegment(0, src->height);
-#endif
+        QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
+        if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
+            return convertSegment(0, src->height);
+
+        QSemaphore semaphore;
+        int y = 0;
+        for (int i = 0; i < segments; ++i) {
+            int yn = (src->height - y) / (segments - i);
+            threadPool->start([&, y, yn]() {
+                convertSegment(y, y + yn);
+                semaphore.release(1);
+            });
+            y += yn;
+        }
+        semaphore.acquire(segments);
+    } else {
+        convertSegment(0, src->height);
+    }
 }
 
 void convert_generic_over_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
@@ -256,28 +266,28 @@ void convert_generic_over_rgb64(QImageData *dest, const QImageData *src, Qt::Ima
             destData += dest->bytes_per_line;
         }
     };
-#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
-    int segments = (qsizetype(src->width) * src->height) >> 16;
-    segments = std::min(segments, src->height);
+    if (useParallelImageConversions()) {
+        int segments = (qsizetype(src->width) * src->height) >> 16;
+        segments = std::min(segments, src->height);
 
-    QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
-    if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
-        return convertSegment(0, src->height);
-
-    QSemaphore semaphore;
-    int y = 0;
-    for (int i = 0; i < segments; ++i) {
-        int yn = (src->height - y) / (segments - i);
-        threadPool->start([&, y, yn]() {
-            convertSegment(y, y + yn);
-            semaphore.release(1);
-        });
-        y += yn;
-    }
-    semaphore.acquire(segments);
-#else
-    convertSegment(0, src->height);
-#endif
+        QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
+        if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
+            return convertSegment(0, src->height);
+
+        QSemaphore semaphore;
+        int y = 0;
+        for (int i = 0; i < segments; ++i) {
+            int yn = (src->height - y) / (segments - i);
+            threadPool->start([&, y, yn]() {
+                convertSegment(y, y + yn);
+                semaphore.release(1);
+            });
+            y += yn;
+        }
+        semaphore.acquire(segments);
+    } else {
+        convertSegment(0, src->height);
+    }
 }
 
 #if QT_CONFIG(raster_fp)
@@ -310,28 +320,28 @@ void convert_generic_over_rgba32f(QImageData *dest, const QImageData *src, Qt::I
             destData += dest->bytes_per_line;
         }
     };
-#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
-    int segments = (qsizetype(src->width) * src->height) >> 16;
-    segments = std::min(segments, src->height);
+    if (useParallelImageConversions()) {
+        int segments = (qsizetype(src->width) * src->height) >> 16;
+        segments = std::min(segments, src->height);
 
-    QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
-    if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
-        return convertSegment(0, src->height);
-
-    QSemaphore semaphore;
-    int y = 0;
-    for (int i = 0; i < segments; ++i) {
-        int yn = (src->height - y) / (segments - i);
-        threadPool->start([&, y, yn]() {
-            convertSegment(y, y + yn);
-            semaphore.release(1);
-        });
-        y += yn;
-    }
-    semaphore.acquire(segments);
-#else
-    convertSegment(0, src->height);
-#endif
+        QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
+        if (segments <= 1 || !threadPool || threadPool->contains(QThread::currentThread()))
+            return convertSegment(0, src->height);
+
+        QSemaphore semaphore;
+        int y = 0;
+        for (int i = 0; i < segments; ++i) {
+            int yn = (src->height - y) / (segments - i);
+            threadPool->start([&, y, yn]() {
+                convertSegment(y, y + yn);
+                semaphore.release(1);
+            });
+            y += yn;
+        }
+        semaphore.acquire(segments);
+    } else {
+        convertSegment(0, src->height);
+    }
 }
 #endif
 
@@ -418,11 +428,10 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
             destData += params.bytesPerLine;
         }
     };
-#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
     int segments = (qsizetype(data->width) * data->height) >> 16;
     segments = std::min(segments, data->height);
     QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
-    if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
+    if (useParallelImageConversions() && segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
         QSemaphore semaphore;
         int y = 0;
         for (int i = 0; i < segments; ++i) {
@@ -446,20 +455,20 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
                 y += yn;
             }
         }
-    } else
-#endif
+    } else {
         convertSegment(0, data->height);
-    if (params.totalSize != data->nbytes) {
-        Q_ASSERT(params.totalSize < data->nbytes);
-        void *newData = realloc(data->data, params.totalSize);
-        if (newData) {
-            data->data = (uchar *)newData;
-            data->nbytes = params.totalSize;
+        if (params.totalSize != data->nbytes) {
+            Q_ASSERT(params.totalSize < data->nbytes);
+            void *newData = realloc(data->data, params.totalSize);
+            if (newData) {
+                data->data = (uchar *)newData;
+                data->nbytes = params.totalSize;
+            }
+            data->bytes_per_line = params.bytesPerLine;
         }
-        data->bytes_per_line = params.bytesPerLine;
+        data->depth = destDepth;
+        data->format = dst_format;
     }
-    data->depth = destDepth;
-    data->format = dst_format;
     return true;
 }
 
@@ -511,11 +520,11 @@ bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_for
             destData += params.bytesPerLine;
         }
     };
-#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
+
     int segments = (qsizetype(data->width) * data->height) >> 16;
     segments = std::min(segments, data->height);
     QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
-    if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
+    if (useParallelImageConversions() &&segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
         QSemaphore semaphore;
         int y = 0;
         for (int i = 0; i < segments; ++i) {
@@ -539,20 +548,20 @@ bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_for
                 y += yn;
             }
         }
-    } else
-#endif
+    } else {
         convertSegment(0, data->height);
-    if (params.totalSize != data->nbytes) {
-        Q_ASSERT(params.totalSize < data->nbytes);
-        void *newData = realloc(data->data, params.totalSize);
-        if (newData) {
-            data->data = (uchar *)newData;
-            data->nbytes = params.totalSize;
+        if (params.totalSize != data->nbytes) {
+            Q_ASSERT(params.totalSize < data->nbytes);
+            void *newData = realloc(data->data, params.totalSize);
+            if (newData) {
+                data->data = (uchar *)newData;
+                data->nbytes = params.totalSize;
+            }
+            data->bytes_per_line = params.bytesPerLine;
         }
-        data->bytes_per_line = params.bytesPerLine;
+        data->depth = destDepth;
+        data->format = dst_format;
     }
-    data->depth = destDepth;
-    data->format = dst_format;
     return true;
 }
 
@@ -605,11 +614,11 @@ bool convert_generic_inplace_over_rgba32f(QImageData *data, QImage::Format dst_f
             destData += params.bytesPerLine;
         }
     };
-#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
+
     int segments = (qsizetype(data->width) * data->height) >> 16;
     segments = std::min(segments, data->height);
     QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
-    if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
+    if (useParallelImageConversions() && segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
         QSemaphore semaphore;
         int y = 0;
         for (int i = 0; i < segments; ++i) {
@@ -633,20 +642,20 @@ bool convert_generic_inplace_over_rgba32f(QImageData *data, QImage::Format dst_f
                 y += yn;
             }
         }
-    } else
-#endif
+    } else {
         convertSegment(0, data->height);
-    if (params.totalSize != data->nbytes) {
-        Q_ASSERT(params.totalSize < data->nbytes);
-        void *newData = realloc(data->data, params.totalSize);
-        if (newData) {
-            data->data = (uchar *)newData;
-            data->nbytes = params.totalSize;
+        if (params.totalSize != data->nbytes) {
+            Q_ASSERT(params.totalSize < data->nbytes);
+            void *newData = realloc(data->data, params.totalSize);
+            if (newData) {
+                data->data = (uchar *)newData;
+                data->nbytes = params.totalSize;
+            }
+            data->bytes_per_line = params.bytesPerLine;
         }
-        data->bytes_per_line = params.bytesPerLine;
+        data->depth = destDepth;
+        data->format = dst_format;
     }
-    data->depth = destDepth;
-    data->format = dst_format;
     return true;
 }
 #endif
-- 
2.34.1

