diff options
Diffstat (limited to 'src')
68 files changed, 642 insertions, 401 deletions
diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp index 80a851e4e4..3d82bbe95a 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(). diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 8616631603..f2216d4113 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 e6620178d8..a482c8b7db 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 db5d44b276..0c574e9a4b 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; diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp index 4aee772366..9dba72923a 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 c4e712b318..9c91903684 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(); diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index da2c44bef6..757f248e8a 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -7626,7 +7626,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/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index e9fe34110a..47539141bd 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -1383,6 +1383,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() */ @@ -1884,6 +1888,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() */ @@ -2244,6 +2252,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 @@ -2641,6 +2653,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() */ @@ -4541,6 +4557,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 @@ -5580,6 +5600,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() */ diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 15f731a603..7ebc374d9f 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 <class Key, class T> int QHash<Key, T>::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 <class Key, class T> int QMultiHash<Key, T>::count(const Key &key) const - - Returns the number of items associated with the \a key. - - \sa contains(), insert() -*/ - /*! \fn template <class Key, class T> int QMultiHash<Key, T>::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 59883e3968..c87cf56988 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -309,10 +309,10 @@ public: QList<Key> keys(const T &value) const; QList<T> values() const; #if QT_DEPRECATED_SINCE(5, 15) - QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QList<Key> uniqueKeys() const; - QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QList<T> 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; + QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") QList<Key> uniqueKeys() const; + QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") QList<T> values(const Key &key) const; #endif + int count(const Key &key) const; class const_iterator; @@ -512,8 +512,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 @@ -711,6 +711,19 @@ Q_OUTOFLINE_TEMPLATE QList<T> QHash<Key, T>::values() const } template <class Key, class T> +Q_OUTOFLINE_TEMPLATE int QHash<Key, T>::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 <class Key, class T> Q_INLINE_TEMPLATE const T QHash<Key, T>::operator[](const Key &akey) const { return value(akey); @@ -1053,7 +1066,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<Key> uniqueKeys() const; @@ -1207,12 +1219,6 @@ Q_OUTOFLINE_TEMPLATE QList<T> QHash<Key, T>::values(const Key &akey) const } template <class Key, class T> -Q_OUTOFLINE_TEMPLATE int QHash<Key, T>::count(const Key &akey) const -{ - return static_cast<const QMultiHash<Key, T> *>(this)->count(akey); -} - -template <class Key, class T> Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::uniqueKeys() const { return static_cast<const QMultiHash<Key, T> *>(this)->uniqueKeys(); @@ -1232,19 +1238,6 @@ Q_OUTOFLINE_TEMPLATE QList<T> QMultiHash<Key, T>::values(const Key &akey) const return res; } -template <class Key, class T> -Q_OUTOFLINE_TEMPLATE int QMultiHash<Key, T>::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 Key, class T> class QHashIterator diff --git a/src/corelib/tools/qiterator.h b/src/corelib/tools/qiterator.h index 84a0e116ca..c4665c7c87 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<Key, T> value_type; - typedef const value_type *pointer; typedef const value_type &reference; QKeyValueIterator() = default; @@ -206,6 +205,31 @@ public: return std::pair<Key, T>(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<Key, T>(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 69f9d52ce5..8cfa665ffd 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<typename Key, typename T, class Iterator> const T &QKeyValueIterator<Key, T, Iterator>::operator*() const +/*! \fn template<typename Key, typename T, class Iterator> std::pair<Key, T> QKeyValueIterator<Key, T, Iterator>::operator*() const Returns the current entry as a pair. */ +/*! \fn template<typename Key, typename T, class Iterator> pointer QKeyValueIterator<Key, T, Iterator>::operator->() const + + Returns the current entry as a pointer-like object to the pair. + + \since 5.15 + + \sa operator*() +*/ + /*! \fn template<typename Key, typename T, class Iterator> bool operator==(QKeyValueIterator<Key, T, Iterator> lhs, QKeyValueIterator<Key, T, Iterator> rhs) \relates QKeyValueIterator diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp index 6d2b8f7a3e..25ea5f25d7 100644 --- a/src/corelib/tools/qmap.cpp +++ b/src/corelib/tools/qmap.cpp @@ -814,11 +814,10 @@ void QMapDataBase::freeData(QMapDataBase *d) */ /*! \fn template <class Key, class T> int QMap<Key, T>::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 <class Key, class T> int QMap<Key, T>::count() const @@ -2115,11 +2114,6 @@ void QMapDataBase::freeData(QMapDataBase *d) inserted one. */ -/*! \fn template <class Key, class T> int QMultiMap<Key, T>::count(const Key &key) const - - Returns the number of items associated with key \a key. -*/ - /*! \fn template <class Key, class T> QList<Key> QMultiMap<Key, T>::uniqueKeys() const \since 4.2 diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index a971919e54..6081019294 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -373,10 +373,10 @@ public: QList<Key> keys(const T &value) const; QList<T> values() const; #if QT_DEPRECATED_SINCE(5, 15) - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") QList<Key> uniqueKeys() const; - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") QList<T> 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<Key> uniqueKeys() const; + QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") QList<T> values(const Key &key) const; #endif + int count(const Key &key) const; inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); } @@ -559,9 +559,9 @@ public: iterator insert(const_iterator pos, const Key &key, const T &value); void insert(const QMap<Key, T> &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<Key, T> &unite(const QMap<Key, T> &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<Key, T> &unite(const QMap<Key, T> &other); #endif // STL compatibility @@ -655,6 +655,23 @@ Q_INLINE_TEMPLATE T &QMap<Key, T>::operator[](const Key &akey) } template <class Key, class T> +Q_INLINE_TEMPLATE int QMap<Key, T>::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 <class Key, class T> Q_INLINE_TEMPLATE bool QMap<Key, T>::contains(const Key &akey) const { return d->findNode(akey) != nullptr; @@ -1116,7 +1133,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<Key, T>::iterator find(const Key &key, const T &value) { @@ -1290,23 +1306,6 @@ Q_INLINE_TEMPLATE int QMultiMap<Key, T>::remove(const Key &key, const T &value) } template <class Key, class T> -Q_INLINE_TEMPLATE int QMultiMap<Key, T>::count(const Key &akey) const -{ - QMultiMap::Node *firstNode; - QMultiMap::Node *lastNode; - this->d->nodeRange(akey, &firstNode, &lastNode); - - typename QMap<Key, T>::const_iterator ci_first(firstNode); - const typename QMap<Key, T>::const_iterator ci_last(lastNode); - int cnt = 0; - while (ci_first != ci_last) { - ++cnt; - ++ci_first; - } - return cnt; -} - -template <class Key, class T> Q_INLINE_TEMPLATE int QMultiMap<Key, T>::count(const Key &key, const T &value) const { int n = 0; @@ -1334,12 +1333,6 @@ QList<T> QMap<Key, T>::values(const Key &key) const } template<class Key, class T> -int QMap<Key, T>::count(const Key &key) const -{ - return static_cast<const QMultiMap<Key, T> *>(this)->count(key); -} - -template<class Key, class T> typename QMap<Key, T>::iterator QMap<Key, T>::insertMulti(const Key &key, const T &value) { return static_cast<QMultiMap<Key, T> *>(this)->insert(key, value); diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index d447faaceb..d559913161 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -870,13 +870,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 33b5b9c501..fd044fc442 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 e6a3604ad4..5738148718 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 5d4da97395..9e12d2d081 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 195e58d283..16136e6be3 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 2f3811b759..f2faf93984 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 3cd15b3e4d..f06561690c 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 ae590a1944..db5f352d46 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 f9424b62bb..07fec929bf 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 a4dd88cd17..646e8df69e 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/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index c099ec9692..702c055fbb 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -1731,7 +1731,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; @@ -1782,8 +1782,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 2de0131640..6ecd908296 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -298,14 +298,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/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 7a0d53e1e4..c805e23ad0 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 */ @@ -2342,6 +2340,31 @@ bool QRhiTexture::buildFrom(QRhiTexture::NativeTexture src) } /*! + 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 \inmodule QtGui diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 8f53808d34..17c911a5ff 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/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index f7c7f4a9f2..7b583e6fd2 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) @@ -608,7 +613,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; @@ -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; @@ -725,7 +739,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 +771,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; @@ -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<int, int> 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<Buffer, 8> buffers; + QVarLengthArray<Texture, 8> textures; + QVarLengthArray<Sampler, 8> samplers; + QVarLengthArray<Uav, 8> 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<int, int> 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<int, int> 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<int, int> 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<int, int> nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps); + if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { + res[RBM_VERTEX].textures.append({ nativeBinding.first, texD->srv }); + res[RBM_VERTEX].samplers.append({ nativeBinding.second, samplerD->samplerState }); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - srbD->fssamplers.feed(b->binding, samplerD->samplerState); - srbD->fsshaderresources.feed(b->binding, texD->srv); + QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps); + if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { + res[RBM_FRAGMENT].textures.append({ nativeBinding.first, texD->srv }); + res[RBM_FRAGMENT].samplers.append({ nativeBinding.second, samplerD->samplerState }); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - srbD->cssamplers.feed(b->binding, samplerD->samplerState); - srbD->csshaderresources.feed(b->binding, texD->srv); + QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { + res[RBM_COMPUTE].textures.append({ nativeBinding.first, texD->srv }); + res[RBM_COMPUTE].samplers.append({ nativeBinding.second, samplerD->samplerState }); + } } } 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<int, int> 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<int, int> 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,31 +1967,79 @@ 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(); } -void QRhiD3D11::executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD) +void QRhiD3D11::executeBufferHostWrites(QD3D11Buffer *bufD) { if (!bufD->hasPendingDynamicUpdates) return; @@ -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<LPCWSTR>(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); @@ -2388,6 +2507,10 @@ bool QD3D11Buffer::build() QRhiBuffer::NativeBuffer QD3D11Buffer::nativeBuffer() { + if (m_type == Dynamic) { + QRHI_RES_RHI(QRhiD3D11); + rhiD->executeBufferHostWrites(this); + } return { { &buffer }, 1 }; } @@ -3133,6 +3256,7 @@ QD3D11ShaderResourceBindings::~QD3D11ShaderResourceBindings() void QD3D11ShaderResourceBindings::release() { sortedBindings.clear(); + boundResourceData.clear(); } bool QD3D11ShaderResourceBindings::build() @@ -3149,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; @@ -3191,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); } @@ -3401,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(); @@ -3459,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())); @@ -3550,20 +3680,23 @@ bool QD3D11GraphicsPipeline::build() if (cacheIt != rhiD->m_shaderCache.constEnd()) { switch (shaderStage.type()) { case QRhiShaderStage::Vertex: - vs = static_cast<ID3D11VertexShader *>(cacheIt->s); - vs->AddRef(); + vs.shader = static_cast<ID3D11VertexShader *>(cacheIt->s); + vs.shader->AddRef(); vsByteCode = cacheIt->bytecode; + vs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; break; case QRhiShaderStage::Fragment: - fs = static_cast<ID3D11PixelShader *>(cacheIt->s); - fs->AddRef(); + fs.shader = static_cast<ID3D11PixelShader *>(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; @@ -3576,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; @@ -3651,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<ID3D11ComputeShader *>(cacheIt->s); + cs.shader = static_cast<ID3D11ComputeShader *>(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 04751397f7..f749b612b5 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,8 +651,9 @@ 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 executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD); + void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, + const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]); + void executeBufferHostWrites(QD3D11Buffer *bufD); void bindShaderResources(QD3D11ShaderResourceBindings *srbD, const uint *dynOfsPairs, int dynOfsPairCount, bool offsetOnlyChange); @@ -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<QRhiShaderStage, Shader> m_shaderCache; diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 48a562ef1d..314c58b0b7 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<char *>(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 212b731b71..a5af5611a6 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 d378e2a4ad..a92c3e14e9 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<QVulkanExtension> devExts; uint32_t devExtCount = 0; f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, nullptr); - QVector<VkExtensionProperties> devExts(devExtCount); - f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, devExts.data()); + if (devExtCount) { + QVector<VkExtensionProperties> 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<const char *> 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; @@ -2903,7 +2927,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 +3324,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 +3342,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<char *>(p) + u.offset, u.data.constData(), size_t(u.data.size())); if (changeBegin == -1 || u.offset < changeBegin) @@ -3330,7 +3354,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 +4190,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 +4264,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 +4373,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 +4419,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 +5212,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; } @@ -5536,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.h b/src/gui/rhi/qrhivulkan_p.h index d495919671..f8870dcd77 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 6322882569..fd65417e75 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(); @@ -778,7 +779,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, @@ -810,6 +811,7 @@ public: QVulkanInstance *inst = nullptr; QWindow *maybeWindow = nullptr; + QByteArrayList requestedDeviceExtensions; bool importedDevice = false; VkPhysicalDevice physDev = VK_NULL_HANDLE; VkDevice dev = VK_NULL_HANDLE; diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp index 69f4a68215..945f4820c2 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 66ef18f391..ec9d25971f 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 96c8d082fc..f3ef5edd12 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 <QDebug> #include <QDataStream> #include <QJsonObject> @@ -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; } @@ -783,6 +784,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 +881,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 +896,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,10 +1136,15 @@ 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; } -static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOutVariable *v) +static void deserializeDecorations(QDataStream *stream, int version, QShaderDescription::InOutVariable *v) { (*stream) >> v->location; (*stream) >> v->binding; @@ -1137,16 +1154,23 @@ static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOu v->imageFormat = QShaderDescription::ImageFormat(f); (*stream) >> f; v->imageFlags = QShaderDescription::ImageFlags(f); + + 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; } @@ -1176,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; @@ -1196,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; } @@ -1304,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 @@ -1312,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); @@ -1331,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; @@ -1343,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; @@ -1358,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; @@ -1368,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; @@ -1378,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) @@ -1420,7 +1444,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 108fc32a56..e5650ed921 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, @@ -216,6 +216,7 @@ public: int descriptorSet = -1; ImageFormat imageFormat = ImageFormatUnknown; ImageFlags imageFlags; + QVector<int> arrayDims; }; struct BlockVariable { diff --git a/src/gui/rhi/qshaderdescription_p_p.h b/src/gui/rhi/qshaderdescription_p_p.h index 69b6e811a1..ec2b0b6b4c 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<QShaderDescription::InOutVariable> inVars; diff --git a/src/gui/text/qtextmarkdownimporter.cpp b/src/gui/text/qtextmarkdownimporter.cpp index 7e18a10895..5e75e7816b 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 f450da5eb3..f12b725d8e 100644 --- a/src/gui/text/qtextmarkdownimporter_p.h +++ b/src/gui/text/qtextmarkdownimporter_p.h @@ -56,6 +56,7 @@ #include <QtGui/qpalette.h> #include <QtGui/qtextdocument.h> #include <QtGui/qtextlist.h> +#include <QtCore/qpointer.h> #include <QtCore/qstack.h> QT_BEGIN_NAMESPACE @@ -113,7 +114,7 @@ private: #endif QString m_blockCodeLanguage; QVector<int> m_nonEmptyTableCells; // in the current row - QStack<QTextList *> m_listStack; + QStack<QPointer<QTextList>> m_listStack; QStack<QTextCharFormat> m_spanFormatStack; QFont m_monoFont; QPalette m_palette; diff --git a/src/gui/vulkan/qvulkaninstance.cpp b/src/gui/vulkan/qvulkaninstance.cpp index 4b961a6f20..555dee3a9c 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) { diff --git a/src/gui/vulkan/qvulkanwindow.cpp b/src/gui/vulkan/qvulkanwindow.cpp index e211863f21..ee49cf0999 100644 --- a/src/gui/vulkan/qvulkanwindow.cpp +++ b/src/gui/vulkan/qvulkanwindow.cpp @@ -1596,19 +1596,6 @@ bool QVulkanWindow::event(QEvent *e) */ /*! - 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. \sa queueCreateInfoModifier() diff --git a/src/gui/vulkan/qvulkanwindow.h b/src/gui/vulkan/qvulkanwindow.h index 530b6c0744..511b9501bd 100644 --- a/src/gui/vulkan/qvulkanwindow.h +++ b/src/gui/vulkan/qvulkanwindow.h @@ -106,7 +106,6 @@ public: typedef std::function<void(const VkQueueFamilyProperties *, uint32_t, QVector<VkDeviceQueueCreateInfo> &)> QueueCreateInfoModifier; - QueueCreateInfoModifier queueCreateInfoModifier() const; void setQueueCreateInfoModifier(QueueCreateInfoModifier modifier); bool isValid() const; diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index fb30bfd4f1..22c522756c 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<QNetworkReply::NetworkError>::of(&QNetworkReply::error)); } /*! diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h index 4a402daa91..82349f9e2a 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<QSslError> &errors); diff --git a/src/network/access/qnetworkreplydataimpl.cpp b/src/network/access/qnetworkreplydataimpl.cpp index 924c905b1a..2f75020446 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 c7d22be8f5..bb65660ba8 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -2253,7 +2253,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 51bb386186..a0b4ace470 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/src/plugins/imageformats/gif/qgifhandler.cpp b/src/plugins/imageformats/gif/qgifhandler.cpp index a672e92006..d45ebfb314 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 c6592043ce..f19777fa18 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 1982e05344..4c8ff7d489 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 328dfce47e..0d44a67dfc 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 c31e2db3c5..fed585a82e 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 fafa930c11..43ca17317a 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; diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp index ca16efe34f..07776a4a76 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<FolderIterator> m_currentIterator; - mutable QVector<QSharedPointer<FolderIterator>> m_stack; + QSharedPointer<FolderIterator> m_currentIterator; }; class AndroidAbstractFileEngine: public QAbstractFileEngine diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 6aa21d78d1..8b76e45616 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 -{ - QStringList result; - for (int i=0; i<mSelectedNameFilter->count(); ++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 - } +- (void)recomputeAcceptableExtensionsForSave +{ + 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 diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index d0e69bdca5..450329f569 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<QCocoaVulkanInstance *>(instance->handle())->createSurface(window); + return static_cast<QCocoaVulkanInstance *>(instance->handle())->surface(window); #endif } return nullptr; diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.h b/src/plugins/platforms/cocoa/qcocoavulkaninstance.h index 5fe6a612af..2a8d04757e 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 7ce78ee738..9e714859f2 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<QCocoaWindow *>(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; } @@ -81,7 +80,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); diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index cadb76d2e4..429c47dc3b 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); diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 77340387d8..8963f2ad17 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -343,7 +343,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/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index 53562c87dd..d6a5b29a71 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; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index e635463951..3dfffa6de6 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1954,10 +1954,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<QWindowSystemInterface::SynchronousDelivery>(window(), newScreen->screen()); } void QWindowsWindow::handleGeometryChange() diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 71ec47b053..5be04a984a 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -274,7 +274,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(); diff --git a/src/tools/uic/python/pythonwriteimports.cpp b/src/tools/uic/python/pythonwriteimports.cpp index d33b4c6210..95e039e6f0 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 <customwidget> if (modulePath.endsWith(QLatin1String(".h"))) modulePath.chop(2); diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index cae776159d..23292062cb 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -1473,6 +1473,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<QWidgetAction*>(action)) + hideUpToMenuBar(); } } } @@ -1640,10 +1643,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(). |