From 6324873543afd7b76d476bd43e3b85e84ea70c00 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Tue, 25 Feb 2020 16:20:42 +0100 Subject: [PATCH 01/41] Stabilize task255529_transformationAnchorMouseAndViewportMargins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test doesn't test whether window activation works, so there is no reason to fail the test if it doesn't. Instead, abort the test, so that we can record it as a skipped test. Change-Id: Ia44308ef17f110d40c6455d7ee85d90914face4f Fixes: QTBUG-22455 Reviewed-by: Jan Arve Sæther Reviewed-by: Levon Sargsyan --- .../widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp index e21b1b889ac..f02835aa90c 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp @@ -4553,7 +4553,9 @@ void tst_QGraphicsView::task255529_transformationAnchorMouseAndViewportMargins() view.show(); qApp->setActiveWindow(&view); QVERIFY(QTest::qWaitForWindowExposed(&view)); - QVERIFY(QTest::qWaitForWindowActive(&view)); + const bool isActiveWindow = QTest::qWaitForWindowActive(&view); + if (!isActiveWindow) + QSKIP("Window activation failed, skipping test", Abort); // This is highly unstable (observed to pass on Windows and some Linux configurations). #ifndef Q_OS_MAC for (int i = 0; i < 4; ++i) { From 529cfe4e22cc02dc7c29f653e8ff23656aa16ff9 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Fri, 21 Feb 2020 09:10:28 +0100 Subject: [PATCH 02/41] qwindowswindow: Fix screen changes between different DPI screens for native windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When asynchronous events are used for notifications about screen changes it is possible that we run into a race condition where the scale factor has not yet been updated for the new screen. This results in a wrong geometry being set for the window that is moved between the screens. We do not have that problem with synchronous events. Change-Id: I4eb6d2a7cb49517d271901b479f973e273a0926a Amends: 7eed1e40d4d3b6a066bac52995eed7e75d17de2d Task-number: QTBUG-65580 Fixes: QTBUG-82312 Reviewed-by: Friedemann Kleint Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/windows/qwindowswindow.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 496b18ba1ae..a11da598fc2 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1943,10 +1943,8 @@ void QWindowsWindow::checkForScreenChanged(ScreenChangeMode mode) qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__ << ' ' << window() << " \"" << (currentScreen ? currentScreen->name() : QString()) << "\"->\"" << newScreen->name() << '"'; - if (mode == FromGeometryChange) - setFlag(SynchronousGeometryChangeEvent); updateFullFrameMargins(); - QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); } void QWindowsWindow::handleGeometryChange() From 715468df40e4ce97da04f327b6e34d535ff9b97d Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Thu, 27 Feb 2020 09:53:49 +0100 Subject: [PATCH 03/41] Fix flaky QElapsedTimer::elapsed test case Much of this test case was testing that the machine it runs on didn't take more than an expected amount of time, which is an assumption that won't hold in a virtual environment where the hypervisor might decide to not allocate any CPU time to the machine at certain times. Instead, take the samples that we want to compare with once, then use them as reference for further comparisons. Also, split the test in two, with the comparison operators and msecsTo test moved into a separate test function. Change-Id: I7db12b8e02552f4d63af933c1b0fee9d62b591eb Fixes: QTBUG-58713 Reviewed-by: Lars Knoll --- .../qelapsedtimer/tst_qelapsedtimer.cpp | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp b/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp index 4ee3ca361f3..bfc4f2ca361 100644 --- a/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp +++ b/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp @@ -48,6 +48,7 @@ private Q_SLOTS: void validity(); void basics(); void elapsed(); + void msecsTo(); }; void tst_QElapsedTimer::statics() @@ -108,30 +109,42 @@ void tst_QElapsedTimer::elapsed() t1.start(); QTest::qSleep(2*minResolution); + + auto nsecs = t1.nsecsElapsed(); + auto msecs = t1.elapsed(); + QVERIFY(nsecs > 0); + QVERIFY(msecs > 0); + // the number of elapsed nanoseconds and milliseconds should match + QVERIFY(nsecs - msecs * 1000000 < 1000000); + + if (msecs > 8 * minResolution) + QSKIP("Sampling timer took too long, aborting test"); + + QVERIFY(t1.hasExpired(minResolution)); + QVERIFY(!t1.hasExpired(8*minResolution)); + QVERIFY(!t1.hasExpired(-1)); + + qint64 elapsed = t1.restart(); + QVERIFY(elapsed >= msecs); + QVERIFY(elapsed < msecs + 3*minResolution); +} + +void tst_QElapsedTimer::msecsTo() +{ + QElapsedTimer t1; + t1.start(); + QTest::qSleep(minResolution); QElapsedTimer t2; t2.start(); QVERIFY(t1 != t2); QVERIFY(!(t1 == t2)); QVERIFY(t1 < t2); - QVERIFY(t1.msecsTo(t2) > 0); - QVERIFY(t1.nsecsElapsed() > 0); - QVERIFY(t1.elapsed() > 0); - // the number of elapsed nanoseconds and milliseconds should match - QVERIFY(t1.nsecsElapsed() - t1.elapsed() * 1000000 < 1000000); - QVERIFY(t1.hasExpired(minResolution)); - QVERIFY(!t1.hasExpired(8*minResolution)); - QVERIFY(!t2.hasExpired(minResolution)); - - QVERIFY(!t1.hasExpired(-1)); - QVERIFY(!t2.hasExpired(-1)); - - qint64 elapsed = t1.restart(); - QVERIFY(elapsed > minResolution); - QVERIFY(elapsed < 3*minResolution); - qint64 diff = t2.msecsTo(t1); - QVERIFY(diff < minResolution); + auto diff = t1.msecsTo(t2); + QVERIFY2(diff > 0, QString("difference t1 and t2 is %1").arg(diff).toLatin1()); + diff = t2.msecsTo(t1); + QVERIFY2(diff < 0, QString("difference t2 and t1 is %1").arg(diff).toLatin1()); } QTEST_MAIN(tst_QElapsedTimer); From de1d51a3fd69a4961816ecfc3982424d5379a00f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=C3=A1n=20Maureira-Fredes?= Date: Tue, 25 Feb 2020 15:59:09 +0100 Subject: [PATCH 04/41] uic: handle header tag for python imports Fixes: PYSIDE-1233 Change-Id: Id2b6e2a8b833da6ea4417d06643b2f7b045515a9 Reviewed-by: Friedemann Kleint --- src/tools/uic/python/pythonwriteimports.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/uic/python/pythonwriteimports.cpp b/src/tools/uic/python/pythonwriteimports.cpp index d33b4c62105..95e039e6f08 100644 --- a/src/tools/uic/python/pythonwriteimports.cpp +++ b/src/tools/uic/python/pythonwriteimports.cpp @@ -131,6 +131,8 @@ void WriteImports::acceptCustomWidget(DomCustomWidget *node) output << "import " << className << '\n'; } else { // When we do have elementHeader, we know it's a relative import. QString modulePath = node->elementHeader()->text(); + // Replace the '/' by '.' + modulePath.replace(QLatin1Char('/'), QLatin1Char('.')); // '.h' is added by default on headers for if (modulePath.endsWith(QLatin1String(".h"))) modulePath.chop(2); From 09c5dfb73271614eb55c6d6c610c873fc9146a2f Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 26 Feb 2020 13:00:42 +0100 Subject: [PATCH 05/41] Windows: Enable closing the system tray menu when clicking outside of it In order for the system to close a menu when clicking outside of it or outside of the controlling window for the system tray then it needs to be at the foreground right before the menu is tracked. This makes it act like other system tray menus then. Change-Id: I663670c506cfd1e2ba59cd3e75b12e1f8ba17c33 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowssystemtrayicon.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index ab830e1461e..9409d2db4d7 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp @@ -424,8 +424,12 @@ bool QWindowsSystemTrayIcon::winEvent(const MSG &message, long *result) if (screen) { emit contextMenuRequested(globalPos, screen); emit activated(Context); - if (m_menu) + if (m_menu) { + // Set the foreground window to the controlling window so that clicking outside + // of the menu or window will cause the menu to close + SetForegroundWindow(m_hwnd); m_menu->trackPopupMenu(message.hwnd, globalPos.x(), globalPos.y()); + } } } break; From eaf7f572bfbcb33b106097923f4e0efdd9c683fc Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 20 Jan 2020 13:30:39 +0100 Subject: [PATCH 06/41] Android: Don't recurse into directories inside the assets when iterating When iterating, it should only return what is in the specified path and not the contents of the sub-directories inside the given path in addition. Change-Id: Iad56f075c22fdf1c633582e37444e26520c24a73 Reviewed-by: BogDan Vatra --- .../qandroidassetsfileenginehandler.cpp | 25 ++++--------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp index ca16efe34f7..07776a4a766 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp @@ -202,9 +202,7 @@ public: const QString &path) : QAbstractFileEngineIterator(filters, nameFilters) { - m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(path), true)); - if (m_stack.last()->empty()) - m_stack.pop_back(); + m_currentIterator = FolderIterator::fromCache(cleanedAssetPath(path), true); } QFileInfo currentFileInfo() const override @@ -228,36 +226,23 @@ public: bool hasNext() const override { - if (m_stack.empty()) + if (!m_currentIterator) return false; - if (!m_stack.last()->hasNext()) { - m_stack.pop_back(); - return hasNext(); - } - return true; + return m_currentIterator->hasNext(); } QString next() override { - if (m_stack.empty()) { - m_currentIterator.reset(); + if (!m_currentIterator) 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()), true)); - if (m_stack.last()->empty()) - m_stack.pop_back(); - } return res->first; } private: - mutable QSharedPointer m_currentIterator; - mutable QVector> m_stack; + QSharedPointer m_currentIterator; }; class AndroidAbstractFileEngine: public QAbstractFileEngine From 7447e2b337f12b4d04935d0f30fc673e4327d5a0 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 24 Feb 2020 16:23:27 +0100 Subject: [PATCH 07/41] QTextMarkdownImporter: fix use after free; add fuzz-generated tests It was possible to end up with a dangling pointer in m_listStack. This is now avoided by using QPointer and doing nullptr checks before accessing any QTextList pointer stored there. We have 2 specimens of garbage that caused crashes before; now they don't. But only fuzz20450 triggered the dangling pointer in the list stack. The crash caused by fuzz20580 was fixed by updating md4c from upstream: 4b0fc030777cd541604f5ebaaad47a2b76d61ff9 Change-Id: I8e1eca23b281256a03aea0f55e9ae20f1bdd2a38 Reviewed-by: Robert Loehning --- src/gui/text/qtextmarkdownimporter.cpp | 7 ++++-- src/gui/text/qtextmarkdownimporter_p.h | 2 +- .../qtextmarkdownimporter/data/fuzz20450.md | 5 ++++ .../qtextmarkdownimporter/data/fuzz20580.md | 1 + .../qtextmarkdownimporter.pro | 2 ++ .../tst_qtextmarkdownimporter.cpp | 24 +++++++++++++++++++ 6 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20450.md create mode 100644 tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20580.md diff --git a/src/gui/text/qtextmarkdownimporter.cpp b/src/gui/text/qtextmarkdownimporter.cpp index 7e18a108955..5e75e7816b5 100644 --- a/src/gui/text/qtextmarkdownimporter.cpp +++ b/src/gui/text/qtextmarkdownimporter.cpp @@ -577,7 +577,10 @@ void QTextMarkdownImporter::insertBlock() QTextBlockFormat blockFormat; if (!m_listStack.isEmpty() && !m_needsInsertList && m_listItem) { QTextList *list = m_listStack.top(); - blockFormat = list->item(list->count() - 1).blockFormat(); + if (list) + blockFormat = list->item(list->count() - 1).blockFormat(); + else + qWarning() << "attempted to insert into a list that no longer exists"; } if (m_blockQuoteDepth) { blockFormat.setProperty(QTextFormat::BlockQuoteLevel, m_blockQuoteDepth); @@ -607,7 +610,7 @@ void QTextMarkdownImporter::insertBlock() } if (m_needsInsertList) { m_listStack.push(m_cursor->createList(m_listFormat)); - } else if (!m_listStack.isEmpty() && m_listItem) { + } else if (!m_listStack.isEmpty() && m_listItem && m_listStack.top()) { m_listStack.top()->add(m_cursor->block()); } m_needsInsertList = false; diff --git a/src/gui/text/qtextmarkdownimporter_p.h b/src/gui/text/qtextmarkdownimporter_p.h index f450da5eb35..e3b4bcd0f2b 100644 --- a/src/gui/text/qtextmarkdownimporter_p.h +++ b/src/gui/text/qtextmarkdownimporter_p.h @@ -113,7 +113,7 @@ private: #endif QString m_blockCodeLanguage; QVector m_nonEmptyTableCells; // in the current row - QStack m_listStack; + QStack> m_listStack; QStack m_spanFormatStack; QFont m_monoFont; QPalette m_palette; diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20450.md b/tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20450.md new file mode 100644 index 00000000000..d7005cb01eb --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20450.md @@ -0,0 +1,5 @@ +ÿ +* ÿ + + ÿ +* ÿ \ No newline at end of file diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20580.md b/tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20580.md new file mode 100644 index 00000000000..22006f58768 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20580.md @@ -0,0 +1 @@ +| --:| ("warning"); + QTest::newRow("fuzz20450") << "attempted to insert into a list that no longer exists"; + QTest::newRow("fuzz20580") << ""; +} + +void tst_QTextMarkdownImporter::pathological() // avoid crashing on crazy input +{ + QFETCH(QString, warning); + QString filename = QLatin1String("data/") + QTest::currentDataTag() + QLatin1String(".md"); + QFile f(QFINDTESTDATA(filename)); + QVERIFY(f.open(QFile::ReadOnly)); +#ifdef QT_NO_DEBUG + Q_UNUSED(warning) +#else + if (!warning.isEmpty()) + QTest::ignoreMessage(QtWarningMsg, warning.toLatin1()); +#endif + QTextDocument().setMarkdown(f.readAll()); +} + QTEST_MAIN(tst_QTextMarkdownImporter) #include "tst_qtextmarkdownimporter.moc" From 08d5059320334223ff1f9009342324f25c231f0b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 14 Oct 2019 14:54:44 +0200 Subject: [PATCH 08/41] Fix geometry handling for native child windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't move the native child window position for native child windows. Initial-patch-by: BÅ‚ażej SzczygieÅ‚ Task-number: QTBUG-82312 Fixes: QTBUG-79166 Change-Id: I117ef08da13c8e90ff60cf034126c9efdc17b836 Reviewed-by: BÅ‚ażej SzczygieÅ‚ Reviewed-by: Morten Johan Sørvig Reviewed-by: Oliver Wolff --- src/gui/kernel/qwindow.cpp | 10 +++++++--- src/gui/kernel/qwindowsysteminterface.cpp | 13 ++++++++++--- .../platforms/windows/qwindowsintegration.cpp | 4 +++- src/plugins/platforms/xcb/qxcbwindow.cpp | 4 +++- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 0a4277c118f..9cb851a7a20 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -1666,7 +1666,7 @@ void QWindow::setGeometry(const QRect &rect) if (newScreen && isTopLevel()) nativeRect = QHighDpi::toNativePixels(rect, newScreen); else - nativeRect = QHighDpi::toNativePixels(rect, this); + nativeRect = QHighDpi::toNativeLocalPosition(rect, newScreen); d->platformWindow->setGeometry(nativeRect); } else { d->geometry = rect; @@ -1717,8 +1717,12 @@ QScreen *QWindowPrivate::screenForGeometry(const QRect &newGeometry) const QRect QWindow::geometry() const { Q_D(const QWindow); - if (d->platformWindow) - return QHighDpi::fromNativePixels(d->platformWindow->geometry(), this); + if (d->platformWindow) { + const auto nativeGeometry = d->platformWindow->geometry(); + return isTopLevel() + ? QHighDpi::fromNativePixels(nativeGeometry, this) + : QHighDpi::fromNativeLocalPosition(nativeGeometry, this); + } return d->geometry; } diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 8457282bed1..8f2927901a2 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -296,14 +296,21 @@ QWindowSystemInterfacePrivate::GeometryChangeEvent::GeometryChangeEvent(QWindow , window(window) , newGeometry(newGeometry) { - if (const QPlatformWindow *pw = window->handle()) - requestedGeometry = QHighDpi::fromNativePixels(pw->QPlatformWindow::geometry(), window); + if (const QPlatformWindow *pw = window->handle()) { + const auto nativeGeometry = pw->QPlatformWindow::geometry(); + requestedGeometry = window->isTopLevel() + ? QHighDpi::fromNativePixels(nativeGeometry, window) + : QHighDpi::fromNativeLocalPosition(nativeGeometry, window); + } } QT_DEFINE_QPA_EVENT_HANDLER(void, handleGeometryChange, QWindow *window, const QRect &newRect) { Q_ASSERT(window); - QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(window, QHighDpi::fromNativePixels(newRect, window)); + const auto newRectDi = window->isTopLevel() + ? QHighDpi::fromNativePixels(newRect, window) + : QHighDpi::fromNativeLocalPosition(newRect, window); + auto e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(window, newRectDi); if (window->handle()) { // Persist the new geometry so that QWindow::geometry() can be queried in the resize event window->handle()->QPlatformWindow::setGeometry(newRect); diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 09117f663d9..d37b405db8d 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -334,7 +334,9 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons QWindowsWindowData requested; requested.flags = window->flags(); - requested.geometry = QHighDpi::toNativePixels(window->geometry(), window); + requested.geometry = window->isTopLevel() + ? QHighDpi::toNativePixels(window->geometry(), window) + : QHighDpi::toNativeLocalPosition(window->geometry(), window); // Apply custom margins (see QWindowsWindow::setCustomMargins())). const QVariant customMarginsV = window->property("_q_windowsCustomMargins"); if (customMarginsV.isValid()) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index cfe048d5c4d..c9d1cfe50ae 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -276,7 +276,9 @@ void QXcbWindow::create() QXcbScreen *currentScreen = xcbScreen(); QXcbScreen *platformScreen = parent() ? parentScreen() : initialScreen(); - QRect rect = QHighDpi::toNativePixels(window()->geometry(), platformScreen); + QRect rect = parent() + ? QHighDpi::toNativeLocalPosition(window()->geometry(), platformScreen) + : QHighDpi::toNativePixels(window()->geometry(), platformScreen); if (type == Qt::Desktop) { m_window = platformScreen->root(); From 4a1de178c9cc891560f38d64d89074799b0fa0e1 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Fri, 28 Feb 2020 12:33:35 +0100 Subject: [PATCH 09/41] Try again to make QDeadlineTimer test robust against context switches Instead of comparing to absolute values, compare the result from QDeadlineTimer with the reference clock types from std::chrono. Pass the test as long as we are within 10% of that reference. In addition, handle the case where QTest::qSleep sleeps for more than 10% longer or shorter than what is requested, and if so, abort the test. Change-Id: If8b77aea55a8c5c53e96427b2fff2f78281d0f82 Reviewed-by: Lars Knoll --- .../qdeadlinetimer/tst_qdeadlinetimer.cpp | 50 +++++++++++++------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp b/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp index 35c5e7cb751..db53c3f20ce 100644 --- a/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp +++ b/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp @@ -573,12 +573,32 @@ void tst_QDeadlineTimer::stdchrono() QCOMPARE(deadline.remainingTimeAsDuration(), nanoseconds::zero()); + /* + Call QTest::qSleep, and return true if the time actually slept is + within \a deviationPercent percent of the requested sleep time. + Otherwise, return false, in which case the test should to abort. + */ + auto sleepHelper = [](int ms, int deviationPercent = 10) -> bool { + auto before = steady_clock::now(); + QTest::qSleep(ms); + auto after = steady_clock::now(); + auto diff = duration_cast(after - before).count(); + bool inRange = qAbs(diff - ms) < ms * deviationPercent/100.0; + if (!inRange) + qWarning() << "sleeping" << diff << "instead of" << ms << inRange; + return inRange; + }; + auto steady_before = steady_clock::now(); auto system_before = system_clock::now(); - QTest::qSleep(minResolution); + if (!sleepHelper(minResolution)) + QSKIP("Slept too long"); auto now = QDeadlineTimer::current(timerType); - QTest::qSleep(minResolution); + auto steady_reference = steady_clock::now(); + auto system_reference = system_clock::now(); + if (!sleepHelper(minResolution)) + QSKIP("Slept too long"); auto sampling_start = steady_clock::now(); auto steady_deadline = now.deadline(); @@ -599,35 +619,33 @@ void tst_QDeadlineTimer::stdchrono() } { - auto diff = duration_cast(steady_after - steady_deadline); - QVERIFY2(diff.count() > minResolution/2, QByteArray::number(qint64(diff.count()))); - QVERIFY2(diff.count() < 3*minResolution/2, QByteArray::number(qint64(diff.count()))); + auto reference = duration_cast(steady_after - steady_reference).count(); + auto diff = duration_cast(steady_after - steady_deadline).count(); + QVERIFY2(diff > reference * 0.9 && diff < reference*1.1, QByteArray::number(qint64(diff))); QDeadlineTimer dt_after(steady_after, timerType); QVERIFY2(now < dt_after, ("now = " + QLocale().toString(now.deadlineNSecs()) + "; after = " + QLocale().toString(dt_after.deadlineNSecs())).toLatin1()); - diff = duration_cast(steady_deadline - steady_before); - QVERIFY2(diff.count() > minResolution/2, QByteArray::number(qint64(diff.count()))); - QVERIFY2(diff.count() < 3*minResolution/2, QByteArray::number(qint64(diff.count()))); + reference = duration_cast(steady_reference - steady_before).count(); + diff = duration_cast(steady_deadline - steady_before).count(); + QVERIFY2(diff > reference * 0.9 && diff < reference*1.1, QByteArray::number(qint64(diff))); QDeadlineTimer dt_before(steady_before, timerType); QVERIFY2(now > dt_before, ("now = " + QLocale().toString(now.deadlineNSecs()) + "; before = " + QLocale().toString(dt_before.deadlineNSecs())).toLatin1()); } { - auto diff = duration_cast(system_after - system_deadline); - QVERIFY2(diff.count() > minResolution/2, QByteArray::number(qint64(diff.count()))); - QVERIFY2(diff.count() < 3*minResolution/2, QByteArray::number(qint64(diff.count()))); - QDeadlineTimer dt_after(system_after, timerType); + auto reference = duration_cast(system_after - system_reference).count(); + auto diff = duration_cast(system_after - system_deadline).count(); + QVERIFY2(diff > reference * 0.9 && diff < reference*1.1, QByteArray::number(qint64(diff))); QDeadlineTimer dt_after(system_after, timerType); QVERIFY2(now < dt_after, ("now = " + QLocale().toString(now.deadlineNSecs()) + "; after = " + QLocale().toString(dt_after.deadlineNSecs())).toLatin1()); - diff = duration_cast(system_deadline - system_before); - QVERIFY2(diff.count() > minResolution/2, QByteArray::number(qint64(diff.count()))); - QVERIFY2(diff.count() < 3*minResolution/2, QByteArray::number(qint64(diff.count()))); - QDeadlineTimer dt_before(system_before, timerType); + reference = duration_cast(system_reference - system_before).count(); + diff = duration_cast(steady_deadline - steady_before).count(); + QVERIFY2(diff > reference * 0.9 && diff < reference*1.1, QByteArray::number(qint64(diff))); QDeadlineTimer dt_before(system_before, timerType); QVERIFY2(now > dt_before, ("now = " + QLocale().toString(now.deadlineNSecs()) + "; before = " + QLocale().toString(dt_before.deadlineNSecs())).toLatin1()); From 54413653d5fb12bb08b9cbf1554b732bc0b8d1fb Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 19 Feb 2020 14:08:22 +0100 Subject: [PATCH 10/41] Rename the endonym members of the Locale type All other members had camelCase names, but the endonyms had prefix_endonym names, requiring munging where they were emitted to XML. So just do that munging upstream in the attribute name of the Locale objects. Makes no change to the data output by the scripts, not even to the intermediate QLocaleXML file. Task-number: QTBUG-81344 Change-Id: I01c15a822216281dc669b3e7ebda096d18b04f9b Reviewed-by: Lars Knoll Reviewed-by: Cristian Maureira-Fredes --- util/locale_database/cldr2qlocalexml.py | 4 ++-- util/locale_database/localexml.py | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/util/locale_database/cldr2qlocalexml.py b/util/locale_database/cldr2qlocalexml.py index a1df872e017..6a0b6cbe1a2 100755 --- a/util/locale_database/cldr2qlocalexml.py +++ b/util/locale_database/cldr2qlocalexml.py @@ -340,8 +340,8 @@ def _generateLocaleInfo(path, language_code, script_code, country_code, variant_ endonym = findEntryDef(path, "localeDisplayNames/languages/language[type=%s_%s]" % (language_code, country_code)) if not endonym: endonym = findEntryDef(path, "localeDisplayNames/languages/language[type=%s]" % (language_code)) - result['language_endonym'] = endonym - result['country_endonym'] = findEntryDef(path, "localeDisplayNames/territories/territory[type=%s]" % (country_code)) + result['languageEndonym'] = endonym + result['countryEndonym'] = findEntryDef(path, "localeDisplayNames/territories/territory[type=%s]" % (country_code)) currency_format = get_number_in_system(path, "numbers/currencyFormats/currencyFormatLength/currencyFormat/pattern", numbering_system) currency_format = parse_number_format(currency_format, result) diff --git a/util/locale_database/localexml.py b/util/locale_database/localexml.py index 9b353f51221..187227886f7 100644 --- a/util/locale_database/localexml.py +++ b/util/locale_database/localexml.py @@ -190,7 +190,7 @@ class Locale: ('minus', '-'), ('plus', '+'), ('exp', 'e')): print inner + "<%s>" % key + fixOrdStr(get(key), std) + "" % key - for key in ('language_endonym', 'country_endonym', + for key in ('languageEndonym', 'countryEndonym', 'quotationStart', 'quotationEnd', 'alternateQuotationStart', 'alternateQuotationEnd', 'listPatternPartStart', 'listPatternPartMiddle', @@ -208,8 +208,7 @@ class Locale: '_'.join((k, cal)) for k in self.propsMonthDay('months') for cal in calendars): - ent = camelCase(key.split('_')) if key.endswith('_endonym') else key - print inner + "<%s>%s" % (ent, escape(get(key)).encode('utf-8'), ent) + print inner + "<%s>%s" % (key, escape(get(key)).encode('utf-8'), key) for key in ('currencyDigits', 'currencyRounding'): print inner + "<%s>%d" % (key, get(key), key) @@ -283,9 +282,9 @@ class Locale: quantifiers=('k', 'M', 'G', 'T', 'P', 'E')): """Returns an object representing the C locale.""" return cls(dict(cls.__monthNames(calendars)), - language='C', language_code='0', language_endonym='', + language='C', language_code='0', languageEndonym='', script='AnyScript', script_code='0', - country='AnyCountry', country_code='0', country_endonym='', + country='AnyCountry', country_code='0', countryEndonym='', decimal='.', group=',', list=';', percent='%', zero='0', minus='-', plus='+', exp='e', quotationStart='"', quotationEnd='"', From 84382bde5c90e68f7c0e9c70c747fce0867fc128 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 19 Feb 2020 14:13:27 +0100 Subject: [PATCH 11/41] Rename the localexml module to qlocalexml It implements interaction with the QLocaleXML file format type, so rename it to match. Task-number: QTBUG-81344 Change-Id: I46302d4ac1038cdfc5929e73b554b6d793814c56 Reviewed-by: Lars Knoll --- util/locale_database/cldr2qlocalexml.py | 2 +- util/locale_database/{localexml.py => qlocalexml.py} | 0 util/locale_database/qlocalexml2cpp.py | 6 +++--- 3 files changed, 4 insertions(+), 4 deletions(-) rename util/locale_database/{localexml.py => qlocalexml.py} (100%) diff --git a/util/locale_database/cldr2qlocalexml.py b/util/locale_database/cldr2qlocalexml.py index 6a0b6cbe1a2..ee53381b224 100755 --- a/util/locale_database/cldr2qlocalexml.py +++ b/util/locale_database/cldr2qlocalexml.py @@ -61,7 +61,7 @@ import enumdata import xpathlite from xpathlite import DraftResolution, findAlias, findEntry, findTagsInFile from dateconverter import convert_date -from localexml import Locale +from qlocalexml import Locale # TODO: make calendars a command-line option calendars = ['gregorian', 'persian', 'islamic'] # 'hebrew' diff --git a/util/locale_database/localexml.py b/util/locale_database/qlocalexml.py similarity index 100% rename from util/locale_database/localexml.py rename to util/locale_database/qlocalexml.py diff --git a/util/locale_database/qlocalexml2cpp.py b/util/locale_database/qlocalexml2cpp.py index 52e6331569f..7c00980bc47 100755 --- a/util/locale_database/qlocalexml2cpp.py +++ b/util/locale_database/qlocalexml2cpp.py @@ -40,7 +40,7 @@ import datetime import xml.dom.minidom from enumdata import language_aliases, country_aliases, script_aliases -from localexml import Locale +from qlocalexml import Locale # TODO: Make calendars a command-line parameter # map { CLDR name: Qt file name } @@ -353,7 +353,7 @@ def main(): if len(sys.argv) != 3: usage() - localexml = sys.argv[1] + qlocalexml = sys.argv[1] qtsrcdir = sys.argv[2] if not (os.path.isdir(qtsrcdir) @@ -370,7 +370,7 @@ def main(): s = qlocaledata_file.readline() data_temp_file.write(GENERATED_BLOCK_START) - doc = xml.dom.minidom.parse(localexml) + doc = xml.dom.minidom.parse(qlocalexml) language_map = loadMap(doc, 'language') script_map = loadMap(doc, 'script') country_map = loadMap(doc, 'country') From 275401f580abe19c1519e3d05acec20c68fd9fa6 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 27 Feb 2020 18:19:59 +0100 Subject: [PATCH 12/41] Warn about Q(Date|Time)+ switching to C locale in Qt 6 Change-Id: I3a3afc3fb4ddca405a75097feb15aee0e72b3b19 Reviewed-by: Thiago Macieira --- src/corelib/time/qdatetime.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index b3a12a4a46b..fe3ebca6eb7 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -1285,6 +1285,10 @@ QT_WARNING_POP If the datetime is invalid, an empty string will be returned. + \note If localized month and day names are desired, please switch to using + QLocale::system().toString() as QDate methods shall change to use English (C + locale) names at Qt 6. + \sa fromString(), QDateTime::toString(), QTime::toString(), QLocale::toString() */ @@ -1786,6 +1790,10 @@ QT_WARNING_POP \snippet code/src_corelib_tools_qdatetime.cpp 3 + \note If localized month and day names are used, please switch to using + QLocale::system().toDate() as QDate methods shall change to only recognize + English (C locale) names at Qt 6. + \sa toString(), QDateTime::fromString(), QTime::fromString(), QLocale::toDate() */ @@ -2146,6 +2154,10 @@ QT_WARNING_POP If the time is invalid, an empty string will be returned. If \a format is empty, the default format "hh:mm:ss" is used. + \note If localized forms of am or pm (the AP, ap, A or a formats) are + desired, please switch to using QLocale::system().toString() as QTime + methods shall change to use English (C locale) at Qt 6. + \sa fromString(), QDate::toString(), QDateTime::toString(), QLocale::toString() */ QString QTime::toString(QStringView format) const @@ -2543,6 +2555,10 @@ QT_WARNING_POP \snippet code/src_corelib_tools_qdatetime.cpp 8 + \note If localized forms of am or pm (the AP, ap, A or a formats) are used, + please switch to using QLocale::system().toTime() as QTime methods shall + change to only recognize English (C locale) at Qt 6. + \sa toString(), QDateTime::fromString(), QDate::fromString(), QLocale::toTime() */ @@ -4465,6 +4481,10 @@ QT_WARNING_POP If the datetime is invalid, an empty string will be returned. + \note If localized month and day names are desired, please switch to using + QLocale::system().toString() as QDateTime methods shall change to use + English (C locale) names at Qt 6. + \sa fromString(), QDate::toString(), QTime::toString(), QLocale::toString() */ QString QDateTime::toString(QStringView format) const @@ -5504,6 +5524,10 @@ QT_WARNING_POP \snippet code/src_corelib_tools_qdatetime.cpp 14 + \note If localized month and day names are used, please switch to using + QLocale::system().toDateTime() as QDateTime methods shall change to only + recognize English (C locale) names at Qt 6. + \sa toString(), QDate::fromString(), QTime::fromString(), QLocale::toDateTime() */ From 873eba3f8bdd1151762fae2dfcee733ebdd7c0be Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Mon, 24 Feb 2020 09:50:51 +0200 Subject: [PATCH 13/41] Examples: use QDialog::showMaximaized() for Android Examples that use QDialog as main window should be maximized on Android to avoid a black view on most of the screen. Task-number: QTBUG-80717 Change-Id: I933c1a01d95d53da009c190c37fa32f27be5af5e Reviewed-by: BogDan Vatra --- examples/network/http/main.cpp | 6 +++++- examples/widgets/layouts/basiclayouts/main.cpp | 4 ++++ examples/widgets/layouts/dynamiclayouts/main.cpp | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/network/http/main.cpp b/examples/network/http/main.cpp index 1339f2f6934..6c86933fd64 100644 --- a/examples/network/http/main.cpp +++ b/examples/network/http/main.cpp @@ -81,7 +81,11 @@ int main(int argc, char *argv[]) const QRect availableSize = httpWin.screen()->availableGeometry(); httpWin.resize(availableSize.width() / 5, availableSize.height() / 5); httpWin.move((availableSize.width() - httpWin.width()) / 2, (availableSize.height() - httpWin.height()) / 2); - +#ifdef Q_OS_ANDROID + httpWin.showMaximized(); +#else httpWin.show(); +#endif + return app.exec(); } diff --git a/examples/widgets/layouts/basiclayouts/main.cpp b/examples/widgets/layouts/basiclayouts/main.cpp index f59de1d3850..cf0ff0a535b 100644 --- a/examples/widgets/layouts/basiclayouts/main.cpp +++ b/examples/widgets/layouts/basiclayouts/main.cpp @@ -56,7 +56,11 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); Dialog dialog; +#ifdef Q_OS_ANDROID + dialog.showMaximized(); +#else dialog.show(); +#endif return app.exec(); } diff --git a/examples/widgets/layouts/dynamiclayouts/main.cpp b/examples/widgets/layouts/dynamiclayouts/main.cpp index 9959c472f4b..cf0ff0a535b 100644 --- a/examples/widgets/layouts/dynamiclayouts/main.cpp +++ b/examples/widgets/layouts/dynamiclayouts/main.cpp @@ -56,6 +56,11 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); Dialog dialog; +#ifdef Q_OS_ANDROID + dialog.showMaximized(); +#else dialog.show(); +#endif + return app.exec(); } From 761f46f8b526147b29a324b65d253077f35867a9 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 2 Mar 2020 14:45:39 +0100 Subject: [PATCH 14/41] Remove overrides of QImageIOHandler::name() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will remove the virtual base class function in Qt 6. For now, name() returns format(). Change-Id: I1597e823b859e4db148b3e5ac0f1c15350a582eb Reviewed-by: Eirik Aavitsland Reviewed-by: Jan Arve Sæther --- src/gui/image/qbmphandler.cpp | 7 ------- src/gui/image/qbmphandler_p.h | 3 --- src/gui/image/qpnghandler.cpp | 7 ------- src/gui/image/qpnghandler_p.h | 4 ---- src/gui/image/qppmhandler.cpp | 7 ------- src/gui/image/qppmhandler_p.h | 4 ---- src/gui/image/qxbmhandler.cpp | 7 ------- src/gui/image/qxbmhandler_p.h | 4 ---- src/gui/image/qxpmhandler.cpp | 7 ------- src/gui/image/qxpmhandler_p.h | 4 ---- src/plugins/imageformats/gif/qgifhandler.cpp | 7 ------- src/plugins/imageformats/gif/qgifhandler_p.h | 4 ---- src/plugins/imageformats/ico/qicohandler.cpp | 11 ----------- src/plugins/imageformats/ico/qicohandler.h | 4 ---- src/plugins/imageformats/jpeg/qjpeghandler.cpp | 7 ------- src/plugins/imageformats/jpeg/qjpeghandler_p.h | 4 ---- 16 files changed, 91 deletions(-) diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index 32b6131309c..387c7b77460 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -866,13 +866,6 @@ void QBmpHandler::setOption(ImageOption option, const QVariant &value) Q_UNUSED(value); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QBmpHandler::name() const -{ - return formatName(); -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_BMP diff --git a/src/gui/image/qbmphandler_p.h b/src/gui/image/qbmphandler_p.h index 33b5b9c5017..fd044fc4420 100644 --- a/src/gui/image/qbmphandler_p.h +++ b/src/gui/image/qbmphandler_p.h @@ -113,9 +113,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif static bool canRead(QIODevice *device); QVariant option(ImageOption option) const override; diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 8435e5a0fe8..f956f254eeb 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -1296,13 +1296,6 @@ void QPngHandler::setOption(ImageOption option, const QVariant &value) d->scaledSize = value.toSize(); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QPngHandler::name() const -{ - return "png"; -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_PNG diff --git a/src/gui/image/qpnghandler_p.h b/src/gui/image/qpnghandler_p.h index 5d4da97395f..9e12d2d0811 100644 --- a/src/gui/image/qpnghandler_p.h +++ b/src/gui/image/qpnghandler_p.h @@ -69,10 +69,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - QVariant option(ImageOption option) const override; void setOption(ImageOption option, const QVariant &value) override; bool supportsOption(ImageOption option) const override; diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp index 13ee2eadd2b..728259ba9e1 100644 --- a/src/gui/image/qppmhandler.cpp +++ b/src/gui/image/qppmhandler.cpp @@ -576,13 +576,6 @@ void QPpmHandler::setOption(ImageOption option, const QVariant &value) subType = value.toByteArray().toLower(); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QPpmHandler::name() const -{ - return subType.isEmpty() ? QByteArray("ppm") : subType; -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_PPM diff --git a/src/gui/image/qppmhandler_p.h b/src/gui/image/qppmhandler_p.h index 2f3811b7592..f2faf93984c 100644 --- a/src/gui/image/qppmhandler_p.h +++ b/src/gui/image/qppmhandler_p.h @@ -67,10 +67,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - static bool canRead(QIODevice *device, QByteArray *subType = nullptr); QVariant option(ImageOption option) const override; diff --git a/src/gui/image/qxbmhandler.cpp b/src/gui/image/qxbmhandler.cpp index 3cd15b3e4d4..f06561690c5 100644 --- a/src/gui/image/qxbmhandler.cpp +++ b/src/gui/image/qxbmhandler.cpp @@ -357,13 +357,6 @@ void QXbmHandler::setOption(ImageOption option, const QVariant &value) fileName = value.toString(); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QXbmHandler::name() const -{ - return "xbm"; -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_XBM diff --git a/src/gui/image/qxbmhandler_p.h b/src/gui/image/qxbmhandler_p.h index ae590a19443..db5f352d469 100644 --- a/src/gui/image/qxbmhandler_p.h +++ b/src/gui/image/qxbmhandler_p.h @@ -66,10 +66,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - static bool canRead(QIODevice *device); QVariant option(ImageOption option) const override; diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp index f9424b62bba..07fec929bf8 100644 --- a/src/gui/image/qxpmhandler.cpp +++ b/src/gui/image/qxpmhandler.cpp @@ -1280,13 +1280,6 @@ void QXpmHandler::setOption(ImageOption option, const QVariant &value) fileName = value.toString(); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QXpmHandler::name() const -{ - return "xpm"; -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_XPM diff --git a/src/gui/image/qxpmhandler_p.h b/src/gui/image/qxpmhandler_p.h index a4dd88cd17a..646e8df69ee 100644 --- a/src/gui/image/qxpmhandler_p.h +++ b/src/gui/image/qxpmhandler_p.h @@ -68,10 +68,6 @@ public: static bool canRead(QIODevice *device); -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - QVariant option(ImageOption option) const override; void setOption(ImageOption option, const QVariant &value) override; bool supportsOption(ImageOption option) const override; diff --git a/src/plugins/imageformats/gif/qgifhandler.cpp b/src/plugins/imageformats/gif/qgifhandler.cpp index c92cc3ea618..61981b305f3 100644 --- a/src/plugins/imageformats/gif/qgifhandler.cpp +++ b/src/plugins/imageformats/gif/qgifhandler.cpp @@ -1215,11 +1215,4 @@ int QGifHandler::currentImageNumber() const return frameNumber; } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QGifHandler::name() const -{ - return "gif"; -} -#endif - QT_END_NAMESPACE diff --git a/src/plugins/imageformats/gif/qgifhandler_p.h b/src/plugins/imageformats/gif/qgifhandler_p.h index c6592043ce2..f19777fa18e 100644 --- a/src/plugins/imageformats/gif/qgifhandler_p.h +++ b/src/plugins/imageformats/gif/qgifhandler_p.h @@ -73,10 +73,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - static bool canRead(QIODevice *device); QVariant option(ImageOption option) const override; diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp index eb50f52bd63..88ff1f83912 100644 --- a/src/plugins/imageformats/ico/qicohandler.cpp +++ b/src/plugins/imageformats/ico/qicohandler.cpp @@ -809,17 +809,6 @@ bool QtIcoHandler::write(const QImage &image) return ICOReader::write(device, imgs); } -#if QT_DEPRECATED_SINCE(5, 13) -/*! - * Return the common identifier of the format. - * For ICO format this will return "ico". - */ -QByteArray QtIcoHandler::name() const -{ - return "ico"; -} -#endif - /*! \reimp */ diff --git a/src/plugins/imageformats/ico/qicohandler.h b/src/plugins/imageformats/ico/qicohandler.h index 328dfce47eb..0d44a67dfce 100644 --- a/src/plugins/imageformats/ico/qicohandler.h +++ b/src/plugins/imageformats/ico/qicohandler.h @@ -54,10 +54,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - int imageCount() const override; bool jumpToImage(int imageNumber) override; bool jumpToNextImage() override; diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp index c31e2db3c53..fed585a82e8 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp @@ -1184,11 +1184,4 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value) } } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QJpegHandler::name() const -{ - return "jpeg"; -} -#endif - QT_END_NAMESPACE diff --git a/src/plugins/imageformats/jpeg/qjpeghandler_p.h b/src/plugins/imageformats/jpeg/qjpeghandler_p.h index fafa930c111..43ca17317a6 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler_p.h +++ b/src/plugins/imageformats/jpeg/qjpeghandler_p.h @@ -68,10 +68,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - static bool canRead(QIODevice *device); QVariant option(ImageOption option) const override; From c3fc9a24d8695447416b0eb40590fabea7287444 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 28 Feb 2020 10:53:15 +0100 Subject: [PATCH 15/41] Avoid UB in QList::removeAt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always keep the out of bounds check for backwards compatibility, but warn about it, so that we can remove it in Qt 6. Amends commit ebf695bc779a63a5730df05ab246305c0ab342e4 Change-Id: I3f1e7e8f9f20feb0b0f06ff9083c26682f1c7d3b Reviewed-by: Richard Öhlinger Reviewed-by: Thiago Macieira --- src/corelib/tools/qlist.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 37258cc66fd..8a11663c01f 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -583,10 +583,13 @@ inline void QList::removeAt(int i) { #if !QT_DEPRECATED_SINCE(5, 15) Q_ASSERT_X(i >= 0 && i < p.size(), "QList::removeAt", "index out of range"); -#elif !defined(QT_NO_DEBUG) - if (i < 0 || i >= p.size()) +#endif + if (i < 0 || i >= p.size()) { +#if !defined(QT_NO_DEBUG) qWarning("QList::removeAt(): Index out of range."); #endif + return; + } detach(); node_destruct(reinterpret_cast(p.at(i))); p.remove(i); } From f4fca8697ffaf64a2e919bbbb96fbd2639c7ac60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 25 Feb 2020 16:41:13 +0100 Subject: [PATCH 16/41] Undeprecate QHash::count(Key) For compatibility with std::unordered_map. Spotted in the API review. Change-Id: Ic34600d55baebcbbf115c1090cd555984037c44c Reviewed-by: Lars Knoll --- src/corelib/tools/qhash.cpp | 8 -------- src/corelib/tools/qhash.h | 35 ++++++++++++++--------------------- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 15f731a603a..7ebc374d9fe 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -1574,7 +1574,6 @@ uint qHash(long double key, uint seed) noexcept */ /*! \fn template int QHash::count(const Key &key) const - \obsolete Returns the number of items associated with the \a key. @@ -2693,13 +2692,6 @@ uint qHash(long double key, uint seed) noexcept \sa QHash::remove() */ -/*! \fn template int QMultiHash::count(const Key &key) const - - Returns the number of items associated with the \a key. - - \sa contains(), insert() -*/ - /*! \fn template int QMultiHash::count(const Key &key, const T &value) const \since 4.3 diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 91444055016..06313d6c79d 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -314,8 +314,8 @@ public: #if QT_DEPRECATED_SINCE(5, 15) QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QList uniqueKeys() const; QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QList values(const Key &key) const; - QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") int count(const Key &key) const; #endif + int count(const Key &key) const; class const_iterator; @@ -729,6 +729,19 @@ Q_OUTOFLINE_TEMPLATE QList QHash::values() const return res; } +template +Q_OUTOFLINE_TEMPLATE int QHash::count(const Key &akey) const +{ + int cnt = 0; + Node *node = *findNode(akey); + if (node != e) { + do { + ++cnt; + } while ((node = node->next) != e && node->key == akey); + } + return cnt; +} + template Q_INLINE_TEMPLATE const T QHash::operator[](const Key &akey) const { @@ -1072,7 +1085,6 @@ public: int remove(const Key &key, const T &value); - int count(const Key &key) const; int count(const Key &key, const T &value) const; QList uniqueKeys() const; @@ -1225,12 +1237,6 @@ Q_OUTOFLINE_TEMPLATE QList QHash::values(const Key &akey) const return static_cast *>(this)->values(akey); } -template -Q_OUTOFLINE_TEMPLATE int QHash::count(const Key &akey) const -{ - return static_cast *>(this)->count(akey); -} - template Q_OUTOFLINE_TEMPLATE QList QHash::uniqueKeys() const { @@ -1251,19 +1257,6 @@ Q_OUTOFLINE_TEMPLATE QList QMultiHash::values(const Key &akey) const return res; } -template -Q_OUTOFLINE_TEMPLATE int QMultiHash::count(const Key &akey) const -{ - int cnt = 0; - Node *node = *findNode(akey); - if (node != this->e) { - do { - ++cnt; - } while ((node = node->next) != this->e && node->key == akey); - } - return cnt; -} - #if !defined(QT_NO_JAVA_STYLE_ITERATORS) template class QHashIterator From bac89e2f49c1b7dda063aad8635a5d3cffad2c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 25 Feb 2020 16:50:55 +0100 Subject: [PATCH 17/41] QMap/QHash: Use versioned deprecation macro Because then it can be configured Change-Id: Ib4c20dd64bedfe2ebadf13283698c50d4c0bc527 Reviewed-by: Lars Knoll --- src/corelib/tools/qhash.h | 8 ++++---- src/corelib/tools/qmap.h | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 06313d6c79d..5078019602a 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -312,8 +312,8 @@ public: QList keys(const T &value) const; QList values() const; #if QT_DEPRECATED_SINCE(5, 15) - QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QList uniqueKeys() const; - QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QList values(const Key &key) const; + QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") QList uniqueKeys() const; + QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") QList values(const Key &key) const; #endif int count(const Key &key) const; @@ -531,8 +531,8 @@ public: iterator insert(const Key &key, const T &value); void insert(const QHash &hash); #if QT_DEPRECATED_SINCE(5, 15) - QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") iterator insertMulti(const Key &key, const T &value); - QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QHash &unite(const QHash &other); + QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") iterator insertMulti(const Key &key, const T &value); + QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") QHash &unite(const QHash &other); #endif // STL compatibility diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 427a4ad5a09..21628032c87 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -384,9 +384,9 @@ public: QList keys(const T &value) const; QList values() const; #if QT_DEPRECATED_SINCE(5, 15) - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") QList uniqueKeys() const; - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") QList values(const Key &key) const; - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") int count(const Key &key) const; + QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") QList uniqueKeys() const; + QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") QList values(const Key &key) const; + QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") int count(const Key &key) const; #endif @@ -585,9 +585,9 @@ public: iterator insert(const_iterator pos, const Key &key, const T &value); void insert(const QMap &map); #if QT_DEPRECATED_SINCE(5, 15) - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") iterator insertMulti(const Key &key, const T &value); - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") iterator insertMulti(const_iterator pos, const Key &akey, const T &avalue); - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") QMap &unite(const QMap &other); + QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") iterator insertMulti(const Key &key, const T &value); + QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") iterator insertMulti(const_iterator pos, const Key &akey, const T &avalue); + QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") QMap &unite(const QMap &other); #endif // STL compatibility From b30b3248caff5f3221e2de62a35bc16decb93b6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Wed, 26 Feb 2020 14:53:07 +0100 Subject: [PATCH 18/41] QMap: undeprecate QMap::count(Key) For compatibility with std::map Change-Id: Icba536244aadcad97c59dfd4bb22a7fdea881a7b Reviewed-by: Lars Knoll --- src/corelib/tools/qmap.cpp | 8 +------ src/corelib/tools/qmap.h | 43 ++++++++++++++++---------------------- 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp index 6d2b8f7a3ed..25ea5f25d7b 100644 --- a/src/corelib/tools/qmap.cpp +++ b/src/corelib/tools/qmap.cpp @@ -814,11 +814,10 @@ void QMapDataBase::freeData(QMapDataBase *d) */ /*! \fn template int QMap::count(const Key &key) const - \obsolete Returns the number of items associated with key \a key. - \sa QMultiMap::count() + \sa contains(), QMultiMap::count() */ /*! \fn template int QMap::count() const @@ -2115,11 +2114,6 @@ void QMapDataBase::freeData(QMapDataBase *d) inserted one. */ -/*! \fn template int QMultiMap::count(const Key &key) const - - Returns the number of items associated with key \a key. -*/ - /*! \fn template QList QMultiMap::uniqueKeys() const \since 4.2 diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 21628032c87..0c69d132953 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -386,8 +386,8 @@ public: #if QT_DEPRECATED_SINCE(5, 15) QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") QList uniqueKeys() const; QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") QList values(const Key &key) const; - QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") int count(const Key &key) const; #endif + int count(const Key &key) const; inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); } @@ -680,6 +680,23 @@ Q_INLINE_TEMPLATE T &QMap::operator[](const Key &akey) return n->value; } +template +Q_INLINE_TEMPLATE int QMap::count(const Key &akey) const +{ + Node *firstNode; + Node *lastNode; + d->nodeRange(akey, &firstNode, &lastNode); + + const_iterator ci_first(firstNode); + const const_iterator ci_last(lastNode); + int cnt = 0; + while (ci_first != ci_last) { + ++cnt; + ++ci_first; + } + return cnt; +} + template Q_INLINE_TEMPLATE bool QMap::contains(const Key &akey) const { @@ -1142,7 +1159,6 @@ public: int remove(const Key &key, const T &value); - int count(const Key &key) const; int count(const Key &key, const T &value) const; typename QMap::iterator find(const Key &key, const T &value) { @@ -1315,23 +1331,6 @@ Q_INLINE_TEMPLATE int QMultiMap::remove(const Key &key, const T &value) return n; } -template -Q_INLINE_TEMPLATE int QMultiMap::count(const Key &akey) const -{ - QMultiMap::Node *firstNode; - QMultiMap::Node *lastNode; - this->d->nodeRange(akey, &firstNode, &lastNode); - - typename QMap::const_iterator ci_first(firstNode); - const typename QMap::const_iterator ci_last(lastNode); - int cnt = 0; - while (ci_first != ci_last) { - ++cnt; - ++ci_first; - } - return cnt; -} - template Q_INLINE_TEMPLATE int QMultiMap::count(const Key &key, const T &value) const { @@ -1359,12 +1358,6 @@ QList QMap::values(const Key &key) const return static_cast *>(this)->values(key); } -template -int QMap::count(const Key &key) const -{ - return static_cast *>(this)->count(key); -} - template typename QMap::iterator QMap::insertMulti(const Key &key, const T &value) { From 23fd7bdf01ae81ca6ae0bd741bb4d82784e762d0 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 2 Mar 2020 10:09:48 +0100 Subject: [PATCH 19/41] macOS: MoltenVK: Pass in the layer instead of the view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surface creation may be triggered on a thread other than the main thread. To enable this, MoltenVK also accepts the CAMetalLayer instead of the NSView. See https://github.com/KhronosGroup/MoltenVK/pull/258 Task-number: QTBUG-82600 Change-Id: I7b925210d05235baf04441682760f09fe58d8144 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoavulkaninstance.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm index 7ce78ee7387..94c0a11b848 100644 --- a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm +++ b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm @@ -81,7 +81,7 @@ VkSurfaceKHR QCocoaVulkanInstance::createSurface(NSView *view) surfaceInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; surfaceInfo.pNext = nullptr; surfaceInfo.flags = 0; - surfaceInfo.pView = view; + surfaceInfo.pView = view.layer; VkSurfaceKHR surface = nullptr; VkResult err = m_createSurface(m_vkInst, &surfaceInfo, nullptr, &surface); From 7b8616859adcb0c8b38591b0e9c1165c986bad92 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 2 Mar 2020 09:58:50 +0100 Subject: [PATCH 20/41] Do not constantly create new surfaces with MoltenVK on macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Querying the VkSurfaceKHR for a window is expected to create the surface once and then return the same value afterwards. Task-number: QTBUG-82600 Change-Id: Ib3e99dfca4d940de1a14348eb1909d372a7dde04 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoanativeinterface.mm | 2 +- src/plugins/platforms/cocoa/qcocoavulkaninstance.h | 6 ++++-- src/plugins/platforms/cocoa/qcocoavulkaninstance.mm | 7 +++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index d0e69bdca5a..450329f5696 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -107,7 +107,7 @@ void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceS #if QT_CONFIG(vulkan) } else if (resourceString == "vkSurface") { if (QVulkanInstance *instance = window->vulkanInstance()) - return static_cast(instance->handle())->createSurface(window); + return static_cast(instance->handle())->surface(window); #endif } return nullptr; diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.h b/src/plugins/platforms/cocoa/qcocoavulkaninstance.h index 5fe6a612afe..2a8d04757e3 100644 --- a/src/plugins/platforms/cocoa/qcocoavulkaninstance.h +++ b/src/plugins/platforms/cocoa/qcocoavulkaninstance.h @@ -61,9 +61,11 @@ public: void createOrAdoptInstance() override; - VkSurfaceKHR *createSurface(QWindow *window); - VkSurfaceKHR createSurface(NSView *view); + VkSurfaceKHR *surface(QWindow *window); + private: + VkSurfaceKHR createSurface(NSView *view); + QVulkanInstance *m_instance = nullptr; QLibrary m_lib; VkSurfaceKHR m_nullSurface = nullptr; diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm index 94c0a11b848..9e714859f2d 100644 --- a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm +++ b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm @@ -57,12 +57,11 @@ void QCocoaVulkanInstance::createOrAdoptInstance() initInstance(m_instance, QByteArrayList() << QByteArrayLiteral("VK_MVK_macos_surface")); } -VkSurfaceKHR *QCocoaVulkanInstance::createSurface(QWindow *window) +VkSurfaceKHR *QCocoaVulkanInstance::surface(QWindow *window) { QCocoaWindow *cocoaWindow = static_cast(window->handle()); - if (cocoaWindow->m_vulkanSurface) - destroySurface(cocoaWindow->m_vulkanSurface); - cocoaWindow->m_vulkanSurface = createSurface(cocoaWindow->m_view); + if (!cocoaWindow->m_vulkanSurface) + cocoaWindow->m_vulkanSurface = createSurface(cocoaWindow->m_view); return &cocoaWindow->m_vulkanSurface; } From 753e4d82be966b82ff6ba41a0e7c4452f494790a Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sun, 23 Feb 2020 15:05:44 +0100 Subject: [PATCH 21/41] rhi: Execute pending host writes on nativeBuffer() query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise it is impossible to write an application that pulls out the VkBuffer for a Dynamic QRhiBuffer, and then uses it with custom Vulkan operations that read from the buffer. More precisely, the problem arises only if the buffer in question is not used in combination with any QRhi operations, because in that case there is nothing that would trigger doing the host writes queued up by a resource batch's updateDynamicBuffer(). Task-number: QTBUG-82435 Change-Id: Ieb54422f1493921bc6d4d029be56130cd3a1362a Reviewed-by: Christian Strømme --- src/gui/rhi/qrhi.cpp | 8 +++----- src/gui/rhi/qrhid3d11.cpp | 12 ++++++++---- src/gui/rhi/qrhid3d11_p_p.h | 2 +- src/gui/rhi/qrhimetal.mm | 23 +++++++++++++++-------- src/gui/rhi/qrhimetal_p_p.h | 1 + src/gui/rhi/qrhivulkan.cpp | 25 ++++++++++++++----------- src/gui/rhi/qrhivulkan_p_p.h | 2 +- 7 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 7a0d53e1e46..6243bcda58e 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -2048,11 +2048,9 @@ QRhiResource::Type QRhiBuffer::resourceType() const UniformBuffer may not even be backed by a native buffer object at all if uniform buffers are not used or supported by a given backend and graphics API. There are also differences to how data is written to the buffer and - the type of backing memory used, and, if host visible memory is involved, - when memory writes become available and visible. Therefore, in general it - is recommended to limit native buffer object access to vertex and index - buffers with types Static or Immutable, because these operate in a - relatively uniform manner with all backends. + the type of backing memory used. For buffers backed by host visible memory, + calling this function guarantees that pending host writes are executed for + all the returned native buffers. \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight */ diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index f7c7f4a9f2e..ce39b42cf54 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -608,7 +608,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind { QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.ubuf.buf); if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWrites(bufD); if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) { srbUpdate = true; @@ -725,7 +725,7 @@ void QRhiD3D11::setVertexInput(QRhiCommandBuffer *cb, QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, bindings[i].first); Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer)); if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWrites(bufD); if (cbD->currentVertexBuffers[inputSlot] != bufD->buffer || cbD->currentVertexOffsets[inputSlot] != bindings[i].second) @@ -757,7 +757,7 @@ void QRhiD3D11::setVertexInput(QRhiCommandBuffer *cb, QD3D11Buffer *ibufD = QRHI_RES(QD3D11Buffer, indexBuf); Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer)); if (ibufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(ibufD); + executeBufferHostWrites(ibufD); const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; @@ -1920,7 +1920,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) srbD->csUAVs.finish(); } -void QRhiD3D11::executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD) +void QRhiD3D11::executeBufferHostWrites(QD3D11Buffer *bufD) { if (!bufD->hasPendingDynamicUpdates) return; @@ -2388,6 +2388,10 @@ bool QD3D11Buffer::build() QRhiBuffer::NativeBuffer QD3D11Buffer::nativeBuffer() { + if (m_type == Dynamic) { + QRHI_RES_RHI(QRhiD3D11); + rhiD->executeBufferHostWrites(this); + } return { { &buffer }, 1 }; } diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 04751397f75..b70f541c687 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -643,7 +643,7 @@ public: int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc); void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates); void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD); - void executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD); + void executeBufferHostWrites(QD3D11Buffer *bufD); void bindShaderResources(QD3D11ShaderResourceBindings *srbD, const uint *dynOfsPairs, int dynOfsPairCount, bool offsetOnlyChange); diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 48a562ef1d0..314c58b0b74 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -1827,16 +1827,15 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate } // this handles all types of buffers, not just Dynamic -void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD) +void QRhiMetal::executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot) { - const int idx = bufD->d->slotted ? currentFrameSlot : 0; - if (bufD->d->pendingUpdates[idx].isEmpty()) + if (bufD->d->pendingUpdates[slot].isEmpty()) return; - void *p = [bufD->d->buf[idx] contents]; + void *p = [bufD->d->buf[slot] contents]; int changeBegin = -1; int changeEnd = -1; - for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->d->pendingUpdates[idx])) { + for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->d->pendingUpdates[slot])) { Q_ASSERT(bufD == QRHI_RES(QMetalBuffer, u.buf)); memcpy(static_cast(p) + u.offset, u.data.constData(), size_t(u.data.size())); if (changeBegin == -1 || u.offset < changeBegin) @@ -1846,10 +1845,15 @@ void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD) } #ifdef Q_OS_MACOS if (changeBegin >= 0 && bufD->d->managed) - [bufD->d->buf[idx] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))]; + [bufD->d->buf[slot] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))]; #endif - bufD->d->pendingUpdates[idx].clear(); + bufD->d->pendingUpdates[slot].clear(); +} + +void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD) +{ + executeBufferHostWritesForSlot(bufD, bufD->d->slotted ? currentFrameSlot : 0); } void QRhiMetal::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) @@ -2205,8 +2209,11 @@ QRhiBuffer::NativeBuffer QMetalBuffer::nativeBuffer() if (d->slotted) { NativeBuffer b; Q_ASSERT(sizeof(b.objects) / sizeof(b.objects[0]) >= size_t(QMTL_FRAMES_IN_FLIGHT)); - for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) + for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) { + QRHI_RES_RHI(QRhiMetal); + rhiD->executeBufferHostWritesForSlot(this, i); b.objects[i] = &d->buf[i]; + } b.slotCount = QMTL_FRAMES_IN_FLIGHT; return b; } diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index 212b731b713..a5af5611a61 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -437,6 +437,7 @@ public: int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc, qsizetype *curOfs); void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates); + void executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot); void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD); static const int SUPPORTED_STAGES = 3; void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index d378e2a4ad5..8f6f118c9b4 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -2903,7 +2903,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) { QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf); if (bufD->m_type == QRhiBuffer::Dynamic) { - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWritesForSlot(bufD, currentFrameSlot); void *p = nullptr; VmaAllocation a = toVmaAllocation(bufD->allocations[currentFrameSlot]); VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p); @@ -3300,14 +3300,14 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat ud->free(); } -void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD) +void QRhiVulkan::executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot) { - if (bufD->pendingDynamicUpdates[currentFrameSlot].isEmpty()) + if (bufD->pendingDynamicUpdates[slot].isEmpty()) return; Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic); void *p = nullptr; - VmaAllocation a = toVmaAllocation(bufD->allocations[currentFrameSlot]); + VmaAllocation a = toVmaAllocation(bufD->allocations[slot]); // The vmaMap/Unmap are basically a no-op when persistently mapped since it // refcounts; this is great because we don't need to care if the allocation // was created as persistently mapped or not. @@ -3318,7 +3318,7 @@ void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD) } int changeBegin = -1; int changeEnd = -1; - for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->pendingDynamicUpdates[currentFrameSlot])) { + for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->pendingDynamicUpdates[slot])) { Q_ASSERT(bufD == QRHI_RES(QVkBuffer, u.buf)); memcpy(static_cast(p) + u.offset, u.data.constData(), size_t(u.data.size())); if (changeBegin == -1 || u.offset < changeBegin) @@ -3330,7 +3330,7 @@ void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD) if (changeBegin >= 0) vmaFlushAllocation(toVmaAllocator(allocator), a, VkDeviceSize(changeBegin), VkDeviceSize(changeEnd - changeBegin)); - bufD->pendingDynamicUpdates[currentFrameSlot].clear(); + bufD->pendingDynamicUpdates[slot].clear(); } static void qrhivk_releaseBuffer(const QRhiVulkan::DeferredReleaseEntry &e, void *allocator) @@ -4166,7 +4166,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)); if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWritesForSlot(bufD, currentFrameSlot); bufD->lastActiveFrameSlot = currentFrameSlot; trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0, @@ -4240,7 +4240,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer)); if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWritesForSlot(bufD, currentFrameSlot); bufD->lastActiveFrameSlot = currentFrameSlot; QRhiPassResourceTracker::BufferAccess access; @@ -4349,7 +4349,7 @@ void QRhiVulkan::setVertexInput(QRhiCommandBuffer *cb, Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer)); bufD->lastActiveFrameSlot = currentFrameSlot; if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWritesForSlot(bufD, currentFrameSlot); const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0]; if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf @@ -4395,7 +4395,7 @@ void QRhiVulkan::setVertexInput(QRhiCommandBuffer *cb, Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer)); ibufD->lastActiveFrameSlot = currentFrameSlot; if (ibufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(ibufD); + executeBufferHostWritesForSlot(ibufD, currentFrameSlot); const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0; const VkBuffer vkindexbuf = ibufD->buffers[slot]; @@ -5188,10 +5188,13 @@ bool QVkBuffer::build() QRhiBuffer::NativeBuffer QVkBuffer::nativeBuffer() { if (m_type == Dynamic) { + QRHI_RES_RHI(QRhiVulkan); NativeBuffer b; Q_ASSERT(sizeof(b.objects) / sizeof(b.objects[0]) >= size_t(QVK_FRAMES_IN_FLIGHT)); - for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) + for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) { + rhiD->executeBufferHostWritesForSlot(this, i); b.objects[i] = &buffers[i]; + } b.slotCount = QVK_FRAMES_IN_FLIGHT; return b; } diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index 63228825697..0f0a89cbff2 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -778,7 +778,7 @@ public: size_t *curOfs, void *mp, BufferImageCopyList *copyInfos); void enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates); - void executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD); + void executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot); void enqueueTransitionPassResources(QVkCommandBuffer *cbD); void recordPrimaryCommandBuffer(QVkCommandBuffer *cbD); void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker, From 5bbc9986f99a5d61c2e43b79fe815ea8ca450fcd Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 26 Feb 2020 15:07:49 +0100 Subject: [PATCH 22/41] rhi: d3d: Use native resource binding mapping table when present MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Newer versions of QShaderBaker will now use distinct, zero-based b, t+s, and u register spaces in the generated HLSL source. If this is the case, the native resource binding map (which so far we only used with Metal) contains the SPIR-V binding -> HLSL register binding mappings. This way we won't end up with invalid resource binding attempts (consider that e.g. D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT is only 16), just because, for example, a combined image sampler had a binding of 18 which then got blindly mapped to s18 and t18 in HLSL. Task-number: QTBUG-82472 Change-Id: I8bdcb5378634cf159f6367424582f9e9e5821c8e Reviewed-by: Christian Strømme --- src/gui/rhi/qrhid3d11.cpp | 257 +++++++++++++++++++++++++++--------- src/gui/rhi/qrhid3d11_p_p.h | 22 ++- 2 files changed, 215 insertions(+), 64 deletions(-) diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index ce39b42cf54..7b583e6fd2a 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -580,6 +580,11 @@ void QRhiD3D11::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline } } +static const int RBM_SUPPORTED_STAGES = 3; +static const int RBM_VERTEX = 0; +static const int RBM_FRAGMENT = 1; +static const int RBM_COMPUTE = 2; + void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) @@ -667,8 +672,17 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind } } - if (srbUpdate) - updateShaderResourceBindings(srbD); + if (srbUpdate) { + const QShader::NativeResourceBindingMap *resBindMaps[RBM_SUPPORTED_STAGES]; + memset(resBindMaps, 0, sizeof(resBindMaps)); + if (gfxPsD) { + resBindMaps[RBM_VERTEX] = &gfxPsD->vs.nativeResourceBindingMap; + resBindMaps[RBM_FRAGMENT] = &gfxPsD->fs.nativeResourceBindingMap; + } else { + resBindMaps[RBM_COMPUTE] = &compPsD->cs.nativeResourceBindingMap; + } + updateShaderResourceBindings(srbD, resBindMaps); + } const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb); const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation; @@ -1774,7 +1788,26 @@ void QRhiD3D11::dispatch(QRhiCommandBuffer *cb, int x, int y, int z) cbD->commands.append(cmd); } -void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) +static inline QPair mapBinding(int binding, + int stageIndex, + const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]) +{ + const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex]; + if (!map || map->isEmpty()) + return { binding, binding }; // old QShader versions do not have this map, assume 1:1 mapping then + + auto it = map->constFind(binding); + if (it != map->cend()) + return *it; + + // Hitting this path is normal too. It is not given that the resource is + // present in the shaders for all the stages specified by the visibility + // mask in the QRhiShaderResourceBinding. + return { -1, -1 }; +} + +void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, + const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]) { srbD->vsubufs.clear(); srbD->vsubufoffsets.clear(); @@ -1799,6 +1832,31 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) srbD->csUAVs.clear(); + struct Stage { + struct Buffer { + int breg; // b0, b1, ... + ID3D11Buffer *buffer; + uint offsetInConstants; + uint sizeInConstants; + }; + struct Texture { + int treg; // t0, t1, ... + ID3D11ShaderResourceView *srv; + }; + struct Sampler { + int sreg; // s0, s1, ... + ID3D11SamplerState *sampler; + }; + struct Uav { + int ureg; + ID3D11UnorderedAccessView *uav; + }; + QVarLengthArray buffers; + QVarLengthArray textures; + QVarLengthArray samplers; + QVarLengthArray uavs; + } res[RBM_SUPPORTED_STAGES]; + for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) { const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data(); QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]); @@ -1818,26 +1876,24 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) // (ByteWidth) is always a multiple of 256. const uint sizeInConstants = uint(aligned(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size, 256) / 16); if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - srbD->vsubufs.feed(b->binding, bufD->buffer); - srbD->vsubufoffsets.feed(b->binding, offsetInConstants); - srbD->vsubufsizes.feed(b->binding, sizeInConstants); + QPair nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) + res[RBM_VERTEX].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - srbD->fsubufs.feed(b->binding, bufD->buffer); - srbD->fsubufoffsets.feed(b->binding, offsetInConstants); - srbD->fsubufsizes.feed(b->binding, sizeInConstants); + QPair nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) + res[RBM_FRAGMENT].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - srbD->csubufs.feed(b->binding, bufD->buffer); - srbD->csubufoffsets.feed(b->binding, offsetInConstants); - srbD->csubufsizes.feed(b->binding, sizeInConstants); + QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) + res[RBM_COMPUTE].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); } } break; case QRhiShaderResourceBinding::SampledTexture: { - // A sampler with binding N is mapped to a HLSL sampler and texture - // with registers sN and tN by SPIRV-Cross. QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.stex.tex); QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, b->u.stex.sampler); bd.stex.texId = texD->m_id; @@ -1845,16 +1901,25 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) bd.stex.samplerId = samplerD->m_id; bd.stex.samplerGeneration = samplerD->generation; if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - srbD->vssamplers.feed(b->binding, samplerD->samplerState); - srbD->vsshaderresources.feed(b->binding, texD->srv); + QPair nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps); + if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { + res[RBM_VERTEX].textures.append({ nativeBinding.first, texD->srv }); + res[RBM_VERTEX].samplers.append({ nativeBinding.second, samplerD->samplerState }); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - srbD->fssamplers.feed(b->binding, samplerD->samplerState); - srbD->fsshaderresources.feed(b->binding, texD->srv); + QPair nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps); + if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { + res[RBM_FRAGMENT].textures.append({ nativeBinding.first, texD->srv }); + res[RBM_FRAGMENT].samplers.append({ nativeBinding.second, samplerD->samplerState }); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - srbD->cssamplers.feed(b->binding, samplerD->samplerState); - srbD->csshaderresources.feed(b->binding, texD->srv); + QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { + res[RBM_COMPUTE].textures.append({ nativeBinding.first, texD->srv }); + res[RBM_COMPUTE].samplers.append({ nativeBinding.second, samplerD->samplerState }); + } } } break; @@ -1866,9 +1931,12 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) bd.simage.id = texD->m_id; bd.simage.generation = texD->generation; if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level); - if (uav) - srbD->csUAVs.feed(b->binding, uav); + QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) { + ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level); + if (uav) + res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav }); + } } else { qWarning("Unordered access only supported at compute stage"); } @@ -1882,9 +1950,12 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) bd.sbuf.id = bufD->m_id; bd.sbuf.generation = bufD->generation; if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView(); - if (uav) - srbD->csUAVs.feed(b->binding, uav); + QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) { + ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView(); + if (uav) + res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav }); + } } else { qWarning("Unordered access only supported at compute stage"); } @@ -1896,27 +1967,75 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) } } + // QRhiBatchedBindings works with the native bindings and expects + // sorted input. The pre-sorted QRhiShaderResourceBinding list (based + // on the QRhi (SPIR-V) binding) is not helpful in this regard, so we + // have to sort here every time. + for (int stage = 0; stage < RBM_SUPPORTED_STAGES; ++stage) { + std::sort(res[stage].buffers.begin(), res[stage].buffers.end(), [](const Stage::Buffer &a, const Stage::Buffer &b) { + return a.breg < b.breg; + }); + std::sort(res[stage].textures.begin(), res[stage].textures.end(), [](const Stage::Texture &a, const Stage::Texture &b) { + return a.treg < b.treg; + }); + std::sort(res[stage].samplers.begin(), res[stage].samplers.end(), [](const Stage::Sampler &a, const Stage::Sampler &b) { + return a.sreg < b.sreg; + }); + std::sort(res[stage].uavs.begin(), res[stage].uavs.end(), [](const Stage::Uav &a, const Stage::Uav &b) { + return a.ureg < b.ureg; + }); + } + + for (const Stage::Buffer &buf : qAsConst(res[RBM_VERTEX].buffers)) { + srbD->vsubufs.feed(buf.breg, buf.buffer); + srbD->vsubufoffsets.feed(buf.breg, buf.offsetInConstants); + srbD->vsubufsizes.feed(buf.breg, buf.sizeInConstants); + } srbD->vsubufs.finish(); srbD->vsubufoffsets.finish(); srbD->vsubufsizes.finish(); + for (const Stage::Buffer &buf : qAsConst(res[RBM_FRAGMENT].buffers)) { + srbD->fsubufs.feed(buf.breg, buf.buffer); + srbD->fsubufoffsets.feed(buf.breg, buf.offsetInConstants); + srbD->fsubufsizes.feed(buf.breg, buf.sizeInConstants); + } srbD->fsubufs.finish(); srbD->fsubufoffsets.finish(); srbD->fsubufsizes.finish(); + for (const Stage::Buffer &buf : qAsConst(res[RBM_COMPUTE].buffers)) { + srbD->csubufs.feed(buf.breg, buf.buffer); + srbD->csubufoffsets.feed(buf.breg, buf.offsetInConstants); + srbD->csubufsizes.feed(buf.breg, buf.sizeInConstants); + } srbD->csubufs.finish(); srbD->csubufoffsets.finish(); srbD->csubufsizes.finish(); + for (const Stage::Texture &t : qAsConst(res[RBM_VERTEX].textures)) + srbD->vsshaderresources.feed(t.treg, t.srv); + for (const Stage::Sampler &s : qAsConst(res[RBM_VERTEX].samplers)) + srbD->vssamplers.feed(s.sreg, s.sampler); srbD->vssamplers.finish(); srbD->vsshaderresources.finish(); + for (const Stage::Texture &t : qAsConst(res[RBM_FRAGMENT].textures)) + srbD->fsshaderresources.feed(t.treg, t.srv); + for (const Stage::Sampler &s : qAsConst(res[RBM_FRAGMENT].samplers)) + srbD->fssamplers.feed(s.sreg, s.sampler); srbD->fssamplers.finish(); srbD->fsshaderresources.finish(); + for (const Stage::Texture &t : qAsConst(res[RBM_COMPUTE].textures)) + srbD->csshaderresources.feed(t.treg, t.srv); + for (const Stage::Sampler &s : qAsConst(res[RBM_COMPUTE].samplers)) + srbD->cssamplers.feed(s.sreg, s.sampler); srbD->cssamplers.finish(); srbD->csshaderresources.finish(); + for (const Stage::Uav &u : qAsConst(res[RBM_COMPUTE].uavs)) + srbD->csUAVs.feed(u.ureg, u.uav); srbD->csUAVs.finish(); } @@ -2205,8 +2324,8 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain * case QD3D11CommandBuffer::Command::BindGraphicsPipeline: { QD3D11GraphicsPipeline *psD = cmd.args.bindGraphicsPipeline.ps; - context->VSSetShader(psD->vs, nullptr, 0); - context->PSSetShader(psD->fs, nullptr, 0); + context->VSSetShader(psD->vs.shader, nullptr, 0); + context->PSSetShader(psD->fs.shader, nullptr, 0); context->IASetPrimitiveTopology(psD->d3dTopology); context->IASetInputLayout(psD->inputLayout); context->OMSetDepthStencilState(psD->dsState, stencilRef); @@ -2281,7 +2400,7 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain * annotations->SetMarker(reinterpret_cast(QString::fromLatin1(cmd.args.debugMark.s).utf16())); break; case QD3D11CommandBuffer::Command::BindComputePipeline: - context->CSSetShader(cmd.args.bindComputePipeline.ps->cs, nullptr, 0); + context->CSSetShader(cmd.args.bindComputePipeline.ps->cs.shader, nullptr, 0); break; case QD3D11CommandBuffer::Command::Dispatch: context->Dispatch(cmd.args.dispatch.x, cmd.args.dispatch.y, cmd.args.dispatch.z); @@ -3137,6 +3256,7 @@ QD3D11ShaderResourceBindings::~QD3D11ShaderResourceBindings() void QD3D11ShaderResourceBindings::release() { sortedBindings.clear(); + boundResourceData.clear(); } bool QD3D11ShaderResourceBindings::build() @@ -3153,8 +3273,8 @@ bool QD3D11ShaderResourceBindings::build() boundResourceData.resize(sortedBindings.count()); - QRHI_RES_RHI(QRhiD3D11); - rhiD->updateShaderResourceBindings(this); + for (BoundResourceData &bd : boundResourceData) + memset(&bd, 0, sizeof(BoundResourceData)); generation += 1; return true; @@ -3195,15 +3315,17 @@ void QD3D11GraphicsPipeline::release() rastState = nullptr; } - if (vs) { - vs->Release(); - vs = nullptr; + if (vs.shader) { + vs.shader->Release(); + vs.shader = nullptr; } + vs.nativeResourceBindingMap.clear(); - if (fs) { - fs->Release(); - fs = nullptr; + if (fs.shader) { + fs.shader->Release(); + fs.shader = nullptr; } + fs.nativeResourceBindingMap.clear(); rhiD->unregisterResource(this); } @@ -3405,13 +3527,14 @@ static pD3DCompile resolveD3DCompile() return nullptr; } -static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error) +static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error, QShaderKey *usedShaderKey) { QShaderCode dxbc = shader.shader({ QShader::DxbcShader, 50, shaderVariant }); if (!dxbc.shader().isEmpty()) return dxbc.shader(); - QShaderCode hlslSource = shader.shader({ QShader::HlslShader, 50, shaderVariant }); + const QShaderKey key = { QShader::HlslShader, 50, shaderVariant }; + QShaderCode hlslSource = shader.shader(key); if (hlslSource.shader().isEmpty()) { qWarning() << "No HLSL (shader model 5.0) code found in baked shader" << shader; return QByteArray(); @@ -3463,6 +3586,9 @@ static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Varian return QByteArray(); } + if (usedShaderKey) + *usedShaderKey = key; + QByteArray result; result.resize(int(bytecode->GetBufferSize())); memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size())); @@ -3554,20 +3680,23 @@ bool QD3D11GraphicsPipeline::build() if (cacheIt != rhiD->m_shaderCache.constEnd()) { switch (shaderStage.type()) { case QRhiShaderStage::Vertex: - vs = static_cast(cacheIt->s); - vs->AddRef(); + vs.shader = static_cast(cacheIt->s); + vs.shader->AddRef(); vsByteCode = cacheIt->bytecode; + vs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; break; case QRhiShaderStage::Fragment: - fs = static_cast(cacheIt->s); - fs->AddRef(); + fs.shader = static_cast(cacheIt->s); + fs.shader->AddRef(); + fs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; break; default: break; } } else { QString error; - const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error); + QShaderKey shaderKey; + const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error, &shaderKey); if (bytecode.isEmpty()) { qWarning("HLSL shader compilation failed: %s", qPrintable(error)); return false; @@ -3580,23 +3709,27 @@ bool QD3D11GraphicsPipeline::build() switch (shaderStage.type()) { case QRhiShaderStage::Vertex: - hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs); + hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs.shader); if (FAILED(hr)) { qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr))); return false; } vsByteCode = bytecode; - rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs, bytecode)); - vs->AddRef(); + if (const QShader::NativeResourceBindingMap *map = shaderStage.shader().nativeResourceBindingMap(shaderKey)) + vs.nativeResourceBindingMap = *map; + rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs.shader, bytecode, vs.nativeResourceBindingMap)); + vs.shader->AddRef(); break; case QRhiShaderStage::Fragment: - hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs); + hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs.shader); if (FAILED(hr)) { qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr))); return false; } - rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs, bytecode)); - fs->AddRef(); + if (const QShader::NativeResourceBindingMap *map = shaderStage.shader().nativeResourceBindingMap(shaderKey)) + fs.nativeResourceBindingMap = *map; + rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs.shader, bytecode, fs.nativeResourceBindingMap)); + fs.shader->AddRef(); break; default: break; @@ -3655,46 +3788,52 @@ void QD3D11ComputePipeline::release() { QRHI_RES_RHI(QRhiD3D11); - if (!cs) + if (!cs.shader) return; - cs->Release(); - cs = nullptr; + cs.shader->Release(); + cs.shader = nullptr; + cs.nativeResourceBindingMap.clear(); rhiD->unregisterResource(this); } bool QD3D11ComputePipeline::build() { - if (cs) + if (cs.shader) release(); QRHI_RES_RHI(QRhiD3D11); auto cacheIt = rhiD->m_shaderCache.constFind(m_shaderStage); if (cacheIt != rhiD->m_shaderCache.constEnd()) { - cs = static_cast(cacheIt->s); + cs.shader = static_cast(cacheIt->s); + cs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; } else { QString error; - const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error); + QShaderKey shaderKey; + const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error, &shaderKey); if (bytecode.isEmpty()) { qWarning("HLSL compute shader compilation failed: %s", qPrintable(error)); return false; } - HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs); + HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs.shader); if (FAILED(hr)) { qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr))); return false; } + if (const QShader::NativeResourceBindingMap *map = m_shaderStage.shader().nativeResourceBindingMap(shaderKey)) + cs.nativeResourceBindingMap = *map; + if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES) rhiD->clearShaderCache(); - rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs, bytecode)); + rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs.shader, bytecode, cs.nativeResourceBindingMap)); } - cs->AddRef(); + cs.shader->AddRef(); generation += 1; rhiD->registerResource(this); diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index b70f541c687..f749b612b50 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -270,8 +270,14 @@ struct QD3D11GraphicsPipeline : public QRhiGraphicsPipeline ID3D11DepthStencilState *dsState = nullptr; ID3D11BlendState *blendState = nullptr; - ID3D11VertexShader *vs = nullptr; - ID3D11PixelShader *fs = nullptr; + struct { + ID3D11VertexShader *shader = nullptr; + QShader::NativeResourceBindingMap nativeResourceBindingMap; + } vs; + struct { + ID3D11PixelShader *shader = nullptr; + QShader::NativeResourceBindingMap nativeResourceBindingMap; + } fs; ID3D11InputLayout *inputLayout = nullptr; D3D11_PRIMITIVE_TOPOLOGY d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; ID3D11RasterizerState *rastState = nullptr; @@ -286,7 +292,10 @@ struct QD3D11ComputePipeline : public QRhiComputePipeline void release() override; bool build() override; - ID3D11ComputeShader *cs = nullptr; + struct { + ID3D11ComputeShader *shader = nullptr; + QShader::NativeResourceBindingMap nativeResourceBindingMap; + } cs; uint generation = 0; friend class QRhiD3D11; }; @@ -642,7 +651,8 @@ public: void enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD, int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc); void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates); - void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD); + void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, + const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]); void executeBufferHostWrites(QD3D11Buffer *bufD); void bindShaderResources(QD3D11ShaderResourceBindings *srbD, const uint *dynOfsPairs, int dynOfsPairCount, @@ -701,9 +711,11 @@ public: struct Shader { Shader() = default; - Shader(IUnknown *s, const QByteArray &bytecode) : s(s), bytecode(bytecode) { } + Shader(IUnknown *s, const QByteArray &bytecode, const QShader::NativeResourceBindingMap &rbm) + : s(s), bytecode(bytecode), nativeResourceBindingMap(rbm) { } IUnknown *s; QByteArray bytecode; + QShader::NativeResourceBindingMap nativeResourceBindingMap; }; QHash m_shaderCache; From bd2b77120e1db8cb991aff23dd1f99cec792fa8e Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sat, 29 Feb 2020 15:38:07 +0100 Subject: [PATCH 23/41] rhi: vulkan: Sanitize device extension handling Instead of qputenv("QT_VULKAN_DEVICE_EXTENSIONS", "VK_KHR_get_memory_requirements2;VK_NV_ray_tracing"); one can now do params.deviceExtensions = { "VK_KHR_get_memory_requirements2", "VK_NV_ray_tracing" }; on the QRhiVulkanInitParams passed to QRhi::create(). The environment variable stays important for Qt Quick applications, which provide no configurability for the QRhi construction (yet). On the other hand, applications using QRhi directly can now also use the new approach to specify the list of device extensions to enable. In addition, take QVulkanInfoVector into use. There is no reason not to rely on the infrastructure provided by QVulkanInstance. This also implies showing an informative warning for unsupported extensions, instead of merely failing the device creation. (applications will likely not be able to recover of course, but at least the reason for failing is made obvious this way) Task-number: QTBUG-82435 Change-Id: Ib47fd1a10c02be5ceef2c973e61e896c34f92fa3 Reviewed-by: Eirik Aavitsland --- src/gui/rhi/qrhivulkan.cpp | 60 +++++++++++++++++++++++++----------- src/gui/rhi/qrhivulkan_p.h | 1 + src/gui/rhi/qrhivulkan_p_p.h | 1 + 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 8f6f118c9b4..60ab15e89d6 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -149,6 +149,10 @@ QT_BEGIN_NAMESPACE for other windows as well, as long as they all have their QWindow::surfaceType() set to QSurface::VulkanSurface. + To request additional extensions to be enabled on the Vulkan device, list them + in deviceExtensions. This can be relevant when integrating with native Vulkan + rendering code. + \section2 Working with existing Vulkan devices When interoperating with another graphics engine, it may be necessary to @@ -299,6 +303,7 @@ QRhiVulkan::QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *im { inst = params->inst; maybeWindow = params->window; // may be null + requestedDeviceExtensions = params->deviceExtensions; importedDevice = importDevice != nullptr; if (importedDevice) { @@ -463,40 +468,59 @@ bool QRhiVulkan::create(QRhi::Flags flags) if (inst->layers().contains("VK_LAYER_LUNARG_standard_validation")) devLayers.append("VK_LAYER_LUNARG_standard_validation"); + QVulkanInfoVector devExts; uint32_t devExtCount = 0; f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, nullptr); - QVector devExts(devExtCount); - f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, devExts.data()); + if (devExtCount) { + QVector extProps(devExtCount); + f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, extProps.data()); + for (const VkExtensionProperties &p : qAsConst(extProps)) + devExts.append({ p.extensionName, p.specVersion }); + } qCDebug(QRHI_LOG_INFO, "%d device extensions available", devExts.count()); QVector requestedDevExts; requestedDevExts.append("VK_KHR_swapchain"); debugMarkersAvailable = false; + if (devExts.contains(VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { + requestedDevExts.append(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); + debugMarkersAvailable = true; + } + vertexAttribDivisorAvailable = false; - for (const VkExtensionProperties &ext : devExts) { - if (!strcmp(ext.extensionName, VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { - requestedDevExts.append(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); - debugMarkersAvailable = true; - } else if (!strcmp(ext.extensionName, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) { - if (inst->extensions().contains(QByteArrayLiteral("VK_KHR_get_physical_device_properties2"))) { - requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); - vertexAttribDivisorAvailable = true; - } + if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) { + if (inst->extensions().contains(QByteArrayLiteral("VK_KHR_get_physical_device_properties2"))) { + requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); + vertexAttribDivisorAvailable = true; } } - QByteArrayList envExtList; - if (qEnvironmentVariableIsSet("QT_VULKAN_DEVICE_EXTENSIONS")) { - envExtList = qgetenv("QT_VULKAN_DEVICE_EXTENSIONS").split(';'); - for (auto ext : requestedDevExts) - envExtList.removeAll(ext); - for (const QByteArray &ext : envExtList) { - if (!ext.isEmpty()) + for (const QByteArray &ext : requestedDeviceExtensions) { + if (!ext.isEmpty()) { + if (devExts.contains(ext)) requestedDevExts.append(ext.constData()); + else + qWarning("Device extension %s is not supported", ext.constData()); } } + QByteArrayList envExtList = qgetenv("QT_VULKAN_DEVICE_EXTENSIONS").split(';'); + for (const QByteArray &ext : envExtList) { + if (!ext.isEmpty() && !requestedDevExts.contains(ext)) { + if (devExts.contains(ext)) + requestedDevExts.append(ext.constData()); + else + qWarning("Device extension %s is not supported", ext.constData()); + } + } + + if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) { + qCDebug(QRHI_LOG_INFO, "Enabling device extensions:"); + for (const char *ext : requestedDevExts) + qCDebug(QRHI_LOG_INFO, " %s", ext); + } + VkDeviceCreateInfo devInfo; memset(&devInfo, 0, sizeof(devInfo)); devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h index d4959196710..f8870dcd774 100644 --- a/src/gui/rhi/qrhivulkan_p.h +++ b/src/gui/rhi/qrhivulkan_p.h @@ -57,6 +57,7 @@ struct Q_GUI_EXPORT QRhiVulkanInitParams : public QRhiInitParams { QVulkanInstance *inst = nullptr; QWindow *window = nullptr; + QByteArrayList deviceExtensions; }; struct Q_GUI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index 0f0a89cbff2..a6bcb7e7b67 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -810,6 +810,7 @@ public: QVulkanInstance *inst = nullptr; QWindow *maybeWindow = nullptr; + QByteArrayList requestedDeviceExtensions; bool importedDevice = false; VkPhysicalDevice physDev = VK_NULL_HANDLE; VkDevice dev = VK_NULL_HANDLE; From 4cff6e102dc65693d4f535079c72b0f8a63e8ebf Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 2 Mar 2020 17:23:28 +0100 Subject: [PATCH 24/41] rhi: Include an arrayDims vector in InOutVariable too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use the this struct to describe combined image samplers and storage images as well. Especially with the former, it is not unlikely that we will need arrays, so e.g. layout(binding = 1) uniform samplerCube shadowCubes[8]. In this case the '8' is something that must be reported in to the reflection information. The new arrayDims member is expected to work exactly like the similarly named member in BlockVariable. Task-number: QTBUG-82624 Change-Id: I1fb8b0318906ff4c116c1a7ec23a399c6545c730 Reviewed-by: Christian Strømme --- src/gui/rhi/qshaderdescription.cpp | 23 ++++++++++++++++++++++- src/gui/rhi/qshaderdescription_p.h | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp index 96c8d082fcc..80cda259ec2 100644 --- a/src/gui/rhi/qshaderdescription.cpp +++ b/src/gui/rhi/qshaderdescription.cpp @@ -783,6 +783,8 @@ QDebug operator<<(QDebug dbg, const QShaderDescription::InOutVariable &var) dbg.nospace() << " imageFormat=" << imageFormatStr(var.imageFormat); if (var.imageFlags) dbg.nospace() << " imageFlags=" << var.imageFlags; + if (!var.arrayDims.isEmpty()) + dbg.nospace() << " array=" << var.arrayDims; dbg.nospace() << ')'; return dbg; } @@ -878,6 +880,12 @@ static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v (*obj)[imageFormatKey] = imageFormatStr(v.imageFormat); if (v.imageFlags) (*obj)[imageFlagsKey] = int(v.imageFlags); + if (!v.arrayDims.isEmpty()) { + QJsonArray dimArr; + for (int dim : v.arrayDims) + dimArr.append(dim); + (*obj)[arrayDimsKey] = dimArr; + } } static void serializeDecorations(QDataStream *stream, const QShaderDescription::InOutVariable &v) @@ -887,6 +895,9 @@ static void serializeDecorations(QDataStream *stream, const QShaderDescription:: (*stream) << v.descriptorSet; (*stream) << int(v.imageFormat); (*stream) << int(v.imageFlags); + (*stream) << v.arrayDims.count(); + for (int dim : v.arrayDims) + (*stream) << dim; } static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v) @@ -1124,6 +1135,11 @@ static QShaderDescription::InOutVariable inOutVar(const QJsonObject &obj) var.imageFormat = mapImageFormat(obj[imageFormatKey].toString()); if (obj.contains(imageFlagsKey)) var.imageFlags = QShaderDescription::ImageFlags(obj[imageFlagsKey].toInt()); + if (obj.contains(arrayDimsKey)) { + QJsonArray dimArr = obj[arrayDimsKey].toArray(); + for (int i = 0; i < dimArr.count(); ++i) + var.arrayDims.append(dimArr.at(i).toInt()); + } return var; } @@ -1137,6 +1153,10 @@ static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOu v->imageFormat = QShaderDescription::ImageFormat(f); (*stream) >> f; v->imageFlags = QShaderDescription::ImageFlags(f); + (*stream) >> f; + v->arrayDims.resize(f); + for (int i = 0; i < f; ++i) + (*stream) >> v->arrayDims[i]; } static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream) @@ -1420,7 +1440,8 @@ bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescr && lhs.binding == rhs.binding && lhs.descriptorSet == rhs.descriptorSet && lhs.imageFormat == rhs.imageFormat - && lhs.imageFlags == rhs.imageFlags; + && lhs.imageFlags == rhs.imageFlags + && lhs.arrayDims == rhs.arrayDims; } /*! diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h index 108fc32a56f..783aa384e15 100644 --- a/src/gui/rhi/qshaderdescription_p.h +++ b/src/gui/rhi/qshaderdescription_p.h @@ -216,6 +216,7 @@ public: int descriptorSet = -1; ImageFormat imageFormat = ImageFormatUnknown; ImageFlags imageFlags; + QVector arrayDims; }; struct BlockVariable { From 0378332bc1a6cf3592a4bf5f7e73fe10963168ca Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 3 Mar 2020 11:19:14 +0100 Subject: [PATCH 25/41] rhi: Use versioning in QShaderDescription serialization as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the first time that we add something to QShaderDescription after migrating to the non-JSON based serialization system. This now involves checking the "qsb version" when deserializing. Task-number: QTBUG-82624 Change-Id: I2bd875ef21e461559b878dccc5537cdfa43feaa2 Reviewed-by: Christian Strømme --- src/gui/rhi/qshader.cpp | 3 +- src/gui/rhi/qshader_p_p.h | 3 +- src/gui/rhi/qshaderdescription.cpp | 42 ++++++++++++---------- src/gui/rhi/qshaderdescription_p.h | 2 +- src/gui/rhi/qshaderdescription_p_p.h | 2 +- tests/auto/gui/rhi/qshader/tst_qshader.cpp | 4 +-- 6 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp index 69f4a682151..945f4820c2c 100644 --- a/src/gui/rhi/qshader.cpp +++ b/src/gui/rhi/qshader.cpp @@ -428,6 +428,7 @@ QShader QShader::fromSerialized(const QByteArray &data) ds >> intVal; d->qsbVersion = intVal; if (d->qsbVersion != QShaderPrivate::QSB_VERSION + && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_VAR_ARRAYDIMS && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_CBOR && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_BINDINGS) @@ -439,7 +440,7 @@ QShader QShader::fromSerialized(const QByteArray &data) ds >> intVal; d->stage = Stage(intVal); if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_CBOR) { - d->desc = QShaderDescription::deserialize(&ds); + d->desc = QShaderDescription::deserialize(&ds, d->qsbVersion); } else if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON) { QByteArray descBin; ds >> descBin; diff --git a/src/gui/rhi/qshader_p_p.h b/src/gui/rhi/qshader_p_p.h index 66ef18f3918..ec9d25971fd 100644 --- a/src/gui/rhi/qshader_p_p.h +++ b/src/gui/rhi/qshader_p_p.h @@ -57,7 +57,8 @@ QT_BEGIN_NAMESPACE struct Q_GUI_EXPORT QShaderPrivate { - static const int QSB_VERSION = 4; + static const int QSB_VERSION = 5; + static const int QSB_VERSION_WITHOUT_VAR_ARRAYDIMS = 4; static const int QSB_VERSION_WITH_CBOR = 3; static const int QSB_VERSION_WITH_BINARY_JSON = 2; static const int QSB_VERSION_WITHOUT_BINDINGS = 1; diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp index 80cda259ec2..f3ef5edd126 100644 --- a/src/gui/rhi/qshaderdescription.cpp +++ b/src/gui/rhi/qshaderdescription.cpp @@ -35,6 +35,7 @@ ****************************************************************************/ #include "qshaderdescription_p_p.h" +#include "qshader_p_p.h" #include #include #include @@ -402,10 +403,10 @@ QShaderDescription QShaderDescription::fromCbor(const QByteArray &data) return desc; } -QShaderDescription QShaderDescription::deserialize(QDataStream *stream) +QShaderDescription QShaderDescription::deserialize(QDataStream *stream, int version) { QShaderDescription desc; - QShaderDescriptionPrivate::get(&desc)->loadFromStream(stream); + QShaderDescriptionPrivate::get(&desc)->loadFromStream(stream, version); return desc; } @@ -1143,7 +1144,7 @@ static QShaderDescription::InOutVariable inOutVar(const QJsonObject &obj) return var; } -static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOutVariable *v) +static void deserializeDecorations(QDataStream *stream, int version, QShaderDescription::InOutVariable *v) { (*stream) >> v->location; (*stream) >> v->binding; @@ -1153,20 +1154,23 @@ static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOu v->imageFormat = QShaderDescription::ImageFormat(f); (*stream) >> f; v->imageFlags = QShaderDescription::ImageFlags(f); - (*stream) >> f; - v->arrayDims.resize(f); - for (int i = 0; i < f; ++i) - (*stream) >> v->arrayDims[i]; + + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_VAR_ARRAYDIMS) { + (*stream) >> f; + v->arrayDims.resize(f); + for (int i = 0; i < f; ++i) + (*stream) >> v->arrayDims[i]; + } } -static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream) +static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream, int version) { QShaderDescription::InOutVariable var; (*stream) >> var.name; int t; (*stream) >> t; var.type = QShaderDescription::VariableType(t); - deserializeDecorations(stream, &var); + deserializeDecorations(stream, version, &var); return var; } @@ -1196,7 +1200,7 @@ static QShaderDescription::BlockVariable blockVar(const QJsonObject &obj) return var; } -static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream *stream) +static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream *stream, int version) { QShaderDescription::BlockVariable var; (*stream) >> var.name; @@ -1216,7 +1220,7 @@ static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream * (*stream) >> count; var.structMembers.resize(count); for (int i = 0; i < count; ++i) - var.structMembers[i] = deserializeBlockMemberVar(stream); + var.structMembers[i] = deserializeBlockMemberVar(stream, version); return var; } @@ -1324,7 +1328,7 @@ void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc) } } -void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) +void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream, int version) { Q_ASSERT(ref.loadRelaxed() == 1); // must be detached @@ -1332,12 +1336,12 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) (*stream) >> count; inVars.resize(count); for (int i = 0; i < count; ++i) - inVars[i] = deserializeInOutVar(stream); + inVars[i] = deserializeInOutVar(stream, version); (*stream) >> count; outVars.resize(count); for (int i = 0; i < count; ++i) - outVars[i] = deserializeInOutVar(stream); + outVars[i] = deserializeInOutVar(stream, version); (*stream) >> count; uniformBlocks.resize(count); @@ -1351,7 +1355,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) (*stream) >> memberCount; uniformBlocks[i].members.resize(memberCount); for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) - uniformBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream); + uniformBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version); } (*stream) >> count; @@ -1363,7 +1367,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) (*stream) >> memberCount; pushConstantBlocks[i].members.resize(memberCount); for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) - pushConstantBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream); + pushConstantBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version); } (*stream) >> count; @@ -1378,7 +1382,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) (*stream) >> memberCount; storageBlocks[i].members.resize(memberCount); for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) - storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream); + storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version); } (*stream) >> count; @@ -1388,7 +1392,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) int t; (*stream) >> t; combinedImageSamplers[i].type = QShaderDescription::VariableType(t); - deserializeDecorations(stream, &combinedImageSamplers[i]); + deserializeDecorations(stream, version, &combinedImageSamplers[i]); } (*stream) >> count; @@ -1398,7 +1402,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) int t; (*stream) >> t; storageImages[i].type = QShaderDescription::VariableType(t); - deserializeDecorations(stream, &storageImages[i]); + deserializeDecorations(stream, version, &storageImages[i]); } for (size_t i = 0; i < 3; ++i) diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h index 783aa384e15..e5650ed921c 100644 --- a/src/gui/rhi/qshaderdescription_p.h +++ b/src/gui/rhi/qshaderdescription_p.h @@ -78,7 +78,7 @@ public: static QShaderDescription fromBinaryJson(const QByteArray &data); #endif static QShaderDescription fromCbor(const QByteArray &data); - static QShaderDescription deserialize(QDataStream *stream); + static QShaderDescription deserialize(QDataStream *stream, int version); enum VariableType { Unknown = 0, diff --git a/src/gui/rhi/qshaderdescription_p_p.h b/src/gui/rhi/qshaderdescription_p_p.h index 69b6e811a11..ec2b0b6b4ce 100644 --- a/src/gui/rhi/qshaderdescription_p_p.h +++ b/src/gui/rhi/qshaderdescription_p_p.h @@ -82,7 +82,7 @@ struct Q_GUI_EXPORT QShaderDescriptionPrivate QJsonDocument makeDoc(); void writeToStream(QDataStream *stream); void loadDoc(const QJsonDocument &doc); - void loadFromStream(QDataStream *stream); + void loadFromStream(QDataStream *stream, int version); QAtomicInt ref; QVector inVars; diff --git a/tests/auto/gui/rhi/qshader/tst_qshader.cpp b/tests/auto/gui/rhi/qshader/tst_qshader.cpp index ab7115b74a1..378d1e85e71 100644 --- a/tests/auto/gui/rhi/qshader/tst_qshader.cpp +++ b/tests/auto/gui/rhi/qshader/tst_qshader.cpp @@ -368,7 +368,7 @@ void tst_QShader::serializeShaderDesc() QBuffer buf(&data); QDataStream ds(&buf); QVERIFY(buf.open(QIODevice::ReadOnly)); - QShaderDescription desc2 = QShaderDescription::deserialize(&ds); + QShaderDescription desc2 = QShaderDescription::deserialize(&ds, QShaderPrivate::QSB_VERSION); QVERIFY(!desc2.isValid()); } } @@ -400,7 +400,7 @@ void tst_QShader::serializeShaderDesc() QBuffer buf(&data); QDataStream ds(&buf); QVERIFY(buf.open(QIODevice::ReadOnly)); - QShaderDescription desc2 = QShaderDescription::deserialize(&ds); + QShaderDescription desc2 = QShaderDescription::deserialize(&ds, QShaderPrivate::QSB_VERSION); QVERIFY(desc2.isValid()); QCOMPARE(desc, desc2); } From eff6f77c1a38a5a89268b2dfbe9ab03cf9b2d652 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 27 Feb 2020 14:50:38 +0100 Subject: [PATCH 26/41] Add since 5.15 to new QVulkanInstance function Change-Id: Ib1fb6186a8c76d6848d5eda1756e7749383dae40 Reviewed-by: Eirik Aavitsland --- src/gui/vulkan/qvulkaninstance.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/vulkan/qvulkaninstance.cpp b/src/gui/vulkan/qvulkaninstance.cpp index 4b961a6f206..555dee3a9ce 100644 --- a/src/gui/vulkan/qvulkaninstance.cpp +++ b/src/gui/vulkan/qvulkaninstance.cpp @@ -781,6 +781,8 @@ bool QVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, uint32_t system dependent synchronization. For example, on Wayland this will add send a wl_surface.frame request in order to prevent the driver from blocking for minimized windows. + + \since 5.15 */ void QVulkanInstance::presentAboutToBeQueued(QWindow *window) { From bbc52a043da3b38a2d44a5502c8587a1fdc8ad59 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sat, 29 Feb 2020 16:47:55 +0100 Subject: [PATCH 27/41] rhi: Add a way to communicate back the native image layout for a QRhiTexture Relevant when doing custom rendering combined with QRhi, and only for APIs like Vulkan, where image layouts are a thing. As shown by demo apps, it is not currently possible to implement a correct application that renders or raytraces into a QRhiTexture's backing VkImage, and then uses that QRhiTexture in a QRhi-based render pass. This is because QRhi has no knowledge of the image layout if it changes due to commands recorded by direct Vulkan calls, and not via QRhi itself. So, except for certain simple cases, one will end up with incorrect image layout transitions in the barriers. (at minimum this will be caught by the validation layer) To remedy this, add a simple function taking the layout as int (we already do the opposite in nativeTexture()). Task-number: QTBUG-82435 Change-Id: Ic9e9c1b820b018f3b236742f99fe99fa6de63d36 Reviewed-by: Eirik Aavitsland --- src/gui/rhi/qrhi.cpp | 25 +++++++++++++++++++++++++ src/gui/rhi/qrhi_p.h | 1 + src/gui/rhi/qrhivulkan.cpp | 5 +++++ src/gui/rhi/qrhivulkan_p_p.h | 1 + 4 files changed, 32 insertions(+) diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 6243bcda58e..c805e23ad07 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -2339,6 +2339,31 @@ bool QRhiTexture::buildFrom(QRhiTexture::NativeTexture src) return false; } +/*! + With some graphics APIs, such as Vulkan, integrating custom rendering code + that uses the graphics API directly needs special care when it comes to + image layouts. This function allows communicating the expected layout the + image backing the QRhiTexture is in after the native rendering commands. + + For example, consider rendering into a QRhiTexture's VkImage directly with + Vulkan in a code block enclosed by QRhiCommandBuffer::beginExternal() and + QRhiCommandBuffer::endExternal(), followed by using the image for texture + sampling in a QRhi-based render pass. To avoid potentially incorrect image + layout transitions, this function can be used to indicate what the image + layout will be once the commands recorded in said code block complete. + + Calling this function makes sense only after + QRhiCommandBuffer::endExternal() and before a subsequent + QRhiCommandBuffer::beginPass(). + + This function has no effect with QRhi backends where the underlying + graphics API does not expose a concept of image layouts. + */ +void QRhiTexture::setNativeLayout(int layout) +{ + Q_UNUSED(layout); +} + /*! \class QRhiSampler \internal diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 8f53808d34c..17c911a5ff2 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -791,6 +791,7 @@ public: virtual bool build() = 0; virtual NativeTexture nativeTexture(); virtual bool buildFrom(NativeTexture src); + virtual void setNativeLayout(int layout); protected: QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_, diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 60ab15e89d6..a92c3e14e9c 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -5563,6 +5563,11 @@ QRhiTexture::NativeTexture QVkTexture::nativeTexture() return {&image, usageState.layout}; } +void QVkTexture::setNativeLayout(int layout) +{ + usageState.layout = VkImageLayout(layout); +} + VkImageView QVkTexture::imageViewForLevel(int level) { Q_ASSERT(level >= 0 && level < int(mipLevelCount)); diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index a6bcb7e7b67..fd65417e754 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -123,6 +123,7 @@ struct QVkTexture : public QRhiTexture bool build() override; bool buildFrom(NativeTexture src) override; NativeTexture nativeTexture() override; + void setNativeLayout(int layout) override; bool prepareBuild(QSize *adjustedSize = nullptr); bool finishBuild(); From dd0a197be40bdec1af02e58f50926afb11af9509 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 27 Feb 2020 14:58:10 +0100 Subject: [PATCH 28/41] QVulkanWindow: Remove queueCreateInfoModifier getter This is inconsistent with the other similar functions in QVulkanWindow, we do not provide getters for those either. Change-Id: If764b49f4b26ff14a2fa908b8d5b37429047250c Reviewed-by: Paul Olav Tvete --- src/gui/vulkan/qvulkanwindow.cpp | 13 ------------- src/gui/vulkan/qvulkanwindow.h | 1 - 2 files changed, 14 deletions(-) diff --git a/src/gui/vulkan/qvulkanwindow.cpp b/src/gui/vulkan/qvulkanwindow.cpp index e211863f21e..ee49cf0999b 100644 --- a/src/gui/vulkan/qvulkanwindow.cpp +++ b/src/gui/vulkan/qvulkanwindow.cpp @@ -1595,19 +1595,6 @@ bool QVulkanWindow::event(QEvent *e) \sa setQueueCreateInfoModifier() */ -/*! - Return a previously set queue create info modification function. - - \sa setQueueCreateInfoModifier() - - \since 5.15 - */ -QVulkanWindow::QueueCreateInfoModifier QVulkanWindow::queueCreateInfoModifier() const -{ - Q_D(const QVulkanWindow); - return d->queueCreateInfoModifier; -} - /*! Set a queue create info modification function. diff --git a/src/gui/vulkan/qvulkanwindow.h b/src/gui/vulkan/qvulkanwindow.h index 530b6c07447..511b9501bd4 100644 --- a/src/gui/vulkan/qvulkanwindow.h +++ b/src/gui/vulkan/qvulkanwindow.h @@ -106,7 +106,6 @@ public: typedef std::function &)> QueueCreateInfoModifier; - QueueCreateInfoModifier queueCreateInfoModifier() const; void setQueueCreateInfoModifier(QueueCreateInfoModifier modifier); bool isValid() const; From 8f8eb99991216c0833c23a0f068e036a70e3b060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Sat, 29 Feb 2020 11:39:58 +0100 Subject: [PATCH 29/41] QNetworkReply: Deprecate 'error' signal, use 'errorOccurred' instead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ChangeLog][Deprecation Notice] QNetworkReply::error() (the signal) is deprecated; superseded by errorOccurred() Change-Id: I4f1ef410fd22d34ddf87e89cc5709cc60703af95 Reviewed-by: MÃ¥rten Nordheim --- examples/xml/rsslisting/rsslisting.cpp | 2 +- src/network/access/qnetworkreply.cpp | 15 ++++++- src/network/access/qnetworkreply.h | 4 ++ src/network/access/qnetworkreplydataimpl.cpp | 2 +- src/network/access/qnetworkreplyhttpimpl.cpp | 2 +- src/network/access/qnetworkreplyimpl.cpp | 4 +- tests/auto/network/access/http2/tst_http2.cpp | 2 +- .../tst_qhttpnetworkconnection.cpp | 6 +-- .../tst_qnetworkaccessmanager.cpp | 2 +- .../qnetworkreply/tst_qnetworkreply.cpp | 42 +++++++++---------- tests/auto/network/access/spdy/tst_spdy.cpp | 2 +- 11 files changed, 48 insertions(+), 35 deletions(-) diff --git a/examples/xml/rsslisting/rsslisting.cpp b/examples/xml/rsslisting/rsslisting.cpp index d1b43735316..143ad6dcbad 100644 --- a/examples/xml/rsslisting/rsslisting.cpp +++ b/examples/xml/rsslisting/rsslisting.cpp @@ -131,7 +131,7 @@ void RSSListing::get(const QUrl &url) currentReply = manager.get(request); connect(currentReply, SIGNAL(readyRead()), this, SLOT(readyRead())); connect(currentReply, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged())); - connect(currentReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError))); + connect(currentReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError))); } /* diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index fb30bfd4f18..22c522756c5 100644 --- a/src/network/access/qnetworkreply.cpp +++ b/src/network/access/qnetworkreply.cpp @@ -91,7 +91,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() content. \note Do not delete the object in the slot connected to the - error() or finished() signal. Use deleteLater(). + errorOccurred() or finished() signal. Use deleteLater(). \sa QNetworkRequest, QNetworkAccessManager */ @@ -219,6 +219,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() the server response was detected \sa error() + \sa errorOccurred() */ /*! @@ -362,6 +363,14 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() /*! \fn void QNetworkReply::error(QNetworkReply::NetworkError code) + \obsolete + + Use errorOccurred() instead. +*/ + +/*! + \fn void QNetworkReply::errorOccurred(QNetworkReply::NetworkError code) + \since 5.15 This signal is emitted when the reply detects an error in processing. The finished() signal will probably follow, indicating @@ -442,7 +451,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() QNetworkAccessManager functions to do that. */ QNetworkReply::QNetworkReply(QObject *parent) - : QIODevice(*new QNetworkReplyPrivate, parent) + : QNetworkReply(*new QNetworkReplyPrivate, parent) { } @@ -452,6 +461,8 @@ QNetworkReply::QNetworkReply(QObject *parent) QNetworkReply::QNetworkReply(QNetworkReplyPrivate &dd, QObject *parent) : QIODevice(dd, parent) { + // Support the deprecated error() signal: + connect(this, &QNetworkReply::errorOccurred, this, QOverload::of(&QNetworkReply::error)); } /*! diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h index 4a402daa91a..82349f9e2a3 100644 --- a/src/network/access/qnetworkreply.h +++ b/src/network/access/qnetworkreply.h @@ -156,7 +156,11 @@ public Q_SLOTS: Q_SIGNALS: void metaDataChanged(); void finished(); +#if QT_DEPRECATED_SINCE(5,15) + QT_DEPRECATED_X("Use QNetworkReply::errorOccurred(QNetworkReply::NetworkError) instead") void error(QNetworkReply::NetworkError); +#endif + void errorOccurred(QNetworkReply::NetworkError); #if QT_CONFIG(ssl) void encrypted(); void sslErrors(const QList &errors); diff --git a/src/network/access/qnetworkreplydataimpl.cpp b/src/network/access/qnetworkreplydataimpl.cpp index 924c905b1ac..2f750204469 100644 --- a/src/network/access/qnetworkreplydataimpl.cpp +++ b/src/network/access/qnetworkreplydataimpl.cpp @@ -88,7 +88,7 @@ QNetworkReplyDataImpl::QNetworkReplyDataImpl(QObject *parent, const QNetworkRequ const QString msg = QCoreApplication::translate("QNetworkAccessDataBackend", "Invalid URI: %1").arg(url.toString()); setError(QNetworkReply::ProtocolFailure, msg); - QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProtocolFailure)); QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); } diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 12f402cabd9..2a9d2812569 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -2265,7 +2265,7 @@ void QNetworkReplyHttpImplPrivate::error(QNetworkReplyImpl::NetworkError code, c // note: might not be a good idea, since users could decide to delete us // which would delete the backend too... // maybe we should protect the backend - emit q->error(code); + emit q->errorOccurred(code); } void QNetworkReplyHttpImplPrivate::_q_metaDataChanged() diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 51bb3861864..a0b4ace470c 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -855,7 +855,7 @@ void QNetworkReplyImplPrivate::error(QNetworkReplyImpl::NetworkError code, const // note: might not be a good idea, since users could decide to delete us // which would delete the backend too... // maybe we should protect the backend - emit q->error(code); + emit q->errorOccurred(code); } void QNetworkReplyImplPrivate::metaDataChanged() @@ -1128,7 +1128,7 @@ QDisabledNetworkReply::QDisabledNetworkReply(QObject *parent, "Network access is disabled."); setError(UnknownNetworkError, msg); - QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, UnknownNetworkError)); QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); } diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp index 6f94692cb19..6a07ae78fbd 100644 --- a/tests/auto/network/access/http2/tst_http2.cpp +++ b/tests/auto/network/access/http2/tst_http2.cpp @@ -513,7 +513,7 @@ void tst_Http2::goaway() replies[i] = manager->get(request); QCOMPARE(replies[i]->error(), QNetworkReply::NoError); void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) = - &QNetworkReply::error; + &QNetworkReply::errorOccurred; connect(replies[i], errorSignal, this, &tst_Http2::replyFinishedWithError); // Since we're using self-signed certificates, ignore SSL errors: replies[i]->ignoreSslErrors(); diff --git a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp index 57fa5a613c4..e8d4c773f0a 100644 --- a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp +++ b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp @@ -1005,10 +1005,8 @@ void tst_QHttpNetworkConnection::overlappingCloseAndWrite() for (int i = 0; i < 10; ++i) { QNetworkRequest request(url); QNetworkReply *reply = accessManager.get(request); - // Not using Qt5 connection syntax here because of overly baroque syntax to discern between - // different error() methods. - QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - &server, SLOT(onReply(QNetworkReply::NetworkError))); + QObject::connect(reply, &QNetworkReply::errorOccurred, + &server, &TestTcpServer::onReply); } QTRY_COMPARE(server.errorCodeReports, 10); diff --git a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp index 752655ee947..b5ded86d586 100644 --- a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp +++ b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp @@ -87,7 +87,7 @@ void tst_QNetworkAccessManager::networkAccessible() // When network is not accessible, all requests fail QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("http://www.example.org"))); QSignalSpy finishedSpy(reply, &QNetworkReply::finished); - QSignalSpy errorSpy(reply, QOverload::of(&QNetworkReply::error)); + QSignalSpy errorSpy(reply, &QNetworkReply::errorOccurred); QVERIFY(finishedSpy.wait()); QCOMPARE(reply->isFinished(), true); QCOMPARE(reply->errorString(), QStringLiteral("Network access is disabled.")); diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 65f355ca255..7d065f1248e 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -1371,7 +1371,7 @@ QString tst_QNetworkReply::runMultipartRequest(const QNetworkRequest &request, // the code below is copied from tst_QNetworkReply::runSimpleRequest, see below reply->setParent(this); connect(reply, SIGNAL(finished()), SLOT(finished())); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError())); + connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(gotError())); multiPart->setParent(reply.data()); returnCode = Timeout; @@ -1431,7 +1431,7 @@ QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op, code = Failure; } else { connect(reply, SIGNAL(finished()), SLOT(finished())); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError())); + connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(gotError())); int count = 0; loop = new QEventLoop; @@ -1466,7 +1466,7 @@ QString tst_QNetworkReply::runCustomRequest(const QNetworkRequest &request, reply.reset(manager.sendCustomRequest(request, verb, data)); reply->setParent(this); connect(reply, SIGNAL(finished()), SLOT(finished())); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError())); + connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(gotError())); returnCode = Timeout; loop = new QEventLoop; @@ -1503,7 +1503,7 @@ int tst_QNetworkReply::waitForFinish(QNetworkReplyPtr &reply) int count = 0; connect(reply, SIGNAL(finished()), SLOT(finished())); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError())); + connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(gotError())); returnCode = Success; loop = new QEventLoop; QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64))); @@ -1890,7 +1890,7 @@ void tst_QNetworkReply::getFromFtpAfterError() QNetworkRequest invalidRequest(QUrl("ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/invalid.txt")); QNetworkReplyPtr invalidReply; invalidReply.reset(manager.get(invalidRequest)); - QSignalSpy spy(invalidReply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy(invalidReply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QVERIFY(spy.wait()); QCOMPARE(invalidReply->error(), QNetworkReply::ContentNotFoundError); @@ -3911,7 +3911,7 @@ void tst_QNetworkReply::ioGetFromHttpBrokenServer() QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); QNetworkReplyPtr reply(manager.get(request)); - QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply), int(Failure)); @@ -5447,7 +5447,7 @@ void tst_QNetworkReply::rateControl() QNetworkRequest request("debugpipe://localhost:" + QString::number(sender.serverPort())); QNetworkReplyPtr reply(manager.get(request)); reply->setReadBufferSize(32768); - QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy errorSpy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); RateControlledReader reader(sender, reply.data(), rate, 20); @@ -5861,7 +5861,7 @@ void tst_QNetworkReply::nestedEventLoops() QNetworkReplyPtr reply(manager.get(request)); QSignalSpy finishedspy(reply.data(), SIGNAL(finished())); - QSignalSpy errorspy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy errorspy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); connect(reply, SIGNAL(finished()), SLOT(nestedEventLoops_slot())); QTestEventLoop::instance().enterLoop(20); @@ -6094,7 +6094,7 @@ void tst_QNetworkReply::authorizationError() QCOMPARE(reply->error(), QNetworkReply::NoError); - QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy errorSpy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QSignalSpy finishedSpy(reply.data(), SIGNAL(finished())); // now run the request: QCOMPARE(waitForFinish(reply), int(Failure)); @@ -7050,7 +7050,7 @@ void tst_QNetworkReply::qtbug4121unknownAuthentication() QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*))); - QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy errorSpy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); QTestEventLoop::instance().enterLoop(10); @@ -7371,7 +7371,7 @@ void tst_QNetworkReply::httpWithNoCredentialUsage() request.setAttribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Manual); QNetworkReplyPtr reply(manager.get(request)); - QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy errorSpy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); QTestEventLoop::instance().enterLoop(10); @@ -8083,7 +8083,7 @@ void tst_QNetworkReply::emitErrorForAllReplies() // QTBUG-36890 QNetworkRequest request(urls.at(a)); QNetworkReply *reply = manager.get(request); replies.append(reply); - QSignalSpy *errorSpy = new QSignalSpy(reply, SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy *errorSpy = new QSignalSpy(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError))); errorSpies.append(errorSpy); QSignalSpy *finishedSpy = new QSignalSpy(reply, SIGNAL(finished())); finishedSpies.append(finishedSpy); @@ -8474,7 +8474,7 @@ void tst_QNetworkReply::ioHttpChangeMaxRedirects() QNetworkReplyPtr reply(manager.get(request)); QSignalSpy redSpy(reply.data(), SIGNAL(redirected(QUrl))); - QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply), int(Failure)); @@ -8538,7 +8538,7 @@ void tst_QNetworkReply::ioHttpRedirectErrors() QTimer watchDog; watchDog.setSingleShot(true); - reply->connect(reply.data(), QOverload().of(&QNetworkReply::error), + reply->connect(reply.data(), &QNetworkReply::errorOccurred, [&eventLoop](QNetworkReply::NetworkError){ eventLoop.exit(Failure); }); @@ -8704,7 +8704,7 @@ void tst_QNetworkReply::ioHttpRedirectPolicyErrors() if (ssl) reply->ignoreSslErrors(); - QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply), int(Failure)); QCOMPARE(spy.count(), 1); @@ -9352,7 +9352,7 @@ void tst_QNetworkReply::getWithTimeout() QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); QNetworkReplyPtr reply(manager.get(request)); - QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply), int(Success)); @@ -9363,7 +9363,7 @@ void tst_QNetworkReply::getWithTimeout() server.stopTransfer = true; QNetworkReplyPtr reply2(manager.get(request)); - QSignalSpy spy2(reply2.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy2(reply2.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply2), int(Failure)); @@ -9374,7 +9374,7 @@ void tst_QNetworkReply::getWithTimeout() manager.setTransferTimeout(1000); QNetworkReplyPtr reply3(manager.get(request)); - QSignalSpy spy3(reply3.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy3(reply3.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply3), int(Failure)); @@ -9392,7 +9392,7 @@ void tst_QNetworkReply::postWithTimeout() request.setRawHeader("Content-Type", "application/octet-stream"); QByteArray postData("Just some nonsense"); QNetworkReplyPtr reply(manager.post(request, postData)); - QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply), int(Success)); @@ -9403,7 +9403,7 @@ void tst_QNetworkReply::postWithTimeout() server.stopTransfer = true; QNetworkReplyPtr reply2(manager.post(request, postData)); - QSignalSpy spy2(reply2.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy2(reply2.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply2), int(Failure)); @@ -9414,7 +9414,7 @@ void tst_QNetworkReply::postWithTimeout() manager.setTransferTimeout(1000); QNetworkReplyPtr reply3(manager.post(request, postData)); - QSignalSpy spy3(reply3.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy3(reply3.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply3), int(Failure)); diff --git a/tests/auto/network/access/spdy/tst_spdy.cpp b/tests/auto/network/access/spdy/tst_spdy.cpp index 5701f4911cc..1b0b3aec6b7 100644 --- a/tests/auto/network/access/spdy/tst_spdy.cpp +++ b/tests/auto/network/access/spdy/tst_spdy.cpp @@ -581,7 +581,7 @@ void tst_Spdy::errors() if (ignoreSslErrors) reply->ignoreSslErrors(); QSignalSpy finishedSpy(reply, SIGNAL(finished())); - QSignalSpy errorSpy(reply, SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy errorSpy(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); From 466d32160a23e6848fe0a42e74085c79071d7dec Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 3 Mar 2020 08:01:05 +0100 Subject: [PATCH 30/41] Suppress warnings where QString and its tests use SplitBehavior This is a follow-up to commit 895939c7f91d0c8424a0638c42d05cb42293a142 to fix deprecation warnings it added. Change-Id: I3d86655ec2c84c1bdcac9c70436075fc78f2f781 Reviewed-by: Volker Hilsheimer --- src/corelib/text/qstring.cpp | 3 +++ tests/auto/corelib/text/qstring/tst_qstring.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index a2c603c7768..68dec7cfff8 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -7748,7 +7748,10 @@ static ResultList splitString(const StringSource &source, const QChar *sep, #if QT_DEPRECATED_SINCE(5, 15) Qt::SplitBehavior mapSplitBehavior(QString::SplitBehavior sb) { +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED return sb & QString::SkipEmptyParts ? Qt::SkipEmptyParts : Qt::KeepEmptyParts; +QT_WARNING_POP } #endif diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index 7072cb9516d..bc2b19125a8 100644 --- a/tests/auto/corelib/text/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -5824,6 +5824,8 @@ void tst_QString::split(const QString &string, const QString &sep, QStringList r QVERIFY(list == result); } +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED list = str.split(sep, QString::KeepEmptyParts); QVERIFY(list == result); list = str.split(rx, QString::KeepEmptyParts); @@ -5846,6 +5848,7 @@ void tst_QString::split(const QString &string, const QString &sep, QStringList r list = str.split(sep.at(0), QString::SkipEmptyParts); QVERIFY(list == result); } +QT_WARNING_POP } void tst_QString::split() From e5f4e1405947bcecd78f15bd76162ad6b54c2502 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Wed, 12 Feb 2020 17:27:36 +0200 Subject: [PATCH 31/41] Examples: enable HighDPI scaling for examples on Android These examples show very tiny UI elements on Android devices, thus enabling HighDPI. Task-number: QTBUG-80717 Change-Id: I813801d5249dc1fcfc6f61a8d146f60dd19901f6 Reviewed-by: BogDan Vatra --- examples/widgets/graphicsview/collidingmice/main.cpp | 3 +++ examples/widgets/graphicsview/diagramscene/main.cpp | 3 +++ examples/widgets/itemviews/addressbook/main.cpp | 3 +++ examples/widgets/itemviews/spreadsheet/main.cpp | 4 ++++ examples/widgets/mainwindows/application/main.cpp | 3 +++ examples/widgets/mainwindows/dockwidgets/main.cpp | 3 +++ examples/widgets/painting/affine/main.cpp | 4 +++- examples/widgets/painting/concentriccircles/main.cpp | 3 +++ examples/widgets/painting/fontsampler/main.cpp | 3 +++ examples/widgets/painting/gradients/main.cpp | 3 +++ examples/widgets/painting/pathstroke/main.cpp | 3 +++ examples/widgets/tools/undo/main.cpp | 3 +++ examples/widgets/widgets/calculator/main.cpp | 3 +++ examples/widgets/widgets/elidedlabel/main.cpp | 3 +++ examples/widgets/widgets/scribble/main.cpp | 3 +++ examples/widgets/widgets/sliders/main.cpp | 3 +++ 16 files changed, 49 insertions(+), 1 deletion(-) diff --git a/examples/widgets/graphicsview/collidingmice/main.cpp b/examples/widgets/graphicsview/collidingmice/main.cpp index ef6d6cca644..c9ad90260f2 100644 --- a/examples/widgets/graphicsview/collidingmice/main.cpp +++ b/examples/widgets/graphicsview/collidingmice/main.cpp @@ -58,6 +58,9 @@ static constexpr int MouseCount = 7; //! [0] int main(int argc, char **argv) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); //! [0] diff --git a/examples/widgets/graphicsview/diagramscene/main.cpp b/examples/widgets/graphicsview/diagramscene/main.cpp index eefaa865540..3e321259c50 100644 --- a/examples/widgets/graphicsview/diagramscene/main.cpp +++ b/examples/widgets/graphicsview/diagramscene/main.cpp @@ -55,6 +55,9 @@ int main(int argv, char *args[]) { Q_INIT_RESOURCE(diagramscene); +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argv, args); MainWindow mainWindow; diff --git a/examples/widgets/itemviews/addressbook/main.cpp b/examples/widgets/itemviews/addressbook/main.cpp index 0731287cdd3..86a11c58504 100644 --- a/examples/widgets/itemviews/addressbook/main.cpp +++ b/examples/widgets/itemviews/addressbook/main.cpp @@ -55,6 +55,9 @@ //! [0] int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); MainWindow mw; mw.show(); diff --git a/examples/widgets/itemviews/spreadsheet/main.cpp b/examples/widgets/itemviews/spreadsheet/main.cpp index 548dc8d6045..968312d097a 100644 --- a/examples/widgets/itemviews/spreadsheet/main.cpp +++ b/examples/widgets/itemviews/spreadsheet/main.cpp @@ -56,6 +56,10 @@ int main(int argc, char **argv) { Q_INIT_RESOURCE(spreadsheet); +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif + QApplication app(argc, argv); SpreadSheet sheet(10, 6); sheet.setWindowIcon(QPixmap(":/images/interview.png")); diff --git a/examples/widgets/mainwindows/application/main.cpp b/examples/widgets/mainwindows/application/main.cpp index 78db7134a33..b46e1116dc6 100644 --- a/examples/widgets/mainwindows/application/main.cpp +++ b/examples/widgets/mainwindows/application/main.cpp @@ -58,6 +58,9 @@ int main(int argc, char *argv[]) { Q_INIT_RESOURCE(application); +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); QCoreApplication::setOrganizationName("QtProject"); diff --git a/examples/widgets/mainwindows/dockwidgets/main.cpp b/examples/widgets/mainwindows/dockwidgets/main.cpp index ff3ba506a8b..bf3ad9bcf76 100644 --- a/examples/widgets/mainwindows/dockwidgets/main.cpp +++ b/examples/widgets/mainwindows/dockwidgets/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); Q_INIT_RESOURCE(dockwidgets); MainWindow mainWin; diff --git a/examples/widgets/painting/affine/main.cpp b/examples/widgets/painting/affine/main.cpp index 6ce8efe4825..641fc5c204f 100644 --- a/examples/widgets/painting/affine/main.cpp +++ b/examples/widgets/painting/affine/main.cpp @@ -55,7 +55,9 @@ int main(int argc, char **argv) { Q_INIT_RESOURCE(affine); - +#ifdef Q_OS_ANDROID + qputenv("QT_SCALE_FACTOR", "2"); +#endif QApplication app(argc, argv); XFormWidget xformWidget(nullptr); diff --git a/examples/widgets/painting/concentriccircles/main.cpp b/examples/widgets/painting/concentriccircles/main.cpp index d9fa2879c44..00456195d90 100644 --- a/examples/widgets/painting/concentriccircles/main.cpp +++ b/examples/widgets/painting/concentriccircles/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); Window window; window.show(); diff --git a/examples/widgets/painting/fontsampler/main.cpp b/examples/widgets/painting/fontsampler/main.cpp index 1bf46b226f2..cec6929827a 100644 --- a/examples/widgets/painting/fontsampler/main.cpp +++ b/examples/widgets/painting/fontsampler/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); MainWindow window; window.show(); diff --git a/examples/widgets/painting/gradients/main.cpp b/examples/widgets/painting/gradients/main.cpp index 0ddf7a45797..7ffb0326e94 100644 --- a/examples/widgets/painting/gradients/main.cpp +++ b/examples/widgets/painting/gradients/main.cpp @@ -55,6 +55,9 @@ int main(int argc, char *argv[]) { Q_INIT_RESOURCE(gradients); +#ifdef Q_OS_ANDROID + qputenv("QT_SCALE_FACTOR", "2"); +#endif QApplication app(argc, argv); diff --git a/examples/widgets/painting/pathstroke/main.cpp b/examples/widgets/painting/pathstroke/main.cpp index 57c85d73a32..35317480a38 100644 --- a/examples/widgets/painting/pathstroke/main.cpp +++ b/examples/widgets/painting/pathstroke/main.cpp @@ -55,6 +55,9 @@ int main(int argc, char **argv) { Q_INIT_RESOURCE(pathstroke); +#ifdef Q_OS_ANDROID + qputenv("QT_SCALE_FACTOR", "2"); +#endif QApplication app(argc, argv); diff --git a/examples/widgets/tools/undo/main.cpp b/examples/widgets/tools/undo/main.cpp index a5ec1b1b834..1a6dcf8c48d 100644 --- a/examples/widgets/tools/undo/main.cpp +++ b/examples/widgets/tools/undo/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char **argv) { Q_INIT_RESOURCE(undo); +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); diff --git a/examples/widgets/widgets/calculator/main.cpp b/examples/widgets/widgets/calculator/main.cpp index a034bb262e4..5f59d00ca6e 100644 --- a/examples/widgets/widgets/calculator/main.cpp +++ b/examples/widgets/widgets/calculator/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); Calculator calc; calc.show(); diff --git a/examples/widgets/widgets/elidedlabel/main.cpp b/examples/widgets/widgets/elidedlabel/main.cpp index 1c620c1d41d..58507766e7b 100644 --- a/examples/widgets/widgets/elidedlabel/main.cpp +++ b/examples/widgets/widgets/elidedlabel/main.cpp @@ -55,6 +55,9 @@ //! [0] int main( int argc, char *argv[] ) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication application( argc, argv ); TestWidget w; w.showFullScreen(); diff --git a/examples/widgets/widgets/scribble/main.cpp b/examples/widgets/widgets/scribble/main.cpp index 1bf46b226f2..cec6929827a 100644 --- a/examples/widgets/widgets/scribble/main.cpp +++ b/examples/widgets/widgets/scribble/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); MainWindow window; window.show(); diff --git a/examples/widgets/widgets/sliders/main.cpp b/examples/widgets/widgets/sliders/main.cpp index 99725195e5f..9bf18cb6d4c 100644 --- a/examples/widgets/widgets/sliders/main.cpp +++ b/examples/widgets/widgets/sliders/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); Window window; window.show(); From f03202b560e04d032f6485e65bcd430c4641894e Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 27 Feb 2020 19:30:18 +0100 Subject: [PATCH 32/41] Fix missing return-type in doc of qfloat16::copySign() Change-Id: I617081fe3335a85191be7882578644621d5ffede Reviewed-by: Thiago Macieira --- src/corelib/global/qfloat16.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp index 80a851e4e4d..3d82bbe95a6 100644 --- a/src/corelib/global/qfloat16.cpp +++ b/src/corelib/global/qfloat16.cpp @@ -147,7 +147,7 @@ QT_BEGIN_NAMESPACE /*! \since 5.15 - \fn qfloat16::copySign(qfloat16 sign) const noexcept + \fn qfloat16 qfloat16::copySign(qfloat16 sign) const noexcept Returns a qfloat16 with the sign of \a sign but the rest of its value taken from this qfloat16. Serves as qfloat16's equivalent of std::copysign(). From 8a6e1de87c32fcbf8d7946f688635a3ca2a78203 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Wed, 12 Feb 2020 17:28:43 +0200 Subject: [PATCH 33/41] Examples: update examples list for Android Explicitly set the list of examples that works on Android, as many have issues with layout or other issues. Task-number: QTBUG-80716 Change-Id: If71efc45a48c6236f8775e21e4cab6dc0129f024 Reviewed-by: BogDan Vatra Reviewed-by: Eskil Abrahamsen Blomfeldt --- doc/global/manifest-meta.qdocconf | 175 +++++++++++++++++------------- 1 file changed, 97 insertions(+), 78 deletions(-) diff --git a/doc/global/manifest-meta.qdocconf b/doc/global/manifest-meta.qdocconf index 3db67a3131c..f5e5dbf8db0 100644 --- a/doc/global/manifest-meta.qdocconf +++ b/doc/global/manifest-meta.qdocconf @@ -32,84 +32,103 @@ manifestmeta.filters = highlighted android thumbnail ios manifestmeta.highlighted.attributes = isHighlighted:true -manifestmeta.android.names = "QtQuick/Qt Quick Demo - Calqlatr" \ - "QtWidgets/Application Chooser Example" \ - "QtWidgets/Stickman Example" \ - "QtWidgets/Move Blocks Example" \ - "QtWidgets/Border Layout Example" \ - "QtWidgets/Flow Layout Example" \ - "QtWidgets/Dock Widgets Example" \ - "QtWidgets/Recent Files Example" \ - "QtWidgets/Concentric Circles Example" \ - "QtWidgets/Gradients" \ - "QtWidgets/Font Sampler Example" \ - "QtWidgets/Path Stroking" \ - "QtWidgets/Transformations Example" \ - "QtWidgets/Syntax Highlighter Example" \ - "QtWidgets/Calendar Example" \ - "QtWidgets/Analog Clock Example" \ - "QtWidgets/Calculator Example" \ - "QtWidgets/Mouse Button Tester" \ - "QtWidgets/Character Map Example" \ - "QtWidgets/Digital Clock Example" \ - "QtWidgets/Elided Label Example" \ - "QtWidgets/Sliders Example" \ - "QtWidgets/Tetrix Example" \ - "QtWidgets/Group Box Example" \ - "QtWidgets/Undo Framework" \ - "QtWidgets/Colliding Mice Example" \ - "QtWidgets/Diagram Scene Example" \ - "QtWidgets/Elastic Nodes Example" \ - "QtWidgets/Weather Anchor Layout Example" \ - "QtNetwork/Torrent Example" \ - "QtNetwork/Network Chat Example" \ - "QtSQL/Master Detail Example" \ - "QtLinguist/Arrow Pad Example" \ - "QtGui/Raster Window Example" \ - "QtGui/Analog Clock Window Example" \ - "QtAndroidExtras/Qt Notifier" \ - "QtMultimedia/QML Video Shader Effects Example" \ - "QtMultimedia/QML Video Example" \ - "QtMultimedia/QML Camera Example" \ - "QtSVG/Text Object Example" \ - "QtQML/Qt Quick Examples - XMLHttpRequest" \ - "QtQuick/Qt Quick Particles Examples - *" \ - "QtQuick/Qt Quick Examples - Touch Interaction" \ - "QtQuick/Scene Graph - Custom Geometry" \ - "QtQuick/Scene Graph - Graph" \ - "QtQuick/Scene Graph - OpenGL Under QML" \ - "QtQuick/Scene Graph - Painted Item" \ - "QtQuick/Scene Graph - Rendering FBOs" \ - "QtQuick/Scene Graph - Simple Material" \ - "QtQuick/Qt Quick Examples - Image Elements" \ - "QtQuick/Qt Quick Examples - Key Interaction" \ - "QtQuick/Qt Quick Examples - Text" \ - "QtQuick/Qt Quick Examples - Animation" \ - "QtQuick/Qt Quick Examples - Shader Effects" \ - "QtQuick/Qt Quick Examples - Canvas" \ - "QtQuick/Qt Quick Examples - MouseArea" \ - "QtQuick/Qt Quick Examples - Positioners" \ - "QtQuick/Qt Quick Examples - Right to Left" \ - "QtWidgets/Interview" \ - "QtWidgets/Spreadsheet" \ - "QtWidgets/Pixelator Example" \ - "QtWidgets/Animated Tiles Example" \ - "QtWidgets/Affine Transformations" \ - "QtWidgets/Image Composition Example" \ - "QtWidgets/Basic Drawing Example" \ - "QtWidgets/Vector Deformation" \ - "QtWidgets/Painter Paths Example" \ - "QtWidgets/Style Sheet Example" \ - "QtWidgets/Code Editor Example" \ - "QtWidgets/Scribble Example" \ - "QtWidgets/Line Edits Example" \ - "QtWidgets/Calendar Widget Example" \ - "QtWidgets/Completer Example" \ - "QtWidgets/I18N Example" \ - "QtQML/Extending QML - Grouped Properties Example" \ - "QtQML/Extending QML - Methods Example" \ - "QtQML/Extending QML - Signal Support Example" \ - "QtQML/Extending QML - Attached Properties Example" +manifestmeta.android.names = "Qt3D/Qt 3D: Basic Shapes C++ Example" \ + "Qt3D/Qt 3D: Planets QML Example" \ + "Qt3D/Qt 3D: Simple Custom Material QML Example" \ + "QtAndroidExtras/Qt Notifier" \ + "QtBluetooth/Bluetooth Low Energy Scanner Example" \ + "QtBluetooth/Bluetooth Scanner Example" \ + "QtBluetooth/QML Bluetooth Scanner Example" \ + "QtCharts/*" \ + "QtConcurrent/QtConcurrent Progress Dialog Example" \ + "QtDataVisualization/Audiolevels Example" \ + "QtDataVisualization/Qt Quick 2 Scatter Example" \ + "QtDataVisualization/Qt Quick 2 Surface Multiseries Example" \ + "QtGui/Analog Clock Window Example" \ + "QtGui/OpenGL Window Example" \ + "QtGui/Raster Window Example" \ + "QtLinguist/Arrow Pad Example" \ + "QtLinguistManual/Hello tr() Example" \ + "QtLocation/Map Viewer (QML)" \ + "QtLocation/Places Map (QML)" \ + "QtLocation/Plane Spotter (QML)" \ + "QtMultimedia/AudioEngine Example" \ + "QtMultimedia/Camera Example" \ + "QtMultimedia/QML Camera Example" \ + "QtMultimedia/QML Video Example" \ + "QtMultimedia/QML Video Shader Effects Example" \ + "QtNFC/Annotated URL Example" \ + "QtNFC/QML Poster Example" \ + "QtOpenGL/2D Painting Example" \ + "QtOpenGL/Hello GLES3 Example" \ + "QtOpenGL/Textures Example" \ + "QtPositioning/SatelliteInfo (C++/QML)" \ + "QtPositioning/Weather Info (C++/QML)" \ + "QtPurchasing/Qt Purchasing Examples - QtHangman" \ + "QtQML/Extending QML - Attached Properties Example" \ + "QtQML/Extending QML - Grouped Properties Example" \ + "QtQML/Extending QML - Methods Example" \ + "QtQML/Extending QML - Signal Support Example" \ + "QtQML/Qt Quick Examples - XMLHttpRequest" \ + "QtQml/Qt Quick Examples - XMLHttpRequest" \ + "QtQuick/*" \ + "QtQuickControls/*" \ + "QtQuickControls1/Qt Quick Controls 1 - Calendar Example" \ + "QtQuickControls1/Qt Quick Controls 1 - Gallery" \ + "QtQuickControls1/Qt Quick Controls 1 - Styles Example" \ + "QtQuickControls1/Qt Quick Controls 1 - Table View Example" \ + "QtQuickControls1/Qt Quick Controls 1 - Touch Gallery" \ + "QtQuickDialogs/*" \ + "QtQuickExtras/*" \ + "QtSCXML/Qt SCXML Calculator QML Example" \ + "QtSCXML/Qt SCXML Sudoku Example" \ + "QtSCXML/Qt SCXML Traffic Light Example (Dynamic)" \ + "QtSCXML/Qt SCXML Traffic Light QML Example (Dynamic)" \ + "QtSQL/Master Detail Example" \ + "QtSVG/Text Object Example" \ + "QtUiTools/Text Finder Example" \ + "QtWebView/Qt WebView Examples - Minibrowser" \ + "QtWidgets/Address Book Example" \ + "QtWidgets/Affine Transformations" \ + "QtWidgets/Analog Clock Example" \ + "QtWidgets/Animated Tiles Example" \ + "QtWidgets/Application Chooser Example" \ + "QtWidgets/Basic Layouts Example" \ + "QtWidgets/Border Layout Example" \ + "QtWidgets/Code Editor Example" \ + "QtWidgets/Colliding Mice Example" \ + "QtWidgets/Concentric Circles Example" \ + "QtWidgets/Digital Clock Example" \ + "QtWidgets/Dynamic Layouts Example" \ + "QtWidgets/Easing Curves Example" \ + "QtWidgets/Editable Tree Model Example" \ + "QtWidgets/Elided Label Example" \ + "QtWidgets/Event Transitions Example" \ + "QtWidgets/Fade Message Effect Example" \ + "QtWidgets/Flow Layout Example" \ + "QtWidgets/Font Sampler Example" \ + "QtWidgets/Frozen Column Example" \ + "QtWidgets/Gradients" \ + "QtWidgets/Group Box Example" \ + "QtWidgets/Image Composition Example" \ + "QtWidgets/Line Edits Example" \ + "QtWidgets/Mouse Button Tester" \ + "QtWidgets/Move Blocks Example" \ + "QtWidgets/Painter Paths Example" \ + "QtWidgets/Painter Paths Example" \ + "QtWidgets/Path Stroking" \ + "QtWidgets/Pixelator Example" \ + "QtWidgets/Recent Files Example" \ + "QtWidgets/SDI Example" \ + "QtWidgets/Scribble Example" \ + "QtWidgets/Simple Tree Model Example" \ + "QtWidgets/Sliders Example" \ + "QtWidgets/Spreadsheet" \ + "QtWidgets/Touch Dials Example" \ + "QtWidgets/Transformations Example" \ + "QtWidgets/Undo Framework" \ + "QtWidgets/Vector Deformation" \ + "QtWidgets/Wiggly Example" manifestmeta.android.tags = android From b711ee255515440b923a898f65f6afe13d63916f Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Sun, 23 Feb 2020 23:37:11 +0200 Subject: [PATCH 34/41] Examples: add scrollbar to allow viewing all options on Android This fix is most relevant for Android for affine and gradients examples. Currently, if the screen size is small the settings will show cramped and not usable. Thus, adding a scrollbar to fix that. Task-number: QTBUG-80717 Change-Id: Ic25460e5ce37a5c53bbcae48e11b6b787c45e999 Reviewed-by: BogDan Vatra --- examples/widgets/painting/affine/xform.cpp | 22 +++++++++++++----- .../widgets/painting/gradients/gradients.cpp | 23 ++++++++++++++----- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/examples/widgets/painting/affine/xform.cpp b/examples/widgets/painting/affine/xform.cpp index 4e7cb91ce1d..d7ed2125d23 100644 --- a/examples/widgets/painting/affine/xform.cpp +++ b/examples/widgets/painting/affine/xform.cpp @@ -787,8 +787,8 @@ XFormWidget::XFormWidget(QWidget *parent) view = new XFormView(this); view->setMinimumSize(200, 200); - QGroupBox *mainGroup = new QGroupBox(this); - mainGroup->setFixedWidth(180); + QWidget *mainContentWidget = new QWidget(); + QGroupBox *mainGroup = new QGroupBox(mainContentWidget); mainGroup->setTitle(tr("Affine Transformations")); QGroupBox *rotateGroup = new QGroupBox(mainGroup); @@ -837,10 +837,6 @@ XFormWidget::XFormWidget(QWidget *parent) whatsThisButton->setText(tr("What's This?")); whatsThisButton->setCheckable(true); - QHBoxLayout *viewLayout = new QHBoxLayout(this); - viewLayout->addWidget(view); - viewLayout->addWidget(mainGroup); - QVBoxLayout *rotateGroupLayout = new QVBoxLayout(rotateGroup); rotateGroupLayout->addWidget(rotateSlider); @@ -871,6 +867,20 @@ XFormWidget::XFormWidget(QWidget *parent) #endif mainGroupLayout->addWidget(whatsThisButton); + mainGroup->setLayout(mainGroupLayout); + + QVBoxLayout *mainContentLayout = new QVBoxLayout(); + mainContentLayout->addWidget(mainGroup); + mainContentWidget->setLayout(mainContentLayout); + + QScrollArea *mainScrollArea = new QScrollArea(); + mainScrollArea->setWidget(mainContentWidget); + mainScrollArea->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + + QHBoxLayout *viewLayout = new QHBoxLayout(this); + viewLayout->addWidget(view); + viewLayout->addWidget(mainScrollArea); + connect(rotateSlider, &QSlider::valueChanged, view, &XFormView::changeRotation); connect(shearSlider, &QSlider::valueChanged, view, &XFormView::changeShear); connect(scaleSlider, &QSlider::valueChanged, view, &XFormView::changeScale); diff --git a/examples/widgets/painting/gradients/gradients.cpp b/examples/widgets/painting/gradients/gradients.cpp index d62ae93a15c..cb1a0177e95 100644 --- a/examples/widgets/painting/gradients/gradients.cpp +++ b/examples/widgets/painting/gradients/gradients.cpp @@ -282,7 +282,8 @@ GradientWidget::GradientWidget(QWidget *parent) m_renderer = new GradientRenderer(this); - QGroupBox *mainGroup = new QGroupBox(this); + QWidget *mainContentWidget = new QWidget(); + QGroupBox *mainGroup = new QGroupBox(mainContentWidget); mainGroup->setTitle(tr("Gradients")); QGroupBox *editorGroup = new QGroupBox(mainGroup); @@ -327,11 +328,6 @@ GradientWidget::GradientWidget(QWidget *parent) whatsThisButton->setText(tr("What's This?")); whatsThisButton->setCheckable(true); - // Layouts - QHBoxLayout *mainLayout = new QHBoxLayout(this); - mainLayout->addWidget(m_renderer); - mainLayout->addWidget(mainGroup); - mainGroup->setFixedWidth(200); QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup); mainGroupLayout->addWidget(editorGroup); @@ -370,6 +366,21 @@ GradientWidget::GradientWidget(QWidget *parent) defaultsGroupLayout->addWidget(default3Button); editorGroupLayout->addWidget(default4Button); + mainGroup->setLayout(mainGroupLayout); + + QVBoxLayout *mainContentLayout = new QVBoxLayout(); + mainContentLayout->addWidget(mainGroup); + mainContentWidget->setLayout(mainContentLayout); + + QScrollArea *mainScrollArea = new QScrollArea(); + mainScrollArea->setWidget(mainContentWidget); + mainScrollArea->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + + // Layouts + QHBoxLayout *mainLayout = new QHBoxLayout(this); + mainLayout->addWidget(m_renderer); + mainLayout->addWidget(mainScrollArea); + connect(m_editor, &GradientEditor::gradientStopsChanged, m_renderer, &GradientRenderer::setGradientStops); connect(m_linearButton, &QRadioButton::clicked, From 23785face5a01bf63334fd32975718468d5f816e Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Sat, 16 Nov 2019 16:02:29 +0200 Subject: [PATCH 35/41] QEventDispatcherWin32: unregister event notifiers on close When QEventDispatcherWin32::closingDown() is called, threadData->eventDispatcher is already nullptr and the application will no longer process the events. Thus, just as it works for socket notifiers and timers, it makes sense to disable all active event notifiers at this point. Otherwise, it seems possible that an object in signalled state can provoke a data race in the notifier's callback on 'edp' pointer, if QWin32EventDispatcher destructor is running simultaneously. Task-number: QTBUG-64152 Task-number: QTBUG-70214 Change-Id: I6e77f3eeca1b0ea639021e73b86798cba0200ebf Reviewed-by: Edward Welbourne Reviewed-by: Volker Hilsheimer --- src/corelib/kernel/qeventdispatcher_win.cpp | 8 ++++++++ src/corelib/kernel/qeventdispatcher_win_p.h | 1 + src/corelib/kernel/qwineventnotifier.cpp | 5 +---- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 8616631603d..f2216d4113d 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -884,7 +884,11 @@ void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier) return; } #endif + doUnregisterEventNotifier(notifier); +} +void QEventDispatcherWin32::doUnregisterEventNotifier(QWinEventNotifier *notifier) +{ Q_D(QEventDispatcherWin32); int i = d->winEventNotifierList.indexOf(notifier); @@ -996,6 +1000,10 @@ void QEventDispatcherWin32::closingDown() doUnregisterSocketNotifier((*(d->sn_except.begin()))->obj); Q_ASSERT(d->active_fd.isEmpty()); + // clean up any eventnotifiers + while (!d->winEventNotifierList.isEmpty()) + doUnregisterEventNotifier(d->winEventNotifierList.first()); + // clean up any timers for (int i = 0; i < d->timerVec.count(); ++i) d->unregisterTimer(d->timerVec.at(i)); diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h index e6620178d86..a482c8b7dba 100644 --- a/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -110,6 +110,7 @@ protected: QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent = 0); virtual void sendPostedEvents(); void doUnregisterSocketNotifier(QSocketNotifier *notifier); + void doUnregisterEventNotifier(QWinEventNotifier *notifier); private: friend LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); diff --git a/src/corelib/kernel/qwineventnotifier.cpp b/src/corelib/kernel/qwineventnotifier.cpp index db5d44b276b..0c574e9a4b4 100644 --- a/src/corelib/kernel/qwineventnotifier.cpp +++ b/src/corelib/kernel/qwineventnotifier.cpp @@ -198,11 +198,8 @@ void QWinEventNotifier::setEnabled(bool enable) d->enabled = enable; QAbstractEventDispatcher *eventDispatcher = d->threadData.loadRelaxed()->eventDispatcher.loadRelaxed(); - if (!eventDispatcher) { // perhaps application is shutting down - if (!enable && d->waitHandle != nullptr) - d->unregisterWaitObject(); + if (!eventDispatcher) // perhaps application is shutting down return; - } if (Q_UNLIKELY(thread() != QThread::currentThread())) { qWarning("QWinEventNotifier: Event notifiers cannot be enabled or disabled from another thread"); return; From b4669b919048c1dbdac2b3e9b2e79f3d023aa078 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 26 Feb 2020 16:59:52 +0100 Subject: [PATCH 36/41] QMenu: hide when a QWidgetAction fires the trigged signal QMenu hides regularly when the user interacts with it, and manages the firing of signals based on that. It ignores if a QAction that is added to it fires the triggered() signal programmatically. With QWidgetActions added to the menu, the menu usually doesn't get interacted with directly, as the widget gets the input events. Since the action can be added to multiple menus, neither widget nor action can interact with the menus programmatically. Instead, the menu needs to hide when the widget action triggers. Test included that covers the case where a QWidgetAction is added to multiple menus that are visible. Documentation updated, and removed a redudant paragraph as a drive-by change. [ChangeLog][QtWidgets][QMenu] a popup menu hides when a QWidgetAction added to it fires the triggered signal. Change-Id: I69f378426a45c2e46cebdaa5e6f1b21c8fb03633 Fixes: QTBUG-10427 Reviewed-by: Richard Moe Gustavsen --- src/widgets/widgets/qmenu.cpp | 9 ++- .../auto/widgets/widgets/qmenu/tst_qmenu.cpp | 79 +++++++++++++++++++ 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index abe4e485c0d..0233fa136d8 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -1470,6 +1470,9 @@ void QMenuPrivate::_q_actionTriggered() } } activateCausedStack(list, action, QAction::Trigger, false); + // if a widget action fires, we need to hide the menu explicitly + if (qobject_cast(action)) + hideUpToMenuBar(); } } } @@ -1637,10 +1640,8 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) Widgets can be inserted into menus with the QWidgetAction class. Instances of this class are used to hold widgets, and are inserted - into menus with the addAction() overload that takes a QAction. - - Conversely, actions can be added to widgets with the addAction(), - addActions() and insertAction() functions. + into menus with the addAction() overload that takes a QAction. If the + QWidgetAction fires the triggered() signal, the menu will close. \warning To make QMenu visible on the screen, exec() or popup() should be used instead of show(). diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp index d7d3a934f8b..7e391384737 100644 --- a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp +++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp @@ -116,6 +116,7 @@ private slots: void QTBUG20403_nested_popup_on_shortcut_trigger(); void QTBUG47515_widgetActionEnterLeave(); void QTBUG8122_widgetActionCrashOnClose(); + void widgetActionTriggerClosesMenu(); void QTBUG_10735_crashWithDialog(); #ifdef Q_OS_MAC @@ -1407,6 +1408,84 @@ void tst_QMenu::QTBUG8122_widgetActionCrashOnClose() QTRY_VERIFY(menu->isHidden()); } +/*! + Test that a QWidgetAction that fires closes the menus that it is in. +*/ +void tst_QMenu::widgetActionTriggerClosesMenu() +{ + class ButtonAction : public QWidgetAction + { + public: + ButtonAction() + : QWidgetAction(nullptr) + {} + + void click() + { + if (pushButton) + pushButton->click(); + } + + protected: + QWidget *createWidget(QWidget *parent) + { + QPushButton *button = new QPushButton(QLatin1String("Button"), parent); + connect(button, &QPushButton::clicked, this, &QAction::trigger); + + if (!pushButton) + pushButton = button; + return button; + } + + private: + QPointer pushButton; + }; + + QMenu menu; + QMenu submenu; + + int menuTriggeredCount = 0; + int menuAboutToHideCount = 0; + QAction *actionTriggered = nullptr; + + connect(&menu, &QMenu::triggered, this, [&](QAction *action){ + ++menuTriggeredCount; + actionTriggered = action; + }); + connect (&menu, &QMenu::aboutToHide, this, [&](){ + ++menuAboutToHideCount; + }); + + QAction regularAction(QLatin1String("Action")); + ButtonAction widgetAction; + + submenu.addAction(®ularAction); + submenu.addAction(&widgetAction); + + menu.addMenu(&submenu); + menu.addAction(®ularAction); + menu.addAction(&widgetAction); + + menu.popup(QPoint(200,200)); + submenu.popup(QPoint(250,250)); + if (!QTest::qWaitForWindowExposed(&menu) || !QTest::qWaitForWindowExposed(&submenu)) + QSKIP("Failed to show menus, aborting test"); + + regularAction.trigger(); + QVERIFY(menu.isVisible()); + QVERIFY(submenu.isVisible()); + QCOMPARE(menuTriggeredCount, 1); + QCOMPARE(actionTriggered, ®ularAction); + menuTriggeredCount = 0; + actionTriggered = nullptr; + + widgetAction.click(); + QVERIFY(!menu.isVisible()); + QVERIFY(!submenu.isVisible()); + QCOMPARE(menuTriggeredCount, 1); + QCOMPARE(menuAboutToHideCount, 1); + QCOMPARE(actionTriggered, &widgetAction); +} class MyMenu : public QMenu { From 065ace2bca656467c3bc2ef760bfff1fd198dbdc Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 3 Mar 2020 11:29:23 +0100 Subject: [PATCH 37/41] Generate separate debug info for Qt tools too If Qt was configured with -separate-debug-info, Qt's tools should be separated from their debug information too. Fixes: QTBUG-56482 Change-Id: Ief0130db1787b767496d0052716183fe773460bf Reviewed-by: Ulf Hermann Reviewed-by: Kai Koehne --- mkspecs/features/qt_common.prf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/features/qt_common.prf b/mkspecs/features/qt_common.prf index 02460a2e0c2..ac24b03b6b9 100644 --- a/mkspecs/features/qt_common.prf +++ b/mkspecs/features/qt_common.prf @@ -20,11 +20,11 @@ qtConfig(c++1z): CONFIG += c++1z qtConfig(c++2a): CONFIG += c++2a qtConfig(c99): CONFIG += c99 qtConfig(c11): CONFIG += c11 +qtConfig(separate_debug_info): CONFIG += separate_debug_info qtConfig(stack-protector-strong): CONFIG += stack_protector_strong contains(TEMPLATE, .*lib) { # module and plugins unix:qtConfig(reduce_relocations): CONFIG += bsymbolic_functions - qtConfig(separate_debug_info): CONFIG += separate_debug_info !isEmpty(_QMAKE_SUPER_CACHE_): \ rplbase = $$dirname(_QMAKE_SUPER_CACHE_)/[^/][^/]* From 14420b359b2d14d202df8df841af5e88f16352a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C4=8Cuki=C4=87?= Date: Fri, 10 Jan 2020 18:13:41 +0100 Subject: [PATCH 38/41] Add operator-> to the key-value iterator for QHash and QMap This patch adds the arrow operator to the stl-like key-value iterator (QKeyValueIterator) for QMap and QHash. This allows using normal member access syntax it->first and it->second instead of having to use (*it).first and (*it).second. [ChangeLog][QtCore][Containers] Added operator-> to the key-value iterator for QHash/QMap. Change-Id: I9cfa6480784ebce147fcfbf37fec5ad0080e2899 Reviewed-by: Vitaly Fanaskov --- src/corelib/tools/qiterator.h | 26 +++++++++++++++++++- src/corelib/tools/qiterator.qdoc | 13 ++++++++-- tests/auto/corelib/tools/qhash/tst_qhash.cpp | 6 +++++ tests/auto/corelib/tools/qmap/tst_qmap.cpp | 6 +++++ 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/corelib/tools/qiterator.h b/src/corelib/tools/qiterator.h index 84a0e116ca0..c4665c7c87b 100644 --- a/src/corelib/tools/qiterator.h +++ b/src/corelib/tools/qiterator.h @@ -195,7 +195,6 @@ public: typedef typename Iterator::iterator_category iterator_category; typedef typename Iterator::difference_type difference_type; typedef std::pair value_type; - typedef const value_type *pointer; typedef const value_type &reference; QKeyValueIterator() = default; @@ -206,6 +205,31 @@ public: return std::pair(i.key(), i.value()); } + struct pointer { + pointer(value_type&& r_) + : r(std::move(r_)) + {} + + pointer() = default; + pointer(const pointer &other) = default; + pointer(pointer &&other) = default; + pointer& operator=(const pointer &other) = default; + pointer& operator=(pointer &&other) = default; + + value_type& operator*() const { + return r; + } + + value_type r; + const value_type *operator->() const { + return &r; + } + }; + + pointer operator->() const { + return pointer(std::pair(i.key(), i.value())); + } + friend bool operator==(QKeyValueIterator lhs, QKeyValueIterator rhs) noexcept { return lhs.i == rhs.i; } friend bool operator!=(QKeyValueIterator lhs, QKeyValueIterator rhs) noexcept { return lhs.i != rhs.i; } diff --git a/src/corelib/tools/qiterator.qdoc b/src/corelib/tools/qiterator.qdoc index 3531fb202c4..ed39fe28c3c 100644 --- a/src/corelib/tools/qiterator.qdoc +++ b/src/corelib/tools/qiterator.qdoc @@ -57,7 +57,7 @@ \internal */ -/*! \typedef QKeyValueIterator::pointer +/*! \struct QKeyValueIterator::pointer \internal */ @@ -75,11 +75,20 @@ Constructs a QKeyValueIterator on top of \a o. */ -/*! \fn template const T &QKeyValueIterator::operator*() const +/*! \fn template std::pair QKeyValueIterator::operator*() const Returns the current entry as a pair. */ +/*! \fn template pointer QKeyValueIterator::operator->() const + + Returns the current entry as a pointer-like object to the pair. + + \since 5.15 + + \sa operator*() +*/ + /*! \fn template bool operator==(QKeyValueIterator lhs, QKeyValueIterator rhs) \relates QKeyValueIterator diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp index b98ac382887..134b3ff4c0d 100644 --- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp +++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp @@ -1144,6 +1144,12 @@ void tst_QHash::keyValueIterator() entry_type pair(it.key(), it.value()); QCOMPARE(*key_value_it, pair); + QCOMPARE(key_value_it->first, pair.first); + QCOMPARE(key_value_it->second, pair.second); + QCOMPARE(&(*key_value_it).first, &it.key()); + QCOMPARE(&key_value_it->first, &it.key()); + QCOMPARE(&(*key_value_it).second, &it.value()); + QCOMPARE(&key_value_it->second, &it.value()); ++key_value_it; ++it; } diff --git a/tests/auto/corelib/tools/qmap/tst_qmap.cpp b/tests/auto/corelib/tools/qmap/tst_qmap.cpp index c3a8a88f0cb..ba4b190f06e 100644 --- a/tests/auto/corelib/tools/qmap/tst_qmap.cpp +++ b/tests/auto/corelib/tools/qmap/tst_qmap.cpp @@ -882,6 +882,12 @@ void tst_QMap::keyValueIterator() entry_type pair(it.key(), it.value()); QCOMPARE(*key_value_it, pair); + QCOMPARE(key_value_it->first, pair.first); + QCOMPARE(key_value_it->second, pair.second); + QCOMPARE(&(*key_value_it).first, &it.key()); + QCOMPARE(&key_value_it->first, &it.key()); + QCOMPARE(&(*key_value_it).second, &it.value()); + QCOMPARE(&key_value_it->second, &it.value()); ++key_value_it; ++it; } From 1edf586ed73596e1d53a0d612a77f86ea34a65bf Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 28 Feb 2020 08:26:49 -0800 Subject: [PATCH 39/41] QMimeXMLProvider: fix another issue with -no-mimetype-database The compiler must emit the destructor for the members of a class in an inline constructor, in case the constructor throws. This won't work in Qt 5.15 due to QList requiring knowing whether QMimeMagicRuleMatcher is trivial or not. Another solution would be to use QVector. Fixes: QTBUG-82547 Change-Id: Ia8b65350cd5d49debca9fffd15f79db872ed7c0c Reviewed-by: David Faure --- src/corelib/mimetypes/qmimeprovider.cpp | 10 +++++++++- src/corelib/mimetypes/qmimeprovider_p.h | 5 +---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp index 4aee772366f..9dba72923a4 100644 --- a/src/corelib/mimetypes/qmimeprovider.cpp +++ b/src/corelib/mimetypes/qmimeprovider.cpp @@ -664,7 +664,15 @@ QMimeXMLProvider::QMimeXMLProvider(QMimeDatabasePrivate *db, InternalDatabaseEnu load(data, size); } -#endif +#else // !QT_CONFIG(mimetype_database) +// never called in release mode, but some debug builds may need +// this to be defined. +QMimeXMLProvider::QMimeXMLProvider(QMimeDatabasePrivate *db, InternalDatabaseEnum) + : QMimeProviderBase(db, QString()) +{ + Q_UNREACHABLE(); +} +#endif // QT_CONFIG(mimetype_database) QMimeXMLProvider::QMimeXMLProvider(QMimeDatabasePrivate *db, const QString &directory) : QMimeProviderBase(db, directory) diff --git a/src/corelib/mimetypes/qmimeprovider_p.h b/src/corelib/mimetypes/qmimeprovider_p.h index c4e712b318c..9c919036846 100644 --- a/src/corelib/mimetypes/qmimeprovider_p.h +++ b/src/corelib/mimetypes/qmimeprovider_p.h @@ -135,13 +135,10 @@ public: enum InternalDatabaseEnum { InternalDatabase }; #if QT_CONFIG(mimetype_database) enum : bool { InternalDatabaseAvailable = true }; - QMimeXMLProvider(QMimeDatabasePrivate *db, InternalDatabaseEnum); #else enum : bool { InternalDatabaseAvailable = false }; - QMimeXMLProvider(QMimeDatabasePrivate *db, InternalDatabaseEnum) - : QMimeProviderBase(db, QString()) - { Q_UNREACHABLE(); }; #endif + QMimeXMLProvider(QMimeDatabasePrivate *db, InternalDatabaseEnum); QMimeXMLProvider(QMimeDatabasePrivate *db, const QString &directory); ~QMimeXMLProvider(); From 5d9d3ff3269f92366b022e17485fa4dd98f5ba95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 2 Mar 2020 19:36:26 +0100 Subject: [PATCH 40/41] macOS: Reduce save dialog extension filters to their last component NSSavePanel does not deal well with multi-part extensions, to the point where it will fail to open if that's the only acceptable extension. We follow Chromium's lead here and reduce the extension to its last component, which enables selecting and saving files such as 'foo.tar.gz'. To improve the user experience we always show file extensions when we detect a multi-part extension. This makes it clearer what the final extension will be, and avoids confusing macOS about the intention of the user when choosing a file that without the final extension also matches another known extension. Fixes: QTBUG-38303 Fixes: QTBUG-44227 Change-Id: Id0cee84f758c2cd59fcf1b339caa30f7da07dd1e Reviewed-by: Timur Pocheptsov --- .../platforms/cocoa/qcocoafiledialoghelper.mm | 59 +++++++++++++------ 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 6aa21d78d1f..8b76e456167 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -419,8 +419,7 @@ static QString strippedText(QString s) [mPopUpButton setHidden:chooseDirsOnly]; // TODO hide the whole sunken pane instead? if (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) { - const QStringList ext = [self acceptableExtensionsForSave]; - [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : qt_mac_QStringListToNSMutableArray(ext)]; + [self recomputeAcceptableExtensionsForSave]; } else { [mOpenPanel setAllowedFileTypes:nil]; // delegate panel:shouldEnableURL: does the file filtering for NSOpenPanel } @@ -457,25 +456,49 @@ static QString strippedText(QString s) } /* - Returns a list of extensions (e.g. "png", "jpg", "gif") - for the current name filter. If a filter do not conform - to the format *.xyz or * or *.*, an empty list - is returned meaning accept everything. + Computes a list of extensions (e.g. "png", "jpg", "gif") + for the current name filter, and updates the save panel. + + If a filter do not conform to the format *.xyz or * or *.*, + all files types are allowed. + + Extensions with more than one part (e.g. "tar.gz") are + reduced to their final part, as NSSavePanel does not deal + well with multi-part extensions. */ -- (QStringList)acceptableExtensionsForSave +- (void)recomputeAcceptableExtensionsForSave { - QStringList result; - for (int i=0; icount(); ++i) { - const QString &filter = mSelectedNameFilter->at(i); - if (filter.startsWith(QLatin1String("*.")) - && !filter.contains(QLatin1Char('?')) - && filter.count(QLatin1Char('*')) == 1) { - result += filter.mid(2); - } else { - return QStringList(); // Accept everything - } + QStringList fileTypes; + for (const QString &filter : *mSelectedNameFilter) { + if (!filter.startsWith(QLatin1String("*."))) + continue; + + if (filter.contains(QLatin1Char('?'))) + continue; + + if (filter.count(QLatin1Char('*')) != 1) + continue; + + auto extensions = filter.split('.', Qt::SkipEmptyParts); + fileTypes += extensions.last(); + + // Explicitly show extensions if we detect a filter + // that has a multi-part extension. This prevents + // confusing situations where the user clicks e.g. + // 'foo.tar.gz' and 'foo.tar' is populated in the + // file name box, but when then clicking save macOS + // will warn that the file needs to end in .gz, + // due to thinking the user tried to save the file + // as a 'tar' file instead. Unfortunately this + // property can only be set before the panel is + // shown, so it will not have any effect when + // swithcing filters in an already opened dialog. + if (extensions.size() > 2) + mSavePanel.extensionHidden = NO; } - return result; + + mSavePanel.allowedFileTypes = fileTypes.isEmpty() ? nil + : qt_mac_QStringListToNSMutableArray(fileTypes); } - (QString)removeExtensions:(const QString &)filter From 048f0a00fa7b46f531fbe3ed6d1babae9858e8c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 2 Mar 2020 16:08:05 +0100 Subject: [PATCH 41/41] macOS: Don't create QMacCGContext when printing We adopt the context of the print session, so the code is not needed, and would just produce a warning since QMacCGContext didn't know what to do about the printer paint device. Change-Id: I9ac079f5cb5d98022045632592d0e375710eecc3 Reviewed-by: Timur Pocheptsov --- .../platforms/cocoa/qpaintengine_mac.mm | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index 00b2267f0df..df71f766449 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -394,16 +394,19 @@ QCoreGraphicsPaintEngine::begin(QPaintDevice *pdev) d->cosmeticPenSize = 1; d->current.clipEnabled = false; d->pixelSize = QPoint(1,1); - QMacCGContext ctx(pdev); - d->hd = CGContextRetain(ctx); - if (d->hd) { - d->saveGraphicsState(); - d->orig_xform = CGContextGetCTM(d->hd); - if (d->shading) { - CGShadingRelease(d->shading); - d->shading = nullptr; + + if (pdev->devType() != QInternal::Printer) { + QMacCGContext ctx(pdev); + d->hd = CGContextRetain(ctx); + if (d->hd) { + d->saveGraphicsState(); + d->orig_xform = CGContextGetCTM(d->hd); + if (d->shading) { + CGShadingRelease(d->shading); + d->shading = nullptr; + } + d->setClip(nullptr); //clear the context's clipping } - d->setClip(nullptr); //clear the context's clipping } setActive(true);