From 295a16b0d3836a8f41b5133bcd9f355afb03f38b Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Tue, 3 Mar 2020 11:16:58 +0100 Subject: Don't use deprecated QPixmapCache::find overload Silence compile time warning and show correct usage in example snippet. Change-Id: I1936f006e4b5f3ca71bbc0100ed039beeb459271 Reviewed-by: Paul Wicking --- src/gui/doc/snippets/code/src_gui_image_qpixmapcache.cpp | 3 +-- src/widgets/styles/qcommonstyle.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gui/doc/snippets/code/src_gui_image_qpixmapcache.cpp b/src/gui/doc/snippets/code/src_gui_image_qpixmapcache.cpp index 3870237ac3..9043ee6361 100644 --- a/src/gui/doc/snippets/code/src_gui_image_qpixmapcache.cpp +++ b/src/gui/doc/snippets/code/src_gui_image_qpixmapcache.cpp @@ -49,9 +49,8 @@ ****************************************************************************/ //! [0] -QPixmap* pp; QPixmap p; -if ((pp=QPixmapCache::find("my_big_image", pm))) { +if (QPixmap *pp = QPixmapCache::find("my_big_image"))) { p = *pp; } else { p.load("bigimage.png"); diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 4b0094e578..45ac6712b4 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -6125,7 +6125,7 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size.width()); if (standardIcon >= QStyle::SP_CustomBase) { mainIcon = theme->standardPixmap(sp, QSizeF(size)); - } else if (QPixmapCache::find(cacheKey, mainIcon) == false) { + } else if (QPixmapCache::find(cacheKey, &mainIcon) == false) { mainIcon = theme->standardPixmap(sp, QSizeF(size)); QPixmapCache::insert(cacheKey, mainIcon); } -- cgit v1.2.3 From 566def740ec58e842e6bb37177f80e20aebaa245 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Mon, 2 Mar 2020 20:30:13 +0100 Subject: Windows QPA: Add support to UiaRaiseNotificationEvent() This change adds support to UiaRaiseNotificationEvent() in the UI Automation-based accessibility code, and uses it to notify changes in string-typed values, allowing Narrator, NVDA and other screen readers to notice changes in the application state that were previously missed. Fixes: QTBUG-75003 Change-Id: I646ca3a851ab7b69817d900b002eb91a3bf607a6 Reviewed-by: Friedemann Kleint --- .../windowsuiautomation/qwindowsuiawrapper.cpp | 10 ++++++++- .../windowsuiautomation/qwindowsuiawrapper_p.h | 3 +++ .../windowsuiautomation/uiatypes_p.h | 16 +++++++++++++ .../uiautomation/qwindowsuiamainprovider.cpp | 26 +++++++++++++++++----- 4 files changed, 49 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp b/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp index 79541fe636..8038e1a3c3 100644 --- a/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp +++ b/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp @@ -53,6 +53,7 @@ QWindowsUiaWrapper::QWindowsUiaWrapper() m_pUiaHostProviderFromHwnd = reinterpret_cast(uiaLib.resolve("UiaHostProviderFromHwnd")); m_pUiaRaiseAutomationPropertyChangedEvent = reinterpret_cast(uiaLib.resolve("UiaRaiseAutomationPropertyChangedEvent")); m_pUiaRaiseAutomationEvent = reinterpret_cast(uiaLib.resolve("UiaRaiseAutomationEvent")); + m_pUiaRaiseNotificationEvent = reinterpret_cast(uiaLib.resolve("UiaRaiseNotificationEvent")); m_pUiaClientsAreListening = reinterpret_cast(uiaLib.resolve("UiaClientsAreListening")); } } @@ -68,7 +69,7 @@ QWindowsUiaWrapper *QWindowsUiaWrapper::instance() return &wrapper; } -// True if all symbols resolved. +// True if most symbols resolved (UiaRaiseNotificationEvent is optional). BOOL QWindowsUiaWrapper::ready() { return m_pUiaReturnRawElementProvider @@ -113,5 +114,12 @@ HRESULT QWindowsUiaWrapper::raiseAutomationEvent(IRawElementProviderSimple *pPro return m_pUiaRaiseAutomationEvent(pProvider, id); } +HRESULT QWindowsUiaWrapper::raiseNotificationEvent(IRawElementProviderSimple *provider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId) +{ + if (!m_pUiaRaiseNotificationEvent) + return UIA_E_NOTSUPPORTED; + return m_pUiaRaiseNotificationEvent(provider, notificationKind, notificationProcessing, displayString, activityId); +} + QT_END_NAMESPACE diff --git a/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h b/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h index 3ebc3008d3..9208acbc31 100644 --- a/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h +++ b/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h @@ -80,17 +80,20 @@ public: HRESULT hostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **ppProvider); HRESULT raiseAutomationPropertyChangedEvent(IRawElementProviderSimple *pProvider, PROPERTYID id, VARIANT oldValue, VARIANT newValue); HRESULT raiseAutomationEvent(IRawElementProviderSimple *pProvider, EVENTID id); + HRESULT raiseNotificationEvent(IRawElementProviderSimple *provider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId); private: typedef LRESULT (WINAPI *PtrUiaReturnRawElementProvider)(HWND, WPARAM, LPARAM, IRawElementProviderSimple *); typedef HRESULT (WINAPI *PtrUiaHostProviderFromHwnd)(HWND, IRawElementProviderSimple **); typedef HRESULT (WINAPI *PtrUiaRaiseAutomationPropertyChangedEvent)(IRawElementProviderSimple *, PROPERTYID, VARIANT, VARIANT); typedef HRESULT (WINAPI *PtrUiaRaiseAutomationEvent)(IRawElementProviderSimple *, EVENTID); + typedef HRESULT (WINAPI *PtrUiaRaiseNotificationEvent)(IRawElementProviderSimple *, NotificationKind, NotificationProcessing, BSTR, BSTR); typedef BOOL (WINAPI *PtrUiaClientsAreListening)(); PtrUiaReturnRawElementProvider m_pUiaReturnRawElementProvider = nullptr; PtrUiaHostProviderFromHwnd m_pUiaHostProviderFromHwnd = nullptr; PtrUiaRaiseAutomationPropertyChangedEvent m_pUiaRaiseAutomationPropertyChangedEvent = nullptr; PtrUiaRaiseAutomationEvent m_pUiaRaiseAutomationEvent = nullptr; + PtrUiaRaiseNotificationEvent m_pUiaRaiseNotificationEvent = nullptr; PtrUiaClientsAreListening m_pUiaClientsAreListening = nullptr; }; diff --git a/src/platformsupport/windowsuiautomation/uiatypes_p.h b/src/platformsupport/windowsuiautomation/uiatypes_p.h index afbc957094..0d2e1161e4 100644 --- a/src/platformsupport/windowsuiautomation/uiatypes_p.h +++ b/src/platformsupport/windowsuiautomation/uiatypes_p.h @@ -162,6 +162,22 @@ enum ExpandCollapseState { ExpandCollapseState_LeafNode = 3 }; +enum NotificationKind { + NotificationKind_ItemAdded = 0, + NotificationKind_ItemRemoved = 1, + NotificationKind_ActionCompleted = 2, + NotificationKind_ActionAborted = 3, + NotificationKind_Other = 4 +}; + +enum NotificationProcessing { + NotificationProcessing_ImportantAll = 0, + NotificationProcessing_ImportantMostRecent = 1, + NotificationProcessing_All = 2, + NotificationProcessing_MostRecent = 3, + NotificationProcessing_CurrentThenMostRecent = 4 +}; + struct UiaRect { double left; double top; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index 9adc5c78dd..59360616a1 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -166,11 +166,27 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve } if (event->value().type() == QVariant::String) { if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { - // Notifies changes in string values. - VARIANT oldVal, newVal; - clearVariant(&oldVal); - setVariantString(event->value().toString(), &newVal); - QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal); + + // Tries to notify the change using UiaRaiseNotificationEvent(), which is only available on + // Windows 10 version 1709 or newer. Otherwise uses UiaRaiseAutomationPropertyChangedEvent(). + + BSTR displayString = bStrFromQString(event->value().toString()); + BSTR activityId = bStrFromQString(QString()); + + HRESULT hr = QWindowsUiaWrapper::instance()->raiseNotificationEvent(provider, NotificationKind_Other, + NotificationProcessing_ImportantMostRecent, + displayString, activityId); + + ::SysFreeString(displayString); + ::SysFreeString(activityId); + + if (hr == static_cast(UIA_E_NOTSUPPORTED)) { + VARIANT oldVal, newVal; + clearVariant(&oldVal); + setVariantString(event->value().toString(), &newVal); + QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal); + ::SysFreeString(newVal.bstrVal); + } } } else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) { if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { -- cgit v1.2.3 From 813111689629a71e51d7d149a5f689b2961f2716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 25 Feb 2020 11:55:30 +0100 Subject: QSslCertificate: Turn enum into enum class and expand abbreviation From API review Change-Id: Id174ff1a0a123585e41723ef1c1876b2f3bd39c5 Reviewed-by: Timur Pocheptsov --- src/network/ssl/qsslcertificate.cpp | 8 ++++---- src/network/ssl/qsslcertificate.h | 4 ++-- src/network/ssl/qsslconfiguration.h | 5 +++-- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp index c179cf9c4a..791dc7852f 100644 --- a/src/network/ssl/qsslcertificate.cpp +++ b/src/network/ssl/qsslcertificate.cpp @@ -573,12 +573,12 @@ QList QSslCertificate::fromPath(const QString &path, int pos = -1; #if QT_CONFIG(regularexpression) - if (syntax == Wildcard) + if (syntax == PatternSyntax::Wildcard) pos = pathPrefix.indexOf(QRegularExpression(QLatin1String("[*?[]"))); - else if (syntax == RegExp) + else if (syntax == PatternSyntax::RegularExpression) pos = sourcePath.indexOf(QRegularExpression(QLatin1String("[\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]"))); #else - if (syntax == Wildcard || syntax == RegExp) + if (syntax == PatternSyntax::Wildcard || syntax == PatternSyntax::RegExp) qWarning("Regular expression support is disabled in this build. Only fixed string can be searched"); return QList(); #endif @@ -615,7 +615,7 @@ QList QSslCertificate::fromPath(const QString &path, QList certs; #if QT_CONFIG(regularexpression) - if (syntax == Wildcard) + if (syntax == PatternSyntax::Wildcard) sourcePath = QRegularExpression::wildcardToRegularExpression(sourcePath); QRegularExpression pattern(QRegularExpression::anchoredPattern(sourcePath)); diff --git a/src/network/ssl/qsslcertificate.h b/src/network/ssl/qsslcertificate.h index 9993769888..b98c5cfcab 100644 --- a/src/network/ssl/qsslcertificate.h +++ b/src/network/ssl/qsslcertificate.h @@ -84,8 +84,8 @@ public: EmailAddress }; - enum PatternSyntax { - RegExp, + enum class PatternSyntax { + RegularExpression, Wildcard, FixedString }; diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h index 09616098a5..1c181121f4 100644 --- a/src/network/ssl/qsslconfiguration.h +++ b/src/network/ssl/qsslconfiguration.h @@ -131,8 +131,9 @@ public: // Certificate Authority (CA) settings QList caCertificates() const; void setCaCertificates(const QList &certificates); - bool addCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem, - QSslCertificate::PatternSyntax syntax = QSslCertificate::FixedString); + bool addCaCertificates( + const QString &path, QSsl::EncodingFormat format = QSsl::Pem, + QSslCertificate::PatternSyntax syntax = QSslCertificate::PatternSyntax::FixedString); void addCaCertificate(const QSslCertificate &certificate); void addCaCertificates(const QList &certificates); -- cgit v1.2.3 From 519ea72108fae7f5c4ed7c3e9fed3a999a16ed73 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Mon, 2 Mar 2020 17:00:04 +0200 Subject: Android: Bump gradle (plugin) versions Move min & target sdk from AndroidManifest.xml to build.gradle Fixes: QTBUG-70817 Change-Id: Id9bb9825a3232587e0255b2d3d6f0273c5f9b66a Reviewed-by: Assam Boudjelthia Reviewed-by: Joerg Bornemann --- .../gradle/gradle/wrapper/gradle-wrapper.properties | 2 +- src/android/templates/AndroidManifest.xml | 2 -- src/android/templates/build.gradle | 8 +++++++- src/corelib/Qt5AndroidSupport.cmake | 5 +++++ src/tools/androiddeployqt/main.cpp | 16 ++++++++++++++++ 5 files changed, 29 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties index 4b7e1f3d38..5028f28f8e 100644 --- a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties +++ b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/android/templates/AndroidManifest.xml b/src/android/templates/AndroidManifest.xml index 6d0f4e0d45..e31dea6a8c 100644 --- a/src/android/templates/AndroidManifest.xml +++ b/src/android/templates/AndroidManifest.xml @@ -1,7 +1,5 @@ - - diff --git a/src/android/templates/build.gradle b/src/android/templates/build.gradle index 3087d08c83..d5b3b93499 100644 --- a/src/android/templates/build.gradle +++ b/src/android/templates/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:3.6.0' } } @@ -59,4 +59,10 @@ android { aaptOptions { noCompress 'rcc' } + + defaultConfig { + resConfig "en" + minSdkVersion = qtMinSdkVersion + targetSdkVersion = qtTargetSdkVersion + } } diff --git a/src/corelib/Qt5AndroidSupport.cmake b/src/corelib/Qt5AndroidSupport.cmake index 5f24fb0e8c..4db38f3957 100644 --- a/src/corelib/Qt5AndroidSupport.cmake +++ b/src/corelib/Qt5AndroidSupport.cmake @@ -18,6 +18,8 @@ if (NOT ${PROJECT_NAME}-MultiAbiBuild) option(ANDROID_BUILD_ABI_${abi} "Enable the build for Android ${abi}" ${abi_initial_value}) endif() endforeach() + option(ANDROID_MIN_SDK_VERSION "Android minimum SDK version" "21") + option(ANDROID_TARGET_SDK_VERSION "Android target SDK version" "28") # Make sure to delete the "android-build" directory, which contains all the # build artefacts, and also the androiddeployqt/gradle artefacts @@ -101,6 +103,9 @@ if (NOT ${PROJECT_NAME}-MultiAbiBuild) generate_json_variable(ANDROID_VERSION_NAME "android-version-name") generate_json_variable_list(ANDROID_EXTRA_LIBS "android-extra-libs") generate_json_variable_list(QML_IMPORT_PATH "qml-import-paths") + generate_json_variable_list(ANDROID_MIN_SDK_VERSION "android-min-sdk-version") + generate_json_variable_list(ANDROID_TARGET_SDK_VERSION "android-target-sdk-version") + configure_file( "${CMAKE_BINARY_DIR}/android_deployment_settings.json.in" diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index 97e5c9eb69..2799f97fe8 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -169,6 +169,8 @@ struct Options // Versioning QString versionName; QString versionCode; + QByteArray minSdkVersion{"21"}; + QByteArray targetSdkVersion{"28"}; // lib c++ path QString stdCppPath; @@ -849,6 +851,18 @@ bool readInputFile(Options *options) options->versionCode = QStringLiteral("1"); } + { + const QJsonValue ver = jsonObject.value(QLatin1String("android-min-sdk-version")); + if (!ver.isUndefined()) + options->minSdkVersion = ver.toString().toUtf8(); + } + + { + const QJsonValue ver = jsonObject.value(QLatin1String("android-target-sdk-version")); + if (!ver.isUndefined()) + options->targetSdkVersion = ver.toString().toUtf8(); + } + { const QJsonObject targetArchitectures = jsonObject.value(QLatin1String("architectures")).toObject(); if (targetArchitectures.isEmpty()) { @@ -2298,6 +2312,8 @@ bool buildAndroidProject(const Options &options) gradleProperties["buildDir"] = "build"; gradleProperties["qt5AndroidDir"] = (options.qtInstallDirectory + QLatin1String("/src/android/java")).toUtf8(); gradleProperties["androidCompileSdkVersion"] = options.androidPlatform.split(QLatin1Char('-')).last().toLocal8Bit(); + gradleProperties["qtMinSdkVersion"] = options.minSdkVersion; + gradleProperties["qtTargetSdkVersion"] = options.targetSdkVersion; if (gradleProperties["androidBuildToolsVersion"].isEmpty()) gradleProperties["androidBuildToolsVersion"] = options.sdkBuildToolsVersion.toLocal8Bit(); -- cgit v1.2.3 From 9e46dd7719b63710a6e4ffc6c43e55be710b2c5a Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 3 Mar 2020 15:46:17 +0100 Subject: Document TlsV1SslV3 as deprecated MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id127b6d985d0085982e47b4f80886e3831ce07c7 Reviewed-by: Mårten Nordheim --- src/network/ssl/qssl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp index c9fa7f85d9..beb03b646a 100644 --- a/src/network/ssl/qssl.cpp +++ b/src/network/ssl/qssl.cpp @@ -137,7 +137,7 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl"); \value TlsV1_3OrLater TLSv1.3 and later versions. (Since Qt 5.12) \value UnknownProtocol The cipher's protocol cannot be determined. \value AnyProtocol Any supported protocol. This value is used by QSslSocket only. - \value TlsV1SslV3 Same as TlsV1_0. + \value TlsV1SslV3 Same as TlsV1_0. This enumerator is deprecated, use TlsV1_0 instead. \value SecureProtocols The default option, using protocols known to be secure. */ -- cgit v1.2.3 From 728cc964f3f25d23c72317a119b839701f5941e8 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 27 Jul 2019 15:47:54 +0300 Subject: QString/QByteArray: make all symmetry-checked member-compare() combinations noexcept In QByteArray, they were just not marked as such. In QString and QStringRef, the implicit conversion from QChar to QString would destroy it. Add a QChar overload, delegating to QStringView. Added docs for the new overloads, copying from the nearest neighbor so as to not look out of place. All string classes use different wording for these functions. A cleanup of this state of affairs is out of the scope of this patch. Change-Id: I0b7b1d037aa229bcaf29b793841a18caf977d66b Reviewed-by: Volker Hilsheimer Reviewed-by: Lars Knoll --- src/corelib/text/qbytearray.h | 8 ++++---- src/corelib/text/qstring.cpp | 23 +++++++++++++++++++++++ src/corelib/text/qstring.h | 4 ++++ 3 files changed, 31 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h index 36cf580cd9..e3bb9ea937 100644 --- a/src/corelib/text/qbytearray.h +++ b/src/corelib/text/qbytearray.h @@ -240,8 +240,8 @@ public: int count(const char *a) const; int count(const QByteArray &a) const; - inline int compare(const char *c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; - inline int compare(const QByteArray &a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; + inline int compare(const char *c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept; + inline int compare(const QByteArray &a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept; Q_REQUIRED_RESULT QByteArray left(int len) const; Q_REQUIRED_RESULT QByteArray right(int len) const; @@ -663,12 +663,12 @@ inline bool QByteArray::contains(const QByteArray &a) const { return indexOf(a) != -1; } inline bool QByteArray::contains(char c) const { return indexOf(c) != -1; } -inline int QByteArray::compare(const char *c, Qt::CaseSensitivity cs) const +inline int QByteArray::compare(const char *c, Qt::CaseSensitivity cs) const noexcept { return cs == Qt::CaseSensitive ? qstrcmp(*this, c) : qstrnicmp(data(), size(), c, -1); } -inline int QByteArray::compare(const QByteArray &a, Qt::CaseSensitivity cs) const +inline int QByteArray::compare(const QByteArray &a, Qt::CaseSensitivity cs) const noexcept { return cs == Qt::CaseSensitive ? qstrcmp(*this, a) : qstrnicmp(data(), size(), a.data(), a.size()); diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 68dec7cfff..f64f148f49 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -6276,6 +6276,16 @@ QString& QString::fill(QChar ch, int size) sensitivity setting \a cs. */ +/*! + \fn int QString::compare(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + + \since 5.14 + \overload compare() + + Performs a comparison of this with \a ch, using the case + sensitivity setting \a cs. +*/ + #if QT_STRINGVIEW_LEVEL < 2 /*! \overload compare() @@ -11073,6 +11083,19 @@ QStringRef QStringRef::appendTo(QString *string) const Equivalent to \c {compare(*this, other, cs)}. */ +/*! + \overload + \fn int QStringRef::compare(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \since 5.14 + + Compares this string with \a ch and returns an + integer less than, equal to, or greater than zero if this string + is less than, equal to, or greater than \a ch, interpreted as a string of length one. + + If \a cs is Qt::CaseSensitive, the comparison is case sensitive; + otherwise the comparison is case insensitive. +*/ + /*! \overload \fn int QStringRef::compare(QLatin1String other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index bfc190e9e9..d615e6646c 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -732,6 +732,8 @@ public: #endif int compare(QLatin1String other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept; inline int compare(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept; + int compare(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return compare(QStringView{&ch, 1}, cs); } static inline int compare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept @@ -1749,6 +1751,8 @@ public: int compare(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept; int compare(const QStringRef &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept; + int compare(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return QtPrivate::compareStrings(*this, QStringView(&c, 1), cs); } int compare(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept; #if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) int compare(const QByteArray &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const -- cgit v1.2.3 From b2f79cceb11dfd15ac9eea631bc18ad6b036eb91 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 29 Jul 2019 09:44:04 +0300 Subject: QLatin1String/QStringView: add (missing) member compare() [ChangeLog][QtCore][QLatin1String] Added compare(). [ChangeLog][QtCore][QStringView] Added compare() overloads taking QLatin1String, QChar. Change-Id: Ie2aa400299cb63495e65ce29b2a32133066de826 Reviewed-by: Volker Hilsheimer Reviewed-by: Thiago Macieira --- src/corelib/text/qstring.cpp | 17 +++++++++++++++++ src/corelib/text/qstring.h | 11 +++++++++++ src/corelib/text/qstringview.cpp | 26 ++++++++++++++++++++------ src/corelib/text/qstringview.h | 5 +++++ 4 files changed, 53 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index f64f148f49..210a8afc53 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -9717,6 +9717,23 @@ QString &QString::setRawData(const QChar *unicode, int size) \sa front(), at(), operator[]() */ +/*! + \fn int QLatin1String::compare(QStringView str, Qt::CaseSensitivity cs) const + \fn int QLatin1String::compare(QLatin1String l1, Qt::CaseSensitivity cs) const + \fn int QLatin1String::compare(QChar ch) const + \fn int QLatin1String::compare(QChar ch, Qt::CaseSensitivity cs) const + \since 5.14 + + Returns an integer that compares to zero as this Latin-1 string compares to the + string-view \a str, Latin-1 string \a l1, or character \a ch, respectively. + + If \a cs is Qt::CaseSensitive (the default), the comparison is case sensitive; + otherwise the comparison is case-insensitive. + + \sa operator==(), operator<(), operator>() +*/ + + /*! \fn bool QLatin1String::startsWith(QStringView str, Qt::CaseSensitivity cs) const \since 5.10 diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index d615e6646c..99b41c8ebf 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -111,6 +111,15 @@ public: Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QLatin1Char front() const { return at(0); } Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QLatin1Char back() const { return at(size() - 1); } + Q_REQUIRED_RESULT int compare(QStringView other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return QtPrivate::compareStrings(*this, other, cs); } + Q_REQUIRED_RESULT int compare(QLatin1String other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return QtPrivate::compareStrings(*this, other, cs); } + Q_REQUIRED_RESULT Q_DECL_CONSTEXPR int compare(QChar c) const noexcept + { return isEmpty() || front() == c ? size() - 1 : uchar(m_data[0]) - c.unicode() ; } + Q_REQUIRED_RESULT int compare(QChar c, Qt::CaseSensitivity cs) const noexcept + { return QtPrivate::compareStrings(*this, QStringView(&c, 1), cs); } + Q_REQUIRED_RESULT bool startsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return QtPrivate::startsWith(*this, s, cs); } Q_REQUIRED_RESULT bool startsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept @@ -233,6 +242,8 @@ Q_DECL_CONSTEXPR bool QtPrivate::isLatin1(QLatin1String) noexcept // // QStringView members that require QLatin1String: // +int QStringView::compare(QLatin1String s, Qt::CaseSensitivity cs) const noexcept +{ return QtPrivate::compareStrings(*this, s, cs); } bool QStringView::startsWith(QLatin1String s, Qt::CaseSensitivity cs) const noexcept { return QtPrivate::startsWith(*this, s, cs); } bool QStringView::endsWith(QLatin1String s, Qt::CaseSensitivity cs) const noexcept diff --git a/src/corelib/text/qstringview.cpp b/src/corelib/text/qstringview.cpp index 08dade7e68..9df656dc59 100644 --- a/src/corelib/text/qstringview.cpp +++ b/src/corelib/text/qstringview.cpp @@ -692,15 +692,29 @@ QT_BEGIN_NAMESPACE */ /*! - \fn int QStringView::compare(QStringView other, Qt::CaseSensitivity cs) const + \fn int QStringView::compare(QStringView str, Qt::CaseSensitivity cs) const \since 5.12 - Compares this string-view with the \a other string-view and returns an - integer less than, equal to, or greater than zero if this string-view - is less than, equal to, or greater than the other string-view. + Returns an integer that compares to zero as this string-view compares to the + string-view \a str. - If \a cs is Qt::CaseSensitive, the comparison is case sensitive; - otherwise the comparison is case insensitive. + If \a cs is Qt::CaseSensitive (the default), the comparison is case sensitive; + otherwise the comparison is case-insensitive. + + \sa operator==(), operator<(), operator>() +*/ + +/*! + \fn int QStringView::compare(QLatin1String l1, Qt::CaseSensitivity cs) const + \fn int QStringView::compare(QChar ch) const + \fn int QStringView::compare(QChar ch, Qt::CaseSensitivity cs) const + \since 5.14 + + Returns an integer that compares to zero as this string-view compares to the + Latin-1 string \a l1, or character \a ch, respectively. + + If \a cs is Qt::CaseSensitive (the default), the comparison is case sensitive; + otherwise the comparison is case-insensitive. \sa operator==(), operator<(), operator>() */ diff --git a/src/corelib/text/qstringview.h b/src/corelib/text/qstringview.h index 06391ffef4..83418970a5 100644 --- a/src/corelib/text/qstringview.h +++ b/src/corelib/text/qstringview.h @@ -257,6 +257,11 @@ public: Q_REQUIRED_RESULT int compare(QStringView other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return QtPrivate::compareStrings(*this, other, cs); } + Q_REQUIRED_RESULT inline int compare(QLatin1String other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept; + Q_REQUIRED_RESULT Q_DECL_CONSTEXPR int compare(QChar c) const noexcept + { return empty() || front() == c ? size() - 1 : *utf16() - c.unicode() ; } + Q_REQUIRED_RESULT int compare(QChar c, Qt::CaseSensitivity cs) const noexcept + { return QtPrivate::compareStrings(*this, QStringView(&c, 1), cs); } Q_REQUIRED_RESULT bool startsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return QtPrivate::startsWith(*this, s, cs); } -- cgit v1.2.3 From 16f927a4f1ffeff399351b625d73ac3cd7bccd51 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 19 Aug 2019 23:17:48 +0200 Subject: QLoggingRegistry: use QStringView/QLatin1String more - QLoggingRule::parse() and the ctor take pattern as QStringView - parseNextLine takes lines as QStringView and produces the pattern as QStringView for QLoggingRule - (setContent has to wait for QStringTokenizer) - QLoggingRule::pass()'s first argument is always QLatin1String, so take it as one Use chopped() more, add a std::move(). Change-Id: Ic95ea77464a9922fef452846bc6d5053bd5de56e Reviewed-by: Volker Hilsheimer --- src/corelib/io/qloggingregistry.cpp | 40 +++++++++++++++++-------------------- src/corelib/io/qloggingregistry_p.h | 8 ++++---- 2 files changed, 22 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp index e8eb18b4c1..cacebfbda6 100644 --- a/src/corelib/io/qloggingregistry.cpp +++ b/src/corelib/io/qloggingregistry.cpp @@ -75,7 +75,7 @@ QLoggingRule::QLoggingRule() : \internal Constructs a logging rule. */ -QLoggingRule::QLoggingRule(const QStringRef &pattern, bool enabled) : +QLoggingRule::QLoggingRule(QStringView pattern, bool enabled) : messageType(-1), enabled(enabled) { @@ -87,7 +87,7 @@ QLoggingRule::QLoggingRule(const QStringRef &pattern, bool enabled) : Return value 1 means filter passed, 0 means filter doesn't influence this category, -1 means category doesn't pass this filter. */ -int QLoggingRule::pass(const QString &cat, QtMsgType msgType) const +int QLoggingRule::pass(QLatin1String cat, QtMsgType msgType) const { // check message type if (messageType > -1 && messageType != msgType) @@ -113,7 +113,7 @@ int QLoggingRule::pass(const QString &cat, QtMsgType msgType) const return (enabled ? 1 : -1); } else if (flags == RightFilter) { // matches right - if (idx == (cat.count() - category.count())) + if (idx == (cat.size() - category.count())) return (enabled ? 1 : -1); } } @@ -129,26 +129,22 @@ int QLoggingRule::pass(const QString &cat, QtMsgType msgType) const *.io.warning RightFilter, QtWarningMsg *.core.* MidFilter */ -void QLoggingRule::parse(const QStringRef &pattern) +void QLoggingRule::parse(QStringView pattern) { - QStringRef p; + QStringView p; // strip trailing ".messagetype" if (pattern.endsWith(QLatin1String(".debug"))) { - p = QStringRef(pattern.string(), pattern.position(), - pattern.length() - 6); // strlen(".debug") + p = pattern.chopped(6); // strlen(".debug") messageType = QtDebugMsg; } else if (pattern.endsWith(QLatin1String(".info"))) { - p = QStringRef(pattern.string(), pattern.position(), - pattern.length() - 5); // strlen(".info") + p = pattern.chopped(5); // strlen(".info") messageType = QtInfoMsg; } else if (pattern.endsWith(QLatin1String(".warning"))) { - p = QStringRef(pattern.string(), pattern.position(), - pattern.length() - 8); // strlen(".warning") + p = pattern.chopped(8); // strlen(".warning") messageType = QtWarningMsg; } else if (pattern.endsWith(QLatin1String(".critical"))) { - p = QStringRef(pattern.string(), pattern.position(), - pattern.length() - 9); // strlen(".critical") + p = pattern.chopped(9); // strlen(".critical") messageType = QtCriticalMsg; } else { p = pattern; @@ -159,11 +155,11 @@ void QLoggingRule::parse(const QStringRef &pattern) } else { if (p.endsWith(QLatin1Char('*'))) { flags |= LeftFilter; - p = QStringRef(p.string(), p.position(), p.length() - 1); + p = p.chopped(1); } if (p.startsWith(QLatin1Char('*'))) { flags |= RightFilter; - p = QStringRef(p.string(), p.position() + 1, p.length() - 1); + p = p.mid(1); } if (p.contains(QLatin1Char('*'))) // '*' only supported at start/end flags = PatternFlags(); @@ -208,7 +204,7 @@ void QLoggingSettingsParser::setContent(QTextStream &stream) _rules.clear(); QString line; while (stream.readLineInto(&line)) - parseNextLine(QStringRef(&line)); + parseNextLine(qToStringViewIgnoringNull(line)); } /*! @@ -216,7 +212,7 @@ void QLoggingSettingsParser::setContent(QTextStream &stream) Parses one line of the configuation file */ -void QLoggingSettingsParser::parseNextLine(QStringRef line) +void QLoggingSettingsParser::parseNextLine(QStringView line) { // Remove whitespace at start and end of line: line = line.trimmed(); @@ -227,7 +223,7 @@ void QLoggingSettingsParser::parseNextLine(QStringRef line) if (line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) { // new section - auto sectionName = line.mid(1, line.size() - 2).trimmed(); + auto sectionName = line.mid(1).chopped(1).trimmed(); m_inRulesSection = sectionName.compare(QLatin1String("rules"), Qt::CaseInsensitive) == 0; return; } @@ -240,9 +236,9 @@ void QLoggingSettingsParser::parseNextLine(QStringRef line) #if QT_CONFIG(settings) QString tmp; QSettingsPrivate::iniUnescapedKey(key.toUtf8(), 0, key.length(), tmp); - QStringRef pattern = QStringRef(&tmp, 0, tmp.length()); + QStringView pattern = qToStringViewIgnoringNull(tmp); #else - QStringRef pattern = key; + QStringView pattern = key; #endif const auto valueStr = line.mid(equalPos + 1).trimmed(); int value = -1; @@ -252,7 +248,7 @@ void QLoggingSettingsParser::parseNextLine(QStringRef line) value = 0; QLoggingRule rule(pattern, (value == 1)); if (rule.flags != 0 && (value != -1)) - _rules.append(rule); + _rules.append(std::move(rule)); else warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData()); } else { @@ -460,7 +456,7 @@ void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat) debug = false; } - QString categoryName = QLatin1String(cat->categoryName()); + const auto categoryName = QLatin1String(cat->categoryName()); for (const auto &ruleSet : reg->ruleSets) { for (const auto &rule : ruleSet) { diff --git a/src/corelib/io/qloggingregistry_p.h b/src/corelib/io/qloggingregistry_p.h index 12a1f166b3..3ac429b147 100644 --- a/src/corelib/io/qloggingregistry_p.h +++ b/src/corelib/io/qloggingregistry_p.h @@ -67,8 +67,8 @@ class Q_AUTOTEST_EXPORT QLoggingRule { public: QLoggingRule(); - QLoggingRule(const QStringRef &pattern, bool enabled); - int pass(const QString &categoryName, QtMsgType type) const; + QLoggingRule(QStringView pattern, bool enabled); + int pass(QLatin1String categoryName, QtMsgType type) const; enum PatternFlag { FullText = 0x1, @@ -84,7 +84,7 @@ public: bool enabled; private: - void parse(const QStringRef &pattern); + void parse(QStringView pattern); }; Q_DECLARE_OPERATORS_FOR_FLAGS(QLoggingRule::PatternFlags) @@ -101,7 +101,7 @@ public: QVector rules() const { return _rules; } private: - void parseNextLine(QStringRef line); + void parseNextLine(QStringView line); private: bool m_inRulesSection = false; -- cgit v1.2.3 From 66e905b1c35b5911e6ab7555720045b3029f556a Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 5 Mar 2020 14:17:59 +0100 Subject: Fix deprecation warning in QProcess::execute(QString) Implement this method in terms of splitCommand and QProcess::execute(QString, QStringList). Change-Id: I1fe78fb53d8b6b34a8796f9fbda380a98a840c99 Reviewed-by: Volker Hilsheimer --- src/corelib/io/qprocess.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index df8b306a8d..9400662b97 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -2519,12 +2519,10 @@ int QProcess::execute(const QString &program, const QStringList &arguments) */ int QProcess::execute(const QString &command) { - QProcess process; - process.setProcessChannelMode(ForwardedChannels); - process.start(command); - if (!process.waitForFinished(-1) || process.error() == FailedToStart) + QStringList args = splitCommand(command); + if (args.isEmpty()) return -2; - return process.exitStatus() == QProcess::NormalExit ? process.exitCode() : -1; + return execute(args.takeFirst(), args); } /*! -- cgit v1.2.3 From e1e0862990dbe00462f7faa02845a640a3d84155 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 5 Mar 2020 14:23:48 +0100 Subject: Fix deprecation warning in QGenericUnixServices Do not use the deprecated method QProcess::start(QString) anymore. Change-Id: I09eae2c8a1dbb53fd2de004e5030da9bb3c07b14 Reviewed-by: Volker Hilsheimer --- src/platformsupport/services/genericunix/qgenericunixservices.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/platformsupport/services/genericunix/qgenericunixservices.cpp b/src/platformsupport/services/genericunix/qgenericunixservices.cpp index 734bdcaf75..8e9923e208 100644 --- a/src/platformsupport/services/genericunix/qgenericunixservices.cpp +++ b/src/platformsupport/services/genericunix/qgenericunixservices.cpp @@ -166,7 +166,8 @@ static inline bool launch(const QString &launcher, const QUrl &url) #if !QT_CONFIG(process) const bool ok = ::system(qPrintable(command + QLatin1String(" &"))); #else - const bool ok = QProcess::startDetached(command); + QStringList args = QProcess::splitCommand(command); + const bool ok = !args.isEmpty() && QProcess::startDetached(args.takeFirst(), args); #endif if (!ok) qWarning("Launch failed (%s)", qPrintable(command)); -- cgit v1.2.3 From c3ae30085e4047ee7d5a945c36e2055c2de5197d Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 3 Mar 2020 14:24:11 +0100 Subject: rhi: Add support for arrays of combined image samplers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces a new QRhiShaderResourceBinding function that takes an array of texture-sampler pairs. The existing function is also available and is equivalent to calling the array-based version with array size 1. It is important to note that for Metal one needs MSL 2.0 for array of textures, so qsb needs --msl 20 instead of --msl 12 for such shaders. Comes with an autotest, and also updates all .qsb files for said test with the latest shadertools. Task-number: QTBUG-82624 Change-Id: Ibc1973aae826836f16d842c41d6c8403fd7ff876 Reviewed-by: Christian Strømme --- src/gui/rhi/qrhi.cpp | 66 +++++++++++++++++++++---- src/gui/rhi/qrhi_p.h | 11 ++++- src/gui/rhi/qrhid3d11.cpp | 92 +++++++++++++++++++++-------------- src/gui/rhi/qrhid3d11_p_p.h | 11 +++-- src/gui/rhi/qrhigles2.cpp | 61 ++++++++++++----------- src/gui/rhi/qrhimetal.mm | 112 ++++++++++++++++++++++++++----------------- src/gui/rhi/qrhimetal_p_p.h | 11 +++-- src/gui/rhi/qrhivulkan.cpp | 83 +++++++++++++++++++------------- src/gui/rhi/qrhivulkan_p_p.h | 11 +++-- 9 files changed, 290 insertions(+), 168 deletions(-) (limited to 'src') diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index c805e23ad0..83c1e8eaa2 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -2885,16 +2885,57 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOff \return a shader resource binding for the given binding number, pipeline stages, texture, and sampler specified by \a binding, \a stage, \a tex, \a sampler. + + \note This function is equivalent to calling sampledTextures() with a + \c count of 1. + + \sa sampledTextures() */ QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture( int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler) { + const TextureAndSampler texSampler = { tex, sampler }; + return sampledTextures(binding, stage, 1, &texSampler); +} + +/*! + \return a shader resource binding for the given binding number, pipeline + stages, and the array of texture-sampler pairs specified by \a binding, \a + stage, \a count, and \a texSamplers. + + \note \a count must be at least 1, and not larger than 16. + + \note When \a count is 1, this function is equivalent to sampledTexture(). + + This function is relevant when arrays of combined image samplers are + involved. For example, in GLSL \c{layout(binding = 5) uniform sampler2D + shadowMaps[8];} declares an array of combined image samplers. The + application is then expected provide a QRhiShaderResourceBinding for + binding point 5, set up by calling this function with \a count set to 8 and + a valid texture and sampler for each element of the array. + + \warning All elements of the array must be specified. With the above + example, the only valid, portable approach is calling this function with a + \a count of 8. Additionally, all QRhiTexture and QRhiSampler instances must + be valid, meaning nullptr is not an accepted value. This is due to some of + the underlying APIs, such as, Vulkan, that require a valid image and + sampler object for each element in descriptor arrays. Applications are + advised to provide "dummy" samplers and textures if some array elements are + not relevant (due to not being accessed in the shader). + + \sa sampledTexture() + */ +QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTextures( + int binding, StageFlags stage, int count, const TextureAndSampler *texSamplers) +{ + Q_ASSERT(count >= 1 && count <= Data::MAX_TEX_SAMPLER_ARRAY_SIZE); QRhiShaderResourceBinding b; b.d.binding = binding; b.d.stage = stage; b.d.type = SampledTexture; - b.d.u.stex.tex = tex; - b.d.u.stex.sampler = sampler; + b.d.u.stex.count = count; + for (int i = 0; i < count; ++i) + b.d.u.stex.texSamplers[i] = texSamplers[i]; return b; } @@ -3084,10 +3125,14 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind } break; case QRhiShaderResourceBinding::SampledTexture: - if (da->u.stex.tex != db->u.stex.tex - || da->u.stex.sampler != db->u.stex.sampler) - { + if (da->u.stex.count != db->u.stex.count) return false; + for (int i = 0; i < da->u.stex.count; ++i) { + if (da->u.stex.texSamplers[i].tex != db->u.stex.texSamplers[i].tex + || da->u.stex.texSamplers[i].sampler != db->u.stex.texSamplers[i].sampler) + { + return false; + } } break; case QRhiShaderResourceBinding::ImageLoad: @@ -3162,10 +3207,13 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b) << ')'; break; case QRhiShaderResourceBinding::SampledTexture: - dbg.nospace() << " SampledTexture(" - << "texture=" << d->u.stex.tex - << " sampler=" << d->u.stex.sampler - << ')'; + dbg.nospace() << " SampledTextures(" + << "count=" << d->u.stex.count; + for (int i = 0; i < d->u.stex.count; ++i) { + dbg.nospace() << " texture=" << d->u.stex.texSamplers[i].tex + << " sampler=" << d->u.stex.texSamplers[i].sampler; + } + dbg.nospace() << ')'; break; case QRhiShaderResourceBinding::ImageLoad: dbg.nospace() << " ImageLoad(" diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 17c911a5ff..9d906d7bbd 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -348,6 +348,12 @@ public: static QRhiShaderResourceBinding sampledTexture(int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler); + struct TextureAndSampler { + QRhiTexture *tex; + QRhiSampler *sampler; + }; + static QRhiShaderResourceBinding sampledTextures(int binding, StageFlags stage, int count, const TextureAndSampler *texSamplers); + static QRhiShaderResourceBinding imageLoad(int binding, StageFlags stage, QRhiTexture *tex, int level); static QRhiShaderResourceBinding imageStore(int binding, StageFlags stage, QRhiTexture *tex, int level); static QRhiShaderResourceBinding imageLoadStore(int binding, StageFlags stage, QRhiTexture *tex, int level); @@ -370,9 +376,10 @@ public: int maybeSize; bool hasDynamicOffset; }; + static const int MAX_TEX_SAMPLER_ARRAY_SIZE = 16; struct SampledTextureData { - QRhiTexture *tex; - QRhiSampler *sampler; + int count; + TextureAndSampler texSamplers[MAX_TEX_SAMPLER_ARRAY_SIZE]; }; struct StorageImageData { QRhiTexture *tex; diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 7b583e6fd2..7c53925aca 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -627,18 +627,25 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind break; case QRhiShaderResourceBinding::SampledTexture: { - QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.stex.tex); - QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, b->u.stex.sampler); - if (texD->generation != bd.stex.texGeneration - || texD->m_id != bd.stex.texId - || samplerD->generation != bd.stex.samplerGeneration - || samplerD->m_id != bd.stex.samplerId) - { + const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex; + if (bd.stex.count != data->count) { + bd.stex.count = data->count; srbUpdate = true; - bd.stex.texId = texD->m_id; - bd.stex.texGeneration = texD->generation; - bd.stex.samplerId = samplerD->m_id; - bd.stex.samplerGeneration = samplerD->generation; + } + for (int elem = 0; elem < data->count; ++elem) { + QD3D11Texture *texD = QRHI_RES(QD3D11Texture, data->texSamplers[elem].tex); + QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, data->texSamplers[elem].sampler); + if (texD->generation != bd.stex.d[elem].texGeneration + || texD->m_id != bd.stex.d[elem].texId + || samplerD->generation != bd.stex.d[elem].samplerGeneration + || samplerD->m_id != bd.stex.d[elem].samplerId) + { + srbUpdate = true; + bd.stex.d[elem].texId = texD->m_id; + bd.stex.d[elem].texGeneration = texD->generation; + bd.stex.d[elem].samplerId = samplerD->m_id; + bd.stex.d[elem].samplerGeneration = samplerD->generation; + } } } break; @@ -1894,31 +1901,38 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, break; case QRhiShaderResourceBinding::SampledTexture: { - QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.stex.tex); - QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, b->u.stex.sampler); - bd.stex.texId = texD->m_id; - bd.stex.texGeneration = texD->generation; - bd.stex.samplerId = samplerD->m_id; - bd.stex.samplerGeneration = samplerD->generation; - if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - QPair nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps); - if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { - res[RBM_VERTEX].textures.append({ nativeBinding.first, texD->srv }); - res[RBM_VERTEX].samplers.append({ nativeBinding.second, samplerD->samplerState }); + const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex; + bd.stex.count = data->count; + const QPair nativeBindingVert = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps); + const QPair nativeBindingFrag = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps); + const QPair nativeBindingComp = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + // if SPIR-V binding b is mapped to tN and sN in HLSL, and it + // is an array, then it will use tN, tN+1, tN+2, ..., and sN, + // sN+1, sN+2, ... + for (int elem = 0; elem < data->count; ++elem) { + QD3D11Texture *texD = QRHI_RES(QD3D11Texture, data->texSamplers[elem].tex); + QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, data->texSamplers[elem].sampler); + bd.stex.d[elem].texId = texD->m_id; + bd.stex.d[elem].texGeneration = texD->generation; + bd.stex.d[elem].samplerId = samplerD->m_id; + bd.stex.d[elem].samplerGeneration = samplerD->generation; + if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { + if (nativeBindingVert.first >= 0 && nativeBindingVert.second >= 0) { + res[RBM_VERTEX].textures.append({ nativeBindingVert.first + elem, texD->srv }); + res[RBM_VERTEX].samplers.append({ nativeBindingVert.second + elem, samplerD->samplerState }); + } } - } - if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - QPair nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps); - if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { - res[RBM_FRAGMENT].textures.append({ nativeBinding.first, texD->srv }); - res[RBM_FRAGMENT].samplers.append({ nativeBinding.second, samplerD->samplerState }); + if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { + if (nativeBindingFrag.first >= 0 && nativeBindingFrag.second >= 0) { + res[RBM_FRAGMENT].textures.append({ nativeBindingFrag.first + elem, texD->srv }); + res[RBM_FRAGMENT].samplers.append({ nativeBindingFrag.second + elem, samplerD->samplerState }); + } } - } - if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); - if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { - res[RBM_COMPUTE].textures.append({ nativeBinding.first, texD->srv }); - res[RBM_COMPUTE].samplers.append({ nativeBinding.second, samplerD->samplerState }); + if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { + if (nativeBindingComp.first >= 0 && nativeBindingComp.second >= 0) { + res[RBM_COMPUTE].textures.append({ nativeBindingComp.first + elem, texD->srv }); + res[RBM_COMPUTE].samplers.append({ nativeBindingComp.second + elem, samplerD->samplerState }); + } } } } @@ -3529,11 +3543,15 @@ static pD3DCompile resolveD3DCompile() static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error, QShaderKey *usedShaderKey) { - QShaderCode dxbc = shader.shader({ QShader::DxbcShader, 50, shaderVariant }); - if (!dxbc.shader().isEmpty()) + QShaderKey key = { QShader::DxbcShader, 50, shaderVariant }; + QShaderCode dxbc = shader.shader(key); + if (!dxbc.shader().isEmpty()) { + if (usedShaderKey) + *usedShaderKey = key; return dxbc.shader(); + } - const QShaderKey key = { QShader::HlslShader, 50, shaderVariant }; + key = { QShader::HlslShader, 50, shaderVariant }; QShaderCode hlslSource = shader.shader(key); if (hlslSource.shader().isEmpty()) { qWarning() << "No HLSL (shader model 5.0) code found in baked shader" << shader; diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index f749b612b5..33412b8011 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -210,10 +210,13 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings uint generation; }; struct BoundSampledTextureData { - quint64 texId; - uint texGeneration; - quint64 samplerId; - uint samplerGeneration; + int count; + struct { + quint64 texId; + uint texGeneration; + quint64 samplerId; + uint samplerGeneration; + } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE]; }; struct BoundStorageImageData { quint64 id; diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index feeb65137a..3ba83464d2 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -919,10 +919,12 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind hasDynamicOffsetInSrb = true; break; case QRhiShaderResourceBinding::SampledTexture: - trackedRegisterTexture(&passResTracker, - QRHI_RES(QGles2Texture, b->u.stex.tex), - QRhiPassResourceTracker::TexSample, - QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage)); + for (int elem = 0; elem < b->u.stex.count; ++elem) { + trackedRegisterTexture(&passResTracker, + QRHI_RES(QGles2Texture, b->u.stex.texSamplers[elem].tex), + QRhiPassResourceTracker::TexSample, + QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage)); + } break; case QRhiShaderResourceBinding::ImageLoad: case QRhiShaderResourceBinding::ImageStore: @@ -2574,36 +2576,37 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC break; case QRhiShaderResourceBinding::SampledTexture: { - QGles2Texture *texD = QRHI_RES(QGles2Texture, b->u.stex.tex); - QGles2Sampler *samplerD = QRHI_RES(QGles2Sampler, b->u.stex.sampler); QVector &samplers(maybeGraphicsPs ? QRHI_RES(QGles2GraphicsPipeline, maybeGraphicsPs)->samplers : QRHI_RES(QGles2ComputePipeline, maybeComputePs)->samplers); - - for (QGles2SamplerDescription &sampler : samplers) { - if (sampler.binding == b->binding) { - f->glActiveTexture(GL_TEXTURE0 + uint(texUnit)); - f->glBindTexture(texD->target, texD->texture); - - if (texD->samplerState != samplerD->d) { - f->glTexParameteri(texD->target, GL_TEXTURE_MIN_FILTER, GLint(samplerD->d.glminfilter)); - f->glTexParameteri(texD->target, GL_TEXTURE_MAG_FILTER, GLint(samplerD->d.glmagfilter)); - f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_S, GLint(samplerD->d.glwraps)); - f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_T, GLint(samplerD->d.glwrapt)); - // 3D textures not supported by GLES 2.0 or by us atm... - //f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_R, samplerD->d.glwrapr); - if (caps.textureCompareMode) { - if (samplerD->d.gltexcomparefunc != GL_NEVER) { - f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_FUNC, GLint(samplerD->d.gltexcomparefunc)); - } else { - f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_MODE, GL_NONE); + for (int elem = 0; elem < b->u.stex.count; ++elem) { + QGles2Texture *texD = QRHI_RES(QGles2Texture, b->u.stex.texSamplers[elem].tex); + QGles2Sampler *samplerD = QRHI_RES(QGles2Sampler, b->u.stex.texSamplers[elem].sampler); + for (QGles2SamplerDescription &sampler : samplers) { + if (sampler.binding == b->binding) { + f->glActiveTexture(GL_TEXTURE0 + uint(texUnit)); + f->glBindTexture(texD->target, texD->texture); + + if (texD->samplerState != samplerD->d) { + f->glTexParameteri(texD->target, GL_TEXTURE_MIN_FILTER, GLint(samplerD->d.glminfilter)); + f->glTexParameteri(texD->target, GL_TEXTURE_MAG_FILTER, GLint(samplerD->d.glmagfilter)); + f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_S, GLint(samplerD->d.glwraps)); + f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_T, GLint(samplerD->d.glwrapt)); + // 3D textures not supported by GLES 2.0 or by us atm... + //f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_R, samplerD->d.glwrapr); + if (caps.textureCompareMode) { + if (samplerD->d.gltexcomparefunc != GL_NEVER) { + f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_FUNC, GLint(samplerD->d.gltexcomparefunc)); + } else { + f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } } + texD->samplerState = samplerD->d; } - texD->samplerState = samplerD->d; - } - f->glUniform1i(sampler.glslLocation, texUnit); - ++texUnit; + f->glUniform1i(sampler.glslLocation + elem, texUnit); + ++texUnit; + } } } } diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 314c58b0b7..0806c8a052 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -748,30 +748,33 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD break; case QRhiShaderResourceBinding::SampledTexture: { - QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex); - QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler); - if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - const int nativeBindingTexture = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture); - const int nativeBindingSampler = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler); - if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) { - res[VERTEX].textures.append({ nativeBindingTexture, texD->d->tex }); - res[VERTEX].samplers.append({ nativeBindingSampler, samplerD->d->samplerState }); + const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex; + for (int elem = 0; elem < data->count; ++elem) { + QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.texSamplers[elem].tex); + QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.texSamplers[elem].sampler); + if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { + const int nativeBindingTexture = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture); + const int nativeBindingSampler = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler); + if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) { + res[VERTEX].textures.append({ nativeBindingTexture + elem, texD->d->tex }); + res[VERTEX].samplers.append({ nativeBindingSampler + elem, samplerD->d->samplerState }); + } } - } - if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - const int nativeBindingTexture = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture); - const int nativeBindingSampler = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler); - if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) { - res[FRAGMENT].textures.append({ nativeBindingTexture, texD->d->tex }); - res[FRAGMENT].samplers.append({ nativeBindingSampler, samplerD->d->samplerState }); + if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { + const int nativeBindingTexture = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture); + const int nativeBindingSampler = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler); + if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) { + res[FRAGMENT].textures.append({ nativeBindingTexture + elem, texD->d->tex }); + res[FRAGMENT].samplers.append({ nativeBindingSampler + elem, samplerD->d->samplerState }); + } } - } - if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - const int nativeBindingTexture = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture); - const int nativeBindingSampler = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler); - if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) { - res[COMPUTE].textures.append({ nativeBindingTexture, texD->d->tex }); - res[COMPUTE].samplers.append({ nativeBindingSampler, samplerD->d->samplerState }); + if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { + const int nativeBindingTexture = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture); + const int nativeBindingSampler = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler); + if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) { + res[COMPUTE].textures.append({ nativeBindingTexture + elem, texD->d->tex }); + res[COMPUTE].samplers.append({ nativeBindingSampler + elem, samplerD->d->samplerState }); + } } } } @@ -1020,21 +1023,28 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind break; case QRhiShaderResourceBinding::SampledTexture: { - QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex); - QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler); - if (texD->generation != bd.stex.texGeneration - || texD->m_id != bd.stex.texId - || samplerD->generation != bd.stex.samplerGeneration - || samplerD->m_id != bd.stex.samplerId) - { + const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex; + if (bd.stex.count != data->count) { + bd.stex.count = data->count; resNeedsRebind = true; - bd.stex.texId = texD->m_id; - bd.stex.texGeneration = texD->generation; - bd.stex.samplerId = samplerD->m_id; - bd.stex.samplerGeneration = samplerD->generation; } - texD->lastActiveFrameSlot = currentFrameSlot; - samplerD->lastActiveFrameSlot = currentFrameSlot; + for (int elem = 0; elem < data->count; ++elem) { + QMetalTexture *texD = QRHI_RES(QMetalTexture, data->texSamplers[elem].tex); + QMetalSampler *samplerD = QRHI_RES(QMetalSampler, data->texSamplers[elem].sampler); + if (texD->generation != bd.stex.d[elem].texGeneration + || texD->m_id != bd.stex.d[elem].texId + || samplerD->generation != bd.stex.d[elem].samplerGeneration + || samplerD->m_id != bd.stex.d[elem].samplerId) + { + resNeedsRebind = true; + bd.stex.d[elem].texId = texD->m_id; + bd.stex.d[elem].texGeneration = texD->generation; + bd.stex.d[elem].samplerId = samplerD->m_id; + bd.stex.d[elem].samplerGeneration = samplerD->generation; + } + texD->lastActiveFrameSlot = currentFrameSlot; + samplerD->lastActiveFrameSlot = currentFrameSlot; + } } break; case QRhiShaderResourceBinding::ImageLoad: @@ -2981,12 +2991,16 @@ bool QMetalShaderResourceBindings::build() break; case QRhiShaderResourceBinding::SampledTexture: { - QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex); - QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler); - bd.stex.texId = texD->m_id; - bd.stex.texGeneration = texD->generation; - bd.stex.samplerId = samplerD->m_id; - bd.stex.samplerGeneration = samplerD->generation; + const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex; + bd.stex.count = data->count; + for (int elem = 0; elem < data->count; ++elem) { + QMetalTexture *texD = QRHI_RES(QMetalTexture, data->texSamplers[elem].tex); + QMetalSampler *samplerD = QRHI_RES(QMetalSampler, data->texSamplers[elem].sampler); + bd.stex.d[elem].texId = texD->m_id; + bd.stex.d[elem].texGeneration = texD->generation; + bd.stex.d[elem].samplerId = samplerD->m_id; + bd.stex.d[elem].samplerGeneration = samplerD->generation; + } } break; case QRhiShaderResourceBinding::ImageLoad: @@ -3241,8 +3255,12 @@ static inline MTLCullMode toMetalCullMode(QRhiGraphicsPipeline::CullMode c) id QRhiMetalData::createMetalLib(const QShader &shader, QShader::Variant shaderVariant, QString *error, QByteArray *entryPoint, QShaderKey *activeKey) { - QShaderKey key = { QShader::MetalLibShader, 12, shaderVariant }; + QShaderKey key = { QShader::MetalLibShader, 20, shaderVariant }; QShaderCode mtllib = shader.shader(key); + if (mtllib.shader().isEmpty()) { + key.setSourceVersion(12); + mtllib = shader.shader(key); + } if (!mtllib.shader().isEmpty()) { dispatch_data_t data = dispatch_data_create(mtllib.shader().constData(), size_t(mtllib.shader().size()), @@ -3261,16 +3279,20 @@ id QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var } } - key = { QShader::MslShader, 12, shaderVariant }; + key = { QShader::MslShader, 20, shaderVariant }; QShaderCode mslSource = shader.shader(key); if (mslSource.shader().isEmpty()) { - qWarning() << "No MSL 1.2 code found in baked shader" << shader; + key.setSourceVersion(12); + mslSource = shader.shader(key); + } + if (mslSource.shader().isEmpty()) { + qWarning() << "No MSL 2.0 or 1.2 code found in baked shader" << shader; return nil; } NSString *src = [NSString stringWithUTF8String: mslSource.shader().constData()]; MTLCompileOptions *opts = [[MTLCompileOptions alloc] init]; - opts.languageVersion = MTLLanguageVersion1_2; + opts.languageVersion = key.sourceVersion() == 20 ? MTLLanguageVersion2_0 : MTLLanguageVersion1_2; NSError *err = nil; id lib = [dev newLibraryWithSource: src options: opts error: &err]; [opts release]; diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index a5af5611a6..cb4b777d88 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -197,10 +197,13 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings uint generation; }; struct BoundSampledTextureData { - quint64 texId; - uint texGeneration; - quint64 samplerId; - uint samplerGeneration; + int count; + struct { + quint64 texId; + uint texGeneration; + quint64 samplerId; + uint samplerGeneration; + } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE]; }; struct BoundStorageImageData { quint64 id; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index a92c3e14e9..ca913475a5 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -2487,7 +2487,8 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i QVkShaderResourceBindings *srbD = QRHI_RES(QVkShaderResourceBindings, srb); QVarLengthArray bufferInfos; - QVarLengthArray imageInfos; + using ArrayOfImageDesc = QVarLengthArray; + QVarLengthArray imageInfos; QVarLengthArray writeInfos; QVarLengthArray, 12> infoIndices; @@ -2530,17 +2531,22 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i break; case QRhiShaderResourceBinding::SampledTexture: { - QVkTexture *texD = QRHI_RES(QVkTexture, b->u.stex.tex); - QVkSampler *samplerD = QRHI_RES(QVkSampler, b->u.stex.sampler); + const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex; + writeInfo.descriptorCount = data->count; // arrays of combined image samplers are supported writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bd.stex.texId = texD->m_id; - bd.stex.texGeneration = texD->generation; - bd.stex.samplerId = samplerD->m_id; - bd.stex.samplerGeneration = samplerD->generation; - VkDescriptorImageInfo imageInfo; - imageInfo.sampler = samplerD->sampler; - imageInfo.imageView = texD->imageView; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + ArrayOfImageDesc imageInfo(data->count); + for (int elem = 0; elem < data->count; ++elem) { + QVkTexture *texD = QRHI_RES(QVkTexture, data->texSamplers[elem].tex); + QVkSampler *samplerD = QRHI_RES(QVkSampler, data->texSamplers[elem].sampler); + bd.stex.d[elem].texId = texD->m_id; + bd.stex.d[elem].texGeneration = texD->generation; + bd.stex.d[elem].samplerId = samplerD->m_id; + bd.stex.d[elem].samplerGeneration = samplerD->generation; + imageInfo[elem].sampler = samplerD->sampler; + imageInfo[elem].imageView = texD->imageView; + imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + bd.stex.count = data->count; imageInfoIndex = imageInfos.count(); imageInfos.append(imageInfo); } @@ -2555,10 +2561,10 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; bd.simage.id = texD->m_id; bd.simage.generation = texD->generation; - VkDescriptorImageInfo imageInfo; - imageInfo.sampler = VK_NULL_HANDLE; - imageInfo.imageView = view; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + ArrayOfImageDesc imageInfo(1); + imageInfo[0].sampler = VK_NULL_HANDLE; + imageInfo[0].imageView = view; + imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL; imageInfoIndex = imageInfos.count(); imageInfos.append(imageInfo); } @@ -2596,7 +2602,7 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i if (bufferInfoIndex >= 0) writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex]; else if (imageInfoIndex >= 0) - writeInfos[i].pImageInfo = &imageInfos[imageInfoIndex]; + writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData(); } df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.count()), writeInfos.constData(), 0, nullptr); @@ -4210,24 +4216,30 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin break; case QRhiShaderResourceBinding::SampledTexture: { - QVkTexture *texD = QRHI_RES(QVkTexture, b->u.stex.tex); - QVkSampler *samplerD = QRHI_RES(QVkSampler, b->u.stex.sampler); - texD->lastActiveFrameSlot = currentFrameSlot; - samplerD->lastActiveFrameSlot = currentFrameSlot; - trackedRegisterTexture(&passResTracker, texD, - QRhiPassResourceTracker::TexSample, - QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage)); - - if (texD->generation != bd.stex.texGeneration - || texD->m_id != bd.stex.texId - || samplerD->generation != bd.stex.samplerGeneration - || samplerD->m_id != bd.stex.samplerId) - { + const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex; + if (bd.stex.count != data->count) { + bd.stex.count = data->count; rewriteDescSet = true; - bd.stex.texId = texD->m_id; - bd.stex.texGeneration = texD->generation; - bd.stex.samplerId = samplerD->m_id; - bd.stex.samplerGeneration = samplerD->generation; + } + for (int elem = 0; elem < data->count; ++elem) { + QVkTexture *texD = QRHI_RES(QVkTexture, data->texSamplers[elem].tex); + QVkSampler *samplerD = QRHI_RES(QVkSampler, data->texSamplers[elem].sampler); + texD->lastActiveFrameSlot = currentFrameSlot; + samplerD->lastActiveFrameSlot = currentFrameSlot; + trackedRegisterTexture(&passResTracker, texD, + QRhiPassResourceTracker::TexSample, + QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage)); + if (texD->generation != bd.stex.d[elem].texGeneration + || texD->m_id != bd.stex.d[elem].texId + || samplerD->generation != bd.stex.d[elem].samplerGeneration + || samplerD->m_id != bd.stex.d[elem].samplerId) + { + rewriteDescSet = true; + bd.stex.d[elem].texId = texD->m_id; + bd.stex.d[elem].texGeneration = texD->generation; + bd.stex.d[elem].samplerId = samplerD->m_id; + bd.stex.d[elem].samplerGeneration = samplerD->generation; + } } } break; @@ -6065,7 +6077,10 @@ bool QVkShaderResourceBindings::build() memset(&vkbinding, 0, sizeof(vkbinding)); vkbinding.binding = uint32_t(b->binding); vkbinding.descriptorType = toVkDescriptorType(b); - vkbinding.descriptorCount = 1; // no array support yet + if (b->type == QRhiShaderResourceBinding::SampledTexture) + vkbinding.descriptorCount = b->u.stex.count; + else + vkbinding.descriptorCount = 1; vkbinding.stageFlags = toVkShaderStageFlags(b->stage); vkbindings.append(vkbinding); } diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index fd65417e75..62516e268d 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -254,10 +254,13 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings uint generation; }; struct BoundSampledTextureData { - quint64 texId; - uint texGeneration; - quint64 samplerId; - uint samplerGeneration; + int count; + struct { + quint64 texId; + uint texGeneration; + quint64 samplerId; + uint samplerGeneration; + } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE]; }; struct BoundStorageImageData { quint64 id; -- cgit v1.2.3 From b80503b377abb04d5b6f9b243fa9d1ab503c7110 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 26 Feb 2020 14:03:19 +0100 Subject: Doc: Fix \sa link for QResource::uncompressedData() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No point in linking to itself. Change-Id: Id0bf3fa6878417e541ec0997d34758b0c59e99b3 Reviewed-by: Mårten Nordheim Reviewed-by: Thiago Macieira --- src/corelib/io/qresource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index 225ee0a769..8bf63e8a63 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -732,7 +732,7 @@ const uchar *QResource::data() const \note If the data was compressed, this function will decompress every time it is called. The result is not cached between calls. - \sa uncompressedData(), size(), isCompressed(), isFile() + \sa uncompressedSize(), size(), isCompressed(), isFile() */ QByteArray QResource::uncompressedData() const -- cgit v1.2.3 From 1a9c29289a76454e8b361430dd7f025f8fdc3061 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 26 Feb 2020 14:19:18 +0100 Subject: Doc: Mark QColorSpace enum as introduced in Qt 5.15 Change-Id: Ibf2da1ebb4eb9520a2a507ed6afb89f7176391bb Reviewed-by: Allan Sandfeld Jensen --- src/corelib/kernel/qmetatype.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 662283f737..99452eb606 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -252,7 +252,7 @@ struct DefinedTypesFilter { \value QPolygon QPolygon \value QPolygonF QPolygonF \value QColor QColor - \value QColorSpace QColorSpace + \value QColorSpace QColorSpace (introduced in Qt 5.15) \value QSizeF QSizeF \value QRectF QRectF \value QLine QLine @@ -299,7 +299,7 @@ struct DefinedTypesFilter { \value QCborMap QCborMap \value QCborSimpleType QCborSimpleType \value QModelIndex QModelIndex - \value QPersistentModelIndex QPersistentModelIndex (since 5.5) + \value QPersistentModelIndex QPersistentModelIndex (introduced in Qt 5.5) \value QUuid QUuid \value QByteArrayList QByteArrayList -- cgit v1.2.3 From 2de3bfced35ae060acffc06e66e18279de6f5099 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Fri, 6 Mar 2020 09:44:05 +0100 Subject: Fix UB in QProcess deprecation warning fixes The commits e1e08629 and 66e905b1 introduced undefined behavior. Fix this by assigning the result of takeFirst to a temporary. Change-Id: I9e29412cf632d4836b95d47e12d8c07ab0645fbb Reviewed-by: Volker Hilsheimer --- src/corelib/io/qprocess.cpp | 3 ++- src/platformsupport/services/genericunix/qgenericunixservices.cpp | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 9400662b97..4500467ac2 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -2522,7 +2522,8 @@ int QProcess::execute(const QString &command) QStringList args = splitCommand(command); if (args.isEmpty()) return -2; - return execute(args.takeFirst(), args); + QString program = args.takeFirst(); + return execute(program, args); } /*! diff --git a/src/platformsupport/services/genericunix/qgenericunixservices.cpp b/src/platformsupport/services/genericunix/qgenericunixservices.cpp index 8e9923e208..b583d636c0 100644 --- a/src/platformsupport/services/genericunix/qgenericunixservices.cpp +++ b/src/platformsupport/services/genericunix/qgenericunixservices.cpp @@ -167,7 +167,11 @@ static inline bool launch(const QString &launcher, const QUrl &url) const bool ok = ::system(qPrintable(command + QLatin1String(" &"))); #else QStringList args = QProcess::splitCommand(command); - const bool ok = !args.isEmpty() && QProcess::startDetached(args.takeFirst(), args); + bool ok = false; + if (!args.isEmpty()) { + QString program = args.takeFirst(); + ok = QProcess::startDetached(program, args); + } #endif if (!ok) qWarning("Launch failed (%s)", qPrintable(command)); -- cgit v1.2.3 From 94fc977b2bcb46d7ddc206a83009dcaa7d7532d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 2 Mar 2020 12:51:15 +0100 Subject: macOS: Disable system provided tabbing by default macOS 10.12 introduced automatic window tabbing, where the OS provides tab handling on behalf of the application. The feature defaulted to being on, and the release notes asked applications that had their own tab handling to disable the automatic tab handling explicitly. Qt has its own tab handling, and should therefore disable the automatic handling. We do this on a per NSWindow basis, using the tabbingMode property of the window, instead of the global allowsAutomaticWindowTabbing property on NSWindow, so that individual windows can still opt in to the automatic tab handling. Doing it via the tabbingMode property also ensures that we're not affecting the host application's behavior in a plug-in setting. Ideally Qt's tab handling should read the userTabbingPreference property of NSWindow to pick up the system preference choice of whether to open new windows as standalone windows or tabs, but this is left for a later change. An alternative would also be to use the automatic window tabbing instead of our own implementation. Fixes: QTBUG-61707 Change-Id: Icf2078b63ec16202ff7fd83ea264a48dc61978e1 Reviewed-by: Volker Hilsheimer Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoawindow.mm | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 9cb4470e02..5edc7223b1 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1635,6 +1635,7 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel) nsWindow.restorable = NO; nsWindow.level = windowLevel(flags); + nsWindow.tabbingMode = NSWindowTabbingModeDisallowed; if (shouldBePanel) { // Qt::Tool windows hide on app deactivation, unless Qt::WA_MacAlwaysShowToolWindow is set -- cgit v1.2.3 From ccee938b5193ff90a6fecc1f4635b856a24718bd Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 5 Mar 2020 17:35:03 +0100 Subject: rhi: vulkan: Silence useless desc.set validation warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is deemed more appropriate than having some time consuming tracking of descriptor types in pools, just to avoid the rare case of attempting a failing vkAllocateDescriptorSets(), which is then always followed by another, successful attempt. Change-Id: I7a3a1d80afe400dc96605a3d6c834e8b2c71143a Reviewed-by: Christian Strømme --- src/gui/rhi/qrhivulkan.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index ca913475a5..26c153afff 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -345,6 +345,15 @@ static bool qvk_debug_filter(VkDebugReportFlagsEXT flags, VkDebugReportObjectTyp return true; } + // In certain cases allocateDescriptorSet() will attempt to allocate from a + // pool that does not have enough descriptors of a certain type. This makes + // the validation layer shout. However, this is not an error since we will + // then move on to another pool. If there is a real error, a qWarning + // message is shown by allocateDescriptorSet(), so the validation warning + // does not have any value and is just noise. + if (strstr(pMessage, "VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307")) + return true; + return false; } -- cgit v1.2.3 From 50d2acdc93b4de2ba56eb67787e2bdcb21dd4bea Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 5 Mar 2020 09:36:49 +0100 Subject: Add default arguments to QPainterPath methods using transform Fixes: QTBUG-82602 Change-Id: Id82f145ffb33e6d4ef9b81282ad14657b1c8fbd0 Reviewed-by: Qt CI Bot Reviewed-by: Lars Knoll --- src/gui/painting/qpainterpath.h | 15 +++++++++------ src/gui/painting/qrasterizer.cpp | 2 ++ src/gui/painting/qtextureglyphcache.cpp | 2 ++ src/gui/painting/qtransform.h | 5 +---- src/gui/text/qrawfont.cpp | 1 + .../fontdatabases/freetype/qfontengine_ft.cpp | 1 + .../fontdatabases/mac/qfontengine_coretext.mm | 1 + .../windows/qwindowsfontenginedirectwrite.cpp | 1 + src/plugins/styles/mac/qmacstyle_mac.mm | 1 + src/widgets/graphicsview/qgraphicsscene.cpp | 1 + src/widgets/graphicsview/qgraphicssceneindex.cpp | 1 + src/widgets/graphicsview/qgraphicsview.cpp | 1 + src/widgets/graphicsview/qgraphicswidget.cpp | 1 + src/widgets/styles/qfusionstyle.cpp | 1 + src/widgets/styles/qstylesheetstyle.cpp | 1 + src/widgets/styles/qwindowsstyle.cpp | 1 + 16 files changed, 26 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/gui/painting/qpainterpath.h b/src/gui/painting/qpainterpath.h index 26b92dc6fa..8d4bdf2e19 100644 --- a/src/gui/painting/qpainterpath.h +++ b/src/gui/painting/qpainterpath.h @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -178,15 +179,15 @@ public: #if QT_DEPRECATED_SINCE(5, 15) QT_DEPRECATED_X("Use toSubpathPolygons(const QTransform &)") - QList toSubpathPolygons(const QMatrix &matrix = QMatrix()) const; + QList toSubpathPolygons(const QMatrix &matrix) const; QT_DEPRECATED_X("Use toFillPolygons(const QTransform &") - QList toFillPolygons(const QMatrix &matrix = QMatrix()) const; + QList toFillPolygons(const QMatrix &matrix) const; QT_DEPRECATED_X("Use toFillPolygon(const QTransform &)") - QPolygonF toFillPolygon(const QMatrix &matrix = QMatrix()) const; + QPolygonF toFillPolygon(const QMatrix &matrix) const; #endif // QT_DEPRECATED_SINCE(5, 15) - QList toSubpathPolygons(const QTransform &matrix) const; - QList toFillPolygons(const QTransform &matrix) const; - QPolygonF toFillPolygon(const QTransform &matrix) const; + QList toSubpathPolygons(const QTransform &matrix = QTransform()) const; + QList toFillPolygons(const QTransform &matrix = QTransform()) const; + QPolygonF toFillPolygon(const QTransform &matrix = QTransform()) const; int elementCount() const; QPainterPath::Element elementAt(int i) const; @@ -362,6 +363,8 @@ inline void QPainterPath::translate(const QPointF &offset) inline QPainterPath QPainterPath::translated(const QPointF &offset) const { return translated(offset.x(), offset.y()); } +inline QPainterPath operator *(const QPainterPath &p, const QTransform &m) +{ return m.map(p); } #ifndef QT_NO_DEBUG_STREAM Q_GUI_EXPORT QDebug operator<<(QDebug, const QPainterPath &); diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp index cd31d75f83..f3c193d799 100644 --- a/src/gui/painting/qrasterizer.cpp +++ b/src/gui/painting/qrasterizer.cpp @@ -46,6 +46,8 @@ #include #include +#include + #include QT_BEGIN_NAMESPACE diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 91214f27ca..141b195a42 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -43,6 +43,8 @@ #include "private/qfontengine_p.h" #include "private/qnumeric_p.h" +#include + QT_BEGIN_NAMESPACE // #define CACHE_DEBUG diff --git a/src/gui/painting/qtransform.h b/src/gui/painting/qtransform.h index 485caa5140..41cbfc35f2 100644 --- a/src/gui/painting/qtransform.h +++ b/src/gui/painting/qtransform.h @@ -41,7 +41,6 @@ #include #include -#include #include #include #include @@ -51,8 +50,8 @@ QT_BEGIN_NAMESPACE - class QVariant; +class QPainterPath; class Q_GUI_EXPORT QTransform { @@ -408,8 +407,6 @@ inline QPolygonF operator *(const QPolygonF &a, const QTransform &m) { return m.map(a); } inline QRegion operator *(const QRegion &r, const QTransform &m) { return m.map(r); } -inline QPainterPath operator *(const QPainterPath &p, const QTransform &m) -{ return m.map(p); } inline QTransform operator *(const QTransform &a, qreal n) { QTransform t(a); t *= n; return t; } diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp index 884525bd76..b4b60cbaaf 100644 --- a/src/gui/text/qrawfont.cpp +++ b/src/gui/text/qrawfont.cpp @@ -51,6 +51,7 @@ #include #include +#include QT_BEGIN_NAMESPACE diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp index e65f67d4f1..7e83bcad07 100644 --- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp +++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #ifndef QT_NO_FREETYPE diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm index ce793dfafa..115b13d60d 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm @@ -45,6 +45,7 @@ #include #endif #include +#include #include #include diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp index e8f9cfb2a8..ecf6049504 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #if defined(QT_USE_DIRECTWRITE2) # include diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index d5ad1a8ca0..8e4aaa19c7 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -56,6 +56,7 @@ #include +#include #include #include #include diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp index bbcceb1ce6..b669b0fe61 100644 --- a/src/widgets/graphicsview/qgraphicsscene.cpp +++ b/src/widgets/graphicsview/qgraphicsscene.cpp @@ -233,6 +233,7 @@ #include #include #include +#include #include #include #include diff --git a/src/widgets/graphicsview/qgraphicssceneindex.cpp b/src/widgets/graphicsview/qgraphicssceneindex.cpp index c2e9cb4729..aab9068374 100644 --- a/src/widgets/graphicsview/qgraphicssceneindex.cpp +++ b/src/widgets/graphicsview/qgraphicssceneindex.cpp @@ -60,6 +60,7 @@ #include "qgraphicswidget.h" #include "qgraphicssceneindex_p.h" #include "qgraphicsscenebsptreeindex_p.h" +#include QT_BEGIN_NAMESPACE diff --git a/src/widgets/graphicsview/qgraphicsview.cpp b/src/widgets/graphicsview/qgraphicsview.cpp index a75f1ab24b..17c13e47d6 100644 --- a/src/widgets/graphicsview/qgraphicsview.cpp +++ b/src/widgets/graphicsview/qgraphicsview.cpp @@ -294,6 +294,7 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime < #include #include #include +#include #include #include diff --git a/src/widgets/graphicsview/qgraphicswidget.cpp b/src/widgets/graphicsview/qgraphicswidget.cpp index 6242314e1d..472d61d437 100644 --- a/src/widgets/graphicsview/qgraphicswidget.cpp +++ b/src/widgets/graphicsview/qgraphicswidget.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #include #include diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index ce5f084618..751ce36bb3 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -52,6 +52,7 @@ #include #endif #include +#include #include #include #include diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 1e032b237a..b07abe4f51 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -118,6 +118,7 @@ #include #endif +#include #include QT_BEGIN_NAMESPACE diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 4965d146b0..e275e3a714 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -78,6 +78,7 @@ #endif #include #include +#include #include #include #include -- cgit v1.2.3 From 114394702b2975b5d890833a5f14510b5e1a2e2b Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Wed, 26 Feb 2020 19:35:06 +0100 Subject: QtSql/ODBC: allow table names with unicode chars The ODBC driver did not properly decode table names with unicode chars. Fix it by explicitly passing the unicode flag to qGetStringData(). Fixes: QTBUG-82401 Change-Id: Id6eb44cc85ce196ea97d0d6aef1cd573fa033970 Reviewed-by: Andy Shaw --- src/plugins/sqldrivers/odbc/qsql_odbc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp index 8e996d0ded..88f1c74028 100644 --- a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp +++ b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp @@ -2379,7 +2379,7 @@ QStringList QODBCDriver::tables(QSql::TableType type) const } while (r == SQL_SUCCESS) { - QString fieldVal = qGetStringData(hStmt, 2, -1, false); + QString fieldVal = qGetStringData(hStmt, 2, -1, d->unicode); tl.append(fieldVal); if (d->hasSQLFetchScroll) -- cgit v1.2.3 From 4bc9e3b8470ed2026604dc06dc027c80e6f7c445 Mon Sep 17 00:00:00 2001 From: David Faure Date: Fri, 28 Feb 2020 20:00:24 +0100 Subject: QDataStream: fix compilation with QT_DISABLE_DEPRECATED_BEFORE=0x0050F00 Fixes: QTBUG-81023 Change-Id: I0d56785d1fed2c4c8e0e87ccefb0b72b0ed3644a Reviewed-by: Giuseppe D'Angelo --- src/corelib/serialization/qdatastream.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h index 4d827772c8..6f6593f9bf 100644 --- a/src/corelib/serialization/qdatastream.h +++ b/src/corelib/serialization/qdatastream.h @@ -285,6 +285,13 @@ QDataStream &readListBasedContainer(QDataStream &s, Container &c) return s; } +template +struct MultiContainer { using type = T; }; +template +struct MultiContainer> { using type = QMultiMap; }; +template +struct MultiContainer> { using type = QMultiHash; }; + template QDataStream &readAssociativeContainer(QDataStream &s, Container &c) { @@ -301,10 +308,7 @@ QDataStream &readAssociativeContainer(QDataStream &s, Container &c) c.clear(); break; } -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED - c.insertMulti(k, t); -QT_WARNING_POP + static_cast::type &>(c).insert(k, t); } return s; -- cgit v1.2.3 From 20167a7fe9c1e62881d1673ad05a9779e614d9d3 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 4 Mar 2020 10:53:14 +0100 Subject: WinRT: Use the fallbacks for getting the save file name To bring it in line with the other platforms, then it needs to check if the initially selected files are set and use the first one. Otherwise it can fall back to the initial directory if that happens to include a filename. Change-Id: If34ae0e7e10b6a3c25e9422d9b4f2c21e6bfc8d1 Reviewed-by: Maurice Kalinowski Reviewed-by: Oliver Wolff --- src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp index 114d6dacd8..fee8063f13 100644 --- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp +++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp @@ -397,7 +397,15 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit RETURN_FALSE_IF_FAILED_WITH_ARGS("Failed to set default file extension \"%s\"", qPrintable(suffix)); } - const QString suggestedName = QFileInfo(d->saveFileName.toLocalFile()).fileName(); + QString suggestedName = QFileInfo(d->saveFileName.toLocalFile()).fileName(); + if (suggestedName.isEmpty() && dialogOptions->initiallySelectedFiles().size() > 0) + suggestedName = QFileInfo(dialogOptions->initiallySelectedFiles().first().toLocalFile()) + .fileName(); + if (suggestedName.isEmpty()) { + const auto fileInfo = QFileInfo(dialogOptions->initialDirectory().toLocalFile()); + if (!fileInfo.isDir()) + suggestedName = fileInfo.fileName(); + } if (!suggestedName.isEmpty()) { HStringReference nativeSuggestedName(reinterpret_cast(suggestedName.utf16()), uint(suggestedName.length())); -- cgit v1.2.3 From 2097932dc54b3ef9a369da956704733792e965b3 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 6 Mar 2020 15:51:29 +0100 Subject: Document how to use CMake for Qt Network Add documentation on how to use a module from CMake, alongside the existing documentation about qmake. While at it, also remove the mentioning of the central include; It is not something we should actively advocate anymore. Instead, the documentation of every class gives the correct include to use. Task-number: QTBUG-73058 Change-Id: I71ed5a62f4f0a6d868dd1f84ea39e5ac385a2fb8 Reviewed-by: Leena Miettinen --- src/network/doc/qtnetwork.qdocconf | 2 +- src/network/doc/snippets/CMakeLists.txt | 12 +++++++++ .../doc/snippets/code/doc_src_qtnetwork.pro | 3 --- src/network/doc/snippets/network/tcpwait.cpp | 2 +- src/network/doc/snippets/snippets.pro | 2 ++ src/network/doc/src/qtnetwork.qdoc | 30 ++++++++-------------- 6 files changed, 26 insertions(+), 25 deletions(-) create mode 100644 src/network/doc/snippets/CMakeLists.txt delete mode 100644 src/network/doc/snippets/code/doc_src_qtnetwork.pro (limited to 'src') diff --git a/src/network/doc/qtnetwork.qdocconf b/src/network/doc/qtnetwork.qdocconf index 5465b1c0af..8c7f3fc912 100644 --- a/src/network/doc/qtnetwork.qdocconf +++ b/src/network/doc/qtnetwork.qdocconf @@ -27,7 +27,7 @@ qhp.QtNetwork.subprojects.classes.sortPages = true tagfile = ../../../doc/qtnetwork/qtnetwork.tags -depends += qtcore qtgui qtdoc qmake +depends += qtcore qtgui qtdoc qmake qtcmake headerdirs += .. diff --git a/src/network/doc/snippets/CMakeLists.txt b/src/network/doc/snippets/CMakeLists.txt new file mode 100644 index 0000000000..a8030dd260 --- /dev/null +++ b/src/network/doc/snippets/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.1.0) + +project(network_cppsnippets) + +add_executable(mytarget + network/tcpwait.cpp +) + +# ![0] +find_package(Qt5 COMPONENTS Network REQUIRED) +target_link_libraries(mytarget Qt5::Network) +# ![0] diff --git a/src/network/doc/snippets/code/doc_src_qtnetwork.pro b/src/network/doc/snippets/code/doc_src_qtnetwork.pro deleted file mode 100644 index a100943e58..0000000000 --- a/src/network/doc/snippets/code/doc_src_qtnetwork.pro +++ /dev/null @@ -1,3 +0,0 @@ -#! [0] -QT += network -#! [0] diff --git a/src/network/doc/snippets/network/tcpwait.cpp b/src/network/doc/snippets/network/tcpwait.cpp index d57305930c..b81c5c1d53 100644 --- a/src/network/doc/snippets/network/tcpwait.cpp +++ b/src/network/doc/snippets/network/tcpwait.cpp @@ -48,7 +48,7 @@ ** ****************************************************************************/ -#include +#include #include int main(int argv, char **args) diff --git a/src/network/doc/snippets/snippets.pro b/src/network/doc/snippets/snippets.pro index 39153e0c8e..bdf854e454 100644 --- a/src/network/doc/snippets/snippets.pro +++ b/src/network/doc/snippets/snippets.pro @@ -2,6 +2,8 @@ TEMPLATE = app TARGET = network_cppsnippets +# ![0] QT += network +# ![0] SOURCES += network/tcpwait.cpp diff --git a/src/network/doc/src/qtnetwork.qdoc b/src/network/doc/src/qtnetwork.qdoc index 85a3c198a0..57b0210b7f 100644 --- a/src/network/doc/src/qtnetwork.qdoc +++ b/src/network/doc/src/qtnetwork.qdoc @@ -34,19 +34,16 @@ TCP/IP. Operations such as requests, cookies, and sending data over HTTP are handled by various C++ classes. - \section1 Getting Started + \include module-use.qdocinc using qt module + \snippet CMakeLists.txt 0 - To use Qt Network classes,add this directive into the C++ files: - \code - #include - \endcode + See also the \l{Build with CMake} overview. - \if !defined(qtforpython) - To link against the Qt Network module, add this line to the project file: - \code - QT += network - \endcode - \endif + \section2 Building with qmake + + Add \c network to the \c QT variable: + + \snippet snippets.pro 0 \section1 Articles and Guides @@ -100,13 +97,6 @@ \qtvariable network \brief Provides classes to make network programming easier and portable. - To include the definitions of the module's classes, use the - following directive: - - \snippet code/doc_src_qtnetwork.cpp 1 - - To link against the module, add this line to your \l qmake \c - .pro file: - - \snippet code/doc_src_qtnetwork.pro 0 + Qt Network provides a set of APIs for programming applications that use + TCP/IP. See the \l{Qt Network} overview for more information. */ -- cgit v1.2.3 From cc59f0de557e2d8fba274a86ba43afc4ffcd935b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 2 Mar 2020 16:10:35 +0100 Subject: macOS: Support printing when no printers are installed Even if there are no printers installed, we can still show the print dialog, which gives the user feedback about no printers being installed, allows them to install one, or allows them to print to PDF as a fallback. The code for printing to PDF has been re-enabled, and the conditions of QTBUG-38820 have been removed as the problem is no longer present. The code also takes into account the possibility that the user chose to print to PostScript, which we don't yet support, but warn about. We now also support opening the printed document in Preview. This requires a minor assumption about the print operation being done synchronously after the print dialog is accepted, but this is something we can improve in the future with internal APIs if it turns out to be a problem. Printing workflows such as sending the printed document via mail or messenger are not not supported, and will give a warning. Fixes: QTBUG-36112 Change-Id: I8ba9e2c5ce31a5a06542c4a7126d005e4b27f2be Reviewed-by: Andy Shaw --- src/printsupport/dialogs/qprintdialog_mac.mm | 72 ++++++++++++++-------------- 1 file changed, 37 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/printsupport/dialogs/qprintdialog_mac.mm b/src/printsupport/dialogs/qprintdialog_mac.mm index ed2d0908c4..a4101f7ec0 100644 --- a/src/printsupport/dialogs/qprintdialog_mac.mm +++ b/src/printsupport/dialogs/qprintdialog_mac.mm @@ -42,6 +42,7 @@ #include "qprintdialog.h" #include "qabstractprintdialog_p.h" +#include #include #include #include @@ -127,21 +128,36 @@ QT_USE_NAMESPACE PMDestinationType dest; PMSessionGetDestinationType(session, settings, &dest); if (dest == kPMDestinationFile) { - // QTBUG-38820 - // If user selected Print to File, leave OSX to generate the PDF, - // otherwise setting PdfFormat would prevent us showing dialog again. - // TODO Restore this when QTBUG-36112 is fixed. - /* QCFType file; PMSessionCopyDestinationLocation(session, settings, &file); UInt8 localFile[2048]; // Assuming there's a POSIX file system here. CFURLGetFileSystemRepresentation(file, true, localFile, sizeof(localFile)); - printer->setOutputFileName(QString::fromUtf8(reinterpret_cast(localFile))); - */ - } else { + auto outputFile = QFileInfo(QString::fromUtf8(reinterpret_cast(localFile))); + if (outputFile.suffix() == QLatin1String("pdf")) + printer->setOutputFileName(outputFile.absoluteFilePath()); + else + qWarning() << "Can not print to file type" << outputFile.suffix(); + } else if (dest == kPMDestinationPreview) { + static QTemporaryDir printPreviews; + auto documentName = printer->docName(); + if (documentName.isEmpty()) + documentName = QGuiApplication::applicationDisplayName(); + auto fileName = printPreviews.filePath(QString(QLatin1String("%1.pdf")).arg(documentName)); + printer->setOutputFileName(fileName); + // Ideally we would have a callback when the PDF engine is done writing + // to the file, and open Preview in response to that. Lacking that, we + // use the quick and dirty assumption that the the print operation will + // happen synchronously after the dialog is accepted, so we can defer + // the opening of the file to the next runloop pass. + dispatch_async(dispatch_get_main_queue(), ^{ + [NSWorkspace.sharedWorkspace openFile:fileName.toNSString()]; + }); + } else if (dest == kPMDestinationProcessPDF) { + qWarning("Printing workflows are not supported"); + } else if (dest == kPMDestinationPrinter) { PMPrinter macPrinter; PMSessionGetCurrentPrinter(session, &macPrinter); - QString printerId = QString::fromCFString(PMPrinterGetID(macPrinter)); + QString printerId = QString::fromCFString(PMPrinterGetID(macPrinter)).trimmed(); if (printer->printerName() != printerId) printer->setPrinterName(printerId); } @@ -199,14 +215,18 @@ void QPrintDialogPrivate::openCocoaPrintPanel(Qt::WindowModality modality) { Q_Q(QPrintDialog); - // get the NSPrintInfo from the print engine in the platform plugin - void *voidp = 0; - (void) QMetaObject::invokeMethod(qApp->platformNativeInterface(), - "NSPrintInfoForPrintEngine", - Q_RETURN_ARG(void *, voidp), - Q_ARG(QPrintEngine *, printer->printEngine())); - printInfo = static_cast(voidp); - [printInfo retain]; + if (printer->outputFormat() == QPrinter::NativeFormat) { + // get the NSPrintInfo from the print engine in the platform plugin + void *voidp = 0; + (void) QMetaObject::invokeMethod(qApp->platformNativeInterface(), + "NSPrintInfoForPrintEngine", + Q_RETURN_ARG(void *, voidp), + Q_ARG(QPrintEngine *, printer->printEngine())); + printInfo = static_cast(voidp); + [printInfo retain]; + } else { + printInfo = [NSPrintInfo.sharedPrintInfo retain]; + } // It seems the only way that PM lets you use all is if the minimum // for the page range is 1. This _kind of_ makes sense if you think about @@ -269,31 +289,15 @@ void QPrintDialogPrivate::closeCocoaPrintPanel() printPanel = 0; } -static bool warnIfNotNative(QPrinter *printer) -{ - if (printer->outputFormat() != QPrinter::NativeFormat) { - qWarning("QPrintDialog: Cannot be used on non-native printers"); - return false; - } - return true; -} - - QPrintDialog::QPrintDialog(QPrinter *printer, QWidget *parent) : QAbstractPrintDialog(*(new QPrintDialogPrivate), printer, parent) { - Q_D(QPrintDialog); - if (!warnIfNotNative(d->printer)) - return; setAttribute(Qt::WA_DontShowOnScreen); } QPrintDialog::QPrintDialog(QWidget *parent) : QAbstractPrintDialog(*(new QPrintDialogPrivate), 0, parent) { - Q_D(QPrintDialog); - if (!warnIfNotNative(d->printer)) - return; setAttribute(Qt::WA_DontShowOnScreen); } @@ -304,8 +308,6 @@ QPrintDialog::~QPrintDialog() int QPrintDialog::exec() { Q_D(QPrintDialog); - if (!warnIfNotNative(d->printer)) - return QDialog::Rejected; QDialog::setVisible(true); -- cgit v1.2.3 From 332816779c42e8a3fed34e9295c09338bc9b4945 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Fri, 22 Nov 2019 13:02:31 +0100 Subject: Multithread some QImage routines Use QThreadPool to process QImage smooth-scaling, format conversions, and colorspace transforms multithreaded. Change-Id: Ic142b1fa899f56e7e5099d36ca713701a47b681b Reviewed-by: Lars Knoll --- src/gui/image/qimage.cpp | 46 +- src/gui/image/qimage_conversions.cpp | 209 ++++++--- src/gui/painting/qimagescale.cpp | 794 ++++++++++++++++++++++------------ src/gui/painting/qimagescale_neon.cpp | 218 ++++++---- src/gui/painting/qimagescale_p.h | 2 + src/gui/painting/qimagescale_sse4.cpp | 246 +++++++---- 6 files changed, 996 insertions(+), 519 deletions(-) (limited to 'src') diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index ec72180f0d..2646d298e9 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -69,6 +69,11 @@ #include #include +#if QT_CONFIG(thread) +#include "qsemaphore.h" +#include "qthreadpool.h" +#endif + QT_BEGIN_NAMESPACE static inline bool isLocked(QImageData *data) @@ -5024,18 +5029,43 @@ void QImage::applyColorTransform(const QColorTransform &transform) Q_UNREACHABLE(); } + std::function transformSegment; + if (depth() > 32) { - for (int i = 0; i < height(); ++i) { - QRgba64 *scanline = reinterpret_cast(scanLine(i)); - transform.d->apply(scanline, scanline, width(), flags); - } + transformSegment = [&](int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + QRgba64 *scanline = reinterpret_cast(scanLine(y)); + transform.d->apply(scanline, scanline, width(), flags); + } + }; } else { - for (int i = 0; i < height(); ++i) { - QRgb *scanline = reinterpret_cast(scanLine(i)); - transform.d->apply(scanline, scanline, width(), flags); - } + transformSegment = [&](int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + QRgb *scanline = reinterpret_cast(scanLine(y)); + transform.d->apply(scanline, scanline, width(), flags); + } + }; } +#if QT_CONFIG(thread) + int segments = sizeInBytes() / (1<<16); + segments = std::min(segments, height()); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (height() - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + transformSegment(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + } else +#endif + transformSegment(0, height()); + if (oldFormat != format()) *this = std::move(*this).convertToFormat(oldFormat); } diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 27088698ec..4f570d8684 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -43,7 +43,12 @@ #include #include #include + #include +#if QT_CONFIG(thread) +#include +#include +#endif QT_BEGIN_NAMESPACE @@ -159,12 +164,8 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio // Cannot be used with indexed formats. Q_ASSERT(dest->format > QImage::Format_Indexed8); Q_ASSERT(src->format > QImage::Format_Indexed8); - uint buf[BufferSize]; - uint *buffer = buf; const QPixelLayout *srcLayout = &qPixelLayouts[src->format]; const QPixelLayout *destLayout = &qPixelLayouts[dest->format]; - const uchar *srcData = src->data; - uchar *destData = dest->data; FetchAndConvertPixelsFunc fetch = srcLayout->fetchToARGB32PM; ConvertAndStorePixelsFunc store = destLayout->storeFromARGB32PM; @@ -197,59 +198,110 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio else store = destLayout->storeFromRGB32; } - QDitherInfo dither; - QDitherInfo *ditherPtr = nullptr; - if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither) - ditherPtr = &dither; - - for (int y = 0; y < src->height; ++y) { - dither.y = y; - int x = 0; - while (x < src->width) { - dither.x = x; - int l = src->width - x; - if (destLayout->bpp == QPixelLayout::BPP32) - buffer = reinterpret_cast(destData) + x; - else - l = qMin(l, BufferSize); - const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr); - store(destData, ptr, x, l, nullptr, ditherPtr); - x += l; + + auto convertSegment = [=](int yStart, int yEnd) { + uint buf[BufferSize]; + uint *buffer = buf; + const uchar *srcData = src->data + src->bytes_per_line * yStart; + uchar *destData = dest->data + dest->bytes_per_line * yStart; + QDitherInfo dither; + QDitherInfo *ditherPtr = nullptr; + if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither) + ditherPtr = &dither; + for (int y = yStart; y < yEnd; ++y) { + dither.y = y; + int x = 0; + while (x < src->width) { + dither.x = x; + int l = src->width - x; + if (destLayout->bpp == QPixelLayout::BPP32) + buffer = reinterpret_cast(destData) + x; + else + l = qMin(l, BufferSize); + const uint *ptr = fetch(buffer, srcData, x, l, 0, ditherPtr); + store(destData, ptr, x, l, 0, ditherPtr); + x += l; + } + srcData += src->bytes_per_line; + destData += dest->bytes_per_line; } - srcData += src->bytes_per_line; - destData += dest->bytes_per_line; - } + }; + +#if QT_CONFIG(thread) + int segments = src->nbytes / (1<<16); + segments = std::min(segments, src->height); + + if (segments <= 1) + return convertSegment(0, src->height); + + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (src->height - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + convertSegment(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); +#else + convertSegment(0, src->height); +#endif } void convert_generic_to_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(dest->format > QImage::Format_Indexed8); Q_ASSERT(src->format > QImage::Format_Indexed8); - QRgba64 buf[BufferSize]; - QRgba64 *buffer = buf; const QPixelLayout *srcLayout = &qPixelLayouts[src->format]; const QPixelLayout *destLayout = &qPixelLayouts[dest->format]; - const uchar *srcData = src->data; - uchar *destData = dest->data; const FetchAndConvertPixelsFunc64 fetch = srcLayout->fetchToRGBA64PM; const ConvertAndStorePixelsFunc64 store = qStoreFromRGBA64PM[dest->format]; - for (int y = 0; y < src->height; ++y) { - int x = 0; - while (x < src->width) { - int l = src->width - x; - if (destLayout->bpp == QPixelLayout::BPP64) - buffer = reinterpret_cast(destData) + x; - else - l = qMin(l, BufferSize); - const QRgba64 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr); - store(destData, ptr, x, l, nullptr, nullptr); - x += l; + auto convertSegment = [=](int yStart, int yEnd) { + QRgba64 buf[BufferSize]; + QRgba64 *buffer = buf; + const uchar *srcData = src->data + yStart * src->bytes_per_line; + uchar *destData = dest->data + yStart * dest->bytes_per_line; + for (int y = yStart; y < yEnd; ++y) { + int x = 0; + while (x < src->width) { + int l = src->width - x; + if (destLayout->bpp == QPixelLayout::BPP64) + buffer = reinterpret_cast(destData) + x; + else + l = qMin(l, BufferSize); + const QRgba64 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr); + store(destData, ptr, x, l, nullptr, nullptr); + x += l; + } + srcData += src->bytes_per_line; + destData += dest->bytes_per_line; } - srcData += src->bytes_per_line; - destData += dest->bytes_per_line; - } + }; +#if QT_CONFIG(thread) + int segments = src->nbytes / (1<<16); + segments = std::min(segments, src->height); + + if (segments <= 1) + return convertSegment(0, src->height); + + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (src->height - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + convertSegment(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); +#else + convertSegment(0, src->height); +#endif } bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags flags) @@ -270,11 +322,6 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im && qt_highColorPrecision(dst_format, !srcLayout->hasAlphaChannel)) return false; - uint buf[BufferSize]; - uint *buffer = buf; - uchar *srcData = data->data; - uchar *destData = data->data; - QImageData::ImageSizeParameters params = { data->bytes_per_line, data->nbytes }; if (data->depth != destDepth) { params = QImageData::calculateImageParameters(data->width, data->height, destDepth); @@ -313,28 +360,52 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im else store = destLayout->storeFromRGB32; } - QDitherInfo dither; - QDitherInfo *ditherPtr = nullptr; - if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither) - ditherPtr = &dither; - - for (int y = 0; y < data->height; ++y) { - dither.y = y; - int x = 0; - while (x < data->width) { - dither.x = x; - int l = data->width - x; - if (srcLayout->bpp == QPixelLayout::BPP32) - buffer = reinterpret_cast(srcData) + x; - else - l = qMin(l, BufferSize); - const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr); - store(destData, ptr, x, l, nullptr, ditherPtr); - x += l; + + auto convertSegment = [=](int yStart, int yEnd) { + uint buf[BufferSize]; + uint *buffer = buf; + uchar *srcData = data->data + data->bytes_per_line * yStart; + uchar *destData = srcData; + QDitherInfo dither; + QDitherInfo *ditherPtr = nullptr; + if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither) + ditherPtr = &dither; + for (int y = yStart; y < yEnd; ++y) { + dither.y = y; + int x = 0; + while (x < data->width) { + dither.x = x; + int l = data->width - x; + if (srcLayout->bpp == QPixelLayout::BPP32) + buffer = reinterpret_cast(srcData) + x; + else + l = qMin(l, BufferSize); + const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr); + store(destData, ptr, x, l, nullptr, ditherPtr); + x += l; + } + srcData += data->bytes_per_line; + destData += params.bytesPerLine; } - srcData += data->bytes_per_line; - destData += params.bytesPerLine; - } + }; +#if QT_CONFIG(thread) + int segments = data->nbytes / (1<<16); + segments = std::min(segments, data->height); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (data->height - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + convertSegment(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + } else +#endif + convertSegment(0, data->height); if (params.totalSize != data->nbytes) { Q_ASSERT(params.totalSize < data->nbytes); void *newData = realloc(data->data, params.totalSize); diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp index 2e2f65b483..ecb0230e71 100644 --- a/src/gui/painting/qimagescale.cpp +++ b/src/gui/painting/qimagescale.cpp @@ -43,6 +43,11 @@ #include "qcolor.h" #include "qrgba64_p.h" +#if QT_CONFIG(thread) +#include "qsemaphore.h" +#include "qthreadpool.h" +#endif + QT_BEGIN_NAMESPACE /* @@ -239,6 +244,8 @@ static QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img, isi = new QImageScaleInfo; if (!isi) return nullptr; + isi->sh = sh; + isi->sw = sw; isi->xup_yup = (qAbs(dw) >= sw) + ((qAbs(dh) >= sh) << 1); @@ -303,33 +310,54 @@ static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest, int *yapoints = isi->yapoints; /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - /* calculate the source line we'll scan from */ - const unsigned int *sptr = ypoints[y]; - unsigned int *dptr = dest + (y * dow); - const int yap = yapoints[y]; - if (yap > 0) { - for (int x = 0; x < dw; x++) { - const unsigned int *pix = sptr + xpoints[x]; - const int xap = xapoints[x]; - if (xap > 0) - *dptr = interpolate_4_pixels(pix, pix + sow, xap, yap); - else - *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - yap, pix[sow], yap); - dptr++; - } - } else { - for (int x = 0; x < dw; x++) { - const unsigned int *pix = sptr + xpoints[x]; - const int xap = xapoints[x]; - if (xap > 0) - *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap); - else - *dptr = pix[0]; - dptr++; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + /* calculate the source line we'll scan from */ + const unsigned int *sptr = ypoints[y]; + unsigned int *dptr = dest + (y * dow); + const int yap = yapoints[y]; + if (yap > 0) { + for (int x = 0; x < dw; x++) { + const unsigned int *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + if (xap > 0) + *dptr = interpolate_4_pixels(pix, pix + sow, xap, yap); + else + *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - yap, pix[sow], yap); + dptr++; + } + } else { + for (int x = 0; x < dw; x++) { + const unsigned int *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + if (xap > 0) + *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap); + else + *dptr = pix[0]; + dptr++; + } } } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } /* scale by area sampling - with alpha */ @@ -411,33 +439,54 @@ static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int int *yapoints = isi->yapoints; /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - int Cy = yapoints[y] >> 16; - int yap = yapoints[y] & 0xffff; - - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - const unsigned int *sptr = ypoints[y] + xpoints[x]; - int r, g, b, a; - qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, r, g, b, a); - - int xap = xapoints[x]; - if (xap > 0) { - int rr, gg, bb, aa; - qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); - - r = r * (256 - xap); - g = g * (256 - xap); - b = b * (256 - xap); - a = a * (256 - xap); - r = (r + (rr * xap)) >> 8; - g = (g + (gg * xap)) >> 8; - b = (b + (bb * xap)) >> 8; - a = (a + (aa * xap)) >> 8; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = yapoints[y] >> 16; + int yap = yapoints[y] & 0xffff; + + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + const unsigned int *sptr = ypoints[y] + xpoints[x]; + int r, g, b, a; + qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, r, g, b, a); + + int xap = xapoints[x]; + if (xap > 0) { + int rr, gg, bb, aa; + qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); + + r = r * (256 - xap); + g = g * (256 - xap); + b = b * (256 - xap); + a = a * (256 - xap); + r = (r + (rr * xap)) >> 8; + g = (g + (gg * xap)) >> 8; + b = (b + (bb * xap)) >> 8; + a = (a + (aa * xap)) >> 8; + } + *dptr++ = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); } - *dptr++ = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, @@ -449,34 +498,55 @@ static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int int *yapoints = isi->yapoints; /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; - - const unsigned int *sptr = ypoints[y] + xpoints[x]; - int r, g, b, a; - qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, r, g, b, a); - - int yap = yapoints[y]; - if (yap > 0) { - int rr, gg, bb, aa; - qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa); - - r = r * (256 - yap); - g = g * (256 - yap); - b = b * (256 - yap); - a = a * (256 - yap); - r = (r + (rr * yap)) >> 8; - g = (g + (gg * yap)) >> 8; - b = (b + (bb * yap)) >> 8; - a = (a + (aa * yap)) >> 8; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[y] + xpoints[x]; + int r, g, b, a; + qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, r, g, b, a); + + int yap = yapoints[y]; + if (yap > 0) { + int rr, gg, bb, aa; + qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa); + + r = r * (256 - yap); + g = g * (256 - yap); + b = b * (256 - yap); + a = a * (256 - yap); + r = (r + (rr * yap)) >> 8; + g = (g + (gg * yap)) >> 8; + b = (b + (bb * yap)) >> 8; + a = (a + (aa * yap)) >> 8; + } + *dptr = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); + dptr++; } - *dptr = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); - dptr++; } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest, @@ -487,45 +557,66 @@ static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *des int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - int Cy = (yapoints[y]) >> 16; - int yap = (yapoints[y]) & 0xffff; - - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = (yapoints[y]) >> 16; + int yap = (yapoints[y]) & 0xffff; - const unsigned int *sptr = ypoints[y] + xpoints[x]; - int rx, gx, bx, ax; - qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; - int r = ((rx>>4) * yap); - int g = ((gx>>4) * yap); - int b = ((bx>>4) * yap); - int a = ((ax>>4) * yap); + const unsigned int *sptr = ypoints[y] + xpoints[x]; + int rx, gx, bx, ax; + qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); - int j; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + int r = ((rx>>4) * yap); + int g = ((gx>>4) * yap); + int b = ((bx>>4) * yap); + int a = ((ax>>4) * yap); + + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); + r += ((rx>>4) * Cy); + g += ((gx>>4) * Cy); + b += ((bx>>4) * Cy); + a += ((ax>>4) * Cy); + } sptr += sow; qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); - r += ((rx>>4) * Cy); - g += ((gx>>4) * Cy); - b += ((bx>>4) * Cy); - a += ((ax>>4) * Cy); - } - sptr += sow; - qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); - r += ((rx>>4) * j); - g += ((gx>>4) * j); - b += ((bx>>4) * j); - a += ((ax>>4) * j); + r += ((rx>>4) * j); + g += ((gx>>4) * j); + b += ((bx>>4) * j); + a += ((ax>>4) * j); - *dptr = qRgba(r >> 24, g >> 24, b >> 24, a >> 24); - dptr++; + *dptr = qRgba(r >> 24, g >> 24, b >> 24, a >> 24); + dptr++; + } } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } #if QT_CONFIG(raster_64bit) @@ -546,32 +637,53 @@ static void qt_qimageScaleRgba64_up_xy(QImageScaleInfo *isi, QRgba64 *dest, int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - const QRgba64 *sptr = ypoints[y]; - QRgba64 *dptr = dest + (y * dow); - const int yap = yapoints[y]; - if (yap > 0) { - for (int x = 0; x < dw; x++) { - const QRgba64 *pix = sptr + xpoints[x]; - const int xap = xapoints[x]; - if (xap > 0) - *dptr = interpolate_4_pixels_rgb64(pix, pix + sow, xap * 256, yap * 256); - else - *dptr = interpolate256(pix[0], 256 - yap, pix[sow], yap); - dptr++; - } - } else { - for (int x = 0; x < dw; x++) { - const QRgba64 *pix = sptr + xpoints[x]; - const int xap = xapoints[x]; - if (xap > 0) - *dptr = interpolate256(pix[0], 256 - xap, pix[1], xap); - else - *dptr = pix[0]; - dptr++; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + const QRgba64 *sptr = ypoints[y]; + QRgba64 *dptr = dest + (y * dow); + const int yap = yapoints[y]; + if (yap > 0) { + for (int x = 0; x < dw; x++) { + const QRgba64 *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + if (xap > 0) + *dptr = interpolate_4_pixels_rgb64(pix, pix + sow, xap * 256, yap * 256); + else + *dptr = interpolate256(pix[0], 256 - yap, pix[sow], yap); + dptr++; + } + } else { + for (int x = 0; x < dw; x++) { + const QRgba64 *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + if (xap > 0) + *dptr = interpolate256(pix[0], 256 - xap, pix[1], xap); + else + *dptr = pix[0]; + dptr++; + } } } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } void qt_qimageScaleRgba64(QImageScaleInfo *isi, QRgba64 *dest, @@ -616,33 +728,54 @@ static void qt_qimageScaleRgba64_up_x_down_y(QImageScaleInfo *isi, QRgba64 *dest int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - int Cy = (yapoints[y]) >> 16; - int yap = (yapoints[y]) & 0xffff; - - QRgba64 *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - const QRgba64 *sptr = ypoints[y] + xpoints[x]; - qint64 r, g, b, a; - qt_qimageScaleRgba64_helper(sptr, yap, Cy, sow, r, g, b, a); - - int xap = xapoints[x]; - if (xap > 0) { - qint64 rr, gg, bb, aa; - qt_qimageScaleRgba64_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); - - r = r * (256 - xap); - g = g * (256 - xap); - b = b * (256 - xap); - a = a * (256 - xap); - r = (r + (rr * xap)) >> 8; - g = (g + (gg * xap)) >> 8; - b = (b + (bb * xap)) >> 8; - a = (a + (aa * xap)) >> 8; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = (yapoints[y]) >> 16; + int yap = (yapoints[y]) & 0xffff; + + QRgba64 *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + const QRgba64 *sptr = ypoints[y] + xpoints[x]; + qint64 r, g, b, a; + qt_qimageScaleRgba64_helper(sptr, yap, Cy, sow, r, g, b, a); + + int xap = xapoints[x]; + if (xap > 0) { + qint64 rr, gg, bb, aa; + qt_qimageScaleRgba64_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); + + r = r * (256 - xap); + g = g * (256 - xap); + b = b * (256 - xap); + a = a * (256 - xap); + r = (r + (rr * xap)) >> 8; + g = (g + (gg * xap)) >> 8; + b = (b + (bb * xap)) >> 8; + a = (a + (aa * xap)) >> 8; + } + *dptr++ = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14); } - *dptr++ = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14); } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest, @@ -653,34 +786,55 @@ static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - QRgba64 *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; - - const QRgba64 *sptr = ypoints[y] + xpoints[x]; - qint64 r, g, b, a; - qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, r, g, b, a); - - int yap = yapoints[y]; - if (yap > 0) { - qint64 rr, gg, bb, aa; - qt_qimageScaleRgba64_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa); - - r = r * (256 - yap); - g = g * (256 - yap); - b = b * (256 - yap); - a = a * (256 - yap); - r = (r + (rr * yap)) >> 8; - g = (g + (gg * yap)) >> 8; - b = (b + (bb * yap)) >> 8; - a = (a + (aa * yap)) >> 8; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + QRgba64 *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const QRgba64 *sptr = ypoints[y] + xpoints[x]; + qint64 r, g, b, a; + qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, r, g, b, a); + + int yap = yapoints[y]; + if (yap > 0) { + qint64 rr, gg, bb, aa; + qt_qimageScaleRgba64_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa); + + r = r * (256 - yap); + g = g * (256 - yap); + b = b * (256 - yap); + a = a * (256 - yap); + r = (r + (rr * yap)) >> 8; + g = (g + (gg * yap)) >> 8; + b = (b + (bb * yap)) >> 8; + a = (a + (aa * yap)) >> 8; + } + *dptr = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14); + dptr++; } - *dptr = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14); - dptr++; } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest, @@ -691,43 +845,64 @@ static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest, int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - int Cy = (yapoints[y]) >> 16; - int yap = (yapoints[y]) & 0xffff; - - QRgba64 *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; - - const QRgba64 *sptr = ypoints[y] + xpoints[x]; - qint64 rx, gx, bx, ax; - qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); - - qint64 r = rx * yap; - qint64 g = gx * yap; - qint64 b = bx * yap; - qint64 a = ax * yap; - int j; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = (yapoints[y]) >> 16; + int yap = (yapoints[y]) & 0xffff; + + QRgba64 *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const QRgba64 *sptr = ypoints[y] + xpoints[x]; + qint64 rx, gx, bx, ax; + qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); + + qint64 r = rx * yap; + qint64 g = gx * yap; + qint64 b = bx * yap; + qint64 a = ax * yap; + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); + r += rx * Cy; + g += gx * Cy; + b += bx * Cy; + a += ax * Cy; + } sptr += sow; qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); - r += rx * Cy; - g += gx * Cy; - b += bx * Cy; - a += ax * Cy; + r += rx * j; + g += gx * j; + b += bx * j; + a += ax * j; + + *dptr = qRgba64(r >> 28, g >> 28, b >> 28, a >> 28); + dptr++; } - sptr += sow; - qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); - r += rx * j; - g += gx * j; - b += bx * j; - a += ax * j; - - *dptr = qRgba64(r >> 28, g >> 28, b >> 28, a >> 28); - dptr++; } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } #endif @@ -817,31 +992,52 @@ static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int * int *yapoints = isi->yapoints; /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - int Cy = yapoints[y] >> 16; - int yap = yapoints[y] & 0xffff; - - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - const unsigned int *sptr = ypoints[y] + xpoints[x]; - int r, g, b; - qt_qimageScaleAARGB_helper(sptr, yap, Cy, sow, r, g, b); - - int xap = xapoints[x]; - if (xap > 0) { - int rr, bb, gg; - qt_qimageScaleAARGB_helper(sptr + 1, yap, Cy, sow, rr, gg, bb); - - r = r * (256 - xap); - g = g * (256 - xap); - b = b * (256 - xap); - r = (r + (rr * xap)) >> 8; - g = (g + (gg * xap)) >> 8; - b = (b + (bb * xap)) >> 8; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = yapoints[y] >> 16; + int yap = yapoints[y] & 0xffff; + + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + const unsigned int *sptr = ypoints[y] + xpoints[x]; + int r, g, b; + qt_qimageScaleAARGB_helper(sptr, yap, Cy, sow, r, g, b); + + int xap = xapoints[x]; + if (xap > 0) { + int rr, bb, gg; + qt_qimageScaleAARGB_helper(sptr + 1, yap, Cy, sow, rr, gg, bb); + + r = r * (256 - xap); + g = g * (256 - xap); + b = b * (256 - xap); + r = (r + (rr * xap)) >> 8; + g = (g + (gg * xap)) >> 8; + b = (b + (bb * xap)) >> 8; + } + *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); } - *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, @@ -853,31 +1049,52 @@ static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int * int *yapoints = isi->yapoints; /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; - - const unsigned int *sptr = ypoints[y] + xpoints[x]; - int r, g, b; - qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, r, g, b); - - int yap = yapoints[y]; - if (yap > 0) { - int rr, bb, gg; - qt_qimageScaleAARGB_helper(sptr + sow, xap, Cx, 1, rr, gg, bb); - - r = r * (256 - yap); - g = g * (256 - yap); - b = b * (256 - yap); - r = (r + (rr * yap)) >> 8; - g = (g + (gg * yap)) >> 8; - b = (b + (bb * yap)) >> 8; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[y] + xpoints[x]; + int r, g, b; + qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, r, g, b); + + int yap = yapoints[y]; + if (yap > 0) { + int rr, bb, gg; + qt_qimageScaleAARGB_helper(sptr + sow, xap, Cx, 1, rr, gg, bb); + + r = r * (256 - yap); + g = g * (256 - yap); + b = b * (256 - yap); + r = (r + (rr * yap)) >> 8; + g = (g + (gg * yap)) >> 8; + b = (b + (bb * yap)) >> 8; + } + *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); } - *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest, @@ -888,43 +1105,64 @@ static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - int Cy = yapoints[y] >> 16; - int yap = yapoints[y] & 0xffff; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = yapoints[y] >> 16; + int yap = yapoints[y] & 0xffff; - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[y] + xpoints[x]; + int rx, gx, bx; + qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx); - const unsigned int *sptr = ypoints[y] + xpoints[x]; - int rx, gx, bx; - qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx); + int r = (rx >> 4) * yap; + int g = (gx >> 4) * yap; + int b = (bx >> 4) * yap; - int r = (rx >> 4) * yap; - int g = (gx >> 4) * yap; - int b = (bx >> 4) * yap; + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx); - int j; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + r += (rx >> 4) * Cy; + g += (gx >> 4) * Cy; + b += (bx >> 4) * Cy; + } sptr += sow; qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx); - r += (rx >> 4) * Cy; - g += (gx >> 4) * Cy; - b += (bx >> 4) * Cy; - } - sptr += sow; - qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx); - - r += (rx >> 4) * j; - g += (gx >> 4) * j; - b += (bx >> 4) * j; + r += (rx >> 4) * j; + g += (gx >> 4) * j; + b += (bx >> 4) * j; - *dptr = qRgb(r >> 24, g >> 24, b >> 24); - dptr++; + *dptr = qRgb(r >> 24, g >> 24, b >> 24); + dptr++; + } } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } QImage qSmoothScaleImage(const QImage &src, int dw, int dh) diff --git a/src/gui/painting/qimagescale_neon.cpp b/src/gui/painting/qimagescale_neon.cpp index 4ae113b002..416155e139 100644 --- a/src/gui/painting/qimagescale_neon.cpp +++ b/src/gui/painting/qimagescale_neon.cpp @@ -41,6 +41,11 @@ #include "qimage.h" #include +#if QT_CONFIG(thread) +#include "qsemaphore.h" +#include "qthreadpool.h" +#endif + #if defined(__ARM_NEON__) QT_BEGIN_NAMESPACE @@ -76,33 +81,54 @@ void qt_qimageScaleAARGBA_up_x_down_y_neon(QImageScaleInfo *isi, unsigned int *d int *yapoints = isi->yapoints; /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - int Cy = yapoints[y] >> 16; - int yap = yapoints[y] & 0xffff; - - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - const unsigned int *sptr = ypoints[y] + xpoints[x]; - uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow); - - int xap = xapoints[x]; - if (xap > 0) { - uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow); - - vx = vmulq_n_u32(vx, 256 - xap); - vr = vmulq_n_u32(vr, xap); - vx = vaddq_u32(vx, vr); - vx = vshrq_n_u32(vx, 8); + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = yapoints[y] >> 16; + int yap = yapoints[y] & 0xffff; + + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + const unsigned int *sptr = ypoints[y] + xpoints[x]; + uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow); + + int xap = xapoints[x]; + if (xap > 0) { + uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow); + + vx = vmulq_n_u32(vx, 256 - xap); + vr = vmulq_n_u32(vr, xap); + vx = vaddq_u32(vx, vr); + vx = vshrq_n_u32(vx, 8); + } + vx = vshrq_n_u32(vx, 14); + const uint16x4_t vx16 = vmovn_u32(vx); + const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16)); + *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0); + if (RGB) + *dptr |= 0xff000000; + dptr++; } - vx = vshrq_n_u32(vx, 14); - const uint16x4_t vx16 = vmovn_u32(vx); - const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16)); - *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0); - if (RGB) - *dptr |= 0xff000000; - dptr++; } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } template @@ -115,33 +141,54 @@ void qt_qimageScaleAARGBA_down_x_up_y_neon(QImageScaleInfo *isi, unsigned int *d int *yapoints = isi->yapoints; /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; - - const unsigned int *sptr = ypoints[y] + xpoints[x]; - uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1); - - int yap = yapoints[y]; - if (yap > 0) { - uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1); - - vx = vmulq_n_u32(vx, 256 - yap); - vr = vmulq_n_u32(vr, yap); - vx = vaddq_u32(vx, vr); - vx = vshrq_n_u32(vx, 8); + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[y] + xpoints[x]; + uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1); + + int yap = yapoints[y]; + if (yap > 0) { + uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1); + + vx = vmulq_n_u32(vx, 256 - yap); + vr = vmulq_n_u32(vr, yap); + vx = vaddq_u32(vx, vr); + vx = vshrq_n_u32(vx, 8); + } + vx = vshrq_n_u32(vx, 14); + const uint16x4_t vx16 = vmovn_u32(vx); + const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16)); + *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0); + if (RGB) + *dptr |= 0xff000000; + dptr++; } - vx = vshrq_n_u32(vx, 14); - const uint16x4_t vx16 = vmovn_u32(vx); - const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16)); - *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0); - if (RGB) - *dptr |= 0xff000000; - dptr++; } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } template @@ -153,43 +200,64 @@ void qt_qimageScaleAARGBA_down_xy_neon(QImageScaleInfo *isi, unsigned int *dest, int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - int Cy = yapoints[y] >> 16; - int yap = yapoints[y] & 0xffff; + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = yapoints[y] >> 16; + int yap = yapoints[y] & 0xffff; - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - const int Cx = xapoints[x] >> 16; - const int xap = xapoints[x] & 0xffff; + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + const int Cx = xapoints[x] >> 16; + const int xap = xapoints[x] & 0xffff; - const unsigned int *sptr = ypoints[y] + xpoints[x]; - uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1); - vx = vshrq_n_u32(vx, 4); - uint32x4_t vr = vmulq_n_u32(vx, yap); + const unsigned int *sptr = ypoints[y] + xpoints[x]; + uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1); + vx = vshrq_n_u32(vx, 4); + uint32x4_t vr = vmulq_n_u32(vx, yap); - int j; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1); + vx = vshrq_n_u32(vx, 4); + vx = vmulq_n_u32(vx, Cy); + vr = vaddq_u32(vr, vx); + } sptr += sow; vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1); vx = vshrq_n_u32(vx, 4); - vx = vmulq_n_u32(vx, Cy); + vx = vmulq_n_u32(vx, j); vr = vaddq_u32(vr, vx); + + vx = vshrq_n_u32(vr, 24); + const uint16x4_t vx16 = vmovn_u32(vx); + const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16)); + *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0); + if (RGB) + *dptr |= 0xff000000; + dptr++; } - sptr += sow; - vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1); - vx = vshrq_n_u32(vx, 4); - vx = vmulq_n_u32(vx, j); - vr = vaddq_u32(vr, vx); - - vx = vshrq_n_u32(vr, 24); - const uint16x4_t vx16 = vmovn_u32(vx); - const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16)); - *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0); - if (RGB) - *dptr |= 0xff000000; - dptr++; } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } template void qt_qimageScaleAARGBA_up_x_down_y_neon(QImageScaleInfo *isi, unsigned int *dest, diff --git a/src/gui/painting/qimagescale_p.h b/src/gui/painting/qimagescale_p.h index 244d681718..a9a4c0f858 100644 --- a/src/gui/painting/qimagescale_p.h +++ b/src/gui/painting/qimagescale_p.h @@ -66,6 +66,8 @@ namespace QImageScale { int *xapoints{nullptr}; int *yapoints{nullptr}; int xup_yup{0}; + int sh = 0; + int sw = 0; }; } diff --git a/src/gui/painting/qimagescale_sse4.cpp b/src/gui/painting/qimagescale_sse4.cpp index 5861a2e2ff..902ae61ed2 100644 --- a/src/gui/painting/qimagescale_sse4.cpp +++ b/src/gui/painting/qimagescale_sse4.cpp @@ -42,6 +42,11 @@ #include #include +#if QT_CONFIG(thread) +#include "qsemaphore.h" +#include "qthreadpool.h" +#endif + #if defined(QT_COMPILER_SUPPORTS_SSE4_1) QT_BEGIN_NAMESPACE @@ -70,44 +75,65 @@ void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *d int dw, int dh, int dow, int sow) { const unsigned int **ypoints = isi->ypoints; - int *xpoints = isi->xpoints; - int *xapoints = isi->xapoints; - int *yapoints = isi->yapoints; + const int *xpoints = isi->xpoints; + const int *xapoints = isi->xapoints; + const int *yapoints = isi->yapoints; const __m128i v256 = _mm_set1_epi32(256); /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - int Cy = yapoints[y] >> 16; - int yap = yapoints[y] & 0xffff; - const __m128i vCy = _mm_set1_epi32(Cy); - const __m128i vyap = _mm_set1_epi32(yap); - - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - const unsigned int *sptr = ypoints[y] + xpoints[x]; - __m128i vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, vyap, vCy); - - int xap = xapoints[x]; - if (xap > 0) { - const __m128i vxap = _mm_set1_epi32(xap); - const __m128i vinvxap = _mm_sub_epi32(v256, vxap); - __m128i vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, vyap, vCy); + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + const int Cy = yapoints[y] >> 16; + const int yap = yapoints[y] & 0xffff; + const __m128i vCy = _mm_set1_epi32(Cy); + const __m128i vyap = _mm_set1_epi32(yap); - vx = _mm_mullo_epi32(vx, vinvxap); - vr = _mm_mullo_epi32(vr, vxap); - vx = _mm_add_epi32(vx, vr); - vx = _mm_srli_epi32(vx, 8); + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + const unsigned int *sptr = ypoints[y] + xpoints[x]; + __m128i vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, vyap, vCy); + + const int xap = xapoints[x]; + if (xap > 0) { + const __m128i vxap = _mm_set1_epi32(xap); + const __m128i vinvxap = _mm_sub_epi32(v256, vxap); + __m128i vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, vyap, vCy); + + vx = _mm_mullo_epi32(vx, vinvxap); + vr = _mm_mullo_epi32(vr, vxap); + vx = _mm_add_epi32(vx, vr); + vx = _mm_srli_epi32(vx, 8); + } + vx = _mm_srli_epi32(vx, 14); + vx = _mm_packus_epi32(vx, vx); + vx = _mm_packus_epi16(vx, vx); + *dptr = _mm_cvtsi128_si32(vx); + if (RGB) + *dptr |= 0xff000000; + dptr++; } - vx = _mm_srli_epi32(vx, 14); - vx = _mm_packus_epi32(vx, _mm_setzero_si128()); - vx = _mm_packus_epi16(vx, _mm_setzero_si128()); - *dptr = _mm_cvtsi128_si32(vx); - if (RGB) - *dptr |= 0xff000000; - dptr++; } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } template @@ -122,37 +148,58 @@ void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *d const __m128i v256 = _mm_set1_epi32(256); /* go through every scanline in the output buffer */ - for (int y = 0; y < dh; y++) { - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - int Cx = xapoints[x] >> 16; - int xap = xapoints[x] & 0xffff; - const __m128i vCx = _mm_set1_epi32(Cx); - const __m128i vxap = _mm_set1_epi32(xap); - - const unsigned int *sptr = ypoints[y] + xpoints[x]; - __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx); - - int yap = yapoints[y]; - if (yap > 0) { - const __m128i vyap = _mm_set1_epi32(yap); - const __m128i vinvyap = _mm_sub_epi32(v256, vyap); - __m128i vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, vxap, vCx); - - vx = _mm_mullo_epi32(vx, vinvyap); - vr = _mm_mullo_epi32(vr, vyap); - vx = _mm_add_epi32(vx, vr); - vx = _mm_srli_epi32(vx, 8); + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + const __m128i vCx = _mm_set1_epi32(Cx); + const __m128i vxap = _mm_set1_epi32(xap); + + const unsigned int *sptr = ypoints[y] + xpoints[x]; + __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx); + + int yap = yapoints[y]; + if (yap > 0) { + const __m128i vyap = _mm_set1_epi32(yap); + const __m128i vinvyap = _mm_sub_epi32(v256, vyap); + __m128i vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, vxap, vCx); + + vx = _mm_mullo_epi32(vx, vinvyap); + vr = _mm_mullo_epi32(vr, vyap); + vx = _mm_add_epi32(vx, vr); + vx = _mm_srli_epi32(vx, 8); + } + vx = _mm_srli_epi32(vx, 14); + vx = _mm_packus_epi32(vx, vx); + vx = _mm_packus_epi16(vx, vx); + *dptr = _mm_cvtsi128_si32(vx); + if (RGB) + *dptr |= 0xff000000; + dptr++; } - vx = _mm_srli_epi32(vx, 14); - vx = _mm_packus_epi32(vx, _mm_setzero_si128()); - vx = _mm_packus_epi16(vx, _mm_setzero_si128()); - *dptr = _mm_cvtsi128_si32(vx); - if (RGB) - *dptr |= 0xff000000; - dptr++; } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } template @@ -164,42 +211,63 @@ void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest, int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - for (int y = 0; y < dh; y++) { - int Cy = yapoints[y] >> 16; - int yap = yapoints[y] & 0xffff; - const __m128i vCy = _mm_set1_epi32(Cy); - const __m128i vyap = _mm_set1_epi32(yap); - - unsigned int *dptr = dest + (y * dow); - for (int x = 0; x < dw; x++) { - const int Cx = xapoints[x] >> 16; - const int xap = xapoints[x] & 0xffff; - const __m128i vCx = _mm_set1_epi32(Cx); - const __m128i vxap = _mm_set1_epi32(xap); - - const unsigned int *sptr = ypoints[y] + xpoints[x]; - __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx); - __m128i vr = _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vyap); - - int j; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + auto scaleSection = [&] (int yStart, int yEnd) { + for (int y = yStart; y < yEnd; ++y) { + int Cy = yapoints[y] >> 16; + int yap = yapoints[y] & 0xffff; + const __m128i vCy = _mm_set1_epi32(Cy); + const __m128i vyap = _mm_set1_epi32(yap); + + unsigned int *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + const int Cx = xapoints[x] >> 16; + const int xap = xapoints[x] & 0xffff; + const __m128i vCx = _mm_set1_epi32(Cx); + const __m128i vxap = _mm_set1_epi32(xap); + + const unsigned int *sptr = ypoints[y] + xpoints[x]; + __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx); + __m128i vr = _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vyap); + + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx); + vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vCy)); + } sptr += sow; vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx); - vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vCy)); + vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), _mm_set1_epi32(j))); + + vr = _mm_srli_epi32(vr, 24); + vr = _mm_packus_epi32(vr, _mm_setzero_si128()); + vr = _mm_packus_epi16(vr, _mm_setzero_si128()); + *dptr = _mm_cvtsi128_si32(vr); + if (RGB) + *dptr |= 0xff000000; + dptr++; } - sptr += sow; - vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx); - vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), _mm_set1_epi32(j))); - - vr = _mm_srli_epi32(vr, 24); - vr = _mm_packus_epi32(vr, _mm_setzero_si128()); - vr = _mm_packus_epi16(vr, _mm_setzero_si128()); - *dptr = _mm_cvtsi128_si32(vr); - if (RGB) - *dptr |= 0xff000000; - dptr++; } + }; +#if QT_CONFIG(thread) + int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); + segments = std::min(segments, dh); + if (segments > 1) { + QSemaphore semaphore; + int y = 0; + for (int i = 0; i < segments; ++i) { + int yn = (dh - y) / (segments - i); + QThreadPool::globalInstance()->start([&, y, yn]() { + scaleSection(y, y + yn); + semaphore.release(1); + }); + y += yn; + } + semaphore.acquire(segments); + return; } +#endif + scaleSection(0, dh); } template void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest, -- cgit v1.2.3 From a8ae9718b01e68c5c0367941f7999c59b6da84d4 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Wed, 12 Jun 2019 11:48:53 +0200 Subject: Doc: Mention .qrc compression attributes in resource compiler docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: QTBUG-76321 Change-Id: Idf7b4157b46d98392314ccddf6b714f9e620b5f8 Reviewed-by: Topi Reiniö --- src/corelib/doc/src/resource-system.qdoc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/corelib/doc/src/resource-system.qdoc b/src/corelib/doc/src/resource-system.qdoc index f9ef317799..6ff10804f5 100644 --- a/src/corelib/doc/src/resource-system.qdoc +++ b/src/corelib/doc/src/resource-system.qdoc @@ -179,6 +179,17 @@ rcc -compress 2 -compress-algo zlib myresources.qrc \endcode + It is also possible to use \c threshold, \c compress, and \c compress-algo + as attributes in a .qrc \c file tag. + + \code + + data.txt + + \endcode + + The above will select the \c zstd algorithm with compression level 1. + \c rcc supports the following compression algorithms and compression levels: @@ -196,10 +207,10 @@ library to choose an implementation-defined default. \li \c{zlib}: use the \l{https://zlib.net}{zlib} library to compress - contents. Valid compression levels range from 1 to 9, with 1the least - compression (least CPU time) and 9 the most compression (most CPU time). - The special value 0 means "no compression" and should not be used. The - default is implementation-defined, but usually is level 6. + contents. Valid compression levels range from 1 to 9, with 1 applying + the least compression (least CPU time) and 9 the most compression (most + CPU time). The special value 0 means "no compression" and should not be + used. The default is implementation-defined, but usually is level 6. \li \c{none}: no compression. This is the same as the \c{-no-compress} option. -- cgit v1.2.3 From d52a5537548a8df81b5cfcb74d040ee783fe7c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 3 Mar 2020 16:36:37 +0100 Subject: Bearer management deprecation cleanup For QNAM: Deprecate the to-be-unused enum and mark the property deprecated in docs For bearermanagement: Add a warning on the bearermanagement documentation page that it is deprecated. Change-Id: I2cbe12ddec444d9f704601f07f3a7c9b70dc4f3c Reviewed-by: Timur Pocheptsov --- src/network/access/qnetworkaccessmanager.cpp | 2 ++ src/network/access/qnetworkaccessmanager.h | 15 ++++++++++++++- src/network/doc/src/bearermanagement.qdoc | 2 ++ 3 files changed, 18 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 695f022e4b..a8cf983ec9 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -253,6 +253,7 @@ static void ensureInitialized() /*! \enum QNetworkAccessManager::NetworkAccessibility + \obsolete Indicates whether the network is accessible via this network access manager. @@ -268,6 +269,7 @@ static void ensureInitialized() /*! \property QNetworkAccessManager::networkAccessible \brief whether the network is currently accessible via this network access manager. + \obsolete \since 4.7 diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index a75b16a6ca..12c7a7cea1 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -92,12 +92,15 @@ public: }; #ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section - enum NetworkAccessibility { + enum QT_DEPRECATED_VERSION_5_15 NetworkAccessibility { UnknownAccessibility = -1, NotAccessible = 0, Accessible = 1 }; +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED Q_ENUM(NetworkAccessibility) +QT_WARNING_POP #endif explicit QNetworkAccessManager(QObject *parent = nullptr); @@ -151,8 +154,11 @@ public: QT_DEPRECATED_VERSION_5_15 QNetworkConfiguration configuration() const; QT_DEPRECATED_VERSION_5_15 QNetworkConfiguration activeConfiguration() const; +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QT_DEPRECATED_VERSION_5_15 void setNetworkAccessible(NetworkAccessibility accessible); QT_DEPRECATED_VERSION_5_15 NetworkAccessibility networkAccessible() const; +QT_WARNING_POP #endif #ifndef QT_NO_SSL @@ -188,7 +194,14 @@ Q_SIGNALS: #ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section QT_DEPRECATED_VERSION_5_15 void networkSessionConnected(); +#ifndef Q_MOC_RUN // moc has trouble with the expansion of these macros +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +#endif QT_DEPRECATED_VERSION_5_15 void networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible); +#ifndef Q_MOC_RUN // moc has trouble with the expansion of these macros +QT_WARNING_POP +#endif #endif protected: diff --git a/src/network/doc/src/bearermanagement.qdoc b/src/network/doc/src/bearermanagement.qdoc index f8d6a807d2..8aec894269 100644 --- a/src/network/doc/src/bearermanagement.qdoc +++ b/src/network/doc/src/bearermanagement.qdoc @@ -31,6 +31,8 @@ \title Bearer Management \brief An API to control the system's connectivity state. +\warning Bearer management is deprecated and will be removed in Qt 6.0. + Bearer Management controls the connectivity state of the system so that the user can start or stop interfaces or roam transparently between access points. -- cgit v1.2.3 From d340cc1512a9bf62d824c33c592358699593c6bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Mon, 9 Mar 2020 12:03:06 +0100 Subject: Schannel: Fix readBufferMaxSize impl with incomplete data optimization Following the incomplete data guesstimation optimization the tst_QSslSocket::readBufferMaxSize test would fail due to it waiting for 16K, but the readBufferMaxSize was 10 bytes. Amends 559b563d711db0760a51b0dce26536dbc8766a9d Change-Id: I5d17fac24e73c1305161aff744710b4c5b0b457a Reviewed-by: Timur Pocheptsov --- src/network/ssl/qsslsocket_schannel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/ssl/qsslsocket_schannel.cpp b/src/network/ssl/qsslsocket_schannel.cpp index 31b0db4818..e47fda17ab 100644 --- a/src/network/ssl/qsslsocket_schannel.cpp +++ b/src/network/ssl/qsslsocket_schannel.cpp @@ -1312,7 +1312,8 @@ void QSslSocketBackendPrivate::transmit() int totalRead = 0; bool hadIncompleteData = false; while (!readBufferMaxSize || buffer.size() < readBufferMaxSize) { - if (missingData > plainSocket->bytesAvailable()) { + if (missingData > plainSocket->bytesAvailable() + && (!readBufferMaxSize || readBufferMaxSize >= missingData)) { #ifdef QSSLSOCKET_DEBUG qCDebug(lcSsl, "We're still missing %lld bytes, will check later.", missingData); #endif -- cgit v1.2.3 From 19a76200ea67a418fb81e3ab5201dbde2343ec03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 25 Feb 2020 10:30:08 +0100 Subject: QDataStream: keep brace delimiters inside #if-scopes Because it looks odd. Change-Id: Ic272ae7b1b5a3e0a70884caa683ccbdd3a61ff6a Reviewed-by: Edward Welbourne --- src/corelib/serialization/qdatastream.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h index 6f6593f9bf..bc05841b52 100644 --- a/src/corelib/serialization/qdatastream.h +++ b/src/corelib/serialization/qdatastream.h @@ -340,6 +340,7 @@ QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c) --it; QT_WARNING_POP s << it.key() << it.value(); + } #else auto it = c.constBegin(); auto end = c.constEnd(); @@ -352,8 +353,8 @@ QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c) auto next = std::next(rangeStart, i); s << next.key() << next.value(); } -#endif } +#endif return s; } -- cgit v1.2.3 From 3dd13d4075a250aa5070b97858a3115d5192e6f6 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 6 Mar 2020 17:20:01 +0100 Subject: rhi: d3d11: Honor resource/sampler slot limits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Show a warning but allow applications to survive by not attempting to call VS/PS/CSSetWhatever() with an invalid number of resources. Relevant for samplers in particular, where the limit is 16. Qt Quick 3D exhibits problems with this when using custom materials combined with shadow mapping, and while this is not a solution to the problem there, at least the problem is now clearly indicated instead of crashing. Task-number: QTBUG-82719 Change-Id: I83914b7648001fa421ed1cf07a7b7444e0ef8fc0 Reviewed-by: Christian Strømme --- src/gui/rhi/qrhid3d11.cpp | 190 ++++++++++++++++++++++++++++++---------------- 1 file changed, 124 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 7c53925aca..ed202958f3 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -113,6 +113,10 @@ QT_BEGIN_NAMESPACE #define DXGI_ADAPTER_FLAG_SOFTWARE 2 #endif +#ifndef D3D11_1_UAV_SLOT_COUNT +#define D3D11_1_UAV_SLOT_COUNT 64 +#endif + QRhiD3D11::QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importDevice) : ofr(this), deviceCurse(this) @@ -2091,102 +2095,156 @@ static void applyDynamicOffsets(QVarLengthArray *offsets, } } +static inline uint clampedResourceCount(uint startSlot, int countSlots, uint maxSlots, const char *resType) +{ + if (startSlot + countSlots > maxSlots) { + qWarning("Not enough D3D11 %s slots to bind %d resources starting at slot %d, max slots is %d", + resType, countSlots, startSlot, maxSlots); + countSlots = maxSlots > startSlot ? maxSlots - startSlot : 0; + } + return countSlots; +} + void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD, const uint *dynOfsPairs, int dynOfsPairCount, bool offsetOnlyChange) { if (!offsetOnlyChange) { - for (const auto &batch : srbD->vssamplers.batches) - context->VSSetSamplers(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData()); + for (const auto &batch : srbD->vssamplers.batches) { + const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), + D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, "VS sampler"); + if (count) + context->VSSetSamplers(batch.startBinding, count, batch.resources.constData()); + } for (const auto &batch : srbD->vsshaderresources.batches) { - context->VSSetShaderResources(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData()); - contextState.vsHighestActiveSrvBinding = qMax(contextState.vsHighestActiveSrvBinding, - int(batch.startBinding) + batch.resources.count() - 1); + const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), + D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, "VS SRV"); + if (count) { + context->VSSetShaderResources(batch.startBinding, count, batch.resources.constData()); + contextState.vsHighestActiveSrvBinding = qMax(contextState.vsHighestActiveSrvBinding, + int(batch.startBinding + count) - 1); + } } - for (const auto &batch : srbD->fssamplers.batches) - context->PSSetSamplers(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData()); + for (const auto &batch : srbD->fssamplers.batches) { + const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), + D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, "PS sampler"); + if (count) + context->PSSetSamplers(batch.startBinding, count, batch.resources.constData()); + } for (const auto &batch : srbD->fsshaderresources.batches) { - context->PSSetShaderResources(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData()); - contextState.fsHighestActiveSrvBinding = qMax(contextState.fsHighestActiveSrvBinding, - int(batch.startBinding) + batch.resources.count() - 1); + const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), + D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, "PS SRV"); + if (count) { + context->PSSetShaderResources(batch.startBinding, count, batch.resources.constData()); + contextState.fsHighestActiveSrvBinding = qMax(contextState.fsHighestActiveSrvBinding, + int(batch.startBinding + count) - 1); + } } - for (const auto &batch : srbD->cssamplers.batches) - context->CSSetSamplers(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData()); + for (const auto &batch : srbD->cssamplers.batches) { + const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), + D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, "CS sampler"); + if (count) + context->CSSetSamplers(batch.startBinding, count, batch.resources.constData()); + } for (const auto &batch : srbD->csshaderresources.batches) { - context->CSSetShaderResources(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData()); - contextState.csHighestActiveSrvBinding = qMax(contextState.csHighestActiveSrvBinding, - int(batch.startBinding) + batch.resources.count() - 1); + const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), + D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, "CS SRV"); + if (count) { + context->CSSetShaderResources(batch.startBinding, count, batch.resources.constData()); + contextState.csHighestActiveSrvBinding = qMax(contextState.csHighestActiveSrvBinding, + int(batch.startBinding + count) - 1); + } } } for (int i = 0, ie = srbD->vsubufs.batches.count(); i != ie; ++i) { - if (!dynOfsPairCount) { - context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding, - UINT(srbD->vsubufs.batches[i].resources.count()), - srbD->vsubufs.batches[i].resources.constData(), - srbD->vsubufoffsets.batches[i].resources.constData(), - srbD->vsubufsizes.batches[i].resources.constData()); - } else { - QVarLengthArray offsets; - applyDynamicOffsets(&offsets, i, &srbD->vsubufs, &srbD->vsubufoffsets, dynOfsPairs, dynOfsPairCount); - context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding, - UINT(srbD->vsubufs.batches[i].resources.count()), - srbD->vsubufs.batches[i].resources.constData(), - offsets.constData(), - srbD->vsubufsizes.batches[i].resources.constData()); + const uint count = clampedResourceCount(srbD->vsubufs.batches[i].startBinding, + srbD->vsubufs.batches[i].resources.count(), + D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, + "VS cbuf"); + if (count) { + if (!dynOfsPairCount) { + context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding, + count, + srbD->vsubufs.batches[i].resources.constData(), + srbD->vsubufoffsets.batches[i].resources.constData(), + srbD->vsubufsizes.batches[i].resources.constData()); + } else { + QVarLengthArray offsets; + applyDynamicOffsets(&offsets, i, &srbD->vsubufs, &srbD->vsubufoffsets, dynOfsPairs, dynOfsPairCount); + context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding, + count, + srbD->vsubufs.batches[i].resources.constData(), + offsets.constData(), + srbD->vsubufsizes.batches[i].resources.constData()); + } } } for (int i = 0, ie = srbD->fsubufs.batches.count(); i != ie; ++i) { - if (!dynOfsPairCount) { - context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding, - UINT(srbD->fsubufs.batches[i].resources.count()), - srbD->fsubufs.batches[i].resources.constData(), - srbD->fsubufoffsets.batches[i].resources.constData(), - srbD->fsubufsizes.batches[i].resources.constData()); - } else { - QVarLengthArray offsets; - applyDynamicOffsets(&offsets, i, &srbD->fsubufs, &srbD->fsubufoffsets, dynOfsPairs, dynOfsPairCount); - context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding, - UINT(srbD->fsubufs.batches[i].resources.count()), - srbD->fsubufs.batches[i].resources.constData(), - offsets.constData(), - srbD->fsubufsizes.batches[i].resources.constData()); + const uint count = clampedResourceCount(srbD->fsubufs.batches[i].startBinding, + srbD->fsubufs.batches[i].resources.count(), + D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, + "PS cbuf"); + if (count) { + if (!dynOfsPairCount) { + context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding, + count, + srbD->fsubufs.batches[i].resources.constData(), + srbD->fsubufoffsets.batches[i].resources.constData(), + srbD->fsubufsizes.batches[i].resources.constData()); + } else { + QVarLengthArray offsets; + applyDynamicOffsets(&offsets, i, &srbD->fsubufs, &srbD->fsubufoffsets, dynOfsPairs, dynOfsPairCount); + context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding, + count, + srbD->fsubufs.batches[i].resources.constData(), + offsets.constData(), + srbD->fsubufsizes.batches[i].resources.constData()); + } } } for (int i = 0, ie = srbD->csubufs.batches.count(); i != ie; ++i) { - if (!dynOfsPairCount) { - context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding, - UINT(srbD->csubufs.batches[i].resources.count()), - srbD->csubufs.batches[i].resources.constData(), - srbD->csubufoffsets.batches[i].resources.constData(), - srbD->csubufsizes.batches[i].resources.constData()); - } else { - QVarLengthArray offsets; - applyDynamicOffsets(&offsets, i, &srbD->csubufs, &srbD->csubufoffsets, dynOfsPairs, dynOfsPairCount); - context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding, - UINT(srbD->csubufs.batches[i].resources.count()), - srbD->csubufs.batches[i].resources.constData(), - offsets.constData(), - srbD->csubufsizes.batches[i].resources.constData()); + const uint count = clampedResourceCount(srbD->csubufs.batches[i].startBinding, + srbD->csubufs.batches[i].resources.count(), + D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, + "CS cbuf"); + if (count) { + if (!dynOfsPairCount) { + context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding, + count, + srbD->csubufs.batches[i].resources.constData(), + srbD->csubufoffsets.batches[i].resources.constData(), + srbD->csubufsizes.batches[i].resources.constData()); + } else { + QVarLengthArray offsets; + applyDynamicOffsets(&offsets, i, &srbD->csubufs, &srbD->csubufoffsets, dynOfsPairs, dynOfsPairCount); + context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding, + count, + srbD->csubufs.batches[i].resources.constData(), + offsets.constData(), + srbD->csubufsizes.batches[i].resources.constData()); + } } } - for (int i = 0, ie = srbD->csUAVs.batches.count(); i != ie; ++i) { - const uint startBinding = srbD->csUAVs.batches[i].startBinding; - const uint count = uint(srbD->csUAVs.batches[i].resources.count()); - context->CSSetUnorderedAccessViews(startBinding, - count, - srbD->csUAVs.batches[i].resources.constData(), - nullptr); - contextState.csHighestActiveUavBinding = qMax(contextState.csHighestActiveUavBinding, - int(startBinding + count - 1)); + for (const auto &batch : srbD->csUAVs.batches) { + const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), + D3D11_1_UAV_SLOT_COUNT, "CS UAV"); + if (count) { + context->CSSetUnorderedAccessViews(batch.startBinding, + count, + batch.resources.constData(), + nullptr); + contextState.csHighestActiveUavBinding = qMax(contextState.csHighestActiveUavBinding, + int(batch.startBinding + count) - 1); + } } } -- cgit v1.2.3 From d4207cb1a95ac866faf61df388fcd7963ccc72e7 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 10 Mar 2020 12:48:29 +0100 Subject: Mimetypes: Build fix for Android builds on Windows Due to Android's multi-abi the build will fail due to concurrent access: cmd /c C:\Projects\Qt\repo\qtbase\src\corelib\mimetypes\mime\generate.bat C:\Projects\Qt\repo\qtbase\src\corelib\mimetypes\mime\packages\freedesktop.org.xml > .rcc\qmimeprovider_database.cpp The process cannot access the file because it is being used by another process. Change-Id: I647e0a6d8aa03cf116b08a1dce6e61e8882661f4 Reviewed-by: Alexandru Croitor --- src/corelib/mimetypes/mimetypes.pri | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/corelib/mimetypes/mimetypes.pri b/src/corelib/mimetypes/mimetypes.pri index 8cbe7b69ae..288ccf063e 100644 --- a/src/corelib/mimetypes/mimetypes.pri +++ b/src/corelib/mimetypes/mimetypes.pri @@ -26,9 +26,12 @@ qtConfig(mimetype) { qtConfig(mimetype-database) { outpath = .rcc + android { + outpath = $$outpath/$${QT_ARCH} + } debug_and_release { - CONFIG(debug, debug|release): outpath = .rcc/debug - else: outpath = .rcc/release + CONFIG(debug, debug|release): outpath = $$outpath/debug + else: outpath = $$outpath/release } mimedb.depends = $$PWD/mime/generate.pl -- cgit v1.2.3 From 67edae9a0837d8efeb105406e546ae3791e1204d Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 3 Mar 2020 13:06:28 +0100 Subject: QVulkanWindow: Fix setQueueCreateInfoModifier signature ...per API review. Change-Id: I4a5a1cc895eac32f21f8a830507b841318509992 Reviewed-by: Paul Olav Tvete --- src/gui/vulkan/qvulkanwindow.cpp | 2 +- src/gui/vulkan/qvulkanwindow.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gui/vulkan/qvulkanwindow.cpp b/src/gui/vulkan/qvulkanwindow.cpp index ee49cf0999..cb89b0b1e6 100644 --- a/src/gui/vulkan/qvulkanwindow.cpp +++ b/src/gui/vulkan/qvulkanwindow.cpp @@ -1602,7 +1602,7 @@ bool QVulkanWindow::event(QEvent *e) \since 5.15 */ -void QVulkanWindow::setQueueCreateInfoModifier(QueueCreateInfoModifier modifier) +void QVulkanWindow::setQueueCreateInfoModifier(const QueueCreateInfoModifier &modifier) { Q_D(QVulkanWindow); d->queueCreateInfoModifier = modifier; diff --git a/src/gui/vulkan/qvulkanwindow.h b/src/gui/vulkan/qvulkanwindow.h index 511b9501bd..a2d1c9995c 100644 --- a/src/gui/vulkan/qvulkanwindow.h +++ b/src/gui/vulkan/qvulkanwindow.h @@ -106,7 +106,7 @@ public: typedef std::function &)> QueueCreateInfoModifier; - void setQueueCreateInfoModifier(QueueCreateInfoModifier modifier); + void setQueueCreateInfoModifier(const QueueCreateInfoModifier &modifier); bool isValid() const; -- cgit v1.2.3 From 52de905d0ec6159d3a1e7ad63fed018b5c6973d2 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Tue, 10 Mar 2020 18:37:33 +0100 Subject: Doc: Fix documentation for class qfloat16 This class has documented member functions, but only the related \headerfile was documented. The class documentation itself was omitted with the \dontdocument command. Replace the \headerfile with a \class command, and move the global functions to be related to the class itself. Keep the title as a \keyword to avoid breaking any external links. The new class page will inherit the .html file name of the header page, so we're safe in that regard as well. Fixes: QTBUG-82800 Change-Id: Id51539b45e0642d91b304a37f95461ca3d6c9841 Reviewed-by: Paul Wicking --- src/corelib/doc/src/dontdocument.qdoc | 2 +- src/corelib/global/qfloat16.cpp | 44 ++++++++++++++++++----------------- 2 files changed, 24 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/corelib/doc/src/dontdocument.qdoc b/src/corelib/doc/src/dontdocument.qdoc index ff0aa98709..01bed99a57 100644 --- a/src/corelib/doc/src/dontdocument.qdoc +++ b/src/corelib/doc/src/dontdocument.qdoc @@ -34,7 +34,7 @@ QMetaTypeId2 QObjectData QObjectUserData QMapNodeBase QMapNode QMapDataBase QMapData QHashData QHashNode QArrayDataPointer QTextStreamManipulator QContiguousCacheData QContiguousCacheTypedData QNoDebug QUrlTwoFlags - QCborValueRef qfloat16 QDeferredDeleteEvent QSpecialInteger QLittleEndianStorageType + QCborValueRef QDeferredDeleteEvent QSpecialInteger QLittleEndianStorageType QBigEndianStorageType QFactoryInterface QFutureWatcherBase QJsonValuePtr QJsonValueRefPtr QLinkedListNode QAbstractConcatenable QStringBuilderCommon QTextCodec::ConverterState QThreadStorageData QTextStreamManipulator) diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp index 3d82bbe95a..1f06b10313 100644 --- a/src/corelib/global/qfloat16.cpp +++ b/src/corelib/global/qfloat16.cpp @@ -45,18 +45,20 @@ QT_BEGIN_NAMESPACE /*! - \headerfile - \title 16-bit Floating Point Support + \class qfloat16 + \keyword 16-bit Floating Point Support \ingroup funclists - \brief The header file provides 16-bit floating point support. - - This header file provides support for half-precision (16-bit) floating - point data with the class \c qfloat16. It is fully compliant with IEEE - 754 as a storage type. This implies that any arithmetic operation on a - \c qfloat16 instance results in the value first being converted to a - \c float. This conversion to and from \c float is performed by hardware - when possible, but on processors that do not natively support half-precision, - the conversion is performed through a sequence of lookup table operations. + \inmodule QtCore + \inheaderfile QFloat16 + \brief Provides 16-bit floating point support. + + The \c qfloat16 class provides support for half-precision (16-bit) floating + point data. It is fully compliant with IEEE 754 as a storage type. This + implies that any arithmetic operation on a \c qfloat16 instance results in + the value first being converted to a \c float. This conversion to and from + \c float is performed by hardware when possible, but on processors that do + not natively support half-precision, the conversion is performed through a + sequence of lookup table operations. \c qfloat16 should be treated as if it were a POD (plain old data) type. Consequently, none of the supported operations need any elaboration beyond @@ -68,7 +70,7 @@ QT_BEGIN_NAMESPACE /*! \macro QT_NO_FLOAT16_OPERATORS - \relates + \relates qfloat16 \since 5.12.4 Defining this macro disables the arithmetic operators for qfloat16. @@ -81,7 +83,7 @@ QT_BEGIN_NAMESPACE /*! \fn bool qIsInf(qfloat16 f) - \relates + \relates qfloat16 Returns true if the \c qfloat16 \a {f} is equivalent to infinity. @@ -90,7 +92,7 @@ QT_BEGIN_NAMESPACE /*! \fn bool qIsNaN(qfloat16 f) - \relates + \relates qfloat16 Returns true if the \c qfloat16 \a {f} is not a number (NaN). @@ -99,7 +101,7 @@ QT_BEGIN_NAMESPACE /*! \fn bool qIsFinite(qfloat16 f) - \relates + \relates qfloat16 Returns true if the \c qfloat16 \a {f} is a finite number. @@ -130,7 +132,7 @@ QT_BEGIN_NAMESPACE \since 5.14 \fn bool qfloat16::isNormal() const noexcept - Tests whether this \c qfloat16 value is finite and in normal form. + Returns \c true if this \c qfloat16 value is finite and in normal form. \sa qFpClassify() */ @@ -167,7 +169,7 @@ int qfloat16::fpClassify() const noexcept } /*! \fn int qRound(qfloat16 value) - \relates + \relates qfloat16 Rounds \a value to the nearest integer. @@ -175,7 +177,7 @@ int qfloat16::fpClassify() const noexcept */ /*! \fn qint64 qRound64(qfloat16 value) - \relates + \relates qfloat16 Rounds \a value to the nearest 64-bit integer. @@ -183,7 +185,7 @@ int qfloat16::fpClassify() const noexcept */ /*! \fn bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) - \relates + \relates qfloat16 Compares the floating point value \a p1 and \a p2 and returns \c true if they are considered equal, otherwise \c false. @@ -256,7 +258,7 @@ static void qFloatFromFloat16_fast(float *, const quint16 *, qsizetype) noexcept #endif /*! \since 5.11 - \relates + \relates qfloat16 Converts \a len floats from \a in to qfloat16 and stores them in \a out. Both \a in and \a out must have \a len allocated entries. @@ -272,7 +274,7 @@ Q_CORE_EXPORT void qFloatToFloat16(qfloat16 *out, const float *in, qsizetype len /*! \since 5.11 - \relates + \relates qfloat16 Converts \a len qfloat16 from \a in to floats and stores them in \a out. Both \a in and \a out must have \a len allocated entries. -- cgit v1.2.3