From fcb78b500076bf3917e5d8bf8507395bbc33a1a5 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Tue, 17 Sep 2019 09:56:14 +0300 Subject: [PATCH 01/16] Android: Fix plugins naming Android 5 doesn't extract the files from libs folder unless they are prefixed with "lib". This patch sets a proper name for the plugin which will make gdb happy and it will also avoid any name clashes. If we rename the plugins when we copy them, gdb won't find them, therefore it can't load their symbols. On Android all the libs are in a single folder, so to make sure we don't have any name clashes, we are prefixing the plugin name with it's relative path to qt folder (we replace / with _). Fixes: QTBUG-78616 Change-Id: I7e0e67d65448532769d69f46b1856c029e2cf5cb Reviewed-by: Eskil Abrahamsen Blomfeldt --- mkspecs/features/qml_plugin.prf | 2 +- mkspecs/features/qt_functions.prf | 8 +++++++- mkspecs/features/qt_plugin.prf | 2 +- src/corelib/corelib.pro | 2 +- src/corelib/plugin/qfactoryloader.cpp | 2 +- src/network/network.pro | 2 +- src/tools/androiddeployqt/main.cpp | 20 +++++++++++--------- 7 files changed, 23 insertions(+), 15 deletions(-) diff --git a/mkspecs/features/qml_plugin.prf b/mkspecs/features/qml_plugin.prf index 02068ae766..f1c5658b04 100644 --- a/mkspecs/features/qml_plugin.prf +++ b/mkspecs/features/qml_plugin.prf @@ -55,7 +55,7 @@ INSTALLS += target # Some final setup -TARGET = $$qt5LibraryTarget($$TARGET) +TARGET = $$qt5LibraryTarget($$TARGET, "qml/$$TARGETPATH/") load(qt_targets) load(qt_common) diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 2c68e91cd7..ee6a4b352a 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -21,7 +21,13 @@ defineReplace(qtLibraryTarget) { } defineReplace(qt5LibraryTarget) { - LIBRARY_NAME = $$qtLibraryTarget($$1) + android { + LIBRARY_NAME_PREFIX = $$2 + LIBRARY_NAME_PREFIX = $$replace(LIBRARY_NAME_PREFIX, "//", "/") + LIBRARY_NAME_PREFIX = $$replace(LIBRARY_NAME_PREFIX, "/", "_") + LIBRARY_NAME = $$LIBRARY_NAME_PREFIX$$qtLibraryTarget($$1) + unset(LIBRARY_NAME_PREFIX) + } else: LIBRARY_NAME = $$qtLibraryTarget($$1) isEmpty(QMAKE_FRAMEWORK_BUNDLE_NAME) { # Insert the major version of Qt in the library name # unless it's a framework build. diff --git a/mkspecs/features/qt_plugin.prf b/mkspecs/features/qt_plugin.prf index 6e7388c352..573d717eea 100644 --- a/mkspecs/features/qt_plugin.prf +++ b/mkspecs/features/qt_plugin.prf @@ -92,7 +92,7 @@ target.path = $$[QT_INSTALL_PLUGINS]/$$PLUGIN_TYPE INSTALLS += target qt_libinfix_plugins: TARGET = $$TARGET$$QT_LIBINFIX -TARGET = $$qt5LibraryTarget($$TARGET) +TARGET = $$qt5LibraryTarget($$TARGET, "plugins/$$PLUGIN_TYPE/") CONFIG += create_cmake diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index ba5f5adf8d..452d2db0fd 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -21,7 +21,7 @@ CONFIG += simd optimize_full QMAKE_DOCS = $$PWD/doc/qtcore.qdocconf ANDROID_LIB_DEPENDENCIES = \ - plugins/platforms/libqtforandroid.so + plugins/platforms/libplugins_platforms_qtforandroid.so ANDROID_BUNDLED_JAR_DEPENDENCIES = \ jar/QtAndroid.jar ANDROID_PERMISSIONS = \ diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index 79315ae50f..18f10c9b43 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -209,7 +209,7 @@ void QFactoryLoader::update() #if defined(Q_OS_WIN) QStringList(QStringLiteral("*.dll")), #elif defined(Q_OS_ANDROID) - QStringList(QLatin1String("plugins_%1_*.so").arg(d->suffix)), + QStringList(QLatin1String("libplugins_%1_*.so").arg(d->suffix)), #endif QDir::Files); QLibraryPrivate *library = 0; diff --git a/src/network/network.pro b/src/network/network.pro index 9082439f1c..d8453e879c 100644 --- a/src/network/network.pro +++ b/src/network/network.pro @@ -26,7 +26,7 @@ qtConfig(bearermanagement) { ANDROID_BUNDLED_JAR_DEPENDENCIES = \ jar/QtAndroidBearer.jar ANDROID_LIB_DEPENDENCIES = \ - plugins/bearer/libqandroidbearer.so + plugins/bearer/libplugins_bearer_qandroidbearer.so MODULE_PLUGIN_TYPES = \ bearer ANDROID_PERMISSIONS += \ diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index 794e3b49ae..6a32a659e6 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -314,10 +314,8 @@ static QString shellQuote(const QString &arg) QString architecureFromName(const QString &name) { - const QFileInfo fi(name); - const QString extractedFileName = fi.fileName(); - QRegExp architecture(QStringLiteral(".*_(.*)\\.so")); - if (!architecture.exactMatch(extractedFileName)) + QRegExp architecture(QStringLiteral(".*_(armeabi-v7a|arm64-v8a|x86|x86_64).so")); + if (!architecture.exactMatch(name)) return {}; return architecture.capturedTexts().last(); } @@ -1177,7 +1175,7 @@ bool copyAndroidExtraResources(Options *options) } else { if (!checkArchitecture(*options, originFile)) continue; - destinationFile = libsDir + QLatin1String("/lib") + QString(resourceDir.dirName() + QLatin1Char('/') + resourceFile).replace(QLatin1Char('/'), QLatin1Char('_')); + destinationFile = libsDir + resourceFile; options->archExtraPlugins[options->currentArchitecture] += resourceFile; } if (!copyFileIfNewer(originFile, destinationFile, *options)) @@ -1330,9 +1328,13 @@ bool updateLibsXml(Options *options) if (options->verbose) fprintf(stdout, " -- Using platform plugin %s\n", qPrintable(plugin)); } - allLocalLibs += QLatin1String(" %1;%2\n").arg(it.key(), localLibs.join(QLatin1Char(':')) - .replace(QLatin1String("lib/"), QString{}) - .replace(QLatin1Char('/'), QLatin1Char('_'))); + + // remove all paths + for (auto &lib : localLibs) { + if (lib.endsWith(QLatin1String(".so"))) + lib = lib.mid(lib.lastIndexOf(QLatin1Char('/')) + 1); + } + allLocalLibs += QLatin1String(" %1;%2\n").arg(it.key(), localLibs.join(QLatin1Char(':'))); } QHash replacements; @@ -2033,7 +2035,7 @@ bool copyQtFiles(Options *options) if (qtDependency.relativePath.startsWith(QLatin1String("lib/"))) { garbledFileName = qtDependency.relativePath.mid(sizeof("lib/") - 1); } else { - garbledFileName = QString(qtDependency.relativePath).replace(QLatin1Char('/'), QLatin1Char('_')); + garbledFileName = qtDependency.relativePath.mid(qtDependency.relativePath.lastIndexOf(QLatin1Char('/')) + 1); } destinationFileName = libsDirectory + options->currentArchitecture + QLatin1Char('/') + garbledFileName; } else if (qtDependency.relativePath.startsWith(QLatin1String("jar/"))) { From beff7805064ec0bb32a16f9a610406134ea5d22d Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Sat, 14 Sep 2019 01:13:44 +0200 Subject: [PATCH 02/16] Android: Turn off rpath support as the platform does not support it Fixes: QTBUG-57909 Change-Id: I3ffe8ad25b97c6d29ea925707a3878d0e47ec9ac Reviewed-by: BogDan Vatra --- configure.json | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.json b/configure.json index 70ad9440c8..159fdf12fa 100644 --- a/configure.json +++ b/configure.json @@ -818,6 +818,7 @@ "rpath": { "label": "Build with RPATH", "autoDetect": "var.QMAKE_LFLAGS_RPATH != '' && features.shared", + "condition": "!config.android", "output": [ "publicFeature", "publicQtConfig" ] }, "rpath_dir": { From 72d62144ab2bf67266aa0474515b54999b459d32 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Mon, 30 Sep 2019 16:36:30 +0200 Subject: [PATCH 03/16] tslib plugin: remove debug print on old tslib versions This introduces a dependency on ts_get_eventpath(), which is only available in tslib 1.15 and newer. This raises the required version to an unneeded level, so just drop the debug message if the API is not available. Change-Id: I4a1cd7abec8d139e70555506d9d21edacf0f4d71 Fixes: QTBUG-78867 Reviewed-by: Shawn Rutledge Reviewed-by: Fabian Vogt --- src/platformsupport/input/tslib/qtslib.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/platformsupport/input/tslib/qtslib.cpp b/src/platformsupport/input/tslib/qtslib.cpp index df57147af6..e105f5ea98 100644 --- a/src/platformsupport/input/tslib/qtslib.cpp +++ b/src/platformsupport/input/tslib/qtslib.cpp @@ -68,7 +68,9 @@ QTsLibMouseHandler::QTsLibMouseHandler(const QString &key, return; } +#ifdef TSLIB_VERSION_EVENTPATH /* also introduced in 1.15 */ qCDebug(qLcTsLib) << "tslib device is" << ts_get_eventpath(m_dev); +#endif m_notify = new QSocketNotifier(ts_fd(m_dev), QSocketNotifier::Read, this); connect(m_notify, &QSocketNotifier::activated, this, &QTsLibMouseHandler::readMouseData); } From fb09a8bfcfb9caeb9066946a7340f60d1d6f169c Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Tue, 17 Sep 2019 09:56:07 +0300 Subject: [PATCH 04/16] Android: rework assets support The new version fix QDirIterators and it lists all the files and dirs. Change-Id: I5a30eedb61ab2397a84365d00f308cda0c194de2 Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../org/qtproject/qt5/android/QtNative.java | 19 + .../platforms/android/androidjnimain.cpp | 11 +- .../platforms/android/androidjnimain.h | 1 + .../qandroidassetsfileenginehandler.cpp | 354 +++++++++--------- .../android/qandroidassetsfileenginehandler.h | 8 - 5 files changed, 202 insertions(+), 191 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java index c33d5016ce..7db16002ff 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -1013,6 +1013,25 @@ public class QtNative }); } + private static String[] listAssetContent(android.content.res.AssetManager asset, String path) { + String [] list; + ArrayList res = new ArrayList(); + try { + list = asset.list(path); + if (list.length > 0) { + for (String file : list) { + try { + String[] isDir = asset.list(path.length() > 0 ? path + "/" + file : file); + if (isDir != null && isDir.length > 0) + file += "/"; + res.add(file); + } catch (Exception e) {} + } + } + } catch (Exception e) {} + return res.toArray(new String[res.size()]); + } + // screen methods public static native void setDisplayMetrics(int screenWidthPixels, int screenHeightPixels, diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 27eb337aaa..13ea9468df 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -75,6 +75,7 @@ static jclass m_applicationClass = nullptr; static jobject m_classLoaderObject = nullptr; static jmethodID m_loadClassMethodID = nullptr; static AAssetManager *m_assetManager = nullptr; +static jobject m_assets = nullptr; static jobject m_resourcesObj = nullptr; static jobject m_activityObject = nullptr; static jmethodID m_createSurfaceMethodID = nullptr; @@ -439,6 +440,11 @@ namespace QtAndroid return block; } + jobject assets() + { + return m_assets; + } + } // namespace QtAndroid static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring paramsString, jstring environmentString) @@ -588,6 +594,8 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/) env->DeleteGlobalRef(m_RGB_565_BitmapConfigValue); if (m_bitmapDrawableClass) env->DeleteGlobalRef(m_bitmapDrawableClass); + if (m_assets) + env->DeleteGlobalRef(m_assets); m_androidPlatformIntegration = nullptr; delete m_androidAssetsFileEngineHandler; m_androidAssetsFileEngineHandler = nullptr; @@ -840,7 +848,8 @@ static int registerNatives(JNIEnv *env) if (object) { FIND_AND_CHECK_CLASS("android/content/ContextWrapper"); GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;"); - m_assetManager = AAssetManager_fromJava(env, env->CallObjectMethod(object, methodID)); + m_assets = env->NewGlobalRef(env->CallObjectMethod(object, methodID)); + m_assetManager = AAssetManager_fromJava(env, m_assets); GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;"); m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(object, methodID)); diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index 08f1d50fe3..17ae30a1be 100644 --- a/src/plugins/platforms/android/androidjnimain.h +++ b/src/plugins/platforms/android/androidjnimain.h @@ -82,6 +82,7 @@ namespace QtAndroid double scaledDensity(); double pixelDensity(); JavaVM *javaVM(); + jobject assets(); AAssetManager *assetManager(); jclass applicationClass(); jobject activity(); diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp index e1dcebfa4c..26e72a480f 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp @@ -39,40 +39,139 @@ #include "qandroidassetsfileenginehandler.h" #include "androidjnimain.h" +#include #include #include +#include QT_BEGIN_NAMESPACE -typedef QVector FilesList; +static const QLatin1String assetsPrefix("assets:"); +const static int prefixSize = 7; -struct AndroidAssetDir +static inline QString cleanedAssetPath(QString file) { - AndroidAssetDir(AAssetDir* ad) + if (file.startsWith(assetsPrefix)) + file.remove(0, prefixSize); + file.replace(QLatin1String("//"), QLatin1String("/")); + if (file.startsWith(QLatin1Char('/'))) + file.remove(0, 1); + if (file.endsWith(QLatin1Char('/'))) + file.chop(1); + return file; +} + +static inline QString prefixedPath(QString path) +{ + path = assetsPrefix + QLatin1Char('/') + path; + path.replace(QLatin1String("//"), QLatin1String("/")); + return path; +} + +struct AssetItem { + enum class Type { + File, + Folder + }; + + AssetItem (const QString &rawName) + : name(rawName) { - if (ad) { - const char *fileName; - while ((fileName = AAssetDir_getNextFileName(ad))) - m_items.push_back(QString::fromUtf8(fileName)); - AAssetDir_close(ad); + if (name.endsWith(QLatin1Char('/'))) { + type = Type::Folder; + name.chop(1); } } - FilesList m_items; + Type type = Type::File; + QString name; }; +using AssetItemList = QVector; + +class FolderIterator : public AssetItemList +{ +public: + static QSharedPointer fromCache(const QString &path) + { + QMutexLocker lock(&m_assetsCacheMutex); + QSharedPointer *folder = m_assetsCache.object(path); + if (!folder) { + folder = new QSharedPointer{new FolderIterator{path}}; + if (!m_assetsCache.insert(path, folder)) { + QSharedPointer res = *folder; + delete folder; + return res; + } + } + return *folder; + } + + FolderIterator(const QString &path) + : m_path(path) + { + QJNIObjectPrivate files = QJNIObjectPrivate::callStaticObjectMethod(QtAndroid::applicationClass(), + "listAssetContent", + "(Landroid/content/res/AssetManager;Ljava/lang/String;)[Ljava/lang/String;", + QtAndroid::assets(), QJNIObjectPrivate::fromString(path).object()); + if (files.isValid()) { + QJNIEnvironmentPrivate env; + jobjectArray jFiles = static_cast(files.object()); + const jint nFiles = env->GetArrayLength(jFiles); + for (int i = 0; i < nFiles; ++i) + push_back({QJNIObjectPrivate(env->GetObjectArrayElement(jFiles, i)).toString()}); + } + m_path = assetsPrefix + QLatin1Char('/') + m_path + QLatin1Char('/'); + m_path.replace(QLatin1String("//"), QLatin1String("/")); + } + + QString currentFileName() const + { + if (m_index < 0 || m_index >= size()) + return {}; + return at(m_index).name; + } + QString currentFilePath() const + { + if (m_index < 0 || m_index >= size()) + return {}; + return m_path + at(m_index).name; + } + + bool hasNext() const + { + return !empty() && m_index + 1 < size(); + } + + std::optional> next() + { + if (!hasNext()) + return {}; + ++m_index; + return std::pair(currentFileName(), at(m_index)); + } + +private: + int m_index = -1; + QString m_path; + static QCache> m_assetsCache; + static QMutex m_assetsCacheMutex; +}; + +QCache> FolderIterator::m_assetsCache(std::max(50, qEnvironmentVariableIntValue("QT_ANDROID_MAX_ASSETS_CACHE_SIZE"))); +QMutex FolderIterator::m_assetsCacheMutex; + class AndroidAbstractFileEngineIterator: public QAbstractFileEngineIterator { public: AndroidAbstractFileEngineIterator(QDir::Filters filters, const QStringList &nameFilters, - QSharedPointer asset, const QString &path) : QAbstractFileEngineIterator(filters, nameFilters) { - m_items = asset->m_items; - m_index = -1; - m_path = path; + m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(path))); + if (m_stack.last()->empty()) + m_stack.pop_back(); } QFileInfo currentFileInfo() const override @@ -82,54 +181,59 @@ public: QString currentFileName() const override { - if (m_index < 0 || m_index >= m_items.size()) - return QString(); - QString fileName = m_items[m_index]; - if (fileName.endsWith(QLatin1Char('/'))) - fileName.chop(1); - return fileName; + if (!m_currentIterator) + return {}; + return m_currentIterator->currentFileName(); } virtual QString currentFilePath() const { - return m_path + currentFileName(); + if (!m_currentIterator) + return {}; + return m_currentIterator->currentFilePath(); } bool hasNext() const override { - return m_items.size() && (m_index < m_items.size() - 1); + if (m_stack.empty()) + return false; + if (!m_stack.last()->hasNext()) { + m_stack.pop_back(); + return hasNext(); + } + return true; } QString next() override { - if (!hasNext()) - return QString(); - m_index++; - return currentFileName(); + if (m_stack.empty()) { + m_currentIterator.reset(); + return {}; + } + m_currentIterator = m_stack.last(); + auto res = m_currentIterator->next(); + if (!res) + return {}; + if (res->second.type == AssetItem::Type::Folder) { + m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(currentFilePath()))); + if (m_stack.last()->empty()) + m_stack.pop_back(); + } + return res->first; } private: - QString m_path; - FilesList m_items; - int m_index; + mutable QSharedPointer m_currentIterator; + mutable QVector> m_stack; }; class AndroidAbstractFileEngine: public QAbstractFileEngine { public: - explicit AndroidAbstractFileEngine(AAsset *asset, const QString &fileName) + explicit AndroidAbstractFileEngine(AAssetManager *assetManager, const QString &fileName) + : m_assetManager(assetManager) { - m_assetFile = asset; - m_fileName = fileName; - } - - explicit AndroidAbstractFileEngine(QSharedPointer asset, const QString &fileName) - { - m_assetFile = 0; - m_assetDir = asset; - m_fileName = fileName; - if (!m_fileName.endsWith(QLatin1Char('/'))) - m_fileName += QLatin1Char('/'); + setFileName(fileName); } ~AndroidAbstractFileEngine() @@ -139,7 +243,11 @@ public: bool open(QIODevice::OpenMode openMode) override { - return m_assetFile != 0 && (openMode & QIODevice::WriteOnly) == 0; + if (m_isFolder || (openMode & QIODevice::WriteOnly)) + return false; + close(); + m_assetFile = AAssetManager_open(m_assetManager, m_fileName.toUtf8(), AASSET_MODE_BUFFER); + return m_assetFile; } bool close() override @@ -200,7 +308,7 @@ public: FileFlags flags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag); if (m_assetFile) flags |= FileType; - if (!m_assetDir.isNull()) + else if (m_isFolder) flags |= DirectoryType; return type & flags; @@ -213,19 +321,19 @@ public: case DefaultName: case AbsoluteName: case CanonicalName: - return m_fileName; + return prefixedPath(m_fileName); case BaseName: if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1) - return m_fileName.mid(pos); + return prefixedPath(m_fileName.mid(pos)); else - return m_fileName; + return prefixedPath(m_fileName); case PathName: case AbsolutePathName: case CanonicalPathName: if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1) - return m_fileName.left(pos); + return prefixedPath(m_fileName.left(pos)); else - return m_fileName; + return prefixedPath(m_fileName); default: return QString(); } @@ -233,164 +341,46 @@ public: void setFileName(const QString &file) override { - if (file == m_fileName) - return; - - m_fileName = file; - if (!m_fileName.endsWith(QLatin1Char('/'))) - m_fileName += QLatin1Char('/'); - close(); + m_fileName = cleanedAssetPath(file); + m_isFolder = !open(QIODevice::ReadOnly) && !FolderIterator::fromCache(m_fileName)->empty(); } Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override { - if (!m_assetDir.isNull()) - return new AndroidAbstractFileEngineIterator(filters, filterNames, m_assetDir, m_fileName); - return 0; + if (m_isFolder) + return new AndroidAbstractFileEngineIterator(filters, filterNames, m_fileName); + return nullptr; } private: - AAsset *m_assetFile; - QSharedPointer m_assetDir; + AAsset *m_assetFile = nullptr; + AAssetManager *m_assetManager; QString m_fileName; + bool m_isFolder; }; AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler() - : m_assetsCache(std::max(5, qEnvironmentVariableIntValue("QT_ANDROID_MAX_ASSETS_CACHE_SIZE"))) - , m_hasPrepopulatedCache(false) - , m_hasTriedPrepopulatingCache(false) { m_assetManager = QtAndroid::assetManager(); } -AndroidAssetsFileEngineHandler::~AndroidAssetsFileEngineHandler() -{ -} - -void AndroidAssetsFileEngineHandler::prepopulateCache() const -{ - Q_ASSERT(!m_hasTriedPrepopulatingCache); - m_hasTriedPrepopulatingCache = true; - - Q_ASSERT(m_assetsCache.isEmpty()); - - // Failsafe: Don't read cache files that are larger than 1MB - static qint64 maxPrepopulatedCacheSize = qMax(1024LL * 1024LL, - qgetenv("QT_ANDROID_MAX_PREPOPULATED_ASSETS_CACHE_SIZE").toLongLong()); - - const char *fileName = "--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list"; - AAsset *asset = AAssetManager_open(m_assetManager, fileName, AASSET_MODE_BUFFER); - if (asset) { - m_hasPrepopulatedCache = true; - AndroidAbstractFileEngine fileEngine(asset, QString::fromLatin1(fileName)); - if (fileEngine.open(QIODevice::ReadOnly)) { - qint64 size = fileEngine.size(); - - if (size <= maxPrepopulatedCacheSize) { - QByteArray bytes(size, Qt::Uninitialized); - qint64 read = fileEngine.read(bytes.data(), size); - if (read != size) { - qWarning("Failed to read prepopulated cache"); - return; - } - - QDataStream stream(&bytes, QIODevice::ReadOnly); - stream.setVersion(QDataStream::Qt_5_3); - if (stream.status() != QDataStream::Ok) { - qWarning("Failed to read prepopulated cache"); - return; - } - - while (!stream.atEnd()) { - QString directoryName; - stream >> directoryName; - - int fileCount; - stream >> fileCount; - - QVector fileList; - fileList.reserve(fileCount); - while (fileCount--) { - QString fileName; - stream >> fileName; - fileList.append(fileName); - } - - QSharedPointer *aad = new QSharedPointer(new AndroidAssetDir(0)); - (*aad)->m_items = fileList; - - // Cost = 0, because we should always cache everything if there's a prepopulated cache - QByteArray key = directoryName != QLatin1String("/") - ? QByteArray("assets:/") + directoryName.toUtf8() - : QByteArray("assets:"); - - bool ok = m_assetsCache.insert(key, aad, 0); - if (!ok) - qWarning("Failed to insert in cache: %s", qPrintable(directoryName)); - } - } else { - qWarning("Prepopulated cache is too large to read.\n" - "Use environment variable QT_ANDROID_MAX_PREPOPULATED_ASSETS_CACHE_SIZE to adjust size."); - } - } - } -} - QAbstractFileEngine * AndroidAssetsFileEngineHandler::create(const QString &fileName) const { if (fileName.isEmpty()) - return 0; + return nullptr; - static QLatin1String assetsPrefix("assets:"); if (!fileName.startsWith(assetsPrefix)) - return 0; + return nullptr; - static int prefixSize = assetsPrefix.size() + 1; - - QByteArray path; - if (!fileName.endsWith(QLatin1Char('/'))) { - path = fileName.toUtf8(); - if (path.size() > prefixSize) { - AAsset *asset = AAssetManager_open(m_assetManager, - path.constData() + prefixSize, - AASSET_MODE_BUFFER); - if (asset) - return new AndroidAbstractFileEngine(asset, fileName); - } - } - - if (!path.size()) - path = fileName.left(fileName.length() - 1).toUtf8(); - - - m_assetsCacheMutext.lock(); - if (!m_hasTriedPrepopulatingCache) - prepopulateCache(); - - QSharedPointer *aad = m_assetsCache.object(path); - m_assetsCacheMutext.unlock(); - if (!aad) { - if (!m_hasPrepopulatedCache && path.size() > prefixSize) { - AAssetDir *assetDir = AAssetManager_openDir(m_assetManager, path.constData() + prefixSize); - if (assetDir) { - if (AAssetDir_getNextFileName(assetDir)) { - AAssetDir_rewind(assetDir); - aad = new QSharedPointer(new AndroidAssetDir(assetDir)); - m_assetsCacheMutext.lock(); - m_assetsCache.insert(path, aad); - m_assetsCacheMutext.unlock(); - return new AndroidAbstractFileEngine(*aad, fileName); - } else { - AAssetDir_close(assetDir); - } - } - } - } else { - return new AndroidAbstractFileEngine(*aad, fileName); - } - return 0; + QString path = fileName.mid(prefixSize); + path.replace(QLatin1String("//"), QLatin1String("/")); + if (path.startsWith(QLatin1Char('/'))) + path.remove(0, 1); + if (path.endsWith(QLatin1Char('/'))) + path.chop(1); + return new AndroidAbstractFileEngine(m_assetManager, path); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.h b/src/plugins/platforms/android/qandroidassetsfileenginehandler.h index f99dc9a11a..51cc5b07a8 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.h +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.h @@ -49,22 +49,14 @@ QT_BEGIN_NAMESPACE -struct AndroidAssetDir; class AndroidAssetsFileEngineHandler: public QAbstractFileEngineHandler { public: AndroidAssetsFileEngineHandler(); - virtual ~AndroidAssetsFileEngineHandler(); QAbstractFileEngine *create(const QString &fileName) const override; private: - void prepopulateCache() const; - AAssetManager *m_assetManager; - mutable QCache> m_assetsCache; - mutable QMutex m_assetsCacheMutext; - mutable bool m_hasPrepopulatedCache; - mutable bool m_hasTriedPrepopulatingCache; }; QT_END_NAMESPACE From c8b07f7da3ff55f92378a1e98522f318bbc43077 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Thu, 15 Aug 2019 08:25:30 +0300 Subject: [PATCH 05/16] Android: Do not extract QML assets data Instead to extract the assets QML file, we create a .rcc bundle file which is register by android qpa plugin before the it invokes the main function. Thsi way we avoid extracting the QML files from assets as they can be accessed directly from resources. [ChangeLog][Android] Instead of bundling QML resources in assets and extracting them on first start, Qt now creates an .rcc file and register it before invoking the main function. Change-Id: Icb2fda79d82c5af102cc9a0276ff26bb0d1599e8 Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../qt5/android/bindings/QtLoader.java | 295 +----------------- src/android/templates/AndroidManifest.xml | 2 - src/android/templates/build.gradle | 5 + src/android/templates/res/values/libs.xml | 10 +- .../platforms/android/androidjnimain.cpp | 5 + src/tools/androiddeployqt/main.cpp | 168 +++++----- 6 files changed, 87 insertions(+), 398 deletions(-) diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java index 45941e8ed8..1e72aa3841 100644 --- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java +++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java @@ -44,8 +44,6 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.ComponentInfo; -import android.content.pm.PackageInfo; -import android.content.res.AssetManager; import android.os.Build; import android.os.Bundle; import android.os.IBinder; @@ -55,15 +53,8 @@ import android.util.Log; import org.kde.necessitas.ministro.IMinistro; import org.kde.necessitas.ministro.IMinistroCallback; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; @@ -88,8 +79,6 @@ public abstract class QtLoader { public static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables"; public static final String APPLICATION_PARAMETERS_KEY = "application.parameters"; public static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries"; - public static final String BUNDLED_IN_LIB_RESOURCE_ID_KEY = "android.app.bundled_in_lib_resource_id"; - public static final String BUNDLED_IN_ASSETS_RESOURCE_ID_KEY = "android.app.bundled_in_assets_resource_id"; public static final String MAIN_LIBRARY_KEY = "main.library"; public static final String STATIC_INIT_CLASSES_KEY = "static.init.classes"; public static final String NECESSITAS_API_LEVEL_KEY = "necessitas.api.level"; @@ -141,7 +130,6 @@ public abstract class QtLoader { public String QT_ANDROID_DEFAULT_THEME = null; // sets the default theme. public static final int INCOMPATIBLE_MINISTRO_VERSION = 1; // Incompatible Ministro version. Ministro needs to be upgraded. - public static final int BUFFER_SIZE = 1024; public String[] m_sources = {"https://download.qt-project.org/ministro/android/qt5/qt-5.7"}; // Make sure you are using ONLY secure locations public String m_repository = "default"; // Overwrites the default Ministro repository @@ -368,263 +356,6 @@ public abstract class QtLoader { errorDialog.show(); } - static private void copyFile(InputStream inputStream, OutputStream outputStream) - throws IOException - { - byte[] buffer = new byte[BUFFER_SIZE]; - - int count; - while ((count = inputStream.read(buffer)) > 0) - outputStream.write(buffer, 0, count); - } - - private void copyAsset(String source, String destination) - throws IOException - { - // Already exists, we don't have to do anything - File destinationFile = new File(destination); - if (destinationFile.exists()) - return; - - File parentDirectory = destinationFile.getParentFile(); - if (!parentDirectory.exists()) - parentDirectory.mkdirs(); - - destinationFile.createNewFile(); - - AssetManager assetsManager = m_context.getAssets(); - InputStream inputStream = null; - FileOutputStream outputStream = null; - try { - inputStream = assetsManager.open(source); - outputStream = new FileOutputStream(destinationFile); - copyFile(inputStream, outputStream); - } catch (Exception e) { - e.printStackTrace(); - } finally { - if (inputStream != null) - inputStream.close(); - - if (outputStream != null) - // Ensure that the buffered data is flushed to the OS for writing. - outputStream.flush(); - } - // Mark the output stream as still needing to be written to physical disk. - // The output stream will be closed after this sync completes. - m_fileOutputStreams.add(outputStream); - } - - private static void createBundledBinary(String source, String destination) - throws IOException - { - // Already exists, we don't have to do anything - File destinationFile = new File(destination); - if (destinationFile.exists()) - return; - - File parentDirectory = destinationFile.getParentFile(); - if (!parentDirectory.exists()) - parentDirectory.mkdirs(); - - destinationFile.createNewFile(); - - InputStream inputStream = null; - FileOutputStream outputStream = null; - try { - inputStream = new FileInputStream(source); - outputStream = new FileOutputStream(destinationFile); - copyFile(inputStream, outputStream); - } catch (Exception e) { - e.printStackTrace(); - } finally { - if (inputStream != null) - inputStream.close(); - - if (outputStream != null) - // Ensure that the buffered data is flushed to the OS for writing. - outputStream.flush(); - } - // Mark the output stream as still needing to be written to physical disk. - // The output stream will be closed after this sync completes. - m_fileOutputStreams.add(outputStream); - } - - private boolean cleanCacheIfNecessary(String pluginsPrefix, long packageVersion) - { - File versionFile = new File(pluginsPrefix + "cache.version"); - - long cacheVersion = 0; - if (versionFile.exists() && versionFile.canRead()) { - DataInputStream inputStream = null; - try { - inputStream = new DataInputStream(new FileInputStream(versionFile)); - cacheVersion = inputStream.readLong(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - - if (cacheVersion != packageVersion) { - deleteRecursively(new File(pluginsPrefix)); - return true; - } else { - return false; - } - } - - private void extractBundledPluginsAndImports(String pluginsPrefix, String libsDir) - throws IOException - { - long packageVersion = -1; - try { - PackageInfo packageInfo = m_context.getPackageManager().getPackageInfo(m_context.getPackageName(), 0); - packageVersion = packageInfo.lastUpdateTime; - } catch (Exception e) { - e.printStackTrace(); - } - - if (!cleanCacheIfNecessary(pluginsPrefix, packageVersion)) - return; - - { - // why can't we load the plugins directly from libs ?!?! - String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY; - if (m_contextInfo.metaData.containsKey(key)) { - int resourceId = m_contextInfo.metaData.getInt(key); - ArrayList list = prefferedAbiLibs(m_context.getResources().getStringArray(resourceId)); - - for (String bundledImportBinary : list) { - String[] split = bundledImportBinary.split(":"); - String sourceFileName = libsDir + split[0]; - String destinationFileName = pluginsPrefix + split[1]; - createBundledBinary(sourceFileName, destinationFileName); - } - } - } - - { - String key = BUNDLED_IN_ASSETS_RESOURCE_ID_KEY; - if (m_contextInfo.metaData.containsKey(key)) { - String[] list = m_context.getResources().getStringArray(m_contextInfo.metaData.getInt(key)); - - for (String fileName : list) { - String[] split = fileName.split(":"); - String sourceFileName = split[0]; - String destinationFileName = pluginsPrefix + split[1]; - copyAsset(sourceFileName, destinationFileName); - } - } - - } - - // The Java compiler must be assured that variables belonging to this parent thread will not - // go out of scope during the runtime of the spawned thread (since in general spawned - // threads can outlive their parent threads). Copy variables and declare as 'final' before - // passing into the spawned thread. - final String pluginsPrefixFinal = pluginsPrefix; - final long packageVersionFinal = packageVersion; - - // Spawn a worker thread to write all installed files to physical disk and indicate - // successful installation by creating the 'cache.version' file. - new Thread(new Runnable() { - @Override - public void run() { - try { - finalizeInstallation(pluginsPrefixFinal, packageVersionFinal); - } catch (Exception e) { - Log.e(QtApplication.QtTAG, e.getMessage()); - e.printStackTrace(); - return; - } - } - }).start(); - } - - private void finalizeInstallation(String pluginsPrefix, long packageVersion) - throws IOException - { - { - // Write all installed files to physical disk and close each output stream - for (FileOutputStream fileOutputStream : m_fileOutputStreams) { - fileOutputStream.getFD().sync(); - fileOutputStream.close(); - } - - m_fileOutputStreams.clear(); - } - - { - // Create 'cache.version' file - - File versionFile = new File(pluginsPrefix + "cache.version"); - - File parentDirectory = versionFile.getParentFile(); - if (!parentDirectory.exists()) - parentDirectory.mkdirs(); - - versionFile.createNewFile(); - - DataOutputStream outputStream = null; - try { - outputStream = new DataOutputStream(new FileOutputStream(versionFile)); - outputStream.writeLong(packageVersion); - } catch (Exception e) { - e.printStackTrace(); - } finally { - if (outputStream != null) - outputStream.close(); - } - } - - } - - private void deleteRecursively(File directory) - { - File[] files = directory.listFiles(); - if (files != null) { - for (File file : files) { - if (file.isDirectory()) - deleteRecursively(file); - else - file.delete(); - } - - directory.delete(); - } - } - - private void cleanOldCacheIfNecessary(String oldLocalPrefix, String localPrefix) - { - File newCache = new File(localPrefix); - if (!newCache.exists()) { - { - File oldPluginsCache = new File(oldLocalPrefix + "plugins/"); - if (oldPluginsCache.exists() && oldPluginsCache.isDirectory()) - deleteRecursively(oldPluginsCache); - } - - { - File oldImportsCache = new File(oldLocalPrefix + "imports/"); - if (oldImportsCache.exists() && oldImportsCache.isDirectory()) - deleteRecursively(oldImportsCache); - } - - { - File oldQmlCache = new File(oldLocalPrefix + "qml/"); - if (oldQmlCache.exists() && oldQmlCache.isDirectory()) - deleteRecursively(oldQmlCache); - } - } - } - public void startApp(final boolean firstStart) { try { @@ -688,29 +419,13 @@ public abstract class QtLoader { if (m_contextInfo.metaData.containsKey("android.app.bundle_local_qt_libs") && m_contextInfo.metaData.getInt("android.app.bundle_local_qt_libs") == 1) { - File dataDir = new File(m_context.getApplicationInfo().dataDir); - String dataPath = dataDir.getCanonicalPath() + "/"; - String pluginsPrefix = dataPath + "qt-reserved-files/"; - - if (libsDir == null) - throw new Exception("Invalid libsDir"); - - cleanOldCacheIfNecessary(dataPath, pluginsPrefix); - extractBundledPluginsAndImports(pluginsPrefix, libsDir); - - if (m_contextInfo.metaData.containsKey(BUNDLED_IN_LIB_RESOURCE_ID_KEY)) { - int resourceId = m_contextInfo.metaData.getInt("android.app.load_local_libs_resource_id"); - for (String libs : prefferedAbiLibs(m_context.getResources().getStringArray(resourceId))) { - for (String lib : libs.split(":")) { - if (!lib.isEmpty()) - libraryList.add(libsDir + lib); - } + int resourceId = m_contextInfo.metaData.getInt("android.app.load_local_libs_resource_id"); + for (String libs : prefferedAbiLibs(m_context.getResources().getStringArray(resourceId))) { + for (String lib : libs.split(":")) { + if (!lib.isEmpty()) + libraryList.add(libsDir + lib); } } - - ENVIRONMENT_VARIABLES += "\tQML2_IMPORT_PATH=" + pluginsPrefix + "/qml" - + "\tQML_IMPORT_PATH=" + pluginsPrefix + "/imports" - + "\tQT_PLUGIN_PATH=" + pluginsPrefix + "/plugins"; if (bundledLibsDir != null) ENVIRONMENT_VARIABLES += "\tQT_BUNDLED_LIBS_PATH=" + bundledLibsDir; } diff --git a/src/android/templates/AndroidManifest.xml b/src/android/templates/AndroidManifest.xml index 75da314c2b..6d0f4e0d45 100644 --- a/src/android/templates/AndroidManifest.xml +++ b/src/android/templates/AndroidManifest.xml @@ -34,8 +34,6 @@ - - diff --git a/src/android/templates/build.gradle b/src/android/templates/build.gradle index d2da115936..3087d08c83 100644 --- a/src/android/templates/build.gradle +++ b/src/android/templates/build.gradle @@ -54,4 +54,9 @@ android { lintOptions { abortOnError false } + + // Do not compress Qt binary resources file + aaptOptions { + noCompress 'rcc' + } } diff --git a/src/android/templates/res/values/libs.xml b/src/android/templates/res/values/libs.xml index db777bf433..6b1a4a2a02 100644 --- a/src/android/templates/res/values/libs.xml +++ b/src/android/templates/res/values/libs.xml @@ -11,20 +11,12 @@ - + - - - - - - - - diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 13ea9468df..fd2644717e 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -60,6 +60,7 @@ #include "qandroideventdispatcher.h" #include +#include #include #include #include @@ -525,6 +526,10 @@ static jboolean startQtApplication(JNIEnv */*env*/, jclass /*clazz*/) vm->AttachCurrentThread(&env, &args); } + // Register resources if they are available + if (QFile{QStringLiteral("assets:/android_rcc_bundle.rcc")}.exists()) + QResource::registerResource(QStringLiteral("assets:/android_rcc_bundle.rcc")); + QVarLengthArray params(m_applicationParams.size()); for (int i = 0; i < m_applicationParams.size(); i++) params[i] = static_cast(m_applicationParams[i].constData()); diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index 6a32a659e6..7101a2bf3c 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -116,7 +116,6 @@ struct Options : helpRequested(false) , verbose(false) , timing(false) - , generateAssetsFileList(true) , build(true) , auxMode(false) , deploymentMechanism(Bundled) @@ -146,7 +145,6 @@ struct Options bool helpRequested; bool verbose; bool timing; - bool generateAssetsFileList; bool build; bool auxMode; ActionTimer timer; @@ -521,8 +519,6 @@ Options parseOptions() options.protectedAuthenticationPath = true; } else if (argument.compare(QLatin1String("--jarsigner"), Qt::CaseInsensitive) == 0) { options.jarSigner = true; - } else if (argument.compare(QLatin1String("--no-generated-assets-cache"), Qt::CaseInsensitive) == 0) { - options.generateAssetsFileList = false; } else if (argument.compare(QLatin1String("--aux-mode"), Qt::CaseInsensitive) == 0) { options.auxMode = true; } @@ -1242,8 +1238,6 @@ bool updateLibsXml(Options *options) } QString qtLibs; - QString bundledInLibs; - QString bundledInAssets; QString allLocalLibs; QString extraLibs; @@ -1256,33 +1250,6 @@ bool updateLibsXml(Options *options) QString s = bundledFile.second.mid(sizeof("lib/lib") - 1); s.chop(sizeof(".so") - 1); qtLibs += QLatin1String(" %1;%2\n").arg(it.key(), s); - } else if (bundledFile.first.startsWith(libsPath)) { - QString s = bundledFile.first.mid(libsPath.length()); - bundledInLibs += QString::fromLatin1(" %1;%2:%3\n") - .arg(it.key(), s, bundledFile.second); - } else if (bundledFile.first.startsWith(QLatin1String("assets/"))) { - QString s = bundledFile.first.mid(sizeof("assets/") - 1); - bundledInAssets += QString::fromLatin1(" %1:%2\n") - .arg(s, bundledFile.second); - } - } - - if (!options->archExtraPlugins[it.key()].isEmpty()) { - for (const QString &extraRes : options->archExtraPlugins[it.key()]) { - QDir resourceDir(extraRes); - const QStringList files = allFilesInside(resourceDir, resourceDir); - for (const QString &file : files) { - QString destinationPath = resourceDir.dirName() + QLatin1Char('/') + file; - if (!file.endsWith(QLatin1String(".so"))) { - bundledInAssets += QLatin1String(" %1:%1\n") - .arg(destinationPath); - } else { - bundledInLibs += QLatin1String(" %1;lib%2:%3\n") - .arg(it.key(), - QString(destinationPath).replace(QLatin1Char('/'), QLatin1Char('_')), - destinationPath); - } - } } } @@ -1342,11 +1309,6 @@ bool updateLibsXml(Options *options) replacements[QStringLiteral("")] = allLocalLibs.trimmed(); replacements[QStringLiteral("")] = extraLibs.trimmed(); - if (options->deploymentMechanism == Options::Bundled) { - replacements[QStringLiteral("")] += bundledInLibs.trimmed(); - replacements[QStringLiteral("")] += bundledInAssets.trimmed(); - } - if (!updateFile(fileName, replacements)) return false; @@ -1871,6 +1833,70 @@ bool scanImports(Options *options, QSet *usedDependencies) return true; } +bool runCommand(const Options &options, const QString &command) +{ + if (options.verbose) + fprintf(stdout, "Running command '%s'\n", qPrintable(command)); + + FILE *runCommand = openProcess(command); + if (runCommand == nullptr) { + fprintf(stderr, "Cannot run command '%s'\n", qPrintable(command)); + return false; + } + char buffer[4096]; + while (fgets(buffer, sizeof(buffer), runCommand) != nullptr) { + if (options.verbose) + fprintf(stdout, "%s", buffer); + } + pclose(runCommand); + fflush(stdout); + fflush(stderr); + return true; +} + +bool createRcc(const Options &options) +{ + auto assetsDir = QLatin1String("%1/assets").arg(options.outputDirectory); + if (!QDir{QLatin1String("%1/android_rcc_bundle").arg(assetsDir)}.exists()) { + fprintf(stdout, "Skipping createRCC\n"); + return true; + } + + if (options.verbose) + fprintf(stdout, "Create rcc bundle.\n"); + + QString rcc = options.qtInstallDirectory + QLatin1String("/bin/rcc"); +#if defined(Q_OS_WIN32) + rcc += QLatin1String(".exe"); +#endif + + if (!QFile::exists(rcc)) { + fprintf(stderr, "rcc not found: %s\n", qPrintable(rcc)); + return false; + } + auto currentDir = QDir::currentPath(); + if (!QDir::setCurrent(QLatin1String("%1/android_rcc_bundle").arg(assetsDir))) { + fprintf(stderr, "Cannot set current dir to: %s\n", qPrintable(QLatin1String("%1/android_rcc_bundle").arg(assetsDir))); + return false; + } + + bool res = runCommand(options, QLatin1String("%1 --project -o %2").arg(rcc, shellQuote(QLatin1String("%1/android_rcc_bundle.qrc").arg(assetsDir)))); + if (!res) + return false; + + QFile::rename(QLatin1String("%1/android_rcc_bundle.qrc").arg(assetsDir), QLatin1String("%1/android_rcc_bundle/android_rcc_bundle.qrc").arg(assetsDir)); + + res = runCommand(options, QLatin1String("%1 %2 --binary -o %3 android_rcc_bundle.qrc").arg(rcc, shellQuote(QLatin1String("--root=/android_rcc_bundle/")), + shellQuote(QLatin1String("%1/android_rcc_bundle.rcc").arg(assetsDir)))); + if (!QDir::setCurrent(currentDir)) { + fprintf(stderr, "Cannot set current dir to: %s\n", qPrintable(currentDir)); + return false; + } + QFile::remove(QLatin1String("%1/android_rcc_bundle.qrc").arg(assetsDir)); + QDir{QLatin1String("%1/android_rcc_bundle").arg(assetsDir)}.removeRecursively(); + return res; +} + bool readDependencies(Options *options) { if (options->verbose) @@ -2025,7 +2051,7 @@ bool copyQtFiles(Options *options) QString libsDirectory = QLatin1String("libs/"); // Copy other Qt dependencies - auto assetsDestinationDirectory = QLatin1String("assets/--Added-by-androiddeployqt--/"); + auto assetsDestinationDirectory = QLatin1String("assets/android_rcc_bundle/"); for (const QtDependency &qtDependency : qAsConst(options->qtDependencies[options->currentArchitecture])) { QString sourceFileName = qtDependency.absolutePath; QString destinationFileName; @@ -2681,57 +2707,6 @@ bool signPackage(const Options &options) return apkSignerRunner() && QFile::remove(packagePath(options, UnsignedAPK)); } -bool generateAssetsFileList(const Options &options) -{ - if (options.verbose) - fprintf(stdout, "Pregenerating entry list for assets file engine.\n"); - - QString assetsPath = options.outputDirectory + QLatin1String("/assets/"); - QString addedByAndroidDeployQtPath = assetsPath + QLatin1String("--Added-by-androiddeployqt--/"); - if (!QDir().mkpath(addedByAndroidDeployQtPath)) { - fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath)); - return false; - } - - QFile file(addedByAndroidDeployQtPath + QLatin1String("/qt_cache_pregenerated_file_list")); - if (file.open(QIODevice::WriteOnly)) { - QDirIterator dirIterator(assetsPath, - QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, - QDirIterator::Subdirectories); - - QHash directoryContents; - while (dirIterator.hasNext()) { - const QString name = dirIterator.next().mid(assetsPath.length()); - - int slashIndex = name.lastIndexOf(QLatin1Char('/')); - QString pathName = slashIndex >= 0 ? name.left(slashIndex) : QStringLiteral("/"); - QString fileName = slashIndex >= 0 ? name.mid(pathName.length() + 1) : name; - - if (!fileName.isEmpty() && dirIterator.fileInfo().isDir() && !fileName.endsWith(QLatin1Char('/'))) - fileName += QLatin1Char('/'); - - if (fileName.isEmpty() && !directoryContents.contains(pathName)) - directoryContents[pathName] = QStringList(); - else if (!fileName.isEmpty()) - directoryContents[pathName].append(fileName); - } - - QDataStream stream(&file); - stream.setVersion(QDataStream::Qt_5_3); - for (auto it = directoryContents.cbegin(), end = directoryContents.cend(); it != end; ++it) { - const QStringList &entryList = it.value(); - stream << it.key() << entryList.size(); - for (const QString &entry : entryList) - stream << entry; - } - } else { - fprintf(stderr, "Pregenerating entry list for assets file engine failed!\n"); - return false; - } - - return true; -} - enum ErrorCode { Success, @@ -2749,9 +2724,9 @@ enum ErrorCode CannotBuildAndroidProject = 14, CannotSignPackage = 15, CannotInstallApk = 16, - CannotGenerateAssetsFileList = 18, CannotCopyAndroidExtraResources = 19, - CannotCopyApk = 20 + CannotCopyApk = 20, + CannotCreateRcc = 21 }; int main(int argc, char *argv[]) @@ -2848,14 +2823,16 @@ int main(int argc, char *argv[]) } } + if (!createRcc(options)) + return CannotCreateRcc; + if (options.auxMode) { if (!updateAndroidFiles(options)) return CannotUpdateAndroidFiles; - if (options.generateAssetsFileList && !generateAssetsFileList(options)) - return CannotGenerateAssetsFileList; return 0; } + if (options.build) { if (!copyAndroidSources(options)) return CannotCopyAndroidSources; @@ -2866,9 +2843,6 @@ int main(int argc, char *argv[]) if (!updateAndroidFiles(options)) return CannotUpdateAndroidFiles; - if (options.generateAssetsFileList && !generateAssetsFileList(options)) - return CannotGenerateAssetsFileList; - if (Q_UNLIKELY(options.timing)) fprintf(stdout, "[TIMING] %d ms: Updated files\n", options.timer.elapsed()); From ad86c2f0abb4fab5bf871fe49b37e0a2f4a346bc Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 2 Oct 2019 14:08:34 +0200 Subject: [PATCH 06/16] Quiet several more warnings about QWheelEvent deprecations We want to ensure that the qt4D and qt4O members are still initialized the same way whenever deprecated constructors are used; and we want to be able to verify it using qDebug. So we merely suppress these warnings. Change-Id: Ic2e5f0dd6feeabe81f06f9c31693c550ac0781e3 Reviewed-by: Thiago Macieira --- src/gui/kernel/qevent.cpp | 14 ++++++++++++-- src/gui/kernel/qguiapplication.cpp | 3 +++ src/widgets/kernel/qapplication.cpp | 6 ++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index d41e3e5e3c..2b28052dd5 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -791,37 +791,44 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, int delta \obsolete This constructor has been deprecated. */ - +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) : QWheelEvent(pos, globalPos, pixelDelta, angleDelta, qt4Delta, qt4Orientation, buttons, modifiers, Qt::NoScrollPhase) {} +QT_WARNING_POP /*! \obsolete This constructor has been deprecated. */ - +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase) : QWheelEvent(pos, globalPos, pixelDelta, angleDelta, qt4Delta, qt4Orientation, buttons, modifiers, phase, Qt::MouseEventNotSynthesized) {} +QT_WARNING_POP /*! \obsolete This constructor has been deprecated. */ +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase, Qt::MouseEventSource source) : QWheelEvent(pos, globalPos, pixelDelta, angleDelta, qt4Delta, qt4Orientation, buttons, modifiers, phase, source, false) {} +QT_WARNING_POP /*! \obsolete @@ -3930,12 +3937,15 @@ QDebug operator<<(QDebug dbg, const QEvent *e) case QEvent::Wheel: { const QWheelEvent *we = static_cast(e); dbg << "QWheelEvent(" << we->phase(); +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED // delta() and orientation() if (!we->pixelDelta().isNull() || !we->angleDelta().isNull()) dbg << ", pixelDelta=" << we->pixelDelta() << ", angleDelta=" << we->angleDelta(); #if QT_DEPRECATED_SINCE(5, 14) else if (int qt4Delta = we->delta()) dbg << ", delta=" << qt4Delta << ", orientation=" << we->orientation(); #endif +QT_WARNING_POP dbg << ')'; } break; diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 83ca337aaa..fe73278c62 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -2245,8 +2245,11 @@ void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wh } #if QT_DEPRECATED_SINCE(5, 14) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation, mouse_buttons, e->modifiers, e->phase, e->source, e->inverted); +QT_WARNING_POP #else QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, mouse_buttons, e->modifiers, e->phase, e->inverted, e->source); diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 629c696544..3223781b63 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -3224,8 +3224,11 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, relpos); #if QT_DEPRECATED_SINCE(5, 14) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QWheelEvent we(relpos, wheel->globalPos(), wheel->pixelDelta(), wheel->angleDelta(), wheel->delta(), wheel->orientation(), wheel->buttons(), wheel->modifiers(), phase, wheel->source(), wheel->inverted()); +QT_WARNING_POP #else QWheelEvent we(relpos, wheel->globalPosition(), wheel->pixelDelta(), wheel->angleDelta(), wheel->buttons(), wheel->modifiers(), phase, wheel->inverted(), wheel->source()); @@ -3266,8 +3269,11 @@ bool QApplication::notify(QObject *receiver, QEvent *e) // the end of the natural scrolling sequence. const QPoint &relpos = QApplicationPrivate::wheel_widget->mapFromGlobal(wheel->globalPosition().toPoint()); #if QT_DEPRECATED_SINCE(5, 0) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QWheelEvent we(relpos, wheel->globalPos(), wheel->pixelDelta(), wheel->angleDelta(), wheel->delta(), wheel->orientation(), wheel->buttons(), wheel->modifiers(), wheel->phase(), wheel->source()); +QT_WARNING_POP #else QWheelEvent we(relpos, wheel->globalPosition(), wheel->pixelDelta(), wheel->angleDelta(), wheel->buttons(), wheel->modifiers(), wheel->phase(), wheel->inverted(), wheel->source()); From 1a8f4a3c8fa30265e7f184373c738dbc3574663a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Mon, 30 Sep 2019 16:56:01 +0200 Subject: [PATCH 07/16] GSSAPI: strengthen configure test and make it a library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way we can actually filter out times in sitatuations where it proved to not be available and as a library we can simply "use" it. Added in the pkgConfig source as well to make sure we can pick it up on systems where it has a different name. Fixes: QTBUG-78765 Change-Id: I4754923ddafd9274105e4f93d66a4039872e310c Reviewed-by: Joerg Bornemann Reviewed-by: André Klitzing --- src/network/configure.json | 25 +++++++++++++++---------- src/network/kernel/kernel.pri | 2 +- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/network/configure.json b/src/network/configure.json index bebe592088..a1cb77b6d1 100644 --- a/src/network/configure.json +++ b/src/network/configure.json @@ -98,6 +98,20 @@ "condition": "!config.msvc" } ] + }, + "gssapi": { + "label": "KRB5 GSSAPI Support", + "test": { + "main": [ + "gss_ctx_id_t ctx;", + "gss_context_time(nullptr, ctx, nullptr);" + ] + }, + "headers": [ "gssapi/gssapi.h" ], + "sources": [ + { "type": "pkgConfig", "args": "krb5-gssapi" }, + "-lgssapi_krb5" + ] } }, @@ -200,15 +214,6 @@ }, "use": "openssl" }, - "gssapi": { - "label": "KRB5 GSSAPI support", - "type": "compile", - "test": { - "include": [ "gssapi/gssapi.h" ], - "main": ["gss_ctx_id_t ctx;"], - "qmake": "LIBS += -lgssapi_krb5" - } - }, "netlistmgr": { "label": "Network List Manager", "type": "compile", @@ -408,7 +413,7 @@ "label": "GSSAPI", "purpose": "Enable SPNEGO authentication through GSSAPI", "section": "Networking", - "condition": "!config.win32 && tests.gssapi", + "condition": "!config.win32 && libs.gssapi", "output": [ "publicFeature", "feature" ] }, "sspi": { diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index a55648dbc7..110d9f56bf 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -83,7 +83,7 @@ macos | ios { SOURCES += kernel/qnetconmonitor_stub.cpp } -qtConfig(gssapi): LIBS_PRIVATE += -lgssapi_krb5 +qtConfig(gssapi): QMAKE_USE_PRIVATE += gssapi uikit:HEADERS += kernel/qnetworkinterface_uikit_p.h osx:SOURCES += kernel/qnetworkproxy_mac.cpp From f1c7814a55903dad5a5e77683bdcca5fc3805394 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 2 Oct 2019 10:58:44 +0200 Subject: [PATCH 08/16] rhi: Remove QVectors from the data description structs as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As usual, keep some QVector overloads around to allow Qt Quick to compile. Color attachments and vertex input bindings get an at(index) type of accessor, unlike any other of similar lists. This is because there the index is significant, and sequential iteration is not the only type of operation that is performed. Sometimes a lookup based on an index will be needed as well. Task-number: QTBUG-78883 Change-Id: I3882941f09e94ee2f179e0e9b8161551f0d5dae7 Reviewed-by: Christian Strømme Reviewed-by: Paul Olav Tvete --- src/gui/rhi/qrhi.cpp | 38 +++---- src/gui/rhi/qrhi_p.h | 72 +++++++++--- src/gui/rhi/qrhi_p_p.h | 5 +- src/gui/rhi/qrhid3d11.cpp | 69 ++++++------ src/gui/rhi/qrhigles2.cpp | 69 ++++++------ src/gui/rhi/qrhimetal.mm | 86 ++++++++------- src/gui/rhi/qrhinull.cpp | 7 +- src/gui/rhi/qrhivulkan.cpp | 103 +++++++++--------- src/gui/rhi/qrhivulkan_p_p.h | 3 +- .../compressedtexture_bc1.cpp | 6 +- tests/manual/rhi/mrt/mrt.cpp | 6 +- .../rhi/triquadcube/texturedcuberenderer.cpp | 8 +- 12 files changed, 265 insertions(+), 207 deletions(-) diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 08bafebdec..e4f6da6d46 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -1199,8 +1199,7 @@ QDebug operator<<(QDebug dbg, const QRhiVertexInputAttribute &a) */ bool operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) Q_DECL_NOTHROW { - return a.bindings() == b.bindings() - && a.attributes() == b.attributes(); + return a.m_bindings == b.m_bindings && a.m_attributes == b.m_attributes; } /*! @@ -1221,15 +1220,21 @@ bool operator!=(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) */ uint qHash(const QRhiVertexInputLayout &v, uint seed) Q_DECL_NOTHROW { - return qHash(v.bindings(), seed) + qHash(v.attributes(), seed); + return qHash(v.m_bindings, seed) + qHash(v.m_attributes, seed); } #ifndef QT_NO_DEBUG_STREAM +template +QDebug operator<<(QDebug dbg, const QVarLengthArray &vla) +{ + return QtPrivate::printSequentialContainer(dbg, "VLA", vla); +} + QDebug operator<<(QDebug dbg, const QRhiVertexInputLayout &v) { QDebugStateSaver saver(dbg); - dbg.nospace() << "QRhiVertexInputLayout(bindings=" << v.bindings() - << " attributes=" << v.attributes() + dbg.nospace() << "QRhiVertexInputLayout(bindings=" << v.m_bindings + << " attributes=" << v.m_attributes << ')'; return dbg; } @@ -1630,27 +1635,19 @@ QRhiTextureUploadDescription::QRhiTextureUploadDescription(const QRhiTextureUplo } /*! - Constructs a texture upload description with the specified list of \a entries. + Constructs a texture upload description with the specified \a list of entries. - \note \a entries can also contain multiple QRhiTextureUploadEntry elements + \note \a list can also contain multiple QRhiTextureUploadEntry elements with the the same layer and level. This makes sense when those uploads are partial, meaning their subresource description has a source size or image smaller than the subresource dimensions, and can be more efficient than issuing separate uploadTexture()'s. */ -QRhiTextureUploadDescription::QRhiTextureUploadDescription(const QVector &entries) - : m_entries(entries) +QRhiTextureUploadDescription::QRhiTextureUploadDescription(std::initializer_list list) + : m_entries(list) { } -/*! - Adds \a entry to the list of subresource uploads. - */ -void QRhiTextureUploadDescription::append(const QRhiTextureUploadEntry &entry) -{ - m_entries.append(entry); -} - /*! \class QRhiTextureCopyDescription \internal @@ -3056,11 +3053,6 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b) #endif #ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug dbg, const QVarLengthArray &bindings) -{ - return QtPrivate::printSequentialContainer(dbg, "Bindings", bindings); -} - QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb) { QDebugStateSaver saver(dbg); @@ -4215,7 +4207,7 @@ void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *da */ void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc) { - if (!desc.entries().isEmpty()) + if (desc.cbeginEntries() != desc.cendEntries()) d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::textureUpload(tex, desc)); } diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index f8f922cfdb..95e9213cac 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -240,15 +240,42 @@ class Q_GUI_EXPORT QRhiVertexInputLayout public: QRhiVertexInputLayout() = default; - QVector bindings() const { return m_bindings; } - void setBindings(const QVector &v) { m_bindings = v; } + void setBindings(std::initializer_list list) { m_bindings = list; } + template + void setBindings(InputIterator first, InputIterator last) + { + m_bindings.clear(); + std::copy(first, last, std::back_inserter(m_bindings)); + } + void setBindings(const QVector &bindings) // compat., to be removed + { + setBindings(bindings.cbegin(), bindings.cend()); + } + const QRhiVertexInputBinding *cbeginBindings() const { return m_bindings.cbegin(); } + const QRhiVertexInputBinding *cendBindings() const { return m_bindings.cend(); } + const QRhiVertexInputBinding *bindingAt(int index) const { return &m_bindings.at(index); } - QVector attributes() const { return m_attributes; } - void setAttributes(const QVector &v) { m_attributes = v; } + void setAttributes(std::initializer_list list) { m_attributes = list; } + template + void setAttributes(InputIterator first, InputIterator last) + { + m_attributes.clear(); + std::copy(first, last, std::back_inserter(m_attributes)); + } + void setAttributes(const QVector &attributes) // compat., to be removed + { + setAttributes(attributes.cbegin(), attributes.cend()); + } + const QRhiVertexInputAttribute *cbeginAttributes() const { return m_attributes.cbegin(); } + const QRhiVertexInputAttribute *cendAttributes() const { return m_attributes.cend(); } private: - QVector m_bindings; - QVector m_attributes; + QVarLengthArray m_bindings; + QVarLengthArray m_attributes; + + friend Q_GUI_EXPORT bool operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) Q_DECL_NOTHROW; + friend Q_GUI_EXPORT uint qHash(const QRhiVertexInputLayout &v, uint seed) Q_DECL_NOTHROW; + friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputLayout &); }; Q_DECLARE_TYPEINFO(QRhiVertexInputLayout, Q_MOVABLE_TYPE); @@ -439,8 +466,16 @@ public: QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, QRhiRenderBuffer *depthStencilBuffer); QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, QRhiTexture *depthTexture); - QVector colorAttachments() const { return m_colorAttachments; } - void setColorAttachments(const QVector &att) { m_colorAttachments = att; } + void setColorAttachments(std::initializer_list list) { m_colorAttachments = list; } + template + void setColorAttachments(InputIterator first, InputIterator last) + { + m_colorAttachments.clear(); + std::copy(first, last, std::back_inserter(m_colorAttachments)); + } + const QRhiColorAttachment *cbeginColorAttachments() const { return m_colorAttachments.cbegin(); } + const QRhiColorAttachment *cendColorAttachments() const { return m_colorAttachments.cend(); } + const QRhiColorAttachment *colorAttachmentAt(int index) const { return &m_colorAttachments.at(index); } QRhiRenderBuffer *depthStencilBuffer() const { return m_depthStencilBuffer; } void setDepthStencilBuffer(QRhiRenderBuffer *renderBuffer) { m_depthStencilBuffer = renderBuffer; } @@ -449,7 +484,7 @@ public: void setDepthTexture(QRhiTexture *texture) { m_depthTexture = texture; } private: - QVector m_colorAttachments; + QVarLengthArray m_colorAttachments; QRhiRenderBuffer *m_depthStencilBuffer = nullptr; QRhiTexture *m_depthTexture = nullptr; }; @@ -516,14 +551,23 @@ class Q_GUI_EXPORT QRhiTextureUploadDescription public: QRhiTextureUploadDescription() = default; QRhiTextureUploadDescription(const QRhiTextureUploadEntry &entry); - QRhiTextureUploadDescription(const QVector &entries); + QRhiTextureUploadDescription(std::initializer_list list); + QRhiTextureUploadDescription(const QVector &entries) // compat., to be removed + : m_entries(entries.cbegin(), entries.cend()) + { } - QVector entries() const { return m_entries; } - void setEntries(const QVector &entries) { m_entries = entries; } - void append(const QRhiTextureUploadEntry &entry); + void setEntries(std::initializer_list list) { m_entries = list; } + template + void setEntries(InputIterator first, InputIterator last) + { + m_entries.clear(); + std::copy(first, last, std::back_inserter(m_entries)); + } + const QRhiTextureUploadEntry *cbeginEntries() const { return m_entries.cbegin(); } + const QRhiTextureUploadEntry *cendEntries() const { return m_entries.cend(); } private: - QVector m_entries; + QVarLengthArray m_entries; }; Q_DECLARE_TYPEINFO(QRhiTextureUploadDescription, Q_MOVABLE_TYPE); diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h index 822da528f1..80a95e2fcc 100644 --- a/src/gui/rhi/qrhi_p_p.h +++ b/src/gui/rhi/qrhi_p_p.h @@ -328,9 +328,8 @@ public: TextureOp op; op.type = Upload; op.upload.tex = tex; - const QVector &entries(desc.entries()); - for (const QRhiTextureUploadEntry &entry : entries) - op.upload.subresDesc[entry.layer()][entry.level()].append(entry.description()); + for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it) + op.upload.subresDesc[it->layer()][it->level()].append(it->description()); return op; } diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index b82a68f3dd..36c95f2306 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -742,13 +742,14 @@ void QRhiD3D11::setVertexInput(QRhiCommandBuffer *cb, cmd.cmd = QD3D11CommandBuffer::Command::BindVertexBuffers; cmd.args.bindVertexBuffers.startSlot = startBinding; cmd.args.bindVertexBuffers.slotCount = bindingCount; - const QVector inputBindings = - QRHI_RES(QD3D11GraphicsPipeline, cbD->currentGraphicsPipeline)->m_vertexInputLayout.bindings(); - for (int i = 0, ie = qMin(bindingCount, inputBindings.count()); i != ie; ++i) { + QD3D11GraphicsPipeline *psD = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentGraphicsPipeline); + const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout); + const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings(); + for (int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) { QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, bindings[i].first); cmd.args.bindVertexBuffers.buffers[i] = bufD->buffer; cmd.args.bindVertexBuffers.offsets[i] = bindings[i].second; - cmd.args.bindVertexBuffers.strides[i] = inputBindings[i].stride(); + cmd.args.bindVertexBuffers.strides[i] = inputLayout.bindingAt(i)->stride(); } cbD->commands.append(cmd); } @@ -1606,9 +1607,10 @@ void QRhiD3D11::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) { QD3D11TextureRenderTarget *rtTex = QRHI_RES(QD3D11TextureRenderTarget, cbD->currentTarget); - const QVector colorAttachments = rtTex->m_desc.colorAttachments(); - for (int att = 0, attCount = colorAttachments.count(); att != attCount; ++att) { - const QRhiColorAttachment &colorAtt(colorAttachments[att]); + for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); + it != itEnd; ++it) + { + const QRhiColorAttachment &colorAtt(*it); if (!colorAtt.resolveTexture()) continue; @@ -2953,17 +2955,20 @@ bool QD3D11TextureRenderTarget::build() if (rtv[0] || dsv) release(); - const QVector colorAttachments = m_desc.colorAttachments(); - Q_ASSERT(!colorAttachments.isEmpty() || m_desc.depthTexture()); + const bool hasColorAttachments = m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments(); + Q_ASSERT(hasColorAttachments || m_desc.depthTexture()); Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture()); const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture(); QRHI_RES_RHI(QRhiD3D11); - d.colorAttCount = colorAttachments.count(); - for (int i = 0; i < d.colorAttCount; ++i) { - QRhiTexture *texture = colorAttachments[i].texture(); - QRhiRenderBuffer *rb = colorAttachments[i].renderBuffer(); + d.colorAttCount = 0; + int attIndex = 0; + for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) { + d.colorAttCount += 1; + const QRhiColorAttachment &colorAtt(*it); + QRhiTexture *texture = colorAtt.texture(); + QRhiRenderBuffer *rb = colorAtt.renderBuffer(); Q_ASSERT(texture || rb); if (texture) { QD3D11Texture *texD = QRHI_RES(QD3D11Texture, texture); @@ -2972,32 +2977,32 @@ bool QD3D11TextureRenderTarget::build() rtvDesc.Format = toD3DTextureFormat(texD->format(), texD->flags()); if (texD->flags().testFlag(QRhiTexture::CubeMap)) { rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = UINT(colorAttachments[i].level()); - rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAttachments[i].layer()); + rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level()); + rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer()); rtvDesc.Texture2DArray.ArraySize = 1; } else { if (texD->sampleDesc.Count > 1) { rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; } else { rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = UINT(colorAttachments[i].level()); + rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level()); } } - HRESULT hr = rhiD->dev->CreateRenderTargetView(texD->tex, &rtvDesc, &rtv[i]); + HRESULT hr = rhiD->dev->CreateRenderTargetView(texD->tex, &rtvDesc, &rtv[attIndex]); if (FAILED(hr)) { qWarning("Failed to create rtv: %s", qPrintable(comErrorMessage(hr))); return false; } - ownsRtv[i] = true; - if (i == 0) { + ownsRtv[attIndex] = true; + if (attIndex == 0) { d.pixelSize = texD->pixelSize(); d.sampleCount = int(texD->sampleDesc.Count); } } else if (rb) { QD3D11RenderBuffer *rbD = QRHI_RES(QD3D11RenderBuffer, rb); - ownsRtv[i] = false; - rtv[i] = rbD->rtv; - if (i == 0) { + ownsRtv[attIndex] = false; + rtv[attIndex] = rbD->rtv; + if (attIndex == 0) { d.pixelSize = rbD->pixelSize(); d.sampleCount = int(rbD->sampleDesc.Count); } @@ -3542,22 +3547,22 @@ bool QD3D11GraphicsPipeline::build() d3dTopology = toD3DTopology(m_topology); if (!vsByteCode.isEmpty()) { - const QVector bindings = m_vertexInputLayout.bindings(); - const QVector attributes = m_vertexInputLayout.attributes(); QVarLengthArray inputDescs; - for (const QRhiVertexInputAttribute &attribute : attributes) { + for (auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes(); + it != itEnd; ++it) + { D3D11_INPUT_ELEMENT_DESC desc; memset(&desc, 0, sizeof(desc)); // the output from SPIRV-Cross uses TEXCOORD as the semantic desc.SemanticName = "TEXCOORD"; - desc.SemanticIndex = UINT(attribute.location()); - desc.Format = toD3DAttributeFormat(attribute.format()); - desc.InputSlot = UINT(attribute.binding()); - desc.AlignedByteOffset = attribute.offset(); - const QRhiVertexInputBinding &binding(bindings[attribute.binding()]); - if (binding.classification() == QRhiVertexInputBinding::PerInstance) { + desc.SemanticIndex = UINT(it->location()); + desc.Format = toD3DAttributeFormat(it->format()); + desc.InputSlot = UINT(it->binding()); + desc.AlignedByteOffset = it->offset(); + const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding()); + if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) { desc.InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA; - desc.InstanceDataStepRate = UINT(binding.instanceStepRate()); + desc.InstanceDataStepRate = UINT(inputBinding->instanceStepRate()); } else { desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; } diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 190385d5de..17b40777b3 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -1898,21 +1898,22 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) { QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, cmd.args.bindVertexBuffer.ps); if (psD) { - const QVector bindings = psD->m_vertexInputLayout.bindings(); - const QVector attributes = psD->m_vertexInputLayout.attributes(); - for (const QRhiVertexInputAttribute &a : attributes) { - const int bindingIdx = a.binding(); + for (auto it = psD->m_vertexInputLayout.cbeginAttributes(), itEnd = psD->m_vertexInputLayout.cendAttributes(); + it != itEnd; ++it) + { + const int bindingIdx = it->binding(); if (bindingIdx != cmd.args.bindVertexBuffer.binding) continue; // we do not support more than one vertex buffer f->glBindBuffer(GL_ARRAY_BUFFER, cmd.args.bindVertexBuffer.buffer); - const int stride = int(bindings[bindingIdx].stride()); + const QRhiVertexInputBinding *inputBinding = psD->m_vertexInputLayout.bindingAt(bindingIdx); + const int stride = int(inputBinding->stride()); int size = 1; GLenum type = GL_FLOAT; bool normalize = false; - switch (a.format()) { + switch (it->format()) { case QRhiVertexInputAttribute::Float4: type = GL_FLOAT; size = 4; @@ -1948,16 +1949,13 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) break; } - const int locationIdx = a.location(); - quint32 ofs = a.offset() + cmd.args.bindVertexBuffer.offset; + const int locationIdx = it->location(); + quint32 ofs = it->offset() + cmd.args.bindVertexBuffer.offset; f->glVertexAttribPointer(GLuint(locationIdx), size, type, normalize, stride, reinterpret_cast(quintptr(ofs))); f->glEnableVertexAttribArray(GLuint(locationIdx)); - if (bindings[bindingIdx].classification() == QRhiVertexInputBinding::PerInstance - && caps.instancing) - { - f->glVertexAttribDivisor(GLuint(locationIdx), GLuint(bindings[bindingIdx].instanceStepRate())); - } + if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance && caps.instancing) + f->glVertexAttribDivisor(GLuint(locationIdx), GLuint(inputBinding->instanceStepRate())); } } else { qWarning("No graphics pipeline active for setVertexInput; ignored"); @@ -2510,10 +2508,12 @@ QGles2RenderTargetData *QRhiGles2::enqueueBindFramebuffer(QRhiRenderTarget *rt, fbCmd.args.bindFramebuffer.fbo = rtTex->framebuffer; fbCmd.args.bindFramebuffer.colorAttCount = rtD->colorAttCount; - const QVector colorAttachments = rtTex->m_desc.colorAttachments(); - for (const QRhiColorAttachment &colorAttachment : colorAttachments) { - QGles2Texture *texD = QRHI_RES(QGles2Texture, colorAttachment.texture()); - QGles2Texture *resolveTexD = QRHI_RES(QGles2Texture, colorAttachment.resolveTexture()); + for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); + it != itEnd; ++it) + { + const QRhiColorAttachment &colorAtt(*it); + QGles2Texture *texD = QRHI_RES(QGles2Texture, colorAtt.texture()); + QGles2Texture *resolveTexD = QRHI_RES(QGles2Texture, colorAtt.resolveTexture()); if (texD) { trackedRegisterTexture(&passResTracker, texD, QRhiPassResourceTracker::TexColorOutput, @@ -2602,10 +2602,9 @@ void QRhiGles2::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) { QGles2TextureRenderTarget *rtTex = QRHI_RES(QGles2TextureRenderTarget, cbD->currentTarget); - const QVector colorAttachments = rtTex->m_desc.colorAttachments(); - if (!colorAttachments.isEmpty()) { + if (rtTex->m_desc.cbeginColorAttachments() != rtTex->m_desc.cendColorAttachments()) { // handle only 1 color attachment and only (msaa) renderbuffer - const QRhiColorAttachment &colorAtt(colorAttachments[0]); + const QRhiColorAttachment &colorAtt(*rtTex->m_desc.cbeginColorAttachments()); if (colorAtt.resolveTexture()) { Q_ASSERT(colorAtt.renderBuffer()); QGles2RenderBuffer *rbD = QRHI_RES(QGles2RenderBuffer, colorAtt.renderBuffer()); @@ -3446,14 +3445,18 @@ bool QGles2TextureRenderTarget::build() if (framebuffer) release(); - const QVector colorAttachments = m_desc.colorAttachments(); - Q_ASSERT(!colorAttachments.isEmpty() || m_desc.depthTexture()); + const bool hasColorAttachments = m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments(); + Q_ASSERT(hasColorAttachments || m_desc.depthTexture()); Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture()); const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture(); - if (colorAttachments.count() > rhiD->caps.maxDrawBuffers) - qWarning("QGles2TextureRenderTarget: Too many color attachments (%d, max is %d)", - colorAttachments.count(), rhiD->caps.maxDrawBuffers); + if (hasColorAttachments) { + const int count = m_desc.cendColorAttachments() - m_desc.cbeginColorAttachments(); + if (count > rhiD->caps.maxDrawBuffers) { + qWarning("QGles2TextureRenderTarget: Too many color attachments (%d, max is %d)", + count, rhiD->caps.maxDrawBuffers); + } + } if (m_desc.depthTexture() && !rhiD->caps.depthTexture) qWarning("QGles2TextureRenderTarget: Depth texture is not supported and will be ignored"); @@ -3463,9 +3466,11 @@ bool QGles2TextureRenderTarget::build() rhiD->f->glGenFramebuffers(1, &framebuffer); rhiD->f->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - d.colorAttCount = colorAttachments.count(); - for (int i = 0; i < d.colorAttCount; ++i) { - const QRhiColorAttachment &colorAtt(colorAttachments[i]); + d.colorAttCount = 0; + int attIndex = 0; + for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) { + d.colorAttCount += 1; + const QRhiColorAttachment &colorAtt(*it); QRhiTexture *texture = colorAtt.texture(); QRhiRenderBuffer *renderBuffer = colorAtt.renderBuffer(); Q_ASSERT(texture || renderBuffer); @@ -3473,16 +3478,16 @@ bool QGles2TextureRenderTarget::build() QGles2Texture *texD = QRHI_RES(QGles2Texture, texture); Q_ASSERT(texD->texture && texD->specified); const GLenum faceTargetBase = texD->flags().testFlag(QRhiTexture::CubeMap) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target; - rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(i), faceTargetBase + uint(colorAtt.layer()), + rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), faceTargetBase + uint(colorAtt.layer()), texD->texture, colorAtt.level()); - if (i == 0) { + if (attIndex == 0) { d.pixelSize = texD->pixelSize(); d.sampleCount = 1; } } else if (renderBuffer) { QGles2RenderBuffer *rbD = QRHI_RES(QGles2RenderBuffer, renderBuffer); - rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(i), GL_RENDERBUFFER, rbD->renderbuffer); - if (i == 0) { + rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), GL_RENDERBUFFER, rbD->renderbuffer); + if (attIndex == 0) { d.pixelSize = rbD->pixelSize(); d.sampleCount = rbD->samples; } diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 4dc12f0691..344be44d48 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -1775,14 +1775,15 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb, cbD->d->currentPassRpDesc.depthAttachment.loadAction = MTLLoadActionLoad; cbD->d->currentPassRpDesc.stencilAttachment.loadAction = MTLLoadActionLoad; } - const QVector colorAttachments = rtTex->m_desc.colorAttachments(); - for (const QRhiColorAttachment &colorAttachment : colorAttachments) { - if (colorAttachment.texture()) - QRHI_RES(QMetalTexture, colorAttachment.texture())->lastActiveFrameSlot = currentFrameSlot; - else if (colorAttachment.renderBuffer()) - QRHI_RES(QMetalRenderBuffer, colorAttachment.renderBuffer())->lastActiveFrameSlot = currentFrameSlot; - if (colorAttachment.resolveTexture()) - QRHI_RES(QMetalTexture, colorAttachment.resolveTexture())->lastActiveFrameSlot = currentFrameSlot; + for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); + it != itEnd; ++it) + { + if (it->texture()) + QRHI_RES(QMetalTexture, it->texture())->lastActiveFrameSlot = currentFrameSlot; + else if (it->renderBuffer()) + QRHI_RES(QMetalRenderBuffer, it->renderBuffer())->lastActiveFrameSlot = currentFrameSlot; + if (it->resolveTexture()) + QRHI_RES(QMetalTexture, it->resolveTexture())->lastActiveFrameSlot = currentFrameSlot; } if (rtTex->m_desc.depthStencilBuffer()) QRHI_RES(QMetalRenderBuffer, rtTex->m_desc.depthStencilBuffer())->lastActiveFrameSlot = currentFrameSlot; @@ -2647,14 +2648,15 @@ void QMetalTextureRenderTarget::release() QRhiRenderPassDescriptor *QMetalTextureRenderTarget::newCompatibleRenderPassDescriptor() { - const QVector colorAttachments = m_desc.colorAttachments(); + const int colorAttachmentCount = m_desc.cendColorAttachments() - m_desc.cbeginColorAttachments(); QMetalRenderPassDescriptor *rpD = new QMetalRenderPassDescriptor(m_rhi); - rpD->colorAttachmentCount = colorAttachments.count(); + rpD->colorAttachmentCount = colorAttachmentCount; rpD->hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture(); - for (int i = 0, ie = colorAttachments.count(); i != ie; ++i) { - QMetalTexture *texD = QRHI_RES(QMetalTexture, colorAttachments[i].texture()); - QMetalRenderBuffer *rbD = QRHI_RES(QMetalRenderBuffer, colorAttachments[i].renderBuffer()); + for (int i = 0; i < colorAttachmentCount; ++i) { + const QRhiColorAttachment *colorAtt = m_desc.colorAttachmentAt(i); + QMetalTexture *texD = QRHI_RES(QMetalTexture, colorAtt->texture()); + QMetalRenderBuffer *rbD = QRHI_RES(QMetalRenderBuffer, colorAtt->renderBuffer()); rpD->colorFormat[i] = int(texD ? texD->d->format : rbD->d->format); } @@ -2668,39 +2670,41 @@ QRhiRenderPassDescriptor *QMetalTextureRenderTarget::newCompatibleRenderPassDesc bool QMetalTextureRenderTarget::build() { - const QVector colorAttachments = m_desc.colorAttachments(); - Q_ASSERT(!colorAttachments.isEmpty() || m_desc.depthTexture()); + const bool hasColorAttachments = m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments(); + Q_ASSERT(hasColorAttachments || m_desc.depthTexture()); Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture()); const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture(); - d->colorAttCount = colorAttachments.count(); - for (int i = 0; i < d->colorAttCount; ++i) { - QMetalTexture *texD = QRHI_RES(QMetalTexture, colorAttachments[i].texture()); - QMetalRenderBuffer *rbD = QRHI_RES(QMetalRenderBuffer, colorAttachments[i].renderBuffer()); + d->colorAttCount = 0; + int attIndex = 0; + for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) { + d->colorAttCount += 1; + QMetalTexture *texD = QRHI_RES(QMetalTexture, it->texture()); + QMetalRenderBuffer *rbD = QRHI_RES(QMetalRenderBuffer, it->renderBuffer()); Q_ASSERT(texD || rbD); id dst = nil; if (texD) { dst = texD->d->tex; - if (i == 0) { + if (attIndex == 0) { d->pixelSize = texD->pixelSize(); d->sampleCount = texD->samples; } } else if (rbD) { dst = rbD->d->tex; - if (i == 0) { + if (attIndex == 0) { d->pixelSize = rbD->pixelSize(); d->sampleCount = rbD->samples; } } QMetalRenderTargetData::ColorAtt colorAtt; colorAtt.tex = dst; - colorAtt.layer = colorAttachments[i].layer(); - colorAtt.level = colorAttachments[i].level(); - QMetalTexture *resTexD = QRHI_RES(QMetalTexture, colorAttachments[i].resolveTexture()); + colorAtt.layer = it->layer(); + colorAtt.level = it->level(); + QMetalTexture *resTexD = QRHI_RES(QMetalTexture, it->resolveTexture()); colorAtt.resolveTex = resTexD ? resTexD->d->tex : nil; - colorAtt.resolveLayer = colorAttachments[i].resolveLayer(); - colorAtt.resolveLevel = colorAttachments[i].resolveLevel(); - d->fb.colorAtt[i] = colorAtt; + colorAtt.resolveLayer = it->resolveLayer(); + colorAtt.resolveLevel = it->resolveLevel(); + d->fb.colorAtt[attIndex] = colorAtt; } d->dpr = 1; @@ -3119,22 +3123,24 @@ bool QMetalGraphicsPipeline::build() const int firstVertexBinding = QRHI_RES(QMetalShaderResourceBindings, m_shaderResourceBindings)->maxBinding + 1; MTLVertexDescriptor *inputLayout = [MTLVertexDescriptor vertexDescriptor]; - const QVector attributes = m_vertexInputLayout.attributes(); - for (const QRhiVertexInputAttribute &attribute : attributes) { - const uint loc = uint(attribute.location()); - inputLayout.attributes[loc].format = toMetalAttributeFormat(attribute.format()); - inputLayout.attributes[loc].offset = NSUInteger(attribute.offset()); - inputLayout.attributes[loc].bufferIndex = NSUInteger(firstVertexBinding + attribute.binding()); + for (auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes(); + it != itEnd; ++it) + { + const uint loc = uint(it->location()); + inputLayout.attributes[loc].format = toMetalAttributeFormat(it->format()); + inputLayout.attributes[loc].offset = NSUInteger(it->offset()); + inputLayout.attributes[loc].bufferIndex = NSUInteger(firstVertexBinding + it->binding()); } - const QVector bindings = m_vertexInputLayout.bindings(); - for (int i = 0, ie = bindings.count(); i != ie; ++i) { - const QRhiVertexInputBinding &binding(bindings[i]); - const uint layoutIdx = uint(firstVertexBinding + i); + int bindingIndex = 0; + for (auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings(); + it != itEnd; ++it, ++bindingIndex) + { + const uint layoutIdx = uint(firstVertexBinding + bindingIndex); inputLayout.layouts[layoutIdx].stepFunction = - binding.classification() == QRhiVertexInputBinding::PerInstance + it->classification() == QRhiVertexInputBinding::PerInstance ? MTLVertexStepFunctionPerInstance : MTLVertexStepFunctionPerVertex; - inputLayout.layouts[layoutIdx].stepRate = NSUInteger(binding.instanceStepRate()); - inputLayout.layouts[layoutIdx].stride = binding.stride(); + inputLayout.layouts[layoutIdx].stepRate = NSUInteger(it->instanceStepRate()); + inputLayout.layouts[layoutIdx].stride = it->stride(); } MTLRenderPipelineDescriptor *rpDesc = [[MTLRenderPipelineDescriptor alloc] init]; diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp index 60d620813b..487afd3ed1 100644 --- a/src/gui/rhi/qrhinull.cpp +++ b/src/gui/rhi/qrhinull.cpp @@ -628,10 +628,9 @@ QRhiRenderPassDescriptor *QNullTextureRenderTarget::newCompatibleRenderPassDescr bool QNullTextureRenderTarget::build() { d.rp = QRHI_RES(QNullRenderPassDescriptor, m_renderPassDesc); - const QVector colorAttachments = m_desc.colorAttachments(); - if (!colorAttachments.isEmpty()) { - QRhiTexture *tex = colorAttachments.first().texture(); - QRhiRenderBuffer *rb = colorAttachments.first().renderBuffer(); + if (m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments()) { + QRhiTexture *tex = m_desc.cbeginColorAttachments()->texture(); + QRhiRenderBuffer *rb = m_desc.cbeginColorAttachments()->renderBuffer(); d.pixelSize = tex ? tex->pixelSize() : rb->pixelSize(); } else if (m_desc.depthStencilBuffer()) { d.pixelSize = m_desc.depthStencilBuffer()->pixelSize(); diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 7e2e914af3..3a2c35b589 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -1111,7 +1111,8 @@ bool QRhiVulkan::createDefaultRenderPass(VkRenderPass *rp, bool hasDepthStencil, } bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, - const QVector &colorAttachments, + const QRhiColorAttachment *firstColorAttachment, + const QRhiColorAttachment *lastColorAttachment, bool preserveColor, bool preserveDs, QRhiRenderBuffer *depthStencilBuffer, @@ -1120,13 +1121,12 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, QVarLengthArray attDescs; QVarLengthArray colorRefs; QVarLengthArray resolveRefs; - const int colorAttCount = colorAttachments.count(); // attachment list layout is color (0-8), ds (0-1), resolve (0-8) - for (int i = 0; i < colorAttCount; ++i) { - QVkTexture *texD = QRHI_RES(QVkTexture, colorAttachments[i].texture()); - QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, colorAttachments[i].renderBuffer()); + for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) { + QVkTexture *texD = QRHI_RES(QVkTexture, it->texture()); + QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, it->renderBuffer()); Q_ASSERT(texD || rbD); const VkFormat vkformat = texD ? texD->vkformat : rbD->vkformat; const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples; @@ -1136,7 +1136,7 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, attDesc.format = vkformat; attDesc.samples = samples; attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR; - attDesc.storeOp = colorAttachments[i].resolveTexture() ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE; + attDesc.storeOp = it->resolveTexture() ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE; attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // this has to interact correctly with activateTextureRenderTarget(), hence leaving in COLOR_ATT @@ -1170,9 +1170,9 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, } VkAttachmentReference dsRef = { uint32_t(attDescs.count() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; - for (int i = 0; i < colorAttCount; ++i) { - if (colorAttachments[i].resolveTexture()) { - QVkTexture *rtexD = QRHI_RES(QVkTexture, colorAttachments[i].resolveTexture()); + for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) { + if (it->resolveTexture()) { + QVkTexture *rtexD = QRHI_RES(QVkTexture, it->resolveTexture()); if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT) qWarning("Resolving into a multisample texture is not supported"); @@ -1979,11 +1979,10 @@ void QRhiVulkan::activateTextureRenderTarget(QVkCommandBuffer *cbD, QVkTextureRe rtD->lastActiveFrameSlot = currentFrameSlot; rtD->d.rp->lastActiveFrameSlot = currentFrameSlot; QRhiPassResourceTracker &passResTracker(cbD->passResTrackers[cbD->currentPassResTrackerIndex]); - const QVector colorAttachments = rtD->m_desc.colorAttachments(); - for (const QRhiColorAttachment &colorAttachment : colorAttachments) { - QVkTexture *texD = QRHI_RES(QVkTexture, colorAttachment.texture()); - QVkTexture *resolveTexD = QRHI_RES(QVkTexture, colorAttachment.resolveTexture()); - QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, colorAttachment.renderBuffer()); + for (auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) { + QVkTexture *texD = QRHI_RES(QVkTexture, it->texture()); + QVkTexture *resolveTexD = QRHI_RES(QVkTexture, it->resolveTexture()); + QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, it->renderBuffer()); if (texD) { trackedRegisterTexture(&passResTracker, texD, QRhiPassResourceTracker::TexColorOutput, @@ -5487,7 +5486,8 @@ QRhiRenderPassDescriptor *QVkTextureRenderTarget::newCompatibleRenderPassDescrip QRHI_RES_RHI(QRhiVulkan); QVkRenderPassDescriptor *rp = new QVkRenderPassDescriptor(m_rhi); if (!rhiD->createOffscreenRenderPass(&rp->rp, - m_desc.colorAttachments(), + m_desc.cbeginColorAttachments(), + m_desc.cendColorAttachments(), m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents), m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents), m_desc.depthStencilBuffer(), @@ -5507,18 +5507,20 @@ bool QVkTextureRenderTarget::build() if (d.fb) release(); - const QVector colorAttachments = m_desc.colorAttachments(); - Q_ASSERT(!colorAttachments.isEmpty() || m_desc.depthTexture()); + const bool hasColorAttachments = m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments(); + Q_ASSERT(hasColorAttachments || m_desc.depthTexture()); Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture()); const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture(); QRHI_RES_RHI(QRhiVulkan); QVarLengthArray views; - d.colorAttCount = colorAttachments.count(); - for (int i = 0; i < d.colorAttCount; ++i) { - QVkTexture *texD = QRHI_RES(QVkTexture, colorAttachments[i].texture()); - QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, colorAttachments[i].renderBuffer()); + d.colorAttCount = 0; + int attIndex = 0; + for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) { + d.colorAttCount += 1; + QVkTexture *texD = QRHI_RES(QVkTexture, it->texture()); + QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, it->renderBuffer()); Q_ASSERT(texD || rbD); if (texD) { Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget)); @@ -5533,24 +5535,24 @@ bool QVkTextureRenderTarget::build() viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewInfo.subresourceRange.baseMipLevel = uint32_t(colorAttachments[i].level()); + viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level()); viewInfo.subresourceRange.levelCount = 1; - viewInfo.subresourceRange.baseArrayLayer = uint32_t(colorAttachments[i].layer()); + viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer()); viewInfo.subresourceRange.layerCount = 1; - VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &rtv[i]); + VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &rtv[attIndex]); if (err != VK_SUCCESS) { qWarning("Failed to create render target image view: %d", err); return false; } - views.append(rtv[i]); - if (i == 0) { + views.append(rtv[attIndex]); + if (attIndex == 0) { d.pixelSize = texD->pixelSize(); d.sampleCount = texD->samples; } } else if (rbD) { Q_ASSERT(rbD->backingTexture); views.append(rbD->backingTexture->imageView); - if (i == 0) { + if (attIndex == 0) { d.pixelSize = rbD->pixelSize(); d.sampleCount = rbD->samples; } @@ -5580,9 +5582,10 @@ bool QVkTextureRenderTarget::build() } d.resolveAttCount = 0; - for (int i = 0; i < d.colorAttCount; ++i) { - if (colorAttachments[i].resolveTexture()) { - QVkTexture *resTexD = QRHI_RES(QVkTexture, colorAttachments[i].resolveTexture()); + attIndex = 0; + for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) { + if (it->resolveTexture()) { + QVkTexture *resTexD = QRHI_RES(QVkTexture, it->resolveTexture()); Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget)); d.resolveAttCount += 1; @@ -5597,16 +5600,16 @@ bool QVkTextureRenderTarget::build() viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewInfo.subresourceRange.baseMipLevel = uint32_t(colorAttachments[i].resolveLevel()); + viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel()); viewInfo.subresourceRange.levelCount = 1; - viewInfo.subresourceRange.baseArrayLayer = uint32_t(colorAttachments[i].resolveLayer()); + viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer()); viewInfo.subresourceRange.layerCount = 1; - VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &resrtv[i]); + VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &resrtv[attIndex]); if (err != VK_SUCCESS) { qWarning("Failed to create render target resolve image view: %d", err); return false; } - views.append(resrtv[i]); + views.append(resrtv[attIndex]); } } @@ -5828,22 +5831,21 @@ bool QVkGraphicsPipeline::build() pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.count()); pipelineInfo.pStages = shaderStageCreateInfos.constData(); - const QVector bindings = m_vertexInputLayout.bindings(); QVarLengthArray vertexBindings; QVarLengthArray nonOneStepRates; - for (int i = 0, ie = bindings.count(); i != ie; ++i) { - const QRhiVertexInputBinding &binding(bindings[i]); + int bindingIndex = 0; + for (auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings(); + it != itEnd; ++it, ++bindingIndex) + { VkVertexInputBindingDescription bindingInfo = { - uint32_t(i), - binding.stride(), - binding.classification() == QRhiVertexInputBinding::PerVertex + uint32_t(bindingIndex), + it->stride(), + it->classification() == QRhiVertexInputBinding::PerVertex ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE }; - if (binding.classification() == QRhiVertexInputBinding::PerInstance - && binding.instanceStepRate() != 1) - { + if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) { if (rhiD->vertexAttribDivisorAvailable) { - nonOneStepRates.append({ uint32_t(i), uint32_t(binding.instanceStepRate()) }); + nonOneStepRates.append({ uint32_t(bindingIndex), uint32_t(it->instanceStepRate()) }); } else { qWarning("QRhiVulkan: Instance step rates other than 1 not supported without " "VK_EXT_vertex_attribute_divisor on the device and " @@ -5852,14 +5854,15 @@ bool QVkGraphicsPipeline::build() } vertexBindings.append(bindingInfo); } - const QVector attributes = m_vertexInputLayout.attributes(); QVarLengthArray vertexAttributes; - for (const QRhiVertexInputAttribute &attribute : attributes) { + for (auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes(); + it != itEnd; ++it) + { VkVertexInputAttributeDescription attributeInfo = { - uint32_t(attribute.location()), - uint32_t(attribute.binding()), - toVkAttributeFormat(attribute.format()), - attribute.offset() + uint32_t(it->location()), + uint32_t(it->binding()), + toVkAttributeFormat(it->format()), + it->offset() }; vertexAttributes.append(attributeInfo); } diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index d83a338acd..7bd20b3671 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -732,7 +732,8 @@ public: VkSampleCountFlagBits samples, VkFormat colorFormat); bool createOffscreenRenderPass(VkRenderPass *rp, - const QVector &colorAttachments, + const QRhiColorAttachment *firstColorAttachment, + const QRhiColorAttachment *lastColorAttachment, bool preserveColor, bool preserveDs, QRhiRenderBuffer *depthStencilBuffer, diff --git a/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.cpp b/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.cpp index bb3722bec5..af454c2487 100644 --- a/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.cpp +++ b/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.cpp @@ -165,11 +165,13 @@ void Window::customRender() u->updateDynamicBuffer(d.ubuf, 64, 4, &flip); } if (!d.compressedData.isEmpty()) { - QRhiTextureUploadDescription desc; + QVarLengthArray descEntries; for (int i = 0; i < d.compressedData.count(); ++i) { QRhiTextureSubresourceUploadDescription image(d.compressedData[i].constData(), d.compressedData[i].size()); - desc.append({ 0, i, image }); + descEntries.append({ 0, i, image }); } + QRhiTextureUploadDescription desc; + desc.setEntries(descEntries.cbegin(), descEntries.cend()); u->uploadTexture(d.tex, desc); d.compressedData.clear(); } diff --git a/tests/manual/rhi/mrt/mrt.cpp b/tests/manual/rhi/mrt/mrt.cpp index dc72c7d194..dfec5bb1d1 100644 --- a/tests/manual/rhi/mrt/mrt.cpp +++ b/tests/manual/rhi/mrt/mrt.cpp @@ -143,10 +143,10 @@ void Window::customInit() } QRhiTextureRenderTargetDescription rtDesc; - QVector att; + QRhiColorAttachment att[ATTCOUNT]; for (int i = 0; i < ATTCOUNT; ++i) - att.append(QRhiColorAttachment(d.colData[i].tex)); - rtDesc.setColorAttachments(att); + att[i] = QRhiColorAttachment(d.colData[i].tex); + rtDesc.setColorAttachments(att, att + ATTCOUNT); d.rt = m_r->newTextureRenderTarget(rtDesc); d.releasePool << d.rt; d.rtRp = d.rt->newCompatibleRenderPassDescriptor(); diff --git a/tests/manual/rhi/triquadcube/texturedcuberenderer.cpp b/tests/manual/rhi/triquadcube/texturedcuberenderer.cpp index 3f15881e2d..8c5845d4fc 100644 --- a/tests/manual/rhi/triquadcube/texturedcuberenderer.cpp +++ b/tests/manual/rhi/triquadcube/texturedcuberenderer.cpp @@ -181,16 +181,18 @@ void TexturedCubeRenderer::queueResourceUpdates(QRhiResourceUpdateBatch *resourc if (!m_image.isNull()) { if (MIPMAP) { - QRhiTextureUploadDescription desc; + QVarLengthArray descEntries; if (!AUTOGENMIPMAP) { // the ghetto mipmap generator... for (int i = 0, ie = m_r->mipLevelsForSize(m_image.size()); i != ie; ++i) { QImage image = m_image.scaled(m_r->sizeForMipLevel(i, m_image.size())); - desc.append({ 0, i, image }); + descEntries.append({ 0, i, image }); } } else { - desc.append({ 0, 0, m_image }); + descEntries.append({ 0, 0, m_image }); } + QRhiTextureUploadDescription desc; + desc.setEntries(descEntries.cbegin(), descEntries.cend()); resourceUpdates->uploadTexture(m_tex, desc); if (AUTOGENMIPMAP) resourceUpdates->generateMips(m_tex); From 5bc972a4118927be7d2b81e4ff66be5bc274fdaa Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 1 Oct 2019 14:36:29 +0200 Subject: [PATCH 09/16] rhi: vulkan: Disable vkmemalloc's own synchronization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need for those mutexes. Task-number: QTBUG-78908 Change-Id: I60c32df1f8729098f1894eff7c71e7fbcbd23ecf Reviewed-by: Christian Strømme --- src/gui/rhi/qrhivulkan.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 3a2c35b589..c7d28a4f18 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -568,6 +568,9 @@ bool QRhiVulkan::create(QRhi::Flags flags) VmaAllocatorCreateInfo allocatorInfo; memset(&allocatorInfo, 0, sizeof(allocatorInfo)); + // A QRhi is supposed to be used from one single thread only. Disable + // the allocator's own mutexes. This gives a performance boost. + allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT; allocatorInfo.physicalDevice = physDev; allocatorInfo.device = dev; allocatorInfo.pVulkanFunctions = &afuncs; From 2e068c7f2aca6a40bcf1e4c5bc85c26f478fe786 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Tue, 1 Oct 2019 15:19:37 +0200 Subject: [PATCH 10/16] Add TriangleFan pipeline topology Triangle fan drawing is only supported on some platforms. The feature flag QRhi::TriangleFanTopology is set accordingly. In general, TriangleStrip topology will be more efficient on most GPUs. However, if polygon data is already stored as triangle fans, the CPU savings may be more significant. Change-Id: I9704fad751d2119eac8791074f58942dd9315601 Reviewed-by: Laszlo Agocs --- src/gui/rhi/qrhi.cpp | 6 +++++- src/gui/rhi/qrhi_p.h | 4 +++- src/gui/rhi/qrhid3d11.cpp | 2 ++ src/gui/rhi/qrhigles2.cpp | 4 ++++ src/gui/rhi/qrhimetal.mm | 2 ++ src/gui/rhi/qrhivulkan.cpp | 4 ++++ 6 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index e4f6da6d46..c8ec8c7410 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -563,7 +563,10 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general") \value BaseInstance Indicates that instanced draw commands support the \c firstInstance argument. When reported as not supported, the firstInstance value is ignored and the instance ID starts from 0. - */ + + \value TriangleFanTopology Indicates that QRhiGraphicsPipeline::setTopology() + supports QRhiGraphicsPipeline::TriangleFan. +*/ /*! \enum QRhi::BeginFrameFlag @@ -3123,6 +3126,7 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb) \value Triangles (default) \value TriangleStrip + \value TriangleFan (only available if QRhi::TriangleFanTopology is supported) \value Lines \value LineStrip \value Points diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 95e9213cac..5b371af727 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -1017,6 +1017,7 @@ public: enum Topology { Triangles, TriangleStrip, + TriangleFan, Lines, LineStrip, Points @@ -1426,7 +1427,8 @@ public: WideLines, VertexShaderPointSize, BaseVertex, - BaseInstance + BaseInstance, + TriangleFanTopology }; enum BeginFrameFlag { diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 36c95f2306..f011d68ada 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -469,6 +469,8 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const return true; case QRhi::BaseInstance: return true; + case QRhi::TriangleFanTopology: + return false; default: Q_UNREACHABLE(); return false; diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 17b40777b3..277cf12fd2 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -732,6 +732,8 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const return caps.baseVertex; case QRhi::BaseInstance: return false; // not in ES 3.2, so won't bother + case QRhi::TriangleFanTopology: + return true; default: Q_UNREACHABLE(); return false; @@ -1539,6 +1541,8 @@ static inline GLenum toGlTopology(QRhiGraphicsPipeline::Topology t) return GL_TRIANGLES; case QRhiGraphicsPipeline::TriangleStrip: return GL_TRIANGLE_STRIP; + case QRhiGraphicsPipeline::TriangleFan: + return GL_TRIANGLE_FAN; case QRhiGraphicsPipeline::Lines: return GL_LINES; case QRhiGraphicsPipeline::LineStrip: diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 344be44d48..f9d9cdc01a 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -550,6 +550,8 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const return true; case QRhi::BaseInstance: return true; + case QRhi::TriangleFanTopology: + return false; default: Q_UNREACHABLE(); return false; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index c7d28a4f18..cb32aa08f3 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -3727,6 +3727,8 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const return true; case QRhi::BaseInstance: return true; + case QRhi::TriangleFanTopology: + return true; default: Q_UNREACHABLE(); return false; @@ -4572,6 +4574,8 @@ static inline VkPrimitiveTopology toVkTopology(QRhiGraphicsPipeline::Topology t) return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; case QRhiGraphicsPipeline::TriangleStrip: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + case QRhiGraphicsPipeline::TriangleFan: + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN; case QRhiGraphicsPipeline::Lines: return VK_PRIMITIVE_TOPOLOGY_LINE_LIST; case QRhiGraphicsPipeline::LineStrip: From b4efdd376996f98375146d154c1dc7737c0edc38 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 17 Sep 2019 18:19:59 +0200 Subject: [PATCH 11/16] Reorganise the qfloat16 auto-test Its limits() test was rather large and had some overlap with an older qNan() test, that needed some clean-up (it combined qfloat16 values with double and float values in ways that caused qfloat16 to be promoted to another type, so we weren't testing qfloat16). Renamed the qNan() test to qNaN(), separated out the parts of it that actually tested infinity. Moved various parts of limits() to these and rationalised the result. Split out a properties() test from limits() for the properties of the qfloat16 type that are supplied by its numeric_limits. Split out a data-driven finite() test to cover some repeated code that was in limits() and extended it to test more values. Added more tests of isNormal(). Fixed my earlier UK-ish spelling of "optimise", in the process, and identify the processor rather than the virtualization as the context where the compiler errs. Change-Id: I8133da6fb7995ee20e5802c6357d611c8c0cba73 Reviewed-by: Thiago Macieira --- .../corelib/global/qfloat16/tst_qfloat16.cpp | 186 ++++++++++-------- 1 file changed, 102 insertions(+), 84 deletions(-) diff --git a/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp b/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp index 5c7737085e..01a1789188 100644 --- a/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp +++ b/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp @@ -41,7 +41,8 @@ private slots: void fuzzyCompare(); void ltgt_data(); void ltgt(); - void qNan(); + void qNaN(); + void infinity(); void float_cast(); void float_cast_data(); void promotionTests(); @@ -49,6 +50,9 @@ private slots: void arithOps(); void floatToFloat16(); void floatFromFloat16(); + void finite_data(); + void finite(); + void properties(); void limits(); }; @@ -154,38 +158,66 @@ void tst_qfloat16::ltgt() # pragma GCC optimize "no-fast-math" #endif -void tst_qfloat16::qNan() +void tst_qfloat16::qNaN() { #if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ < 404) QSKIP("Non-conformant fast math mode is enabled, cannot run test"); #endif - qfloat16 nan = qQNaN(); - QVERIFY(!(0. > nan)); - QVERIFY(!(0. < nan)); + using Bounds = std::numeric_limits; + const qfloat16 nan = Bounds::quiet_NaN(); + const qfloat16 zero(0), one(1); + QVERIFY(!(zero > nan)); + QVERIFY(!(zero < nan)); + QVERIFY(!(zero == nan)); QVERIFY(!qIsInf(nan)); QVERIFY(qIsNaN(nan)); - QVERIFY(qIsNaN(nan + 1.f)); + QVERIFY(qIsNaN(nan + one)); QVERIFY(qIsNaN(-nan)); - qfloat16 inf = qInf(); - QVERIFY(inf > qfloat16(0)); - QVERIFY(-inf < qfloat16(0)); - QVERIFY(!qIsNaN(inf)); - QVERIFY(qIsInf(inf)); - QVERIFY(qIsInf(-inf)); - QVERIFY(qIsInf(2.f*inf)); - QVERIFY(qIsInf(inf*2.f)); - // QTBUG-75812: QEMU/arm64 compiler over-optimizes, so flakily fails 1/inf == 0 :-( - if (qfloat16(9.785e-4f) == qfloat16(9.794e-4f)) - QCOMPARE(qfloat16(1.f) / inf, qfloat16(0.f)); #ifdef Q_CC_INTEL QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue); #endif - QVERIFY(qIsNaN(nan*0.f)); + QVERIFY(qIsNaN(nan * zero)); #ifdef Q_CC_INTEL QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue); #endif - QVERIFY(qIsNaN(inf*0.f)); - QVERIFY(qFuzzyCompare(qfloat16(1.f/inf), qfloat16(0.0))); + QVERIFY(qIsNaN(Bounds::infinity() * zero)); + + QVERIFY(!nan.isNormal()); + QVERIFY(!qIsFinite(nan)); + QVERIFY(!(nan == nan)); + QCOMPARE(nan, nan); // Despite the preceding + QCOMPARE(qFpClassify(nan), FP_NAN); +} + +void tst_qfloat16::infinity() +{ + const qfloat16 huge = std::numeric_limits::infinity(); + const qfloat16 zero(0), one(1), two(2); + QVERIFY(huge > -huge); + QVERIFY(huge > zero); + QVERIFY(-huge < zero); + QCOMPARE(huge, huge); + QCOMPARE(-huge, -huge); + + // QTBUG-75812 - see overOptimized in the limits() test. + if (qfloat16(9.785e-4f) == qfloat16(9.794e-4f)) { + QCOMPARE(one / huge, zero); + QVERIFY(qFuzzyCompare(one / huge, zero)); // (same thing) + } + + QVERIFY(qIsInf(huge)); + QVERIFY(qIsInf(-huge)); + QVERIFY(qIsInf(two * huge)); + QVERIFY(qIsInf(huge * two)); + + QVERIFY(!huge.isNormal()); + QVERIFY(!(-huge).isNormal()); + QVERIFY(!qIsNaN(huge)); + QVERIFY(!qIsNaN(-huge)); + QVERIFY(!qIsFinite(huge)); + QVERIFY(!qIsFinite(-huge)); + QCOMPARE(qFpClassify(huge), FP_INFINITE); + QCOMPARE(qFpClassify(-huge), FP_INFINITE); } void tst_qfloat16::float_cast_data() @@ -366,10 +398,40 @@ static qfloat16 powf16(qfloat16 base, int raise) return answer; } -void tst_qfloat16::limits() +void tst_qfloat16::finite_data() +{ + using Bounds = std::numeric_limits; + QTest::addColumn("value"); + QTest::addColumn("mode"); + + QTest::newRow("zero") << qfloat16(0) << FP_ZERO; + QTest::newRow("one") << qfloat16(1) << FP_NORMAL; + QTest::newRow("-one") << qfloat16(-1) << FP_NORMAL; + QTest::newRow("ten") << qfloat16(10) << FP_NORMAL; + QTest::newRow("-ten") << qfloat16(-10) << FP_NORMAL; + QTest::newRow("max") << Bounds::max() << FP_NORMAL; + QTest::newRow("lowest") << Bounds::lowest() << FP_NORMAL; + QTest::newRow("min") << Bounds::min() << FP_NORMAL; + QTest::newRow("-min") << -Bounds::min() << FP_NORMAL; + QTest::newRow("denorm_min") << Bounds::denorm_min() << FP_SUBNORMAL; + QTest::newRow("-denorm_min") << -Bounds::denorm_min() << FP_SUBNORMAL; +} + +void tst_qfloat16::finite() +{ + QFETCH(qfloat16, value); + QFETCH(int, mode); + QCOMPARE(value.isNormal(), mode != FP_SUBNORMAL); + QCOMPARE(value, value); // Fuzzy + QVERIFY(value == value); // Exact + QVERIFY(qIsFinite(value)); + QVERIFY(!qIsInf(value)); + QVERIFY(!qIsNaN(value)); + QCOMPARE(qFpClassify(value), mode); +} + +void tst_qfloat16::properties() { - // *NOT* using QCOMPARE() on finite qfloat16 values, since that uses fuzzy - // comparison, and we need exact here. using Bounds = std::numeric_limits; QVERIFY(Bounds::is_specialized); QVERIFY(Bounds::is_signed); @@ -386,21 +448,16 @@ void tst_qfloat16::limits() QCOMPARE(Bounds::round_style, std::round_to_nearest); QCOMPARE(Bounds::radix, 2); // Untested: has_denorm_loss +} - // A few common values: +void tst_qfloat16::limits() // See also: qNaN() and infinity() +{ + // *NOT* using QCOMPARE() on finite qfloat16 values, since that uses fuzzy + // comparison, and we need exact here. + using Bounds = std::numeric_limits; + + // A few useful values: const qfloat16 zero(0), one(1), ten(10); - QVERIFY(qIsFinite(zero)); - QVERIFY(!qIsInf(zero)); - QVERIFY(!qIsNaN(zero)); - QCOMPARE(qFpClassify(zero), FP_ZERO); - QVERIFY(qIsFinite(one)); - QVERIFY(!qIsInf(one)); - QCOMPARE(qFpClassify(one), FP_NORMAL); - QVERIFY(!qIsNaN(one)); - QVERIFY(qIsFinite(ten)); - QVERIFY(!qIsInf(ten)); - QVERIFY(!qIsNaN(ten)); - QCOMPARE(qFpClassify(ten), FP_NORMAL); // digits in the mantissa, including the implicit 1 before the binary dot at its left: QVERIFY(qfloat16(1 << (Bounds::digits - 1)) + one > qfloat16(1 << (Bounds::digits - 1))); @@ -436,12 +493,12 @@ void tst_qfloat16::limits() // How many digits are significant ? (Casts avoid linker errors ...) QCOMPARE(int(Bounds::digits10), 3); // 9.79e-4 has enough sigificant digits: qfloat16 below(9.785e-4f), above(9.794e-4f); -#if 0 // Sadly, the QEMU x-compile for arm64 "optimises" comparisons: - const bool overOptimised = false; +#if 0 // Sadly, the QEMU x-compile for arm64 "optimizes" comparisons: + const bool overOptimized = false; #else - const bool overOptimised = (below != above); - if (overOptimised) - QEXPECT_FAIL("", "Over-optimised on QEMU", Continue); + const bool overOptimized = (below != above); + if (overOptimized) + QEXPECT_FAIL("", "Over-optimized on ARM", Continue); #endif // (but it did, so should, pass everywhere else, confirming digits10 is indeed 3). QVERIFY(below == above); QCOMPARE(int(Bounds::max_digits10), 5); // we need 5 to distinguish these two: @@ -450,62 +507,23 @@ void tst_qfloat16::limits() // Actual limiting values of the type: const qfloat16 rose(one + Bounds::epsilon()); QVERIFY(rose > one); - if (overOptimised) - QEXPECT_FAIL("", "Over-optimised on QEMU", Continue); + if (overOptimized) + QEXPECT_FAIL("", "Over-optimized on ARM", Continue); QVERIFY(one + Bounds::epsilon() / rose == one); - QVERIFY(qIsInf(Bounds::infinity())); - QVERIFY(!qIsNaN(Bounds::infinity())); - QVERIFY(!qIsFinite(Bounds::infinity())); - QCOMPARE(Bounds::infinity(), Bounds::infinity()); - QCOMPARE(qFpClassify(Bounds::infinity()), FP_INFINITE); - - QVERIFY(Bounds::infinity() > -Bounds::infinity()); - QVERIFY(Bounds::infinity() > zero); - QVERIFY(qIsInf(-Bounds::infinity())); - QVERIFY(!qIsNaN(-Bounds::infinity())); - QVERIFY(!qIsFinite(-Bounds::infinity())); - QCOMPARE(-Bounds::infinity(), -Bounds::infinity()); - QCOMPARE(qFpClassify(-Bounds::infinity()), FP_INFINITE); - - QVERIFY(-Bounds::infinity() < zero); - QVERIFY(qIsNaN(Bounds::quiet_NaN())); - QVERIFY(!qIsInf(Bounds::quiet_NaN())); - QVERIFY(!qIsFinite(Bounds::quiet_NaN())); - QVERIFY(!(Bounds::quiet_NaN() == Bounds::quiet_NaN())); - QCOMPARE(Bounds::quiet_NaN(), Bounds::quiet_NaN()); - QCOMPARE(qFpClassify(Bounds::quiet_NaN()), FP_NAN); QVERIFY(Bounds::max() > zero); - QVERIFY(qIsFinite(Bounds::max())); - QVERIFY(!qIsInf(Bounds::max())); - QVERIFY(!qIsNaN(Bounds::max())); QVERIFY(qIsInf(Bounds::max() * rose)); - QCOMPARE(qFpClassify(Bounds::max()), FP_NORMAL); QVERIFY(Bounds::lowest() < zero); - QVERIFY(qIsFinite(Bounds::lowest())); - QVERIFY(!qIsInf(Bounds::lowest())); - QVERIFY(!qIsNaN(Bounds::lowest())); QVERIFY(qIsInf(Bounds::lowest() * rose)); - QCOMPARE(qFpClassify(Bounds::lowest()), FP_NORMAL); QVERIFY(Bounds::min() > zero); - QVERIFY(Bounds::min().isNormal()); QVERIFY(!(Bounds::min() / rose).isNormal()); - QVERIFY(qIsFinite(Bounds::min())); - QVERIFY(!qIsInf(Bounds::min())); - QVERIFY(!qIsNaN(Bounds::min())); - QCOMPARE(qFpClassify(Bounds::min()), FP_NORMAL); QVERIFY(Bounds::denorm_min() > zero); - QVERIFY(!Bounds::denorm_min().isNormal()); - QVERIFY(qIsFinite(Bounds::denorm_min())); - QVERIFY(!qIsInf(Bounds::denorm_min())); - QVERIFY(!qIsNaN(Bounds::denorm_min())); - if (overOptimised) - QEXPECT_FAIL("", "Over-optimised on QEMU", Continue); + if (overOptimized) + QEXPECT_FAIL("", "Over-optimized on ARM", Continue); QCOMPARE(Bounds::denorm_min() / rose, zero); - QCOMPARE(qFpClassify(Bounds::denorm_min()), FP_SUBNORMAL); } QTEST_APPLESS_MAIN(tst_qfloat16) From c9478e90ff7abef1f019805f0846e651c484ebc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 24 Sep 2019 17:25:57 +0200 Subject: [PATCH 12/16] Export lcEventDispatcher in private namespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The category is used outside of QtCore, and needs to be exported for shared library builds. Change-Id: I9bba477d37b823146eaec4e1e53197651f09c013 Reviewed-by: Timur Pocheptsov Reviewed-by: Tor Arne Vestbø --- src/corelib/kernel/qeventdispatcher_cf.mm | 11 ++++++++--- src/corelib/kernel/qeventdispatcher_cf_p.h | 6 ++++-- src/plugins/platforms/ios/qioseventdispatcher.mm | 2 ++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_cf.mm b/src/corelib/kernel/qeventdispatcher_cf.mm index b9e334f1f4..177551467c 100644 --- a/src/corelib/kernel/qeventdispatcher_cf.mm +++ b/src/corelib/kernel/qeventdispatcher_cf.mm @@ -56,6 +56,14 @@ # include #endif +QT_BEGIN_NAMESPACE +namespace QtPrivate { +Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher"); +Q_LOGGING_CATEGORY(lcEventDispatcherTimers, "qt.eventdispatcher.timers"); +} +using namespace QtPrivate; +QT_END_NAMESPACE + QT_USE_NAMESPACE /* @@ -148,9 +156,6 @@ static CFStringRef runLoopMode(NSDictionary *dictionary) QT_BEGIN_NAMESPACE -Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher"); -Q_LOGGING_CATEGORY(lcEventDispatcherTimers, "qt.eventdispatcher.timers"); - class RunLoopDebugger : public QObject { Q_OBJECT diff --git a/src/corelib/kernel/qeventdispatcher_cf_p.h b/src/corelib/kernel/qeventdispatcher_cf_p.h index 26191d520c..a2cecd9a93 100644 --- a/src/corelib/kernel/qeventdispatcher_cf_p.h +++ b/src/corelib/kernel/qeventdispatcher_cf_p.h @@ -98,8 +98,10 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(RunLoopModeTracker)); QT_BEGIN_NAMESPACE -Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcher); -Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcherTimers) +namespace QtPrivate { +Q_CORE_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcher); +Q_CORE_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcherTimers) +} class QEventDispatcherCoreFoundation; diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm index 776343c5aa..c5856051de 100644 --- a/src/plugins/platforms/ios/qioseventdispatcher.mm +++ b/src/plugins/platforms/ios/qioseventdispatcher.mm @@ -211,6 +211,8 @@ namespace } logActivity; } +using namespace QT_PREPEND_NAMESPACE(QtPrivate); + extern "C" int qt_main_wrapper(int argc, char *argv[]) { @autoreleasepool { From 74abe983204dab35dcce59001308c54d34ad2c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 27 Sep 2019 15:38:48 +0200 Subject: [PATCH 13/16] qmake: Place prl files under Resources in framework bundles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The root of the framework bundle shouldn't contain random files, and doing so will prevent the bundle from being signable. We still look up prl files in the root, to keep backwards compatibility. Change-Id: Ifd0bc3c6e7924e89eec54d3ef9368dfc95ed402c Reviewed-by: Simon Hausmann Reviewed-by: Tor Arne Vestbø --- qmake/generators/unix/unixmake.cpp | 20 +++++++++++++------- qmake/generators/unix/unixmake2.cpp | 5 +++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index 664c81296c..71bf72100e 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -448,15 +448,21 @@ UnixMakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags) opt.remove(suffixMarker); // Apply suffix by removing marker } for (const QMakeLocalFileName &dir : qAsConst(frameworkdirs)) { + auto processPrlIfFound = [&](QString directory) { + QString suffixedPrl = directory + opt; + if (processPrlFile(suffixedPrl, true)) + return true; + if (hasSuffix) { + QString unsuffixedPrl = directory + frameworkName; + if (processPrlFile(unsuffixedPrl, true)) + return true; + } + return false; + }; QString frameworkDirectory = dir.local() + "/" + frameworkName + + ".framework/"; - QString suffixedPrl = frameworkDirectory + opt; - if (processPrlFile(suffixedPrl, true)) + if (processPrlIfFound(frameworkDirectory + "Resources/") + || processPrlIfFound(frameworkDirectory)) break; - if (hasSuffix) { - QString unsuffixedPrl = frameworkDirectory + frameworkName; - if (processPrlFile(unsuffixedPrl, true)) - break; - } } } else { if (opt.length() == 10) diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index ccb601d4b8..79d19cae8c 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -1230,8 +1230,9 @@ void UnixMakefileGenerator::init2() else ar_cmd.append("$(AR) $(TARGETA) $(OBJECTS)"); if (!project->isEmpty("QMAKE_BUNDLE")) { - project->values("PRL_TARGET").prepend( - project->first("QMAKE_BUNDLE") + Option::dir_sep + project->first("TARGET")); + project->values("PRL_TARGET").prepend(project->first("QMAKE_BUNDLE") + + "/Versions/" + project->first("QMAKE_FRAMEWORK_VERSION") + + "/Resources/" + project->first("TARGET")); ProString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION"); if(!bundle_loc.isEmpty() && !bundle_loc.startsWith("/")) bundle_loc.prepend("/"); From 26d626436b0e57493dc4d5fb3ad84a28a6c8e884 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Tue, 1 Oct 2019 20:17:59 +0200 Subject: [PATCH 14/16] Widgets flowlayout example: Fix crash on startup The flowlayout example crashes on startup because the last change removed a c-style cast which converted -1 to ~0U ... Fixes: QTBUG-78861 Change-Id: I0dbed4472b4f68a92b3f92763d00d28baa186f9a Reviewed-by: Friedemann Kleint --- examples/widgets/graphicsview/flowlayout/flowlayout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/widgets/graphicsview/flowlayout/flowlayout.cpp b/examples/widgets/graphicsview/flowlayout/flowlayout.cpp index 54914b3746..03cf320568 100644 --- a/examples/widgets/graphicsview/flowlayout/flowlayout.cpp +++ b/examples/widgets/graphicsview/flowlayout/flowlayout.cpp @@ -62,7 +62,7 @@ FlowLayout::FlowLayout(QGraphicsLayoutItem *parent) : QGraphicsLayout(parent) void FlowLayout::insertItem(int index, QGraphicsLayoutItem *item) { item->setParentLayoutItem(this); - if (index > m_items.count()) + if (index > m_items.count() || index < 0) index = m_items.count(); m_items.insert(index, item); invalidate(); From dabc33bf9543e552d8627eda4977e82d340e9bcf Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Mon, 30 Sep 2019 22:25:33 +0200 Subject: [PATCH 15/16] QPainter: don't print deprecated warnings for HighQualityAntialiasing Add pragmas to not print warnings about the usage of the deprecated warnings inside QtCore. Change-Id: I2cd9f111cdf13cddff527ab3bac7fa80417d1445 Reviewed-by: Allan Sandfeld Jensen --- src/gui/opengl/qopenglpaintengine.cpp | 3 +++ src/gui/painting/qpaintengine_raster.cpp | 3 +++ src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 3 +++ src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp | 3 +++ 4 files changed, 12 insertions(+) diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index c087326068..47394999c6 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -1474,6 +1474,8 @@ void QOpenGL2PaintEngineEx::renderHintsChanged() #ifndef QT_OPENGL_ES_2 if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGL2PaintEngineEx); +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED if ((state()->renderHints & QPainter::Antialiasing) #if QT_DEPRECATED_SINCE(5, 14) || (state()->renderHints & QPainter::HighQualityAntialiasing) @@ -1482,6 +1484,7 @@ void QOpenGL2PaintEngineEx::renderHintsChanged() d->funcs.glEnable(GL_MULTISAMPLE); else d->funcs.glDisable(GL_MULTISAMPLE); +QT_WARNING_POP } #endif // QT_OPENGL_ES_2 diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 447ecb358a..8c51981120 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -906,8 +906,11 @@ void QRasterPaintEngine::renderHintsChanged() s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing); #if QT_DEPRECATED_SINCE(5, 14) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED if (s->renderHints & QPainter::HighQualityAntialiasing) s->flags.antialiased = true; +QT_WARNING_POP #endif s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform); s->flags.legacy_rounding = !bool(s->renderHints & QPainter::Antialiasing) && bool(s->renderHints & QPainter::Qt4CompatiblePainting); diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index e8ff40304e..2546f6dc13 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1391,6 +1391,8 @@ void QGL2PaintEngineEx::renderHintsChanged() state()->renderHintsChanged = true; #if !defined(QT_OPENGL_ES_2) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED if (!d->ctx->contextHandle()->isOpenGLES()) { if ((state()->renderHints & QPainter::Antialiasing) #if QT_DEPRECATED_SINCE(5, 14) @@ -1401,6 +1403,7 @@ void QGL2PaintEngineEx::renderHintsChanged() else d->glDisable(GL_MULTISAMPLE); } +QT_WARNING_POP #endif d->lastTextureUsed = GLuint(-1); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index d7aba66b2f..03be44e095 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -941,6 +941,8 @@ public: { Q_Q(QWindowsDirect2DPaintEngine); +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED // Default path (no optimization) if (!(path.shape() == QVectorPath::LinesHint || path.shape() == QVectorPath::PolygonHint) || !pen.dashBrush @@ -948,6 +950,7 @@ public: || q->state()->renderHints.testFlag(QPainter::HighQualityAntialiasing) #endif || q->state()->renderHints.testFlag(QPainter::Antialiasing)) { +QT_WARNING_POP ComPtr geometry = vectorPathToID2D1PathGeometry(path); if (!geometry) { qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__); From a978d21dac57697ae9557b99062bc804b005b9d4 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Sun, 29 Sep 2019 21:28:52 +0200 Subject: [PATCH 16/16] PSQL: don't recreate QSqlField in loop in QPSQLResult::record() Move out the QSqlField variable out of the loop to avoid useless (de)allocations of QSqlField. Change-Id: I2c9e4c84f75e994d5eb1438839d502f6da531841 Reviewed-by: Robert Szefner Reviewed-by: Andy Shaw --- src/plugins/sqldrivers/psql/qsql_psql.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index 28be7bdc38..3803f05b9f 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -812,8 +812,8 @@ QSqlRecord QPSQLResult::record() const return info; int count = PQnfields(d->result); + QSqlField f; for (int i = 0; i < count; ++i) { - QSqlField f; if (d->drv_d_func()->isUtf8) f.setName(QString::fromUtf8(PQfname(d->result, i))); else @@ -833,6 +833,8 @@ QSqlRecord QPSQLResult::record() const } } f.setTableName(tableName); + } else { + f.setTableName(QString()); } int ptype = PQftype(d->result, i); f.setType(qDecodePSQLType(ptype));