summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-03-11 01:00:56 +0100
committerSona Kurazyan <sona.kurazyan@qt.io>2020-03-11 15:39:56 +0100
commit3d315860cdf13fe2adf78c8eea07aea10444ed72 (patch)
treeb5a7daa8534b8dadc3abfd665655af3a2450af76 /src
parentcd80f347cf5d40938df7c10d1f6dac3d8c81ff95 (diff)
parent865afac25036d58b18794384e37d42931b2164c5 (diff)
Merge "Merge remote-tracking branch 'origin/5.15' into dev"
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--src/android/templates/AndroidManifest.xml2
-rw-r--r--src/android/templates/build.gradle8
-rw-r--r--src/corelib/Qt5AndroidSupport.cmake5
-rw-r--r--src/corelib/doc/src/dontdocument.qdoc2
-rw-r--r--src/corelib/doc/src/resource-system.qdoc19
-rw-r--r--src/corelib/global/qfloat16.cpp44
-rw-r--r--src/corelib/io/qloggingregistry.cpp40
-rw-r--r--src/corelib/io/qloggingregistry_p.h8
-rw-r--r--src/corelib/io/qprocess.cpp9
-rw-r--r--src/corelib/io/qresource.cpp2
-rw-r--r--src/corelib/kernel/qmetatype.cpp4
-rw-r--r--src/corelib/mimetypes/mimetypes.pri7
-rw-r--r--src/corelib/text/qbytearray.h8
-rw-r--r--src/corelib/text/qstring.cpp40
-rw-r--r--src/corelib/text/qstring.h15
-rw-r--r--src/corelib/text/qstringview.cpp26
-rw-r--r--src/corelib/text/qstringview.h5
-rw-r--r--src/gui/doc/snippets/code/src_gui_image_qpixmapcache.cpp3
-rw-r--r--src/gui/image/qimage.cpp46
-rw-r--r--src/gui/image/qimage_conversions.cpp209
-rw-r--r--src/gui/painting/qimagescale.cpp794
-rw-r--r--src/gui/painting/qimagescale_neon.cpp218
-rw-r--r--src/gui/painting/qimagescale_p.h2
-rw-r--r--src/gui/painting/qimagescale_sse4.cpp246
-rw-r--r--src/gui/painting/qpainterpath.cpp70
-rw-r--r--src/gui/painting/qpainterpath.h12
-rw-r--r--src/gui/painting/qrasterizer.cpp2
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp2
-rw-r--r--src/gui/painting/qtransform.h5
-rw-r--r--src/gui/rhi/qrhi.cpp66
-rw-r--r--src/gui/rhi/qrhi_p.h11
-rw-r--r--src/gui/rhi/qrhid3d11.cpp282
-rw-r--r--src/gui/rhi/qrhid3d11_p_p.h11
-rw-r--r--src/gui/rhi/qrhigles2.cpp61
-rw-r--r--src/gui/rhi/qrhimetal.mm112
-rw-r--r--src/gui/rhi/qrhimetal_p_p.h11
-rw-r--r--src/gui/rhi/qrhivulkan.cpp92
-rw-r--r--src/gui/rhi/qrhivulkan_p_p.h11
-rw-r--r--src/gui/text/qrawfont.cpp1
-rw-r--r--src/gui/vulkan/qvulkanwindow.cpp2
-rw-r--r--src/gui/vulkan/qvulkanwindow.h2
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp2
-rw-r--r--src/network/access/qnetworkaccessmanager.h15
-rw-r--r--src/network/doc/qtnetwork.qdocconf2
-rw-r--r--src/network/doc/snippets/CMakeLists.txt12
-rw-r--r--src/network/doc/snippets/code/doc_src_qtnetwork.pro3
-rw-r--r--src/network/doc/snippets/network/tcpwait.cpp2
-rw-r--r--src/network/doc/snippets/snippets.pro2
-rw-r--r--src/network/doc/src/bearermanagement.qdoc2
-rw-r--r--src/network/doc/src/qtnetwork.qdoc30
-rw-r--r--src/network/ssl/qsslcertificate.cpp8
-rw-r--r--src/network/ssl/qsslcertificate.h4
-rw-r--r--src/network/ssl/qsslconfiguration.h5
-rw-r--r--src/network/ssl/qsslsocket_schannel.cpp3
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp1
-rw-r--r--src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm1
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp1
-rw-r--r--src/platformsupport/services/genericunix/qgenericunixservices.cpp7
-rw-r--r--src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp10
-rw-r--r--src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h3
-rw-r--r--src/platformsupport/windowsuiautomation/uiatypes_p.h16
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm1
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp26
-rw-r--r--src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp10
-rw-r--r--src/plugins/sqldrivers/odbc/qsql_odbc.cpp2
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm1
-rw-r--r--src/printsupport/dialogs/qprintdialog_mac.mm72
-rw-r--r--src/tools/androiddeployqt/main.cpp16
-rw-r--r--src/widgets/graphicsview/qgraphicsscene.cpp1
-rw-r--r--src/widgets/graphicsview/qgraphicssceneindex.cpp1
-rw-r--r--src/widgets/graphicsview/qgraphicsview.cpp1
-rw-r--r--src/widgets/graphicsview/qgraphicswidget.cpp1
-rw-r--r--src/widgets/styles/qcommonstyle.cpp2
-rw-r--r--src/widgets/styles/qfusionstyle.cpp1
-rw-r--r--src/widgets/styles/qstylesheetstyle.cpp1
-rw-r--r--src/widgets/styles/qwindowsstyle.cpp1
77 files changed, 1790 insertions, 993 deletions
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 8dadd1eac8..e31dea6a8c 100644
--- a/src/android/templates/AndroidManifest.xml
+++ b/src/android/templates/AndroidManifest.xml
@@ -1,7 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest package="org.qtproject.example" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="-- %%INSERT_VERSION_NAME%% --" android:versionCode="-- %%INSERT_VERSION_CODE%% --" android:installLocation="auto">
- <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="28"/>
-
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
Remove the comment if you do not require these default permissions. -->
<!-- %%INSERT_PERMISSIONS -->
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/corelib/doc/src/dontdocument.qdoc b/src/corelib/doc/src/dontdocument.qdoc
index b1af82fbe2..c84b789c46 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 QAbstractConcatenable QStringBuilderCommon
QTextCodec::ConverterState QThreadStorageData QTextStreamManipulator)
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
+ <qresource>
+ <file compress="1" compress-algo="zstd">data.txt</file>
+ </qresource>
+ \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.
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 <QFloat16>
- \title 16-bit Floating Point Support
+ \class qfloat16
+ \keyword 16-bit Floating Point Support
\ingroup funclists
- \brief The <QFloat16> 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 <QFloat16>
+ \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 <QFloat16>
+ \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 <QFloat16>
+ \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 <QFloat16>
+ \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 <QFloat16>
+ \relates qfloat16
Rounds \a value to the nearest integer.
@@ -175,7 +177,7 @@ int qfloat16::fpClassify() const noexcept
*/
/*! \fn qint64 qRound64(qfloat16 value)
- \relates <QFloat16>
+ \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 <QFloat16>
+ \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 <QFloat16>
+ \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 <QFloat16>
+ \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.
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<QLoggingRule> rules() const { return _rules; }
private:
- void parseNextLine(QStringRef line);
+ void parseNextLine(QStringView line);
private:
bool m_inRulesSection = false;
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index 3b708d7727..1f4be24913 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -2475,12 +2475,11 @@ 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;
+ QString program = args.takeFirst();
+ return execute(program, args);
}
/*!
diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp
index e636712e57..9a2fd196a2 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
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 4d9f3b01de..ea0016c5af 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -337,7 +337,7 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry)
\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
@@ -383,7 +383,7 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry)
\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
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
diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h
index e3fec1e62c..d260a9d678 100644
--- a/src/corelib/text/qbytearray.h
+++ b/src/corelib/text/qbytearray.h
@@ -219,8 +219,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;
@@ -555,12 +555,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 757f248e8a..745d3d8047 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -6154,6 +6154,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()
@@ -9576,6 +9586,23 @@ QString &QString::setRawData(const QChar *unicode, int size)
*/
/*!
+ \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
\fn bool QLatin1String::startsWith(QLatin1String l1, Qt::CaseSensitivity cs) const
@@ -10943,6 +10970,19 @@ QStringRef QStringRef::appendTo(QString *string) const
/*!
\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
\since 4.5
diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h
index f4d6fc24a5..d5101b7ff3 100644
--- a/src/corelib/text/qstring.h
+++ b/src/corelib/text/qstring.h
@@ -110,6 +110,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
@@ -232,6 +241,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
@@ -729,6 +740,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
@@ -1615,6 +1628,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
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); }
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/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index ce0c6170c1..189f12fd5c 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -68,6 +68,11 @@
#include <private/qimage_p.h>
#include <private/qfont_p.h>
+#if QT_CONFIG(thread)
+#include "qsemaphore.h"
+#include "qthreadpool.h"
+#endif
+
QT_BEGIN_NAMESPACE
static inline bool isLocked(QImageData *data)
@@ -4861,18 +4866,43 @@ void QImage::applyColorTransform(const QColorTransform &transform)
Q_UNREACHABLE();
}
+ std::function<void(int,int)> transformSegment;
+
if (depth() > 32) {
- for (int i = 0; i < height(); ++i) {
- QRgba64 *scanline = reinterpret_cast<QRgba64 *>(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<QRgba64 *>(scanLine(y));
+ transform.d->apply(scanline, scanline, width(), flags);
+ }
+ };
} else {
- for (int i = 0; i < height(); ++i) {
- QRgb *scanline = reinterpret_cast<QRgb *>(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<QRgb *>(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 <private/qendian_p.h>
#include <private/qsimd_p.h>
#include <private/qimage_p.h>
+
#include <qendian.h>
+#if QT_CONFIG(thread)
+#include <qsemaphore.h>
+#include <qthreadpool.h>
+#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<uint *>(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<uint *>(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<QRgba64 *>(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<QRgba64 *>(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<uint *>(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<uint *>(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 <private/qsimd_p.h>
+#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<bool RGB>
@@ -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<bool RGB>
@@ -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<false>(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 <private/qdrawhelper_x86_p.h>
#include <private/qsimd_p.h>
+#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<bool RGB>
@@ -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<bool RGB>
@@ -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<false>(QImageScaleInfo *isi, unsigned int *dest,
diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp
index 11623c78f0..e3cdc218b2 100644
--- a/src/gui/painting/qpainterpath.cpp
+++ b/src/gui/painting/qpainterpath.cpp
@@ -1603,25 +1603,6 @@ QPainterPath QPainterPath::toReversed() const
}
/*!
- \overload
-
- Converts the path into a list of polygons without any transformation,
- and returns the list.
-
- This function creates one polygon for each subpath regardless of
- intersecting subpaths (i.e. overlapping bounding rectangles). To
- make sure that such overlapping subpaths are filled correctly, use
- the toFillPolygons() function instead.
-
- \sa toFillPolygons(), toFillPolygon(), {QPainterPath#QPainterPath
- Conversion}{QPainterPath Conversion}
-*/
-QList<QPolygonF> QPainterPath::toSubpathPolygons() const
-{
- return toSubpathPolygons(QTransform());
-}
-
-/*!
Converts the path into a list of polygons using the QTransform
\a matrix, and returns the list.
@@ -1679,35 +1660,6 @@ QList<QPolygonF> QPainterPath::toSubpathPolygons(const QTransform &matrix) const
}
/*!
- \overload
-
- Converts the path into a list of polygons without any transformation,
- and returns the list.
-
- The function differs from the toFillPolygon() function in that it
- creates several polygons. It is provided because it is usually
- faster to draw several small polygons than to draw one large
- polygon, even though the total number of points drawn is the same.
-
- The toFillPolygons() function differs from the toSubpathPolygons()
- function in that it create only polygon for subpaths that have
- overlapping bounding rectangles.
-
- Like the toFillPolygon() function, this function uses a rewinding
- technique to make sure that overlapping subpaths can be filled
- using the correct fill rule. Note that rewinding inserts addition
- lines in the polygons so the outline of the fill polygon does not
- match the outline of the path.
-
- \sa toSubpathPolygons(), toFillPolygon(),
- {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
-*/
-QList<QPolygonF> QPainterPath::toFillPolygons() const
-{
- return toFillPolygons(QTransform());
-}
-
-/*!
Converts the path into a list of polygons using the
QTransform \a matrix, and returns the list.
@@ -2903,28 +2855,6 @@ void QPainterPathStroker::setDashOffset(qreal offset)
}
/*!
- \overload
-
- Converts the path into a polygon without any transformation,
- and returns the polygon.
-
- The polygon is created by first converting all subpaths to
- polygons, then using a rewinding technique to make sure that
- overlapping subpaths can be filled using the correct fill rule.
-
- Note that rewinding inserts addition lines in the polygon so
- the outline of the fill polygon does not match the outline of
- the path.
-
- \sa toSubpathPolygons(), toFillPolygons(),
- {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
-*/
-QPolygonF QPainterPath::toFillPolygon() const
-{
- return toFillPolygon(QTransform());
-}
-
-/*!
Converts the path into a polygon using the QTransform
\a matrix, and returns the polygon.
diff --git a/src/gui/painting/qpainterpath.h b/src/gui/painting/qpainterpath.h
index 078b665222..aa43c74bee 100644
--- a/src/gui/painting/qpainterpath.h
+++ b/src/gui/painting/qpainterpath.h
@@ -41,6 +41,7 @@
#define QPAINTERPATH_H
#include <QtGui/qtguiglobal.h>
+#include <QtGui/qtransform.h>
#include <QtCore/qglobal.h>
#include <QtCore/qrect.h>
#include <QtCore/qline.h>
@@ -176,12 +177,9 @@ public:
Q_REQUIRED_RESULT QPainterPath toReversed() const;
- QList<QPolygonF> toSubpathPolygons() const;
- QList<QPolygonF> toSubpathPolygons(const QTransform &matrix) const;
- QList<QPolygonF> toFillPolygons() const;
- QList<QPolygonF> toFillPolygons(const QTransform &matrix) const;
- QPolygonF toFillPolygon() const;
- QPolygonF toFillPolygon(const QTransform &matrix) const;
+ QList<QPolygonF> toSubpathPolygons(const QTransform &matrix = QTransform()) const;
+ QList<QPolygonF> toFillPolygons(const QTransform &matrix = QTransform()) const;
+ QPolygonF toFillPolygon(const QTransform &matrix = QTransform()) const;
int elementCount() const;
QPainterPath::Element elementAt(int i) const;
@@ -356,6 +354,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 <private/qdatabuffer_p.h>
#include <private/qdrawhelper_p.h>
+#include <QtGui/qpainterpath.h>
+
#include <algorithm>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index e906397520..3728060caf 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 <QtGui/qpainterpath.h>
+
QT_BEGIN_NAMESPACE
// #define CACHE_DEBUG
diff --git a/src/gui/painting/qtransform.h b/src/gui/painting/qtransform.h
index 351f2b2e4e..d235f15029 100644
--- a/src/gui/painting/qtransform.h
+++ b/src/gui/painting/qtransform.h
@@ -40,7 +40,6 @@
#define QTRANSFORM_H
#include <QtGui/qtguiglobal.h>
-#include <QtGui/qpainterpath.h>
#include <QtGui/qpolygon.h>
#include <QtGui/qregion.h>
#include <QtGui/qwindowdefs.h>
@@ -50,8 +49,8 @@
QT_BEGIN_NAMESPACE
-
class QVariant;
+class QPainterPath;
class Q_GUI_EXPORT QTransform
{
@@ -406,8 +405,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/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..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)
@@ -627,18 +631,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 +1905,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<int, int> 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<int, int> nativeBindingVert = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
+ const QPair<int, int> nativeBindingFrag = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
+ const QPair<int, int> 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<int, int> 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<int, int> 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 });
+ }
}
}
}
@@ -2077,102 +2095,156 @@ static void applyDynamicOffsets(QVarLengthArray<UINT, 4> *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<int>(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<int>(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<int>(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<UINT, 4> 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<UINT, 4> 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<UINT, 4> 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<UINT, 4> 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<UINT, 4> 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<UINT, 4> 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<int>(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);
+ }
}
}
@@ -3529,11 +3601,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 4a442bc582..ea9bce08e4 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -917,10 +917,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:
@@ -2572,36 +2574,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<QGles2SamplerDescription> &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<MTLLibrary> 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<MTLLibrary> 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<MTLLibrary> 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..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;
}
@@ -2487,7 +2496,8 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
QVkShaderResourceBindings *srbD = QRHI_RES(QVkShaderResourceBindings, srb);
QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
- QVarLengthArray<VkDescriptorImageInfo, 8> imageInfos;
+ using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
+ QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
QVarLengthArray<QPair<int, int>, 12> infoIndices;
@@ -2530,17 +2540,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 +2570,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 +2611,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 +4225,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 +6086,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;
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 <QtCore/qendian.h>
#include <QtCore/qfile.h>
+#include <QtGui/qpainterpath.h>
QT_BEGIN_NAMESPACE
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<void(const VkQueueFamilyProperties *,
uint32_t,
QVector<VkDeviceQueueCreateInfo> &)> QueueCreateInfoModifier;
- void setQueueCreateInfoModifier(QueueCreateInfoModifier modifier);
+ void setQueueCreateInfoModifier(const QueueCreateInfoModifier &modifier);
bool isValid() const;
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 21d46011d7..d4df58e885 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 5194afb1be..f50dfbcca4 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -91,12 +91,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);
@@ -150,8 +153,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
@@ -187,7 +193,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/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 <QtGui>
+#include <QCoreApplication>
#include <QTcpSocket>
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/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.
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 <QtNetwork>
- \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.
*/
diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp
index da952f6e6b..aa2f8fed02 100644
--- a/src/network/ssl/qsslcertificate.cpp
+++ b/src/network/ssl/qsslcertificate.cpp
@@ -564,12 +564,12 @@ QList<QSslCertificate> 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<QSslCertificate>();
#endif
@@ -606,7 +606,7 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
QList<QSslCertificate> 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 c46065160a..525642a809 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 5732deaaef..1ce01dbee9 100644
--- a/src/network/ssl/qsslconfiguration.h
+++ b/src/network/ssl/qsslconfiguration.h
@@ -130,8 +130,9 @@ public:
// Certificate Authority (CA) settings
QList<QSslCertificate> caCertificates() const;
void setCaCertificates(const QList<QSslCertificate> &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<QSslCertificate> &certificates);
diff --git a/src/network/ssl/qsslsocket_schannel.cpp b/src/network/ssl/qsslsocket_schannel.cpp
index 2db5c48ff2..c355abad73 100644
--- a/src/network/ssl/qsslsocket_schannel.cpp
+++ b/src/network/ssl/qsslsocket_schannel.cpp
@@ -1306,7 +1306,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
diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
index d7ccd9db92..d38fa299f9 100644
--- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
+++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
@@ -48,6 +48,7 @@
#include <qscreen.h>
#include <qpa/qplatformscreen.h>
#include <QtCore/QUuid>
+#include <QtGui/QPainterPath>
#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 <QtCore/qsettings.h>
#endif
#include <QtCore/qoperatingsystemversion.h>
+#include <QtGui/qpainterpath.h>
#include <private/qcoregraphics_p.h>
#include <private/qimage_p.h>
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
index b11ad46bc7..4e6b22ce94 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
@@ -51,6 +51,7 @@
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
#include <QtGui/private/qhighdpiscaling_p.h>
+#include <QtGui/qpainterpath.h>
#if defined(QT_USE_DIRECTWRITE2)
# include <dwrite_2.h>
diff --git a/src/platformsupport/services/genericunix/qgenericunixservices.cpp b/src/platformsupport/services/genericunix/qgenericunixservices.cpp
index 734bdcaf75..b583d636c0 100644
--- a/src/platformsupport/services/genericunix/qgenericunixservices.cpp
+++ b/src/platformsupport/services/genericunix/qgenericunixservices.cpp
@@ -166,7 +166,12 @@ 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);
+ bool ok = false;
+ if (!args.isEmpty()) {
+ QString program = args.takeFirst();
+ ok = QProcess::startDetached(program, args);
+ }
#endif
if (!ok)
qWarning("Launch failed (%s)", qPrintable(command));
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<PtrUiaHostProviderFromHwnd>(uiaLib.resolve("UiaHostProviderFromHwnd"));
m_pUiaRaiseAutomationPropertyChangedEvent = reinterpret_cast<PtrUiaRaiseAutomationPropertyChangedEvent>(uiaLib.resolve("UiaRaiseAutomationPropertyChangedEvent"));
m_pUiaRaiseAutomationEvent = reinterpret_cast<PtrUiaRaiseAutomationEvent>(uiaLib.resolve("UiaRaiseAutomationEvent"));
+ m_pUiaRaiseNotificationEvent = reinterpret_cast<PtrUiaRaiseNotificationEvent>(uiaLib.resolve("UiaRaiseNotificationEvent"));
m_pUiaClientsAreListening = reinterpret_cast<PtrUiaClientsAreListening>(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/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 28da4fcf5d..61bf0d4a4e 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -1632,6 +1632,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
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<HRESULT>(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)) {
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<const wchar_t *>(suggestedName.utf16()),
uint(suggestedName.length()));
diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
index be1a06bc1d..2f56487f88 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)
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index f473c3cbe3..f8e423456f 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -56,6 +56,7 @@
#include <QtCore/private/qcore_mac_p.h>
+#include <QtGui/qpainterpath.h>
#include <QtGui/private/qcoregraphics_p.h>
#include <QtGui/qpa/qplatformfontdatabase.h>
#include <QtGui/qpa/qplatformtheme.h>
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 <QtCore/qtemporarydir.h>
#include <QtCore/private/qcore_mac_p.h>
#include <QtWidgets/private/qapplication_p.h>
#include <QtPrintSupport/qprinter.h>
@@ -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<CFURLRef> 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<const char *>(localFile)));
- */
- } else {
+ auto outputFile = QFileInfo(QString::fromUtf8(reinterpret_cast<const char *>(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<NSPrintInfo *>(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<NSPrintInfo *>(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);
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp
index bcb96841df..ba3c0dad83 100644
--- a/src/tools/androiddeployqt/main.cpp
+++ b/src/tools/androiddeployqt/main.cpp
@@ -170,6 +170,8 @@ struct Options
// Versioning
QString versionName;
QString versionCode;
+ QByteArray minSdkVersion{"21"};
+ QByteArray targetSdkVersion{"28"};
// lib c++ path
QString stdCppPath;
@@ -860,6 +862,18 @@ bool readInputFile(Options *options)
}
{
+ 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()) {
fprintf(stderr, "No target architecture defined in json file.\n");
@@ -2319,6 +2333,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();
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 <QtWidgets/qgraphicswidget.h>
#include <QtGui/qpaintengine.h>
#include <QtGui/qpainter.h>
+#include <QtGui/qpainterpath.h>
#include <QtGui/qpixmapcache.h>
#include <QtGui/qpolygon.h>
#include <QtGui/qtouchdevice.h>
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 <QtGui/qpainterpath.h>
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/graphicsview/qgraphicsview.cpp b/src/widgets/graphicsview/qgraphicsview.cpp
index a744847f33..1117f5e473 100644
--- a/src/widgets/graphicsview/qgraphicsview.cpp
+++ b/src/widgets/graphicsview/qgraphicsview.cpp
@@ -293,6 +293,7 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime <
#include <QtWidgets/qlayout.h>
#include <QtGui/qtransform.h>
#include <QtGui/qpainter.h>
+#include <QtGui/qpainterpath.h>
#include <QtWidgets/qscrollbar.h>
#include <QtWidgets/qstyleoption.h>
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 <QtWidgets/qgraphicsview.h>
#include <QtWidgets/qgraphicsproxywidget.h>
#include <QtGui/qpalette.h>
+#include <QtGui/qpainterpath.h>
#include <QtWidgets/qstyleoption.h>
#include <qdebug.h>
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);
}
diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp
index 4427d69944..2a0d6d1b40 100644
--- a/src/widgets/styles/qfusionstyle.cpp
+++ b/src/widgets/styles/qfusionstyle.cpp
@@ -52,6 +52,7 @@
#include <qabstractbutton.h>
#endif
#include <qpainter.h>
+#include <qpainterpath.h>
#include <qdir.h>
#include <qstyleoption.h>
#include <qapplication.h>
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 <QtWidgets/qtoolbar.h>
#endif
+#include <QtGui/qpainterpath.h>
#include <QtGui/qscreen.h>
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 <private/qmath_p.h>
#include <qmath.h>
+#include <QtGui/qpainterpath.h>
#include <QtGui/qscreen.h>
#include <QtGui/qwindow.h>
#include <qpa/qplatformtheme.h>