Merge remote-tracking branch 'origin/5.15' into dev
Conflicts: tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp tests/auto/network/access/spdy/tst_spdy.cpp Change-Id: I3196c5f7b34f2ffc9ef1e690d02d5b9bb3270a74
This commit is contained in:
commit
d14fd32d40
@ -144,7 +144,7 @@ public:
|
||||
private slots:
|
||||
|
||||
void handleNetworkData(QNetworkReply *networkReply) {
|
||||
if (!networkReply->error()) {
|
||||
if (!networkReply->networkError()) {
|
||||
if (!mapReplies.contains(networkReply)) {
|
||||
// Assume UTF-8 encoded
|
||||
QByteArray data = networkReply->readAll();
|
||||
|
@ -162,7 +162,7 @@ void SlippyMap::handleNetworkData(QNetworkReply *reply)
|
||||
{
|
||||
QImage img;
|
||||
QPoint tp = reply->request().attribute(QNetworkRequest::User).toPoint();
|
||||
if (!reply->error())
|
||||
if (!reply->networkError())
|
||||
if (!img.load(reply, 0))
|
||||
img = QImage();
|
||||
reply->deleteLater();
|
||||
|
@ -175,7 +175,7 @@ void DownloadManager::sslErrors(const QList<QSslError> &sslErrors)
|
||||
void DownloadManager::downloadFinished(QNetworkReply *reply)
|
||||
{
|
||||
QUrl url = reply->url();
|
||||
if (reply->error()) {
|
||||
if (reply->networkError()) {
|
||||
fprintf(stderr, "Download of %s failed: %s\n",
|
||||
url.toEncoded().constData(),
|
||||
qPrintable(reply->errorString()));
|
||||
|
@ -162,7 +162,7 @@ void DownloadManager::downloadFinished()
|
||||
progressBar.clear();
|
||||
output.close();
|
||||
|
||||
if (currentDownload->error()) {
|
||||
if (currentDownload->networkError()) {
|
||||
// download failed
|
||||
fprintf(stderr, "Failed: %s\n", qPrintable(currentDownload->errorString()));
|
||||
output.remove();
|
||||
|
@ -209,7 +209,7 @@ void GSuggestCompletion::preventSuggest()
|
||||
void GSuggestCompletion::handleNetworkData(QNetworkReply *networkReply)
|
||||
{
|
||||
QUrl url = networkReply->url();
|
||||
if (networkReply->error() == QNetworkReply::NoError) {
|
||||
if (networkReply->networkError() == QNetworkReply::NoError) {
|
||||
QVector<QString> choices;
|
||||
|
||||
QByteArray response(networkReply->readAll());
|
||||
|
@ -249,7 +249,7 @@ void HttpWindow::httpFinished()
|
||||
return;
|
||||
}
|
||||
|
||||
if (reply->error()) {
|
||||
if (reply->networkError()) {
|
||||
QFile::remove(fi.absoluteFilePath());
|
||||
statusLabel->setText(tr("Download failed:\n%1.").arg(reply->errorString()));
|
||||
downloadButton->setEnabled(true);
|
||||
|
@ -29,7 +29,7 @@ qtHaveModule(widgets) {
|
||||
|
||||
}
|
||||
|
||||
qtConfig(openssl): SUBDIRS += securesocketclient
|
||||
qtConfig(ssl): SUBDIRS += securesocketclient
|
||||
qtConfig(dtls): SUBDIRS += secureudpserver secureudpclient
|
||||
qtConfig(sctp): SUBDIRS += multistreamserver multistreamclient
|
||||
}
|
||||
|
@ -165,8 +165,8 @@ void TrackerClient::httpRequestDone(QNetworkReply *reply)
|
||||
return;
|
||||
}
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
emit connectionError(reply->error());
|
||||
if (reply->networkError() != QNetworkReply::NoError) {
|
||||
emit connectionError(reply->networkError());
|
||||
return;
|
||||
}
|
||||
|
||||
|
36
examples/widgets/doc/src/gallery.qdoc
Normal file
36
examples/widgets/doc/src/gallery.qdoc
Normal file
@ -0,0 +1,36 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the documentation of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:FDL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*!
|
||||
\example widgets/gallery
|
||||
\title Widgets Gallery Example
|
||||
\ingroup examples-widgets
|
||||
\brief The Widgets Gallery example shows widgets relevant for designing UIs.
|
||||
|
||||
This example demonstrates widgets typically used in dialogs and forms.
|
||||
It also allows for changing the style.
|
||||
*/
|
@ -75,8 +75,6 @@
|
||||
WidgetGallery::WidgetGallery(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
originalPalette = QApplication::palette();
|
||||
|
||||
styleComboBox = new QComboBox;
|
||||
const QString defaultStyleName = QApplication::style()->objectName();
|
||||
QStringList styleNames = QStyleFactory::keys();
|
||||
@ -162,10 +160,8 @@ void WidgetGallery::changeStyle(const QString &styleName)
|
||||
void WidgetGallery::changePalette()
|
||||
//! [7] //! [8]
|
||||
{
|
||||
if (useStylePaletteCheckBox->isChecked())
|
||||
QApplication::setPalette(QApplication::style()->standardPalette());
|
||||
else
|
||||
QApplication::setPalette(originalPalette);
|
||||
QApplication::setPalette(useStylePaletteCheckBox->isChecked() ?
|
||||
QApplication::style()->standardPalette() : QPalette());
|
||||
}
|
||||
//! [8]
|
||||
|
||||
|
@ -96,8 +96,6 @@ private:
|
||||
void createBottomRightGroupBox();
|
||||
void createProgressBar();
|
||||
|
||||
QPalette originalPalette;
|
||||
|
||||
QLabel *styleLabel;
|
||||
QComboBox *styleComboBox;
|
||||
QCheckBox *useStylePaletteCheckBox;
|
||||
|
@ -139,10 +139,12 @@ Q_CORE_EXPORT void *qMemSet(void *dest, int c, size_t n);
|
||||
// in. The idea here is to error or warn if otherwise implicit Qt
|
||||
// assumptions are not fulfilled on new hardware or compilers
|
||||
// (if this list becomes too long, consider factoring into a separate file)
|
||||
Q_STATIC_ASSERT_X(sizeof(int) == 4, "Qt assumes that int is 32 bits");
|
||||
Q_STATIC_ASSERT_X(UCHAR_MAX == 255, "Qt assumes that char is 8 bits");
|
||||
Q_STATIC_ASSERT_X(sizeof(int) == 4, "Qt assumes that int is 32 bits");
|
||||
Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined incorrectly");
|
||||
Q_STATIC_ASSERT_X(sizeof(float) == 4, "Qt assumes that float is 32 bits");
|
||||
Q_STATIC_ASSERT_X(sizeof(char16_t) == 2, "Qt assumes that char16_t is 16 bits");
|
||||
Q_STATIC_ASSERT_X(sizeof(char32_t) == 4, "Qt assumes that char32_t is 32 bits");
|
||||
|
||||
// While we'd like to check for __STDC_IEC_559__, as per ISO/IEC 9899:2011
|
||||
// Annex F (C11, normative for C++11), there are a few corner cases regarding
|
||||
|
@ -403,6 +403,7 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
|
||||
const QString absolutePath = isDir ? fileInfo.absoluteFilePath() : fileInfo.absolutePath();
|
||||
const uint flags = isDir
|
||||
? (FILE_NOTIFY_CHANGE_DIR_NAME
|
||||
| FILE_NOTIFY_CHANGE_ATTRIBUTES
|
||||
| FILE_NOTIFY_CHANGE_FILE_NAME)
|
||||
: (FILE_NOTIFY_CHANGE_DIR_NAME
|
||||
| FILE_NOTIFY_CHANGE_FILE_NAME
|
||||
|
@ -118,7 +118,7 @@ public:
|
||||
|
||||
int remainingTime(int timerId) final;
|
||||
|
||||
void wakeUp() final;
|
||||
void wakeUp() override;
|
||||
void interrupt() final;
|
||||
void flush() override;
|
||||
|
||||
|
@ -463,10 +463,10 @@ QT_BEGIN_NAMESPACE
|
||||
\c{\xHHHH} with more than 2 digits. A pattern like \c{\x2022} neeeds to
|
||||
be ported to \c{\x{2022}}, or it will match a space (\c{0x20}) followed
|
||||
by the string \c{"22"}. In general, it is highly recommended to always use
|
||||
curly braces with the \c{\\x} escape, no matter the amount of digits
|
||||
curly braces with the \c{\x} escape, no matter the amount of digits
|
||||
specified.
|
||||
|
||||
\li A 0-to-n quantification like \c{{,n}} needs to be ported to c{{0,n}} to
|
||||
\li A 0-to-n quantification like \c{{,n}} needs to be ported to \c{{0,n}} to
|
||||
preserve semantics. Otherwise, a pattern such as \c{\d{,3}} would
|
||||
actually match a digit followed by the exact string \c{"{,3}"}.
|
||||
|
||||
|
@ -5036,21 +5036,25 @@ bool QString::endsWith(QChar c, Qt::CaseSensitivity cs) const
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c true if the string only contains uppercase letters,
|
||||
otherwise returns \c false.
|
||||
Returns \c true if the string is uppercase, that is, it's identical
|
||||
to its toUpper() folding.
|
||||
|
||||
Note that this does \e not mean that the string does not contain
|
||||
lowercase letters (some lowercase letters do not have a uppercase
|
||||
folding; they are left unchanged by toUpper()).
|
||||
For more information, refer to the Unicode standard, section 3.13.
|
||||
|
||||
\since 5.12
|
||||
|
||||
\sa QChar::isUpper(), isLower()
|
||||
\sa QChar::toUpper(), isLower()
|
||||
*/
|
||||
bool QString::isUpper() const
|
||||
{
|
||||
if (isEmpty())
|
||||
return false;
|
||||
QStringIterator it(*this);
|
||||
|
||||
const QChar *d = data();
|
||||
|
||||
for (int i = 0, max = size(); i < max; ++i) {
|
||||
if (!d[i].isUpper())
|
||||
while (it.hasNext()) {
|
||||
uint uc = it.nextUnchecked();
|
||||
if (qGetProp(uc)->cases[QUnicodeTables::UpperCase].diff)
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -5058,21 +5062,25 @@ bool QString::isUpper() const
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c true if the string only contains lowercase letters,
|
||||
otherwise returns \c false.
|
||||
Returns \c true if the string is lowercase, that is, it's identical
|
||||
to its toLower() folding.
|
||||
|
||||
Note that this does \e not mean that the string does not contain
|
||||
uppercase letters (some uppercase letters do not have a lowercase
|
||||
folding; they are left unchanged by toLower()).
|
||||
For more information, refer to the Unicode standard, section 3.13.
|
||||
|
||||
\since 5.12
|
||||
|
||||
\sa QChar::isLower(), isUpper()
|
||||
\sa QChar::toLower(), isUpper()
|
||||
*/
|
||||
bool QString::isLower() const
|
||||
{
|
||||
if (isEmpty())
|
||||
return false;
|
||||
QStringIterator it(*this);
|
||||
|
||||
const QChar *d = data();
|
||||
|
||||
for (int i = 0, max = size(); i < max; ++i) {
|
||||
if (!d[i].isLower())
|
||||
while (it.hasNext()) {
|
||||
uint uc = it.nextUnchecked();
|
||||
if (qGetProp(uc)->cases[QUnicodeTables::LowerCase].diff)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,7 @@ public:
|
||||
{
|
||||
*this = reply;
|
||||
}
|
||||
inline QDBusReply(const QDBusReply &) = default;
|
||||
inline QDBusReply& operator=(const QDBusMessage &reply)
|
||||
{
|
||||
QVariant data(qMetaTypeId<Type>(), nullptr);
|
||||
|
@ -236,21 +236,6 @@ static bool qt_detectRTLLanguage()
|
||||
" and Arabic) to get proper widget layout.") == QLatin1String("RTL"));
|
||||
}
|
||||
|
||||
static void initPalette()
|
||||
{
|
||||
if (!QGuiApplicationPrivate::app_pal)
|
||||
if (const QPalette *themePalette = QGuiApplicationPrivate::platformTheme()->palette())
|
||||
QGuiApplicationPrivate::app_pal = new QPalette(*themePalette);
|
||||
if (!QGuiApplicationPrivate::app_pal)
|
||||
QGuiApplicationPrivate::app_pal = new QPalette(Qt::gray);
|
||||
}
|
||||
|
||||
static inline void clearPalette()
|
||||
{
|
||||
delete QGuiApplicationPrivate::app_pal;
|
||||
QGuiApplicationPrivate::app_pal = nullptr;
|
||||
}
|
||||
|
||||
static void initFontUnlocked()
|
||||
{
|
||||
if (!QGuiApplicationPrivate::app_font) {
|
||||
@ -605,8 +590,13 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
|
||||
The following parameters are available for \c {-platform windows}:
|
||||
|
||||
\list
|
||||
\li \c {altgr}, detect the key \c {AltGr} found on some keyboards as
|
||||
Qt::GroupSwitchModifier (since Qt 5.12).
|
||||
\li \c {dialogs=[xp|none]}, \c xp uses XP-style native dialogs and
|
||||
\c none disables them.
|
||||
|
||||
\li \c {dpiawareness=[0|1|2} Sets the DPI awareness of the process
|
||||
(see \l{High DPI Displays}, since Qt 5.4).
|
||||
\li \c {fontengine=freetype}, uses the FreeType font engine.
|
||||
\li \c {menus=[native|none]}, controls the use of native menus.
|
||||
|
||||
@ -616,10 +606,23 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
|
||||
provide hover signals. They are mainly intended for Qt Quick.
|
||||
By default, they will be used if the application is not an
|
||||
instance of QApplication or for Qt Quick Controls 2
|
||||
applications.
|
||||
applications (since Qt 5.10).
|
||||
|
||||
\li \c {altgr}, detect the key \c {AltGr} found on some keyboards as
|
||||
Qt::GroupSwitchModifier.
|
||||
\li \c {nocolorfonts} Turn off DirectWrite Color fonts
|
||||
(since Qt 5.8).
|
||||
|
||||
\li \c {nodirectwrite} Turn off DirectWrite fonts (since Qt 5.8).
|
||||
|
||||
\li \c {nomousefromtouch} Ignores mouse events synthesized
|
||||
from touch events by the operating system.
|
||||
|
||||
\li \c {nowmpointer} Switches from Pointer Input Messages handling
|
||||
to legacy mouse handling (since Qt 5.12).
|
||||
\li \c {reverse} Activates Right-to-left mode (experimental).
|
||||
Windows title bars will be shown accordingly in Right-to-left locales
|
||||
(since Qt 5.13).
|
||||
\li \c {tabletabsoluterange=<value>} Sets a value for mouse mode detection
|
||||
of WinTab tablets (Legacy, since Qt 5.3).
|
||||
\endlist
|
||||
|
||||
The following parameter is available for \c {-platform cocoa} (on macOS):
|
||||
@ -673,7 +676,7 @@ QGuiApplication::~QGuiApplication()
|
||||
d->session_manager = nullptr;
|
||||
#endif //QT_NO_SESSIONMANAGER
|
||||
|
||||
clearPalette();
|
||||
QGuiApplicationPrivate::clearPalette();
|
||||
QFontDatabase::removeAllApplicationFonts();
|
||||
|
||||
#ifndef QT_NO_CURSOR
|
||||
@ -1597,7 +1600,7 @@ void QGuiApplicationPrivate::init()
|
||||
if (platform_integration == nullptr)
|
||||
createPlatformIntegration();
|
||||
|
||||
initPalette();
|
||||
updatePalette();
|
||||
QFont::initialize();
|
||||
initThemeHints();
|
||||
|
||||
@ -3275,46 +3278,97 @@ QClipboard * QGuiApplication::clipboard()
|
||||
*/
|
||||
|
||||
/*!
|
||||
Returns the default application palette.
|
||||
Returns the current application palette.
|
||||
|
||||
Roles that have not been explicitly set will reflect the system's platform theme.
|
||||
|
||||
\sa setPalette()
|
||||
*/
|
||||
|
||||
QPalette QGuiApplication::palette()
|
||||
{
|
||||
initPalette();
|
||||
if (!QGuiApplicationPrivate::app_pal)
|
||||
QGuiApplicationPrivate::updatePalette();
|
||||
|
||||
return *QGuiApplicationPrivate::app_pal;
|
||||
}
|
||||
|
||||
void QGuiApplicationPrivate::updatePalette()
|
||||
{
|
||||
if (app_pal) {
|
||||
if (setPalette(*app_pal) && qGuiApp)
|
||||
qGuiApp->d_func()->handlePaletteChanged();
|
||||
} else {
|
||||
setPalette(QPalette());
|
||||
}
|
||||
}
|
||||
|
||||
void QGuiApplicationPrivate::clearPalette()
|
||||
{
|
||||
delete app_pal;
|
||||
app_pal = nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
Changes the default application palette to \a pal.
|
||||
Changes the application palette to \a pal.
|
||||
|
||||
The color roles from this palette are combined with the system's platform
|
||||
theme to form the application's final palette.
|
||||
|
||||
\sa palette()
|
||||
*/
|
||||
void QGuiApplication::setPalette(const QPalette &pal)
|
||||
{
|
||||
if (!QGuiApplicationPrivate::setPalette(pal))
|
||||
return;
|
||||
|
||||
QCoreApplication::setAttribute(Qt::AA_SetPalette);
|
||||
|
||||
if (qGuiApp)
|
||||
qGuiApp->d_func()->sendApplicationPaletteChange();
|
||||
if (QGuiApplicationPrivate::setPalette(pal) && qGuiApp)
|
||||
qGuiApp->d_func()->handlePaletteChanged();
|
||||
}
|
||||
|
||||
bool QGuiApplicationPrivate::setPalette(const QPalette &palette)
|
||||
{
|
||||
if (app_pal && palette.isCopyOf(*app_pal))
|
||||
// Resolve the palette against the theme palette, filling in
|
||||
// any missing roles, while keeping the original resolve mask.
|
||||
QPalette basePalette = qGuiApp ? qGuiApp->d_func()->basePalette() : Qt::gray;
|
||||
basePalette.resolve(0); // The base palette only contributes missing colors roles
|
||||
QPalette resolvedPalette = palette.resolve(basePalette);
|
||||
|
||||
if (app_pal && resolvedPalette == *app_pal && resolvedPalette.resolve() == app_pal->resolve())
|
||||
return false;
|
||||
|
||||
if (!app_pal)
|
||||
app_pal = new QPalette(palette);
|
||||
app_pal = new QPalette(resolvedPalette);
|
||||
else
|
||||
*app_pal = palette;
|
||||
*app_pal = resolvedPalette;
|
||||
|
||||
QCoreApplication::setAttribute(Qt::AA_SetPalette, app_pal->resolve() != 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the base palette used to fill in missing roles in
|
||||
the current application palette.
|
||||
|
||||
Normally this is the theme palette, but QApplication
|
||||
overrides this for compatibility reasons.
|
||||
*/
|
||||
QPalette QGuiApplicationPrivate::basePalette() const
|
||||
{
|
||||
return platformTheme() ? *platformTheme()->palette() : Qt::gray;
|
||||
}
|
||||
|
||||
void QGuiApplicationPrivate::handlePaletteChanged(const char *className)
|
||||
{
|
||||
if (!className) {
|
||||
Q_ASSERT(app_pal);
|
||||
emit qGuiApp->paletteChanged(*QGuiApplicationPrivate::app_pal);
|
||||
}
|
||||
|
||||
if (is_app_running && !is_app_closing) {
|
||||
QEvent event(QEvent::ApplicationPaletteChange);
|
||||
QGuiApplication::sendEvent(qGuiApp, &event);
|
||||
}
|
||||
}
|
||||
|
||||
void QGuiApplicationPrivate::applyWindowGeometrySpecificationTo(QWindow *window)
|
||||
{
|
||||
windowGeometrySpecification.applyTo(window);
|
||||
@ -4113,11 +4167,8 @@ QPixmap QGuiApplicationPrivate::getPixmapCursor(Qt::CursorShape cshape)
|
||||
|
||||
void QGuiApplicationPrivate::notifyThemeChanged()
|
||||
{
|
||||
if (!testAttribute(Qt::AA_SetPalette)) {
|
||||
clearPalette();
|
||||
initPalette();
|
||||
sendApplicationPaletteChange();
|
||||
}
|
||||
updatePalette();
|
||||
|
||||
if (!(applicationResourceFlags & ApplicationFontExplicitlySet)) {
|
||||
const auto locker = qt_scoped_lock(applicationFontMutex);
|
||||
clearFontUnlocked();
|
||||
@ -4126,20 +4177,6 @@ void QGuiApplicationPrivate::notifyThemeChanged()
|
||||
initThemeHints();
|
||||
}
|
||||
|
||||
void QGuiApplicationPrivate::sendApplicationPaletteChange(bool toAllWidgets, const char *className)
|
||||
{
|
||||
Q_UNUSED(toAllWidgets)
|
||||
|
||||
if (!className)
|
||||
emit qGuiApp->paletteChanged(*QGuiApplicationPrivate::app_pal);
|
||||
|
||||
if (!is_app_running || is_app_closing)
|
||||
return;
|
||||
|
||||
QEvent event(QEvent::ApplicationPaletteChange);
|
||||
QGuiApplication::sendEvent(QGuiApplication::instance(), &event);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(draganddrop)
|
||||
void QGuiApplicationPrivate::notifyDragStarted(const QDrag *drag)
|
||||
{
|
||||
|
@ -326,17 +326,22 @@ public:
|
||||
|
||||
static void resetCachedDevicePixelRatio();
|
||||
|
||||
static bool setPalette(const QPalette &palette);
|
||||
|
||||
protected:
|
||||
virtual void notifyThemeChanged();
|
||||
virtual void sendApplicationPaletteChange(bool toAllWidgets = false, const char *className = nullptr);
|
||||
|
||||
static bool setPalette(const QPalette &palette);
|
||||
virtual QPalette basePalette() const;
|
||||
virtual void handlePaletteChanged(const char *className = nullptr);
|
||||
|
||||
bool tryCloseRemainingWindows(QWindowList processedWindows);
|
||||
#if QT_CONFIG(draganddrop)
|
||||
virtual void notifyDragStarted(const QDrag *);
|
||||
#endif // QT_CONFIG(draganddrop)
|
||||
|
||||
private:
|
||||
static void clearPalette();
|
||||
static void updatePalette();
|
||||
|
||||
friend class QDragManager;
|
||||
|
||||
static QGuiApplicationPrivate *self;
|
||||
|
@ -269,6 +269,14 @@ QT_BEGIN_NAMESPACE
|
||||
#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
|
||||
#endif
|
||||
|
||||
#ifndef GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
|
||||
#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
|
||||
#endif
|
||||
|
||||
#ifndef GL_SHADER_STORAGE_BARRIER_BIT
|
||||
#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
|
||||
#endif
|
||||
|
||||
#ifndef GL_VERTEX_PROGRAM_POINT_SIZE
|
||||
#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
|
||||
#endif
|
||||
@ -1307,6 +1315,21 @@ QRhi::FrameOpResult QRhiGles2::finish()
|
||||
return QRhi::FrameOpSuccess;
|
||||
}
|
||||
|
||||
static bool bufferAccessIsWrite(QGles2Buffer::Access access)
|
||||
{
|
||||
return access == QGles2Buffer::AccessStorageWrite
|
||||
|| access == QGles2Buffer::AccessStorageReadWrite
|
||||
|| access == QGles2Buffer::AccessUpdate;
|
||||
}
|
||||
|
||||
static bool textureAccessIsWrite(QGles2Texture::Access access)
|
||||
{
|
||||
return access == QGles2Texture::AccessStorageWrite
|
||||
|| access == QGles2Texture::AccessStorageReadWrite
|
||||
|| access == QGles2Texture::AccessUpdate
|
||||
|| access == QGles2Texture::AccessFramebuffer;
|
||||
}
|
||||
|
||||
void QRhiGles2::trackedBufferBarrier(QGles2CommandBuffer *cbD, QGles2Buffer *bufD, QGles2Buffer::Access access)
|
||||
{
|
||||
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::NoPass); // this is for resource updates only
|
||||
@ -1314,7 +1337,7 @@ void QRhiGles2::trackedBufferBarrier(QGles2CommandBuffer *cbD, QGles2Buffer *buf
|
||||
if (access == prevAccess)
|
||||
return;
|
||||
|
||||
if (prevAccess == QGles2Buffer::AccessStorageWrite || prevAccess == QGles2Buffer::AccessStorageReadWrite) {
|
||||
if (bufferAccessIsWrite(prevAccess)) {
|
||||
// Generating the minimal barrier set is way too complicated to do
|
||||
// correctly (prevAccess is overwritten so we won't have proper
|
||||
// tracking across multiple passes) so setting all barrier bits will do
|
||||
@ -1335,7 +1358,7 @@ void QRhiGles2::trackedImageBarrier(QGles2CommandBuffer *cbD, QGles2Texture *tex
|
||||
if (access == prevAccess)
|
||||
return;
|
||||
|
||||
if (prevAccess == QGles2Texture::AccessStorageWrite || prevAccess == QGles2Texture::AccessStorageReadWrite) {
|
||||
if (textureAccessIsWrite(prevAccess)) {
|
||||
QGles2CommandBuffer::Command cmd;
|
||||
cmd.cmd = QGles2CommandBuffer::Command::Barrier;
|
||||
cmd.args.barrier.barriers = GL_ALL_BARRIER_BITS;
|
||||
@ -2273,26 +2296,21 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
||||
// subsequent pass.
|
||||
for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) {
|
||||
QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(it->stateAtPassBegin.access);
|
||||
if (accessBeforePass == QGles2Buffer::AccessStorageWrite
|
||||
|| accessBeforePass == QGles2Buffer::AccessStorageReadWrite)
|
||||
{
|
||||
if (bufferAccessIsWrite(accessBeforePass))
|
||||
barriers |= GL_ALL_BARRIER_BITS;
|
||||
}
|
||||
}
|
||||
for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) {
|
||||
QGles2Texture::Access accessBeforePass = QGles2Texture::Access(it->stateAtPassBegin.access);
|
||||
if (accessBeforePass == QGles2Texture::AccessStorageWrite
|
||||
|| accessBeforePass == QGles2Texture::AccessStorageReadWrite)
|
||||
{
|
||||
if (textureAccessIsWrite(accessBeforePass))
|
||||
barriers |= GL_ALL_BARRIER_BITS;
|
||||
}
|
||||
}
|
||||
if (barriers)
|
||||
if (barriers && caps.compute)
|
||||
f->glMemoryBarrier(barriers);
|
||||
}
|
||||
break;
|
||||
case QGles2CommandBuffer::Command::Barrier:
|
||||
f->glMemoryBarrier(cmd.args.barrier.barriers);
|
||||
if (caps.compute)
|
||||
f->glMemoryBarrier(cmd.args.barrier.barriers);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -2791,6 +2809,8 @@ void QRhiGles2::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch
|
||||
cbD->recordingPass = QGles2CommandBuffer::ComputePass;
|
||||
|
||||
cbD->resetCachedState();
|
||||
|
||||
cbD->computePassState.reset();
|
||||
}
|
||||
|
||||
void QRhiGles2::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||
@ -2823,11 +2843,96 @@ void QRhiGles2::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *p
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void qrhigl_accumulateComputeResource(T *writtenResources, QRhiResource *resource,
|
||||
QRhiShaderResourceBinding::Type bindingType,
|
||||
int loadTypeVal, int storeTypeVal, int loadStoreTypeVal)
|
||||
{
|
||||
int access = 0;
|
||||
if (bindingType == loadTypeVal) {
|
||||
access = QGles2CommandBuffer::ComputePassState::Read;
|
||||
} else {
|
||||
access = QGles2CommandBuffer::ComputePassState::Write;
|
||||
if (bindingType == loadStoreTypeVal)
|
||||
access |= QGles2CommandBuffer::ComputePassState::Read;
|
||||
}
|
||||
auto it = writtenResources->find(resource);
|
||||
if (it != writtenResources->end())
|
||||
it->first |= access;
|
||||
else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
|
||||
writtenResources->insert(resource, { access, true });
|
||||
}
|
||||
|
||||
void QRhiGles2::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
|
||||
{
|
||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::ComputePass);
|
||||
|
||||
if (cbD->currentComputeSrb) {
|
||||
GLbitfield barriers = 0;
|
||||
|
||||
// The key in the writtenResources map indicates that the resource was
|
||||
// written in a previous dispatch, whereas the value accumulates the
|
||||
// access mask in the current one.
|
||||
for (auto &accessAndIsNewFlag : cbD->computePassState.writtenResources)
|
||||
accessAndIsNewFlag = { 0, false };
|
||||
|
||||
QGles2ShaderResourceBindings *srbD = QRHI_RES(QGles2ShaderResourceBindings, cbD->currentComputeSrb);
|
||||
const int bindingCount = srbD->m_bindings.count();
|
||||
for (int i = 0; i < bindingCount; ++i) {
|
||||
const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data();
|
||||
switch (b->type) {
|
||||
case QRhiShaderResourceBinding::ImageLoad:
|
||||
case QRhiShaderResourceBinding::ImageStore:
|
||||
case QRhiShaderResourceBinding::ImageLoadStore:
|
||||
qrhigl_accumulateComputeResource(&cbD->computePassState.writtenResources,
|
||||
b->u.simage.tex,
|
||||
b->type,
|
||||
QRhiShaderResourceBinding::ImageLoad,
|
||||
QRhiShaderResourceBinding::ImageStore,
|
||||
QRhiShaderResourceBinding::ImageLoadStore);
|
||||
break;
|
||||
case QRhiShaderResourceBinding::BufferLoad:
|
||||
case QRhiShaderResourceBinding::BufferStore:
|
||||
case QRhiShaderResourceBinding::BufferLoadStore:
|
||||
qrhigl_accumulateComputeResource(&cbD->computePassState.writtenResources,
|
||||
b->u.sbuf.buf,
|
||||
b->type,
|
||||
QRhiShaderResourceBinding::BufferLoad,
|
||||
QRhiShaderResourceBinding::BufferStore,
|
||||
QRhiShaderResourceBinding::BufferLoadStore);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
|
||||
const int accessInThisDispatch = it->first;
|
||||
const bool isNewInThisDispatch = it->second;
|
||||
if (accessInThisDispatch && !isNewInThisDispatch) {
|
||||
if (it.key()->resourceType() == QRhiResource::Texture)
|
||||
barriers |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
|
||||
else
|
||||
barriers |= GL_SHADER_STORAGE_BARRIER_BIT;
|
||||
}
|
||||
// Anything that was previously written, but is only read now, can be
|
||||
// removed from the written list (because that previous write got a
|
||||
// corresponding barrier now).
|
||||
if (accessInThisDispatch == QGles2CommandBuffer::ComputePassState::Read)
|
||||
it = cbD->computePassState.writtenResources.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
if (barriers) {
|
||||
QGles2CommandBuffer::Command cmd;
|
||||
cmd.cmd = QGles2CommandBuffer::Command::Barrier;
|
||||
cmd.args.barrier.barriers = barriers;
|
||||
cbD->commands.append(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
QGles2CommandBuffer::Command cmd;
|
||||
cmd.cmd = QGles2CommandBuffer::Command::Dispatch;
|
||||
cmd.args.dispatch.x = GLuint(x);
|
||||
|
@ -521,6 +521,17 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
|
||||
QRhiShaderResourceBindings *currentComputeSrb;
|
||||
uint currentSrbGeneration;
|
||||
|
||||
struct ComputePassState {
|
||||
enum Access {
|
||||
Read = 0x01,
|
||||
Write = 0x02
|
||||
};
|
||||
QHash<QRhiResource *, QPair<int, bool> > writtenResources;
|
||||
void reset() {
|
||||
writtenResources.clear();
|
||||
}
|
||||
} computePassState;
|
||||
|
||||
QVector<QByteArray> dataRetainPool;
|
||||
QVector<QImage> imageRetainPool;
|
||||
|
||||
|
@ -2219,6 +2219,8 @@ void QRhiVulkan::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch
|
||||
|
||||
cbD->recordingPass = QVkCommandBuffer::ComputePass;
|
||||
|
||||
cbD->computePassState.reset();
|
||||
|
||||
if (cbD->useSecondaryCb)
|
||||
cbD->secondaryCbs.append(startSecondaryCommandBuffer());
|
||||
}
|
||||
@ -2267,15 +2269,152 @@ void QRhiVulkan::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *
|
||||
psD->lastActiveFrameSlot = currentFrameSlot;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void qrhivk_accumulateComputeResource(T *writtenResources, QRhiResource *resource,
|
||||
QRhiShaderResourceBinding::Type bindingType,
|
||||
int loadTypeVal, int storeTypeVal, int loadStoreTypeVal)
|
||||
{
|
||||
VkAccessFlags access = 0;
|
||||
if (bindingType == loadTypeVal) {
|
||||
access = VK_ACCESS_SHADER_READ_BIT;
|
||||
} else {
|
||||
access = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
if (bindingType == loadStoreTypeVal)
|
||||
access |= VK_ACCESS_SHADER_READ_BIT;
|
||||
}
|
||||
auto it = writtenResources->find(resource);
|
||||
if (it != writtenResources->end())
|
||||
it->first |= access;
|
||||
else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
|
||||
writtenResources->insert(resource, { access, true });
|
||||
}
|
||||
|
||||
void QRhiVulkan::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
|
||||
{
|
||||
QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
|
||||
Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::ComputePass);
|
||||
|
||||
// When there are multiple dispatches, read-after-write and
|
||||
// write-after-write need a barrier.
|
||||
QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
|
||||
QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
|
||||
if (cbD->currentComputeSrb) {
|
||||
// The key in the writtenResources map indicates that the resource was
|
||||
// written in a previous dispatch, whereas the value accumulates the
|
||||
// access mask in the current one.
|
||||
for (auto &accessAndIsNewFlag : cbD->computePassState.writtenResources)
|
||||
accessAndIsNewFlag = { 0, false };
|
||||
|
||||
QVkShaderResourceBindings *srbD = QRHI_RES(QVkShaderResourceBindings, cbD->currentComputeSrb);
|
||||
const int bindingCount = srbD->m_bindings.count();
|
||||
for (int i = 0; i < bindingCount; ++i) {
|
||||
const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data();
|
||||
switch (b->type) {
|
||||
case QRhiShaderResourceBinding::ImageLoad:
|
||||
case QRhiShaderResourceBinding::ImageStore:
|
||||
case QRhiShaderResourceBinding::ImageLoadStore:
|
||||
qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
|
||||
b->u.simage.tex,
|
||||
b->type,
|
||||
QRhiShaderResourceBinding::ImageLoad,
|
||||
QRhiShaderResourceBinding::ImageStore,
|
||||
QRhiShaderResourceBinding::ImageLoadStore);
|
||||
break;
|
||||
case QRhiShaderResourceBinding::BufferLoad:
|
||||
case QRhiShaderResourceBinding::BufferStore:
|
||||
case QRhiShaderResourceBinding::BufferLoadStore:
|
||||
qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
|
||||
b->u.sbuf.buf,
|
||||
b->type,
|
||||
QRhiShaderResourceBinding::BufferLoad,
|
||||
QRhiShaderResourceBinding::BufferStore,
|
||||
QRhiShaderResourceBinding::BufferLoadStore);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
|
||||
const int accessInThisDispatch = it->first;
|
||||
const bool isNewInThisDispatch = it->second;
|
||||
if (accessInThisDispatch && !isNewInThisDispatch) {
|
||||
if (it.key()->resourceType() == QRhiResource::Texture) {
|
||||
QVkTexture *texD = QRHI_RES(QVkTexture, it.key());
|
||||
VkImageMemoryBarrier barrier;
|
||||
memset(&barrier, 0, sizeof(barrier));
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
// won't care about subresources, pretend the whole resource was written
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||
barrier.oldLayout = texD->usageState.layout;
|
||||
barrier.newLayout = texD->usageState.layout;
|
||||
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
barrier.dstAccessMask = accessInThisDispatch;
|
||||
barrier.image = texD->image;
|
||||
imageBarriers.append(barrier);
|
||||
} else {
|
||||
QVkBuffer *bufD = QRHI_RES(QVkBuffer, it.key());
|
||||
VkBufferMemoryBarrier barrier;
|
||||
memset(&barrier, 0, sizeof(barrier));
|
||||
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
barrier.dstAccessMask = accessInThisDispatch;
|
||||
barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
|
||||
barrier.size = VK_WHOLE_SIZE;
|
||||
bufferBarriers.append(barrier);
|
||||
}
|
||||
}
|
||||
// Anything that was previously written, but is only read now, can be
|
||||
// removed from the written list (because that previous write got a
|
||||
// corresponding barrier now).
|
||||
if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
|
||||
it = cbD->computePassState.writtenResources.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if (cbD->useSecondaryCb) {
|
||||
df->vkCmdDispatch(cbD->secondaryCbs.last(), uint32_t(x), uint32_t(y), uint32_t(z));
|
||||
VkCommandBuffer secondaryCb = cbD->secondaryCbs.last();
|
||||
if (!imageBarriers.isEmpty()) {
|
||||
df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0, 0, nullptr,
|
||||
0, nullptr,
|
||||
imageBarriers.count(), imageBarriers.constData());
|
||||
}
|
||||
if (!bufferBarriers.isEmpty()) {
|
||||
df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0, 0, nullptr,
|
||||
bufferBarriers.count(), bufferBarriers.constData(),
|
||||
0, nullptr);
|
||||
}
|
||||
df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
|
||||
} else {
|
||||
QVkCommandBuffer::Command cmd;
|
||||
if (!imageBarriers.isEmpty()) {
|
||||
cmd.cmd = QVkCommandBuffer::Command::ImageBarrier;
|
||||
cmd.args.imageBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
cmd.args.imageBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
cmd.args.imageBarrier.count = imageBarriers.count();
|
||||
cmd.args.imageBarrier.index = cbD->pools.imageBarrier.count();
|
||||
cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.count());
|
||||
cbD->commands.append(cmd);
|
||||
}
|
||||
if (!bufferBarriers.isEmpty()) {
|
||||
cmd.cmd = QVkCommandBuffer::Command::BufferBarrier;
|
||||
cmd.args.bufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
cmd.args.bufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
cmd.args.bufferBarrier.count = bufferBarriers.count();
|
||||
cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.count();
|
||||
cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.count());
|
||||
cbD->commands.append(cmd);
|
||||
}
|
||||
cmd.cmd = QVkCommandBuffer::Command::Dispatch;
|
||||
cmd.args.dispatch.x = x;
|
||||
cmd.args.dispatch.y = y;
|
||||
@ -2465,7 +2604,9 @@ void QRhiVulkan::trackedBufferBarrier(QVkCommandBuffer *cbD, QVkBuffer *bufD, in
|
||||
cmd.cmd = QVkCommandBuffer::Command::BufferBarrier;
|
||||
cmd.args.bufferBarrier.srcStageMask = s.stage;
|
||||
cmd.args.bufferBarrier.dstStageMask = stage;
|
||||
cmd.args.bufferBarrier.desc = bufMemBarrier;
|
||||
cmd.args.bufferBarrier.count = 1;
|
||||
cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.count();
|
||||
cbD->pools.bufferBarrier.append(bufMemBarrier);
|
||||
cbD->commands.append(cmd);
|
||||
|
||||
s.access = access;
|
||||
@ -2507,7 +2648,9 @@ void QRhiVulkan::trackedImageBarrier(QVkCommandBuffer *cbD, QVkTexture *texD,
|
||||
cmd.cmd = QVkCommandBuffer::Command::ImageBarrier;
|
||||
cmd.args.imageBarrier.srcStageMask = srcStage;
|
||||
cmd.args.imageBarrier.dstStageMask = stage;
|
||||
cmd.args.imageBarrier.desc = barrier;
|
||||
cmd.args.imageBarrier.count = 1;
|
||||
cmd.args.imageBarrier.index = cbD->pools.imageBarrier.count();
|
||||
cbD->pools.imageBarrier.append(barrier);
|
||||
cbD->commands.append(cmd);
|
||||
|
||||
s.layout = layout;
|
||||
@ -2541,7 +2684,9 @@ void QRhiVulkan::subresourceBarrier(QVkCommandBuffer *cbD, VkImage image,
|
||||
cmd.cmd = QVkCommandBuffer::Command::ImageBarrier;
|
||||
cmd.args.imageBarrier.srcStageMask = srcStage;
|
||||
cmd.args.imageBarrier.dstStageMask = dstStage;
|
||||
cmd.args.imageBarrier.desc = barrier;
|
||||
cmd.args.imageBarrier.count = 1;
|
||||
cmd.args.imageBarrier.index = cbD->pools.imageBarrier.count();
|
||||
cbD->pools.imageBarrier.append(barrier);
|
||||
cbD->commands.append(cmd);
|
||||
}
|
||||
|
||||
@ -3409,12 +3554,12 @@ void QRhiVulkan::recordPrimaryCommandBuffer(QVkCommandBuffer *cbD)
|
||||
case QVkCommandBuffer::Command::ImageBarrier:
|
||||
df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
|
||||
0, 0, nullptr, 0, nullptr,
|
||||
1, &cmd.args.imageBarrier.desc);
|
||||
cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
|
||||
break;
|
||||
case QVkCommandBuffer::Command::BufferBarrier:
|
||||
df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
|
||||
0, 0, nullptr,
|
||||
1, &cmd.args.bufferBarrier.desc,
|
||||
cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
|
||||
0, nullptr);
|
||||
break;
|
||||
case QVkCommandBuffer::Command::BlitImage:
|
||||
|
@ -370,6 +370,13 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
|
||||
QVarLengthArray<VkCommandBuffer, 4> secondaryCbs;
|
||||
bool inExternal;
|
||||
|
||||
struct {
|
||||
QHash<QRhiResource *, QPair<VkAccessFlags, bool> > writtenResources;
|
||||
void reset() {
|
||||
writtenResources.clear();
|
||||
}
|
||||
} computePassState;
|
||||
|
||||
struct Command {
|
||||
enum Cmd {
|
||||
CopyBuffer,
|
||||
@ -429,12 +436,14 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
|
||||
struct {
|
||||
VkPipelineStageFlags srcStageMask;
|
||||
VkPipelineStageFlags dstStageMask;
|
||||
VkImageMemoryBarrier desc;
|
||||
int count;
|
||||
int index;
|
||||
} imageBarrier;
|
||||
struct {
|
||||
VkPipelineStageFlags srcStageMask;
|
||||
VkPipelineStageFlags dstStageMask;
|
||||
VkBufferMemoryBarrier desc;
|
||||
int count;
|
||||
int index;
|
||||
} bufferBarrier;
|
||||
struct {
|
||||
VkImage src;
|
||||
@ -537,6 +546,8 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
|
||||
pools.vertexBuffer.clear();
|
||||
pools.vertexBufferOffset.clear();
|
||||
pools.debugMarkerData.clear();
|
||||
pools.imageBarrier.clear();
|
||||
pools.bufferBarrier.clear();
|
||||
}
|
||||
|
||||
struct {
|
||||
@ -546,6 +557,8 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
|
||||
QVarLengthArray<VkBuffer, 4> vertexBuffer;
|
||||
QVarLengthArray<VkDeviceSize, 4> vertexBufferOffset;
|
||||
QVarLengthArray<QByteArray, 4> debugMarkerData;
|
||||
QVarLengthArray<VkImageMemoryBarrier, 8> imageBarrier;
|
||||
QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarrier;
|
||||
} pools;
|
||||
|
||||
friend class QRhiVulkan;
|
||||
|
@ -367,7 +367,7 @@ QByteArray QShader::serialized() const
|
||||
|
||||
ds << QShaderPrivate::QSB_VERSION;
|
||||
ds << int(d->stage);
|
||||
ds << d->desc.toCbor();
|
||||
d->desc.serialize(&ds);
|
||||
ds << d->shaders.count();
|
||||
for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) {
|
||||
const QShaderKey &k(it.key());
|
||||
@ -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_WITH_CBOR
|
||||
&& d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON
|
||||
&& d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_BINDINGS)
|
||||
{
|
||||
@ -437,14 +438,18 @@ QShader QShader::fromSerialized(const QByteArray &data)
|
||||
|
||||
ds >> intVal;
|
||||
d->stage = Stage(intVal);
|
||||
QByteArray descBin;
|
||||
ds >> descBin;
|
||||
if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON) {
|
||||
if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_CBOR) {
|
||||
d->desc = QShaderDescription::deserialize(&ds);
|
||||
} else if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON) {
|
||||
QByteArray descBin;
|
||||
ds >> descBin;
|
||||
d->desc = QShaderDescription::fromCbor(descBin);
|
||||
} else {
|
||||
#if QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
|
||||
QT_WARNING_PUSH
|
||||
QT_WARNING_DISABLE_DEPRECATED
|
||||
QByteArray descBin;
|
||||
ds >> descBin;
|
||||
d->desc = QShaderDescription::fromBinaryJson(descBin);
|
||||
QT_WARNING_POP
|
||||
#else
|
||||
|
@ -57,7 +57,8 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
struct Q_GUI_EXPORT QShaderPrivate
|
||||
{
|
||||
static const int QSB_VERSION = 3;
|
||||
static const int QSB_VERSION = 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;
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
#include "qshaderdescription_p_p.h"
|
||||
#include <QDebug>
|
||||
#include <QDataStream>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QCborValue>
|
||||
@ -358,6 +359,11 @@ QByteArray QShaderDescription::toJson() const
|
||||
return d->makeDoc().toJson();
|
||||
}
|
||||
|
||||
void QShaderDescription::serialize(QDataStream *stream) const
|
||||
{
|
||||
d->writeToStream(stream);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
|
||||
/*!
|
||||
\deprecated
|
||||
@ -396,6 +402,13 @@ QShaderDescription QShaderDescription::fromCbor(const QByteArray &data)
|
||||
return desc;
|
||||
}
|
||||
|
||||
QShaderDescription QShaderDescription::deserialize(QDataStream *stream)
|
||||
{
|
||||
QShaderDescription desc;
|
||||
QShaderDescriptionPrivate::get(&desc)->loadFromStream(stream);
|
||||
return desc;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return the list of input variables. This includes vertex inputs (sometimes
|
||||
called attributes) for the vertex stage, and inputs for other stages
|
||||
@ -867,6 +880,15 @@ static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v
|
||||
(*obj)[imageFlagsKey] = int(v.imageFlags);
|
||||
}
|
||||
|
||||
static void serializeDecorations(QDataStream *stream, const QShaderDescription::InOutVariable &v)
|
||||
{
|
||||
(*stream) << v.location;
|
||||
(*stream) << v.binding;
|
||||
(*stream) << v.descriptorSet;
|
||||
(*stream) << int(v.imageFormat);
|
||||
(*stream) << int(v.imageFlags);
|
||||
}
|
||||
|
||||
static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v)
|
||||
{
|
||||
QJsonObject obj;
|
||||
@ -876,6 +898,13 @@ static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v)
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void serializeInOutVar(QDataStream *stream, const QShaderDescription::InOutVariable &v)
|
||||
{
|
||||
(*stream) << v.name;
|
||||
(*stream) << int(v.type);
|
||||
serializeDecorations(stream, v);
|
||||
}
|
||||
|
||||
static QJsonObject blockMemberObject(const QShaderDescription::BlockVariable &v)
|
||||
{
|
||||
QJsonObject obj;
|
||||
@ -904,6 +933,23 @@ static QJsonObject blockMemberObject(const QShaderDescription::BlockVariable &v)
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void serializeBlockMemberVar(QDataStream *stream, const QShaderDescription::BlockVariable &v)
|
||||
{
|
||||
(*stream) << v.name;
|
||||
(*stream) << int(v.type);
|
||||
(*stream) << v.offset;
|
||||
(*stream) << v.size;
|
||||
(*stream) << v.arrayDims.count();
|
||||
for (int dim : v.arrayDims)
|
||||
(*stream) << dim;
|
||||
(*stream) << v.arrayStride;
|
||||
(*stream) << v.matrixStride;
|
||||
(*stream) << v.matrixIsRowMajor;
|
||||
(*stream) << v.structMembers.count();
|
||||
for (const QShaderDescription::BlockVariable &sv : v.structMembers)
|
||||
serializeBlockMemberVar(stream, sv);
|
||||
}
|
||||
|
||||
QJsonDocument QShaderDescriptionPrivate::makeDoc()
|
||||
{
|
||||
QJsonObject root;
|
||||
@ -1002,6 +1048,67 @@ QJsonDocument QShaderDescriptionPrivate::makeDoc()
|
||||
return QJsonDocument(root);
|
||||
}
|
||||
|
||||
void QShaderDescriptionPrivate::writeToStream(QDataStream *stream)
|
||||
{
|
||||
(*stream) << inVars.count();
|
||||
for (const QShaderDescription::InOutVariable &v : qAsConst(inVars))
|
||||
serializeInOutVar(stream, v);
|
||||
|
||||
(*stream) << outVars.count();
|
||||
for (const QShaderDescription::InOutVariable &v : qAsConst(outVars))
|
||||
serializeInOutVar(stream, v);
|
||||
|
||||
(*stream) << uniformBlocks.count();
|
||||
for (const QShaderDescription::UniformBlock &b : uniformBlocks) {
|
||||
(*stream) << b.blockName;
|
||||
(*stream) << b.structName;
|
||||
(*stream) << b.size;
|
||||
(*stream) << b.binding;
|
||||
(*stream) << b.descriptorSet;
|
||||
(*stream) << b.members.count();
|
||||
for (const QShaderDescription::BlockVariable &v : b.members)
|
||||
serializeBlockMemberVar(stream, v);
|
||||
}
|
||||
|
||||
(*stream) << pushConstantBlocks.count();
|
||||
for (const QShaderDescription::PushConstantBlock &b : pushConstantBlocks) {
|
||||
(*stream) << b.name;
|
||||
(*stream) << b.size;
|
||||
(*stream) << b.members.count();
|
||||
for (const QShaderDescription::BlockVariable &v : b.members)
|
||||
serializeBlockMemberVar(stream, v);
|
||||
}
|
||||
|
||||
(*stream) << storageBlocks.count();
|
||||
for (const QShaderDescription::StorageBlock &b : storageBlocks) {
|
||||
(*stream) << b.blockName;
|
||||
(*stream) << b.instanceName;
|
||||
(*stream) << b.knownSize;
|
||||
(*stream) << b.binding;
|
||||
(*stream) << b.descriptorSet;
|
||||
(*stream) << b.members.count();
|
||||
for (const QShaderDescription::BlockVariable &v : b.members)
|
||||
serializeBlockMemberVar(stream, v);
|
||||
}
|
||||
|
||||
(*stream) << combinedImageSamplers.count();
|
||||
for (const QShaderDescription::InOutVariable &v : qAsConst(combinedImageSamplers)) {
|
||||
(*stream) << v.name;
|
||||
(*stream) << int(v.type);
|
||||
serializeDecorations(stream, v);
|
||||
}
|
||||
|
||||
(*stream) << storageImages.count();
|
||||
for (const QShaderDescription::InOutVariable &v : qAsConst(storageImages)) {
|
||||
(*stream) << v.name;
|
||||
(*stream) << int(v.type);
|
||||
serializeDecorations(stream, v);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
(*stream) << localSize[i];
|
||||
}
|
||||
|
||||
static QShaderDescription::InOutVariable inOutVar(const QJsonObject &obj)
|
||||
{
|
||||
QShaderDescription::InOutVariable var;
|
||||
@ -1020,6 +1127,29 @@ static QShaderDescription::InOutVariable inOutVar(const QJsonObject &obj)
|
||||
return var;
|
||||
}
|
||||
|
||||
static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOutVariable *v)
|
||||
{
|
||||
(*stream) >> v->location;
|
||||
(*stream) >> v->binding;
|
||||
(*stream) >> v->descriptorSet;
|
||||
int f;
|
||||
(*stream) >> f;
|
||||
v->imageFormat = QShaderDescription::ImageFormat(f);
|
||||
(*stream) >> f;
|
||||
v->imageFlags = QShaderDescription::ImageFlags(f);
|
||||
}
|
||||
|
||||
static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream)
|
||||
{
|
||||
QShaderDescription::InOutVariable var;
|
||||
(*stream) >> var.name;
|
||||
int t;
|
||||
(*stream) >> t;
|
||||
var.type = QShaderDescription::VariableType(t);
|
||||
deserializeDecorations(stream, &var);
|
||||
return var;
|
||||
}
|
||||
|
||||
static QShaderDescription::BlockVariable blockVar(const QJsonObject &obj)
|
||||
{
|
||||
QShaderDescription::BlockVariable var;
|
||||
@ -1046,6 +1176,30 @@ static QShaderDescription::BlockVariable blockVar(const QJsonObject &obj)
|
||||
return var;
|
||||
}
|
||||
|
||||
static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream *stream)
|
||||
{
|
||||
QShaderDescription::BlockVariable var;
|
||||
(*stream) >> var.name;
|
||||
int t;
|
||||
(*stream) >> t;
|
||||
var.type = QShaderDescription::VariableType(t);
|
||||
(*stream) >> var.offset;
|
||||
(*stream) >> var.size;
|
||||
int count;
|
||||
(*stream) >> count;
|
||||
var.arrayDims.resize(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
(*stream) >> var.arrayDims[i];
|
||||
(*stream) >> var.arrayStride;
|
||||
(*stream) >> var.matrixStride;
|
||||
(*stream) >> var.matrixIsRowMajor;
|
||||
(*stream) >> count;
|
||||
var.structMembers.resize(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
var.structMembers[i] = deserializeBlockMemberVar(stream);
|
||||
return var;
|
||||
}
|
||||
|
||||
void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc)
|
||||
{
|
||||
if (doc.isNull()) {
|
||||
@ -1150,6 +1304,87 @@ void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc)
|
||||
}
|
||||
}
|
||||
|
||||
void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream)
|
||||
{
|
||||
Q_ASSERT(ref.loadRelaxed() == 1); // must be detached
|
||||
|
||||
int count;
|
||||
(*stream) >> count;
|
||||
inVars.resize(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
inVars[i] = deserializeInOutVar(stream);
|
||||
|
||||
(*stream) >> count;
|
||||
outVars.resize(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
outVars[i] = deserializeInOutVar(stream);
|
||||
|
||||
(*stream) >> count;
|
||||
uniformBlocks.resize(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
(*stream) >> uniformBlocks[i].blockName;
|
||||
(*stream) >> uniformBlocks[i].structName;
|
||||
(*stream) >> uniformBlocks[i].size;
|
||||
(*stream) >> uniformBlocks[i].binding;
|
||||
(*stream) >> uniformBlocks[i].descriptorSet;
|
||||
int memberCount;
|
||||
(*stream) >> memberCount;
|
||||
uniformBlocks[i].members.resize(memberCount);
|
||||
for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
|
||||
uniformBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream);
|
||||
}
|
||||
|
||||
(*stream) >> count;
|
||||
pushConstantBlocks.resize(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
(*stream) >> pushConstantBlocks[i].name;
|
||||
(*stream) >> pushConstantBlocks[i].size;
|
||||
int memberCount;
|
||||
(*stream) >> memberCount;
|
||||
pushConstantBlocks[i].members.resize(memberCount);
|
||||
for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
|
||||
pushConstantBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream);
|
||||
}
|
||||
|
||||
(*stream) >> count;
|
||||
storageBlocks.resize(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
(*stream) >> storageBlocks[i].blockName;
|
||||
(*stream) >> storageBlocks[i].instanceName;
|
||||
(*stream) >> storageBlocks[i].knownSize;
|
||||
(*stream) >> storageBlocks[i].binding;
|
||||
(*stream) >> storageBlocks[i].descriptorSet;
|
||||
int memberCount;
|
||||
(*stream) >> memberCount;
|
||||
storageBlocks[i].members.resize(memberCount);
|
||||
for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
|
||||
storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream);
|
||||
}
|
||||
|
||||
(*stream) >> count;
|
||||
combinedImageSamplers.resize(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
(*stream) >> combinedImageSamplers[i].name;
|
||||
int t;
|
||||
(*stream) >> t;
|
||||
combinedImageSamplers[i].type = QShaderDescription::VariableType(t);
|
||||
deserializeDecorations(stream, &combinedImageSamplers[i]);
|
||||
}
|
||||
|
||||
(*stream) >> count;
|
||||
storageImages.resize(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
(*stream) >> storageImages[i].name;
|
||||
int t;
|
||||
(*stream) >> t;
|
||||
storageImages[i].type = QShaderDescription::VariableType(t);
|
||||
deserializeDecorations(stream, &storageImages[i]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
(*stream) >> localSize[i];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c true if the two QShaderDescription objects \a lhs and \a rhs are
|
||||
equal.
|
||||
|
@ -56,6 +56,7 @@
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
struct QShaderDescriptionPrivate;
|
||||
class QDataStream;
|
||||
|
||||
class Q_GUI_EXPORT QShaderDescription
|
||||
{
|
||||
@ -69,6 +70,7 @@ public:
|
||||
bool isValid() const;
|
||||
|
||||
QByteArray toCbor() const;
|
||||
void serialize(QDataStream *stream) const;
|
||||
QByteArray toJson() const;
|
||||
|
||||
#if QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
|
||||
@ -76,6 +78,7 @@ public:
|
||||
static QShaderDescription fromBinaryJson(const QByteArray &data);
|
||||
#endif
|
||||
static QShaderDescription fromCbor(const QByteArray &data);
|
||||
static QShaderDescription deserialize(QDataStream *stream);
|
||||
|
||||
enum VariableType {
|
||||
Unknown = 0,
|
||||
|
@ -80,7 +80,9 @@ struct Q_GUI_EXPORT QShaderDescriptionPrivate
|
||||
static const QShaderDescriptionPrivate *get(const QShaderDescription *desc) { return desc->d; }
|
||||
|
||||
QJsonDocument makeDoc();
|
||||
void writeToStream(QDataStream *stream);
|
||||
void loadDoc(const QJsonDocument &doc);
|
||||
void loadFromStream(QDataStream *stream);
|
||||
|
||||
QAtomicInt ref;
|
||||
QVector<QShaderDescription::InOutVariable> inVars;
|
||||
|
@ -554,13 +554,32 @@ QNetworkAccessManager::Operation QNetworkReply::operation() const
|
||||
return d_func()->operation;
|
||||
}
|
||||
|
||||
#if QT_DEPRECATED_SINCE(5, 15)
|
||||
/*!
|
||||
\deprecated
|
||||
|
||||
Use networkError() instead.
|
||||
|
||||
Returns the error that was found during the processing of this
|
||||
request. If no error was found, returns NoError.
|
||||
|
||||
\sa setError(), networkError()
|
||||
*/
|
||||
QNetworkReply::NetworkError QNetworkReply::error() const
|
||||
{
|
||||
return networkError();
|
||||
}
|
||||
#endif // QT_DEPRECATED_SINCE(5, 15)
|
||||
|
||||
/*!
|
||||
\since 5.15
|
||||
|
||||
Returns the error that was found during the processing of this
|
||||
request. If no error was found, returns NoError.
|
||||
|
||||
\sa setError()
|
||||
*/
|
||||
QNetworkReply::NetworkError QNetworkReply::error() const
|
||||
QNetworkReply::NetworkError QNetworkReply::networkError() const
|
||||
{
|
||||
return d_func()->errorCode;
|
||||
}
|
||||
@ -858,7 +877,7 @@ void QNetworkReply::setRequest(const QNetworkRequest &request)
|
||||
Calling setError() does not emit the error(QNetworkReply::NetworkError)
|
||||
signal.
|
||||
|
||||
\sa error(), errorString()
|
||||
\sa error(), errorString(), networkError()
|
||||
*/
|
||||
void QNetworkReply::setError(NetworkError errorCode, const QString &errorString)
|
||||
{
|
||||
|
@ -124,7 +124,12 @@ public:
|
||||
QNetworkAccessManager *manager() const;
|
||||
QNetworkAccessManager::Operation operation() const;
|
||||
QNetworkRequest request() const;
|
||||
NetworkError error() const;
|
||||
|
||||
#if QT_DEPRECATED_SINCE(5, 15)
|
||||
QT_DEPRECATED_X("Use networkError()") NetworkError error() const;
|
||||
#endif // QT_DEPRECATED_SINCE(5, 15)
|
||||
NetworkError networkError() const;
|
||||
|
||||
bool isFinished() const;
|
||||
bool isRunning() const;
|
||||
QUrl url() const;
|
||||
|
@ -62,6 +62,9 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
// Clang does not consider __declspec(nothrow) as nothrow
|
||||
QT_WARNING_DISABLE_CLANG("-Wmicrosoft-exception-spec")
|
||||
|
||||
// Convert from design units to logical pixels
|
||||
#define DESIGN_TO_LOGICAL(DESIGN_UNIT_VALUE) \
|
||||
QFixed::fromReal((qreal(DESIGN_UNIT_VALUE) / qreal(m_unitsPerEm)) * fontDef.pixelSize)
|
||||
|
@ -33,6 +33,14 @@
|
||||
|
||||
#include <emscripten.h>
|
||||
|
||||
#if (__EMSCRIPTEN_major__ > 1 || __EMSCRIPTEN_minor__ > 38 || __EMSCRIPTEN_minor__ == 38 && __EMSCRIPTEN_tiny__ >= 22)
|
||||
# define EMSCRIPTEN_HAS_ASYNC_RUN_IN_MAIN_RUNTIME_THREAD
|
||||
#endif
|
||||
|
||||
#ifdef EMSCRIPTEN_HAS_ASYNC_RUN_IN_MAIN_RUNTIME_THREAD
|
||||
#include <emscripten/threading.h>
|
||||
#endif
|
||||
|
||||
class QWasmEventDispatcherPrivate : public QEventDispatcherUNIXPrivate
|
||||
{
|
||||
|
||||
@ -179,3 +187,18 @@ void QWasmEventDispatcher::doMaintainTimers()
|
||||
emscripten_async_call(callback, this, toWaitDuration);
|
||||
m_currentTargetTime = newTargetTime;
|
||||
}
|
||||
|
||||
void QWasmEventDispatcher::wakeUp()
|
||||
{
|
||||
#ifdef EMSCRIPTEN_HAS_ASYNC_RUN_IN_MAIN_RUNTIME_THREAD
|
||||
if (!emscripten_is_main_runtime_thread())
|
||||
emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIG_VI, (void*)(&QWasmEventDispatcher::mainThreadWakeUp), this);
|
||||
#endif
|
||||
QEventDispatcherUNIX::wakeUp();
|
||||
}
|
||||
|
||||
void QWasmEventDispatcher::mainThreadWakeUp(void *eventDispatcher)
|
||||
{
|
||||
emscripten_resume_main_loop(); // Service possible requestUpdate Calls
|
||||
static_cast<QWasmEventDispatcher *>(eventDispatcher)->processEvents(QEventLoop::AllEvents);
|
||||
}
|
||||
|
@ -51,6 +51,8 @@ public:
|
||||
protected:
|
||||
bool processEvents(QEventLoop::ProcessEventsFlags flags) override;
|
||||
void doMaintainTimers();
|
||||
void wakeUp() override;
|
||||
static void mainThreadWakeUp(void *eventDispatcher);
|
||||
|
||||
private:
|
||||
bool m_hasMainLoop = false;
|
||||
|
@ -107,6 +107,9 @@ private:
|
||||
ULONG m_ref;
|
||||
};
|
||||
|
||||
// Clang does not consider __declspec(nothrow) as nothrow
|
||||
QT_WARNING_DISABLE_CLANG("-Wmicrosoft-exception-spec")
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QWINDOWSCOMBASE_H
|
||||
|
@ -2585,7 +2585,7 @@ QPalette QMacStyle::standardPalette() const
|
||||
auto platformTheme = QGuiApplicationPrivate::platformTheme();
|
||||
auto styleNames = platformTheme->themeHint(QPlatformTheme::StyleNames);
|
||||
if (styleNames.toStringList().contains("macintosh"))
|
||||
return *platformTheme->palette();
|
||||
return QPalette(); // Inherit everything from theme
|
||||
else
|
||||
return QStyle::standardPalette();
|
||||
}
|
||||
|
@ -3774,8 +3774,7 @@ int QWindowsXPStyle::styleHint(StyleHint hint, const QStyleOption *option, const
|
||||
/*! \reimp */
|
||||
QPalette QWindowsXPStyle::standardPalette() const
|
||||
{
|
||||
return QWindowsXPStylePrivate::useXP() && QApplicationPrivate::sys_pal
|
||||
? *QApplicationPrivate::sys_pal : QWindowsStyle::standardPalette();
|
||||
return QWindowsXPStylePrivate::useXP() ? QPalette() : QWindowsStyle::standardPalette();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -140,30 +140,6 @@ Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int
|
||||
|
||||
QApplicationPrivate *QApplicationPrivate::self = nullptr;
|
||||
|
||||
static void initSystemPalette()
|
||||
{
|
||||
if (QApplicationPrivate::sys_pal)
|
||||
return; // Already initialized
|
||||
|
||||
QPalette defaultPalette;
|
||||
if (QApplicationPrivate::app_style)
|
||||
defaultPalette = QApplicationPrivate::app_style->standardPalette();
|
||||
|
||||
auto *platformTheme = QGuiApplicationPrivate::platformTheme();
|
||||
if (const QPalette *themePalette = platformTheme ? platformTheme->palette() : nullptr) {
|
||||
QApplicationPrivate::setSystemPalette(themePalette->resolve(defaultPalette));
|
||||
QApplicationPrivate::initializeWidgetPaletteHash();
|
||||
} else {
|
||||
QApplicationPrivate::setSystemPalette(defaultPalette);
|
||||
}
|
||||
}
|
||||
|
||||
static void clearSystemPalette()
|
||||
{
|
||||
delete QApplicationPrivate::sys_pal;
|
||||
QApplicationPrivate::sys_pal = nullptr;
|
||||
}
|
||||
|
||||
bool QApplicationPrivate::autoSipEnabled = true;
|
||||
|
||||
QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, int flags)
|
||||
@ -381,8 +357,6 @@ QString QApplicationPrivate::styleSheet; // default application styles
|
||||
#endif
|
||||
QPointer<QWidget> QApplicationPrivate::leaveAfterRelease = nullptr;
|
||||
|
||||
QPalette *QApplicationPrivate::sys_pal = nullptr; // default system palette
|
||||
|
||||
QFont *QApplicationPrivate::sys_font = nullptr; // default system font
|
||||
QFont *QApplicationPrivate::set_font = nullptr; // default font set by programmer
|
||||
|
||||
@ -545,12 +519,7 @@ void QApplicationPrivate::init()
|
||||
|
||||
// Must be called before initialize()
|
||||
QColormap::initialize();
|
||||
if (sys_pal) {
|
||||
// Now that we have a platform theme we need to reset
|
||||
// the system palette to pick up the theme colors.
|
||||
clearSystemPalette();
|
||||
initSystemPalette();
|
||||
}
|
||||
initializeWidgetPalettesFromTheme();
|
||||
qt_init_tooltip_palette();
|
||||
QApplicationPrivate::initializeWidgetFontHash();
|
||||
|
||||
@ -629,38 +598,6 @@ void QApplicationPrivate::initialize()
|
||||
is_app_running = true; // no longer starting up
|
||||
}
|
||||
|
||||
static void setPossiblePalette(const QPalette *palette, const char *className)
|
||||
{
|
||||
if (palette == nullptr)
|
||||
return;
|
||||
QApplicationPrivate::setPalette_helper(*palette, className);
|
||||
}
|
||||
|
||||
void QApplicationPrivate::initializeWidgetPaletteHash()
|
||||
{
|
||||
QPlatformTheme *platformTheme = QGuiApplicationPrivate::platformTheme();
|
||||
if (!platformTheme)
|
||||
return;
|
||||
|
||||
widgetPalettes.clear();
|
||||
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::ToolButtonPalette), "QToolButton");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::ButtonPalette), "QAbstractButton");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::CheckBoxPalette), "QCheckBox");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::RadioButtonPalette), "QRadioButton");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::HeaderPalette), "QHeaderView");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::ItemViewPalette), "QAbstractItemView");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::MessageBoxLabelPalette), "QMessageBoxLabel");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::TabBarPalette), "QTabBar");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::LabelPalette), "QLabel");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::GroupBoxPalette), "QGroupBox");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::MenuPalette), "QMenu");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::MenuBarPalette), "QMenuBar");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::TextEditPalette), "QTextEdit");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::TextEditPalette), "QTextControl");
|
||||
setPossiblePalette(platformTheme->palette(QPlatformTheme::TextLineEditPalette), "QLineEdit");
|
||||
}
|
||||
|
||||
void QApplicationPrivate::initializeWidgetFontHash()
|
||||
{
|
||||
const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
|
||||
@ -798,9 +735,6 @@ QApplication::~QApplication()
|
||||
delete qt_desktopWidget;
|
||||
qt_desktopWidget = nullptr;
|
||||
|
||||
delete QApplicationPrivate::app_pal;
|
||||
QApplicationPrivate::app_pal = nullptr;
|
||||
clearSystemPalette();
|
||||
QApplicationPrivate::widgetPalettes.clear();
|
||||
|
||||
delete QApplicationPrivate::sys_font;
|
||||
@ -1051,10 +985,10 @@ QStyle *QApplication::style()
|
||||
// Take ownership of the style
|
||||
defaultStyle->setParent(qApp);
|
||||
|
||||
initSystemPalette();
|
||||
|
||||
if (testAttribute(Qt::AA_SetPalette))
|
||||
defaultStyle->polish(*QGuiApplicationPrivate::app_pal);
|
||||
else
|
||||
QApplicationPrivate::initializeWidgetPalettesFromTheme();
|
||||
|
||||
#ifndef QT_NO_STYLE_STYLESHEET
|
||||
if (!QApplicationPrivate::styleSheet.isEmpty()) {
|
||||
@ -1128,13 +1062,10 @@ void QApplication::setStyle(QStyle *style)
|
||||
// take care of possible palette requirements of certain gui
|
||||
// styles. Do it before polishing the application since the style
|
||||
// might call QApplication::setPalette() itself
|
||||
if (testAttribute(Qt::AA_SetPalette)) {
|
||||
if (testAttribute(Qt::AA_SetPalette))
|
||||
QApplicationPrivate::app_style->polish(*QGuiApplicationPrivate::app_pal);
|
||||
} else {
|
||||
if (QApplicationPrivate::sys_pal)
|
||||
clearSystemPalette();
|
||||
initSystemPalette();
|
||||
}
|
||||
else
|
||||
QApplicationPrivate::initializeWidgetPalettesFromTheme();
|
||||
|
||||
// The default widget font hash is based on the platform theme,
|
||||
// not the style, but the widget fonts could in theory have been
|
||||
@ -1317,6 +1248,22 @@ void QApplication::setGlobalStrut(const QSize& strut)
|
||||
// Widget specific palettes
|
||||
QApplicationPrivate::PaletteHash QApplicationPrivate::widgetPalettes;
|
||||
|
||||
QPalette QApplicationPrivate::basePalette() const
|
||||
{
|
||||
// Start out with a palette based on the style, in case there's no theme
|
||||
// available, or so that we can fill in missing roles in the theme.
|
||||
QPalette palette = app_style ? app_style->standardPalette() : Qt::gray;
|
||||
|
||||
// Prefer theme palette if available, but fill in missing roles from style
|
||||
// for compatibility. Note that the style's standard palette is not prioritized
|
||||
// over the theme palette, as the documented way of applying the style's palette
|
||||
// is to set it explicitly using QApplication::setPalette().
|
||||
if (const QPalette *themePalette = platformTheme() ? platformTheme()->palette() : nullptr)
|
||||
palette = themePalette->resolve(palette);
|
||||
|
||||
return palette;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn QPalette QApplication::palette(const QWidget* widget)
|
||||
|
||||
@ -1363,35 +1310,8 @@ QPalette QApplication::palette(const char *className)
|
||||
return QGuiApplication::palette();
|
||||
}
|
||||
|
||||
void QApplicationPrivate::setPalette_helper(const QPalette &palette, const char* className)
|
||||
{
|
||||
QPalette pal = palette;
|
||||
|
||||
if (QApplicationPrivate::app_style)
|
||||
QApplicationPrivate::app_style->polish(pal); // NB: non-const reference
|
||||
|
||||
bool all = false;
|
||||
if (!className) {
|
||||
if (!QGuiApplicationPrivate::setPalette(pal))
|
||||
return;
|
||||
|
||||
if (!QApplicationPrivate::sys_pal || !palette.isCopyOf(*QApplicationPrivate::sys_pal))
|
||||
QCoreApplication::setAttribute(Qt::AA_SetPalette);
|
||||
|
||||
if (!widgetPalettes.isEmpty()) {
|
||||
all = true;
|
||||
widgetPalettes.clear();
|
||||
}
|
||||
} else {
|
||||
widgetPalettes.insert(className, pal);
|
||||
}
|
||||
|
||||
if (qApp)
|
||||
qApp->d_func()->sendApplicationPaletteChange(all, className);
|
||||
}
|
||||
|
||||
/*!
|
||||
Changes the default application palette to \a palette.
|
||||
Changes the application palette to \a palette.
|
||||
|
||||
If \a className is passed, the change applies only to widgets that inherit
|
||||
\a className (as reported by QObject::inherits()). If \a className is left
|
||||
@ -1412,23 +1332,87 @@ void QApplicationPrivate::setPalette_helper(const QPalette &palette, const char*
|
||||
|
||||
\sa QWidget::setPalette(), palette(), QStyle::polish()
|
||||
*/
|
||||
|
||||
void QApplication::setPalette(const QPalette &palette, const char* className)
|
||||
{
|
||||
QApplicationPrivate::setPalette_helper(palette, className);
|
||||
QPalette polishedPalette = palette;
|
||||
|
||||
if (QApplicationPrivate::app_style)
|
||||
QApplicationPrivate::app_style->polish(polishedPalette);
|
||||
|
||||
if (className) {
|
||||
QApplicationPrivate::widgetPalettes.insert(className, polishedPalette);
|
||||
if (qApp)
|
||||
qApp->d_func()->handlePaletteChanged(className);
|
||||
} else {
|
||||
QGuiApplication::setPalette(polishedPalette);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void QApplicationPrivate::setSystemPalette(const QPalette &pal)
|
||||
void QApplicationPrivate::handlePaletteChanged(const char *className)
|
||||
{
|
||||
if (!sys_pal)
|
||||
sys_pal = new QPalette(pal);
|
||||
else
|
||||
*sys_pal = pal;
|
||||
if (!is_app_running || is_app_closing)
|
||||
return;
|
||||
|
||||
if (!testAttribute(Qt::AA_SetPalette))
|
||||
QApplication::setPalette(*sys_pal);
|
||||
// Setting the global application palette is documented to
|
||||
// reset any previously set class specific widget palettes.
|
||||
bool sendPaletteChangeToAllWidgets = false;
|
||||
if (!className && !widgetPalettes.isEmpty()) {
|
||||
sendPaletteChangeToAllWidgets = true;
|
||||
widgetPalettes.clear();
|
||||
}
|
||||
|
||||
QGuiApplicationPrivate::handlePaletteChanged(className);
|
||||
|
||||
QEvent event(QEvent::ApplicationPaletteChange);
|
||||
const QWidgetList widgets = QApplication::allWidgets();
|
||||
for (auto widget : widgets) {
|
||||
if (sendPaletteChangeToAllWidgets || (!className && widget->isWindow()) || (className && widget->inherits(className)))
|
||||
QCoreApplication::sendEvent(widget, &event);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(graphicsview)
|
||||
for (auto scene : qAsConst(scene_list))
|
||||
QCoreApplication::sendEvent(scene, &event);
|
||||
#endif
|
||||
|
||||
// Palette has been reset back to the default application palette,
|
||||
// so we need to reinitialize the widget palettes from the theme.
|
||||
if (!className && !testAttribute(Qt::AA_SetPalette))
|
||||
initializeWidgetPalettesFromTheme();
|
||||
}
|
||||
|
||||
void QApplicationPrivate::initializeWidgetPalettesFromTheme()
|
||||
{
|
||||
QPlatformTheme *platformTheme = QGuiApplicationPrivate::platformTheme();
|
||||
if (!platformTheme)
|
||||
return;
|
||||
|
||||
widgetPalettes.clear();
|
||||
|
||||
struct ThemedWidget { const char *className; QPlatformTheme::Palette palette; };
|
||||
|
||||
static const ThemedWidget themedWidgets[] = {
|
||||
{ "QToolButton", QPlatformTheme::ToolButtonPalette },
|
||||
{ "QAbstractButton", QPlatformTheme::ButtonPalette },
|
||||
{ "QCheckBox", QPlatformTheme::CheckBoxPalette },
|
||||
{ "QRadioButton", QPlatformTheme::RadioButtonPalette },
|
||||
{ "QHeaderView", QPlatformTheme::HeaderPalette },
|
||||
{ "QAbstractItemView", QPlatformTheme::ItemViewPalette },
|
||||
{ "QMessageBoxLabel", QPlatformTheme::MessageBoxLabelPalette },
|
||||
{ "QTabBar", QPlatformTheme::TabBarPalette },
|
||||
{ "QLabel", QPlatformTheme::LabelPalette },
|
||||
{ "QGroupBox", QPlatformTheme::GroupBoxPalette },
|
||||
{ "QMenu", QPlatformTheme::MenuPalette },
|
||||
{ "QMenuBar", QPlatformTheme::MenuBarPalette },
|
||||
{ "QTextEdit", QPlatformTheme::TextEditPalette },
|
||||
{ "QTextControl", QPlatformTheme::TextEditPalette },
|
||||
{ "QLineEdit", QPlatformTheme::TextLineEditPalette },
|
||||
};
|
||||
|
||||
for (const auto themedWidget : themedWidgets) {
|
||||
if (auto *palette = platformTheme->palette(themedWidget.palette))
|
||||
QApplication::setPalette(*palette, themedWidget.className);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -4413,31 +4397,10 @@ void QApplicationPrivate::translateTouchCancel(QTouchDevice *device, ulong times
|
||||
void QApplicationPrivate::notifyThemeChanged()
|
||||
{
|
||||
QGuiApplicationPrivate::notifyThemeChanged();
|
||||
clearSystemPalette();
|
||||
initSystemPalette();
|
||||
|
||||
qt_init_tooltip_palette();
|
||||
}
|
||||
|
||||
void QApplicationPrivate::sendApplicationPaletteChange(bool toAllWidgets, const char *className)
|
||||
{
|
||||
if (!is_app_running || is_app_closing)
|
||||
return;
|
||||
|
||||
QGuiApplicationPrivate::sendApplicationPaletteChange(toAllWidgets, className);
|
||||
|
||||
QEvent event(QEvent::ApplicationPaletteChange);
|
||||
const QWidgetList widgets = QApplication::allWidgets();
|
||||
for (auto widget : widgets) {
|
||||
if (toAllWidgets || (!className && widget->isWindow()) || (className && widget->inherits(className)))
|
||||
QCoreApplication::sendEvent(widget, &event);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(graphicsview)
|
||||
for (auto scene : qAsConst(scene_list))
|
||||
QCoreApplication::sendEvent(scene, &event);
|
||||
#endif // QT_CONFIG(graphicsview)
|
||||
}
|
||||
|
||||
#if QT_CONFIG(draganddrop)
|
||||
void QApplicationPrivate::notifyDragStarted(const QDrag *drag)
|
||||
{
|
||||
|
@ -158,12 +158,12 @@ public:
|
||||
static QSize app_strut;
|
||||
static QWidgetList *popupWidgets;
|
||||
static QStyle *app_style;
|
||||
static QPalette *sys_pal;
|
||||
|
||||
protected:
|
||||
void notifyThemeChanged() override;
|
||||
void sendApplicationPaletteChange(bool toAllWidgets = false,
|
||||
const char *className = nullptr) override;
|
||||
|
||||
QPalette basePalette() const override;
|
||||
void handlePaletteChanged(const char *className = nullptr) override;
|
||||
|
||||
#if QT_CONFIG(draganddrop)
|
||||
void notifyDragStarted(const QDrag *) override;
|
||||
@ -184,9 +184,7 @@ public:
|
||||
static int enabledAnimations; // Combination of QPlatformTheme::UiEffect
|
||||
static bool widgetCount; // Coupled with -widgetcount switch
|
||||
|
||||
static void setSystemPalette(const QPalette &pal);
|
||||
static void setPalette_helper(const QPalette &palette, const char* className);
|
||||
static void initializeWidgetPaletteHash();
|
||||
static void initializeWidgetPalettesFromTheme();
|
||||
static void initializeWidgetFontHash();
|
||||
static void setSystemFont(const QFont &font);
|
||||
|
||||
|
@ -34,6 +34,9 @@
|
||||
#include <QElapsedTimer>
|
||||
#include <QTextStream>
|
||||
#include <QDir>
|
||||
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/* All tests need to run in temporary directories not used
|
||||
* by the application to avoid non-deterministic failures on Windows
|
||||
@ -79,6 +82,9 @@ private slots:
|
||||
void signalsEmittedAfterFileMoved();
|
||||
|
||||
void watchUnicodeCharacters();
|
||||
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
|
||||
void watchDirectoryAttributeChanges();
|
||||
#endif
|
||||
|
||||
private:
|
||||
QString m_tempDirPattern;
|
||||
@ -813,5 +819,27 @@ void tst_QFileSystemWatcher::watchUnicodeCharacters()
|
||||
QTRY_COMPARE(changedSpy.count(), 1);
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
|
||||
void tst_QFileSystemWatcher::watchDirectoryAttributeChanges()
|
||||
{
|
||||
QTemporaryDir temporaryDirectory(m_tempDirPattern);
|
||||
QVERIFY2(temporaryDirectory.isValid(), qPrintable(temporaryDirectory.errorString()));
|
||||
|
||||
QDir testDir(temporaryDirectory.path());
|
||||
const QString subDir(QString::fromLatin1("attrib_test"));
|
||||
QVERIFY(testDir.mkdir(subDir));
|
||||
testDir = QDir(temporaryDirectory.path() + QDir::separator() + subDir);
|
||||
|
||||
QFileSystemWatcher watcher;
|
||||
QVERIFY(watcher.addPath(temporaryDirectory.path()));
|
||||
FileSystemWatcherSpy changedSpy(&watcher, FileSystemWatcherSpy::SpyOnDirectoryChanged);
|
||||
QCOMPARE(changedSpy.count(), 0);
|
||||
QVERIFY(SetFileAttributes(reinterpret_cast<LPCWSTR>(testDir.absolutePath().utf16()), FILE_ATTRIBUTE_HIDDEN) != 0);
|
||||
QTRY_COMPARE(changedSpy.count(), 1);
|
||||
QVERIFY(SetFileAttributes(reinterpret_cast<LPCWSTR>(testDir.absolutePath().utf16()), FILE_ATTRIBUTE_NORMAL) != 0);
|
||||
QTRY_COMPARE(changedSpy.count(), 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
QTEST_MAIN(tst_QFileSystemWatcher)
|
||||
#include "tst_qfilesystemwatcher.moc"
|
||||
|
@ -459,8 +459,8 @@ private slots:
|
||||
void trimmed();
|
||||
void toUpper();
|
||||
void toLower();
|
||||
void isUpper();
|
||||
void isLower();
|
||||
void isLower_isUpper_data();
|
||||
void isLower_isUpper();
|
||||
void toCaseFolded();
|
||||
void rightJustified();
|
||||
void leftJustified();
|
||||
@ -2290,44 +2290,83 @@ void tst_QString::toLower()
|
||||
#endif // icu
|
||||
}
|
||||
|
||||
void tst_QString::isUpper()
|
||||
void tst_QString::isLower_isUpper_data()
|
||||
{
|
||||
QVERIFY(!QString().isUpper());
|
||||
QVERIFY(!QString("").isUpper());
|
||||
QVERIFY(QString("TEXT").isUpper());
|
||||
QVERIFY(!QString("text").isUpper());
|
||||
QVERIFY(!QString("Text").isUpper());
|
||||
QVERIFY(!QString("tExt").isUpper());
|
||||
QVERIFY(!QString("teXt").isUpper());
|
||||
QVERIFY(!QString("texT").isUpper());
|
||||
QVERIFY(!QString("TExt").isUpper());
|
||||
QVERIFY(!QString("teXT").isUpper());
|
||||
QVERIFY(!QString("tEXt").isUpper());
|
||||
QVERIFY(!QString("tExT").isUpper());
|
||||
QVERIFY(!QString("@ABYZ[").isUpper());
|
||||
QVERIFY(!QString("@abyz[").isUpper());
|
||||
QVERIFY(!QString("`ABYZ{").isUpper());
|
||||
QVERIFY(!QString("`abyz{").isUpper());
|
||||
QTest::addColumn<QString>("string");
|
||||
QTest::addColumn<bool>("isLower");
|
||||
QTest::addColumn<bool>("isUpper");
|
||||
|
||||
int row = 0;
|
||||
QTest::addRow("lower-and-upper-%02d", row++) << QString() << true << true;
|
||||
QTest::addRow("lower-and-upper-%02d", row++) << QString("") << true << true;
|
||||
QTest::addRow("lower-and-upper-%02d", row++) << QString(" ") << true << true;
|
||||
QTest::addRow("lower-and-upper-%02d", row++) << QString("123") << true << true;
|
||||
QTest::addRow("lower-and-upper-%02d", row++) << QString("@123$#") << true << true;
|
||||
QTest::addRow("lower-and-upper-%02d", row++) << QString("𝄞𝄴𝆏♫") << true << true; // Unicode Block 'Musical Symbols'
|
||||
// not foldable
|
||||
QTest::addRow("lower-and-upper-%02d", row++) << QString("𝚊𝚋𝚌𝚍𝚎") << true << true; // MATHEMATICAL MONOSPACE SMALL A, ... E
|
||||
QTest::addRow("lower-and-upper-%02d", row++) << QString("𝙖,𝙗,𝙘,𝙙,𝙚") << true << true; // MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A, ... E
|
||||
QTest::addRow("lower-and-upper-%02d", row++) << QString("𝗔𝗕𝗖𝗗𝗘") << true << true; // MATHEMATICAL SANS-SERIF BOLD CAPITAL A, ... E
|
||||
QTest::addRow("lower-and-upper-%02d", row++) << QString("𝐀,𝐁,𝐂,𝐃,𝐄") << true << true; // MATHEMATICAL BOLD CAPITAL A, ... E
|
||||
|
||||
row = 0;
|
||||
QTest::addRow("only-lower-%02d", row++) << QString("text") << true << false;
|
||||
QTest::addRow("only-lower-%02d", row++) << QString("àaa") << true << false;
|
||||
QTest::addRow("only-lower-%02d", row++) << QString("øæß") << true << false;
|
||||
QTest::addRow("only-lower-%02d", row++) << QString("text ") << true << false;
|
||||
QTest::addRow("only-lower-%02d", row++) << QString(" text") << true << false;
|
||||
QTest::addRow("only-lower-%02d", row++) << QString("hello, world!") << true << false;
|
||||
QTest::addRow("only-lower-%02d", row++) << QString("123@abyz[") << true << false;
|
||||
QTest::addRow("only-lower-%02d", row++) << QString("`abyz{") << true << false;
|
||||
QTest::addRow("only-lower-%02d", row++) << QString("a𝙖a|b𝙗b|c𝙘c|d𝙙d|e𝙚e") << true << false; // MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A, ... E
|
||||
QTest::addRow("only-lower-%02d", row++) << QString("𐐨") << true << false; // DESERET SMALL LETTER LONG I
|
||||
// uppercase letters, not foldable
|
||||
QTest::addRow("only-lower-%02d", row++) << QString("text𝗔text") << true << false; // MATHEMATICAL SANS-SERIF BOLD CAPITAL A
|
||||
|
||||
row = 0;
|
||||
QTest::addRow("only-upper-%02d", row++) << QString("TEXT") << false << true;
|
||||
QTest::addRow("only-upper-%02d", row++) << QString("ÀAA") << false << true;
|
||||
QTest::addRow("only-upper-%02d", row++) << QString("ØÆẞ") << false << true;
|
||||
QTest::addRow("only-upper-%02d", row++) << QString("TEXT ") << false << true;
|
||||
QTest::addRow("only-upper-%02d", row++) << QString(" TEXT") << false << true;
|
||||
QTest::addRow("only-upper-%02d", row++) << QString("HELLO, WORLD!") << false << true;
|
||||
QTest::addRow("only-upper-%02d", row++) << QString("123@ABYZ[") << false << true;
|
||||
QTest::addRow("only-upper-%02d", row++) << QString("`ABYZ{") << false << true;
|
||||
QTest::addRow("only-upper-%02d", row++) << QString("A𝐀A|B𝐁B|C𝐂C|D𝐃D|E𝐄E") << false << true; // MATHEMATICAL BOLD CAPITAL A, ... E
|
||||
QTest::addRow("only-upper-%02d", row++) << QString("𐐀") << false << true; // DESERET CAPITAL LETTER LONG I
|
||||
// lowercase letters, not foldable
|
||||
QTest::addRow("only-upper-%02d", row++) << QString("TEXT𝚊TEXT") << false << true; // MATHEMATICAL MONOSPACE SMALL A
|
||||
|
||||
row = 0;
|
||||
QTest::addRow("not-lower-nor-upper-%02d", row++) << QString("Text") << false << false;
|
||||
QTest::addRow("not-lower-nor-upper-%02d", row++) << QString("tExt") << false << false;
|
||||
QTest::addRow("not-lower-nor-upper-%02d", row++) << QString("teXt") << false << false;
|
||||
QTest::addRow("not-lower-nor-upper-%02d", row++) << QString("texT") << false << false;
|
||||
QTest::addRow("not-lower-nor-upper-%02d", row++) << QString("TExt") << false << false;
|
||||
QTest::addRow("not-lower-nor-upper-%02d", row++) << QString("teXT") << false << false;
|
||||
QTest::addRow("not-lower-nor-upper-%02d", row++) << QString("tEXt") << false << false;
|
||||
QTest::addRow("not-lower-nor-upper-%02d", row++) << QString("tExT") << false << false;
|
||||
// not foldable
|
||||
QTest::addRow("not-lower-nor-upper-%02d", row++) << QString("TEXT𝚊text") << false << false; // MATHEMATICAL MONOSPACE SMALL A
|
||||
QTest::addRow("not-lower-nor-upper-%02d", row++) << QString("text𝗔TEXT") << false << false; // MATHEMATICAL SANS-SERIF BOLD CAPITAL A
|
||||
// titlecase, foldable
|
||||
QTest::addRow("not-lower-nor-upper-%02d", row++) << QString("abcLjdef") << false << false; // LATIN CAPITAL LETTER L WITH SMALL LETTER J
|
||||
QTest::addRow("not-lower-nor-upper-%02d", row++) << QString("ABCLjDEF") << false << false; // LATIN CAPITAL LETTER L WITH SMALL LETTER J
|
||||
}
|
||||
|
||||
void tst_QString::isLower()
|
||||
void tst_QString::isLower_isUpper()
|
||||
{
|
||||
QVERIFY(!QString().isLower());
|
||||
QVERIFY(!QString("").isLower());
|
||||
QVERIFY(QString("text").isLower());
|
||||
QVERIFY(!QString("Text").isLower());
|
||||
QVERIFY(!QString("tExt").isLower());
|
||||
QVERIFY(!QString("teXt").isLower());
|
||||
QVERIFY(!QString("texT").isLower());
|
||||
QVERIFY(!QString("TExt").isLower());
|
||||
QVERIFY(!QString("teXT").isLower());
|
||||
QVERIFY(!QString("tEXt").isLower());
|
||||
QVERIFY(!QString("tExT").isLower());
|
||||
QVERIFY(!QString("TEXT").isLower());
|
||||
QVERIFY(!QString("@ABYZ[").isLower());
|
||||
QVERIFY(!QString("@abyz[").isLower());
|
||||
QVERIFY(!QString("`ABYZ{").isLower());
|
||||
QVERIFY(!QString("`abyz{").isLower());
|
||||
QFETCH(QString, string);
|
||||
QFETCH(bool, isLower);
|
||||
QFETCH(bool, isUpper);
|
||||
|
||||
QCOMPARE(string.isLower(), isLower);
|
||||
QCOMPARE(string.toLower() == string, isLower);
|
||||
QVERIFY(string.toLower().isLower());
|
||||
|
||||
QCOMPARE(string.isUpper(), isUpper);
|
||||
QCOMPARE(string.toUpper() == string, isUpper);
|
||||
QVERIFY(string.toUpper().isUpper());
|
||||
}
|
||||
|
||||
void tst_QString::toCaseFolded()
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
#include <qstandarditemmodel.h>
|
||||
#include <QStandardItem>
|
||||
|
||||
class tst_QStandardItem : public QObject
|
||||
{
|
||||
@ -48,8 +48,6 @@ private slots:
|
||||
void parent();
|
||||
void insertColumn_data();
|
||||
void insertColumn();
|
||||
void insertColumns_data();
|
||||
void insertColumns();
|
||||
void insertRow_data();
|
||||
void insertRow();
|
||||
void insertRows_data();
|
||||
@ -312,12 +310,15 @@ void tst_QStandardItem::getSetFlags()
|
||||
QCOMPARE(item.checkState(), Qt::Checked);
|
||||
|
||||
#if QT_DEPRECATED_SINCE(5, 6)
|
||||
QT_WARNING_PUSH
|
||||
QT_WARNING_DISABLE_DEPRECATED
|
||||
// deprecated API
|
||||
item.setTristate(true);
|
||||
QVERIFY(item.isTristate());
|
||||
QVERIFY(item.flags() & Qt::ItemIsTristate);
|
||||
item.setTristate(false);
|
||||
QVERIFY(!(item.flags() & Qt::ItemIsTristate));
|
||||
QT_WARNING_POP
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -382,7 +383,7 @@ void tst_QStandardItem::getSetChild()
|
||||
QStandardItem item(rows, columns);
|
||||
bool shouldHaveChildren = (rows > 0) && (columns > 0);
|
||||
QCOMPARE(item.hasChildren(), shouldHaveChildren);
|
||||
QCOMPARE(item.child(row, column), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(item.child(row, column), nullptr);
|
||||
|
||||
QStandardItem *child = new QStandardItem;
|
||||
item.setChild(row, column, child);
|
||||
@ -399,11 +400,11 @@ void tst_QStandardItem::getSetChild()
|
||||
QCOMPARE(item.child(row, column), anotherChild);
|
||||
QCOMPARE(anotherChild->row(), row);
|
||||
QCOMPARE(anotherChild->column(), column);
|
||||
item.setChild(row, column, 0);
|
||||
item.setChild(row, column, nullptr);
|
||||
} else {
|
||||
delete child;
|
||||
}
|
||||
QCOMPARE(item.child(row, column), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(item.child(row, column), nullptr);
|
||||
}
|
||||
|
||||
void tst_QStandardItem::parent()
|
||||
@ -411,7 +412,7 @@ void tst_QStandardItem::parent()
|
||||
{
|
||||
QStandardItem item;
|
||||
QStandardItem *child = new QStandardItem;
|
||||
QCOMPARE(child->parent(), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(child->parent(), nullptr);
|
||||
item.setChild(0, 0, child);
|
||||
QCOMPARE(child->parent(), &item);
|
||||
|
||||
@ -425,7 +426,7 @@ void tst_QStandardItem::parent()
|
||||
QStandardItem *item = new QStandardItem;
|
||||
model.appendRow(item);
|
||||
// parent of a top-level item should be 0
|
||||
QCOMPARE(item->parent(), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(item->parent(), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,7 +486,7 @@ void tst_QStandardItem::insertColumn()
|
||||
for (int i = 0; i < count; ++i)
|
||||
QCOMPARE(item.child(i, column), columnItems.at(i));
|
||||
for (int i = count; i < item.rowCount(); ++i)
|
||||
QCOMPARE(item.child(i, column), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(item.child(i, column), nullptr);
|
||||
} else {
|
||||
QCOMPARE(item.columnCount(), columns);
|
||||
QCOMPARE(item.rowCount(), rows);
|
||||
@ -493,14 +494,6 @@ void tst_QStandardItem::insertColumn()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QStandardItem::insertColumns_data()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QStandardItem::insertColumns()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QStandardItem::insertRow_data()
|
||||
{
|
||||
QTest::addColumn<int>("rows");
|
||||
@ -557,7 +550,7 @@ void tst_QStandardItem::insertRow()
|
||||
for (int i = 0; i < count; ++i)
|
||||
QCOMPARE(item.child(row, i), rowItems.at(i));
|
||||
for (int i = count; i < item.columnCount(); ++i)
|
||||
QCOMPARE(item.child(row, i), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(item.child(row, i), nullptr);
|
||||
} else {
|
||||
QCOMPARE(item.columnCount(), columns);
|
||||
QCOMPARE(item.rowCount(), rows);
|
||||
@ -585,9 +578,8 @@ void tst_QStandardItem::insertRows()
|
||||
QStandardItem item(rows, columns);
|
||||
|
||||
QList<QStandardItem*> items;
|
||||
for (int i = 0; i < insertCount; ++i) {
|
||||
for (int i = 0; i < insertCount; ++i)
|
||||
items.append(new QStandardItem());
|
||||
}
|
||||
item.insertRows(insertAt, items);
|
||||
|
||||
QCOMPARE(item.rowCount(), rows + insertCount);
|
||||
@ -659,7 +651,7 @@ void tst_QStandardItem::appendColumn()
|
||||
for (int i = 0; i < count; ++i)
|
||||
QCOMPARE(item.child(i, columns), columnItems.at(i));
|
||||
for (int i = count; i < item.rowCount(); ++i)
|
||||
QCOMPARE(item.child(i, columns), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(item.child(i, columns), nullptr);
|
||||
|
||||
// make sure original children remained unchanged
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
@ -734,7 +726,7 @@ void tst_QStandardItem::appendRow()
|
||||
for (int i = 0; i < count; ++i)
|
||||
QCOMPARE(item.child(rows, i), rowItems.at(i));
|
||||
for (int i = count; i < item.columnCount(); ++i)
|
||||
QCOMPARE(item.child(rows, i), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(item.child(rows, i), nullptr);
|
||||
|
||||
// make sure original children remained unchanged
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
@ -753,7 +745,7 @@ void tst_QStandardItem::takeChild()
|
||||
|
||||
for (int i = 0; i < item.rowCount(); ++i) {
|
||||
QCOMPARE(item.takeChild(i), itemList.at(i));
|
||||
QCOMPARE(item.takeChild(0, 0), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(item.takeChild(0, 0), nullptr);
|
||||
for (int j = i + 1; j < item.rowCount(); ++j)
|
||||
QCOMPARE(item.child(j), itemList.at(j));
|
||||
}
|
||||
@ -938,7 +930,7 @@ void tst_QStandardItem::deleteItem()
|
||||
for (int j = 0; j < model.columnCount(); ++j) {
|
||||
QStandardItem *item = model.item(i, j);
|
||||
delete item;
|
||||
QCOMPARE(model.item(i, j), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(model.item(i, j), nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -995,9 +987,9 @@ void tst_QStandardItem::sortChildren()
|
||||
item->appendRow(two);
|
||||
|
||||
QSignalSpy layoutAboutToBeChangedSpy(
|
||||
model, SIGNAL(layoutAboutToBeChanged()));
|
||||
model, &QAbstractItemModel::layoutAboutToBeChanged);
|
||||
QSignalSpy layoutChangedSpy(
|
||||
model, SIGNAL(layoutChanged()));
|
||||
model, &QAbstractItemModel::layoutChanged);
|
||||
|
||||
one->sortChildren(0, Qt::DescendingOrder);
|
||||
// verify sorted
|
||||
@ -1040,19 +1032,16 @@ void tst_QStandardItem::sortChildren()
|
||||
class CustomItem : public QStandardItem
|
||||
{
|
||||
public:
|
||||
CustomItem(const QString &text) : QStandardItem(text) { }
|
||||
CustomItem() { }
|
||||
virtual ~CustomItem() { }
|
||||
using QStandardItem::QStandardItem;
|
||||
|
||||
virtual int type() const { return QStandardItem::UserType + 1; }
|
||||
int type() const override { return QStandardItem::UserType + 1; }
|
||||
|
||||
virtual QStandardItem *clone() const { return QStandardItem::clone(); }
|
||||
|
||||
void emitDataChanged() { QStandardItem::emitDataChanged(); }
|
||||
|
||||
virtual bool operator<(const QStandardItem &other) const {
|
||||
bool operator<(const QStandardItem &other) const override {
|
||||
return text().length() < other.text().length();
|
||||
}
|
||||
|
||||
using QStandardItem::clone;
|
||||
using QStandardItem::emitDataChanged;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QStandardItem*)
|
||||
@ -1072,11 +1061,11 @@ void tst_QStandardItem::subclassing()
|
||||
QStandardItemModel model;
|
||||
model.appendRow(item);
|
||||
|
||||
QSignalSpy itemChangedSpy(&model, SIGNAL(itemChanged(QStandardItem*)));
|
||||
QSignalSpy itemChangedSpy(&model, &QStandardItemModel::itemChanged);
|
||||
item->emitDataChanged();
|
||||
QCOMPARE(itemChangedSpy.count(), 1);
|
||||
QCOMPARE(itemChangedSpy.at(0).count(), 1);
|
||||
QCOMPARE(qvariant_cast<QStandardItem*>(itemChangedSpy.at(0).at(0)), (QStandardItem*)item);
|
||||
QCOMPARE(qvariant_cast<QStandardItem*>(itemChangedSpy.at(0).at(0)), item);
|
||||
|
||||
CustomItem *child0 = new CustomItem("cc");
|
||||
CustomItem *child1 = new CustomItem("bbb");
|
||||
@ -1085,9 +1074,9 @@ void tst_QStandardItem::subclassing()
|
||||
item->appendRow(child1);
|
||||
item->appendRow(child2);
|
||||
item->sortChildren(0);
|
||||
QCOMPARE(item->child(0), (QStandardItem*)child2);
|
||||
QCOMPARE(item->child(1), (QStandardItem*)child0);
|
||||
QCOMPARE(item->child(2), (QStandardItem*)child1);
|
||||
QCOMPARE(item->child(0), child2);
|
||||
QCOMPARE(item->child(1), child0);
|
||||
QCOMPARE(item->child(2), child1);
|
||||
}
|
||||
|
||||
void tst_QStandardItem::lessThan()
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
#include <qstandarditemmodel.h>
|
||||
#include <QStandardItemModel>
|
||||
#include <QTreeView>
|
||||
#include <private/qtreeview_p.h>
|
||||
|
||||
@ -134,28 +134,30 @@ private slots:
|
||||
void setItemPersistentIndex();
|
||||
|
||||
private:
|
||||
QStandardItemModel *m_model;
|
||||
QStandardItemModel *m_model = nullptr;
|
||||
QPersistentModelIndex persistent;
|
||||
QVector<QModelIndex> rcParent;
|
||||
QVector<int> rcFirst;
|
||||
QVector<int> rcLast;
|
||||
QVector<QModelIndex> rcParent = QVector<QModelIndex>(8);
|
||||
QVector<int> rcFirst = QVector<int>(8, 0);
|
||||
QVector<int> rcLast = QVector<int>(8, 0);
|
||||
QVector<int> currentRoles;
|
||||
|
||||
//return true if models have the same structure, and all child have the same text
|
||||
bool compareModels(QStandardItemModel *model1, QStandardItemModel *model2);
|
||||
static bool compareModels(QStandardItemModel *model1, QStandardItemModel *model2);
|
||||
//return true if models have the same structure, and all child have the same text
|
||||
bool compareItems(QStandardItem *item1, QStandardItem *item2);
|
||||
static bool compareItems(QStandardItem *item1, QStandardItem *item2);
|
||||
};
|
||||
|
||||
static const int defaultSize = 3;
|
||||
static constexpr int defaultSize = 3;
|
||||
|
||||
Q_DECLARE_METATYPE(QStandardItem*)
|
||||
Q_DECLARE_METATYPE(Qt::Orientation)
|
||||
|
||||
tst_QStandardItemModel::tst_QStandardItemModel() : m_model(0), rcParent(8), rcFirst(8,0), rcLast(8,0)
|
||||
tst_QStandardItemModel::tst_QStandardItemModel()
|
||||
{
|
||||
qRegisterMetaType<QStandardItem*>("QStandardItem*");
|
||||
qRegisterMetaType<Qt::Orientation>("Qt::Orientation");
|
||||
qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>("QAbstractItemModel::LayoutChangeHint");
|
||||
qRegisterMetaType<QList<QPersistentModelIndex>>("QList<QPersistentModelIndex>");
|
||||
}
|
||||
|
||||
/*
|
||||
@ -171,23 +173,23 @@ tst_QStandardItemModel::tst_QStandardItemModel() : m_model(0), rcParent(8), rcFi
|
||||
void tst_QStandardItemModel::init()
|
||||
{
|
||||
m_model = new QStandardItemModel(defaultSize, defaultSize);
|
||||
connect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
|
||||
this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int)));
|
||||
connect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)),
|
||||
this, SLOT(rowsInserted(QModelIndex,int,int)));
|
||||
connect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
|
||||
connect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(rowsRemoved(QModelIndex,int,int)));
|
||||
connect(m_model, &QStandardItemModel::rowsAboutToBeInserted,
|
||||
this, &tst_QStandardItemModel::rowsAboutToBeInserted);
|
||||
connect(m_model, &QStandardItemModel::rowsInserted,
|
||||
this, &tst_QStandardItemModel::rowsInserted);
|
||||
connect(m_model, &QStandardItemModel::rowsAboutToBeRemoved,
|
||||
this, &tst_QStandardItemModel::rowsAboutToBeRemoved);
|
||||
connect(m_model, &QStandardItemModel::rowsRemoved,
|
||||
this, &tst_QStandardItemModel::rowsRemoved);
|
||||
|
||||
connect(m_model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
|
||||
this, SLOT(columnsAboutToBeInserted(QModelIndex,int,int)));
|
||||
connect(m_model, SIGNAL(columnsInserted(QModelIndex,int,int)),
|
||||
this, SLOT(columnsInserted(QModelIndex,int,int)));
|
||||
connect(m_model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(columnsAboutToBeRemoved(QModelIndex,int,int)));
|
||||
connect(m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(columnsRemoved(QModelIndex,int,int)));
|
||||
connect(m_model, &QStandardItemModel::columnsAboutToBeInserted,
|
||||
this, &tst_QStandardItemModel::columnsAboutToBeInserted);
|
||||
connect(m_model, &QStandardItemModel::columnsInserted,
|
||||
this, &tst_QStandardItemModel::columnsInserted);
|
||||
connect(m_model, &QStandardItemModel::columnsAboutToBeRemoved,
|
||||
this, &tst_QStandardItemModel::columnsAboutToBeRemoved);
|
||||
connect(m_model, &QStandardItemModel::columnsRemoved,
|
||||
this, &tst_QStandardItemModel::columnsRemoved);
|
||||
|
||||
connect(m_model, &QAbstractItemModel::dataChanged,
|
||||
this, [this](const QModelIndex &, const QModelIndex &, const QVector<int> &roles)
|
||||
@ -201,25 +203,9 @@ void tst_QStandardItemModel::init()
|
||||
|
||||
void tst_QStandardItemModel::cleanup()
|
||||
{
|
||||
disconnect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
|
||||
this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int)));
|
||||
disconnect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)),
|
||||
this, SLOT(rowsInserted(QModelIndex,int,int)));
|
||||
disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
|
||||
disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(rowsRemoved(QModelIndex,int,int)));
|
||||
|
||||
disconnect(m_model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
|
||||
this, SLOT(columnsAboutToBeInserted(QModelIndex,int,int)));
|
||||
disconnect(m_model, SIGNAL(columnsInserted(QModelIndex,int,int)),
|
||||
this, SLOT(columnsInserted(QModelIndex,int,int)));
|
||||
disconnect(m_model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(columnsAboutToBeRemoved(QModelIndex,int,int)));
|
||||
disconnect(m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(columnsRemoved(QModelIndex,int,int)));
|
||||
m_model->disconnect(this);
|
||||
delete m_model;
|
||||
m_model = 0;
|
||||
m_model = nullptr;
|
||||
}
|
||||
|
||||
void tst_QStandardItemModel::insertRow_data()
|
||||
@ -241,9 +227,9 @@ void tst_QStandardItemModel::insertRow()
|
||||
|
||||
QIcon icon;
|
||||
// default all initial items to DisplayRole: "initalitem"
|
||||
for (int r=0; r < m_model->rowCount(); ++r) {
|
||||
for (int c=0; c < m_model->columnCount(); ++c) {
|
||||
m_model->setData(m_model->index(r,c), "initialitem", Qt::DisplayRole);
|
||||
for (int r = 0; r < m_model->rowCount(); ++r) {
|
||||
for (int c = 0; c < m_model->columnCount(); ++c) {
|
||||
m_model->setData(m_model->index(r, c), "initialitem", Qt::DisplayRole);
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,7 +293,7 @@ void tst_QStandardItemModel::insertRowsItems()
|
||||
int rowCount = m_model->rowCount();
|
||||
|
||||
QList<QStandardItem *> items;
|
||||
QStandardItemModel *m = qobject_cast<QStandardItemModel*>(m_model);
|
||||
QStandardItemModel *m = m_model;
|
||||
QStandardItem *hiddenRoot = m->invisibleRootItem();
|
||||
for (int i = 0; i < 3; ++i)
|
||||
items.append(new QStandardItem(QString::number(i + 10)));
|
||||
@ -318,7 +304,7 @@ void tst_QStandardItemModel::insertRowsItems()
|
||||
QCOMPARE(m_model->index(rowCount + 2, 0).data().toInt(), 12);
|
||||
for (int i = rowCount; i < rowCount + 3; ++i) {
|
||||
QVERIFY(m->item(i));
|
||||
QCOMPARE(static_cast<QAbstractItemModel *>(m->item(i)->model()), m_model);
|
||||
QCOMPARE(m->item(i)->model(), m_model);
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,9 +343,9 @@ void tst_QStandardItemModel::insertColumn()
|
||||
QFETCH(int, expectedColumn);
|
||||
|
||||
// default all initial items to DisplayRole: "initalitem"
|
||||
for (int r=0; r < m_model->rowCount(); ++r) {
|
||||
for (int c=0; c < m_model->columnCount(); ++c) {
|
||||
m_model->setData(m_model->index(r,c), "initialitem", Qt::DisplayRole);
|
||||
for (int r = 0; r < m_model->rowCount(); ++r) {
|
||||
for (int c = 0; c < m_model->columnCount(); ++c) {
|
||||
m_model->setData(m_model->index(r, c), "initialitem", Qt::DisplayRole);
|
||||
}
|
||||
}
|
||||
|
||||
@ -475,9 +461,9 @@ void tst_QStandardItemModel::setHeaderData()
|
||||
QCOMPARE(m_model->headerData(i, orient).toString(), QString::number(i + 1));
|
||||
|
||||
QSignalSpy headerDataChangedSpy(
|
||||
m_model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)));
|
||||
m_model, &QAbstractItemModel::headerDataChanged);
|
||||
QSignalSpy dataChangedSpy(
|
||||
m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)));
|
||||
m_model, &QAbstractItemModel::dataChanged);
|
||||
// insert custom values and check
|
||||
for (int i = 0; i < count; ++i) {
|
||||
QString customString = QString("custom") + QString::number(i);
|
||||
@ -593,14 +579,14 @@ void tst_QStandardItemModel::removingPersistentIndexes()
|
||||
QVERIFY(m_model->insertRows(0, 10));
|
||||
QVERIFY(m_model->insertColumns(0, 10));
|
||||
|
||||
QObject::connect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(checkAboutToBeRemoved()));
|
||||
QObject::connect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(checkRemoved()));
|
||||
QObject::connect(m_model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(checkAboutToBeRemoved()));
|
||||
QObject::connect(m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(checkRemoved()));
|
||||
connect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
|
||||
this, &tst_QStandardItemModel::checkAboutToBeRemoved);
|
||||
connect(m_model, &QAbstractItemModel::rowsRemoved,
|
||||
this, &tst_QStandardItemModel::checkRemoved);
|
||||
connect(m_model, &QAbstractItemModel::columnsAboutToBeRemoved,
|
||||
this, &tst_QStandardItemModel::checkAboutToBeRemoved);
|
||||
connect(m_model, &QAbstractItemModel::columnsRemoved,
|
||||
this, &tst_QStandardItemModel::checkRemoved);
|
||||
|
||||
|
||||
// test removeRow
|
||||
@ -635,14 +621,14 @@ void tst_QStandardItemModel::removingPersistentIndexes()
|
||||
QVERIFY(m_model->removeColumn(0));
|
||||
|
||||
|
||||
QObject::disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(checkAboutToBeRemoved()));
|
||||
QObject::disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(checkRemoved()));
|
||||
QObject::disconnect(m_model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(checkAboutToBeRemoved()));
|
||||
QObject::disconnect(m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(checkRemoved()));
|
||||
disconnect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
|
||||
this, &tst_QStandardItemModel::checkAboutToBeRemoved);
|
||||
disconnect(m_model, &QAbstractItemModel::rowsRemoved,
|
||||
this, &tst_QStandardItemModel::checkRemoved);
|
||||
disconnect(m_model, &QAbstractItemModel::columnsAboutToBeRemoved,
|
||||
this, &tst_QStandardItemModel::checkAboutToBeRemoved);
|
||||
disconnect(m_model, &QAbstractItemModel::columnsRemoved,
|
||||
this, &tst_QStandardItemModel::checkRemoved);
|
||||
}
|
||||
|
||||
void tst_QStandardItemModel::updateRowAboutToBeRemoved()
|
||||
@ -654,8 +640,8 @@ void tst_QStandardItemModel::updateRowAboutToBeRemoved()
|
||||
|
||||
void tst_QStandardItemModel::updatingPersistentIndexes()
|
||||
{
|
||||
QObject::connect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(updateRowAboutToBeRemoved()));
|
||||
connect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
|
||||
this, &tst_QStandardItemModel::updateRowAboutToBeRemoved);
|
||||
|
||||
persistent = m_model->index(1, 0);
|
||||
QVERIFY(persistent.isValid());
|
||||
@ -664,8 +650,8 @@ void tst_QStandardItemModel::updatingPersistentIndexes()
|
||||
QPersistentModelIndex tmp = m_model->index(0, 0);
|
||||
QCOMPARE(persistent, tmp);
|
||||
|
||||
QObject::disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
this, SLOT(updateRowAboutToBeRemoved()));
|
||||
disconnect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
|
||||
this, &tst_QStandardItemModel::updateRowAboutToBeRemoved);
|
||||
}
|
||||
|
||||
void tst_QStandardItemModel::modelChanged(ModelChanged change, const QModelIndex &parent,
|
||||
@ -738,8 +724,8 @@ void tst_QStandardItemModel::data()
|
||||
QCOMPARE(currentRoles, QVector<int>{});
|
||||
|
||||
QIcon icon;
|
||||
for (int r=0; r < m_model->rowCount(); ++r) {
|
||||
for (int c=0; c < m_model->columnCount(); ++c) {
|
||||
for (int r = 0; r < m_model->rowCount(); ++r) {
|
||||
for (int c = 0; c < m_model->columnCount(); ++c) {
|
||||
m_model->setData(m_model->index(r,c), "initialitem", Qt::DisplayRole);
|
||||
QCOMPARE(currentRoles, QVector<int>({Qt::DisplayRole, Qt::EditRole}));
|
||||
m_model->setData(m_model->index(r,c), "tooltip", Qt::ToolTipRole);
|
||||
@ -787,9 +773,9 @@ void tst_QStandardItemModel::clear()
|
||||
QCOMPARE(model.columnCount(), 10);
|
||||
QCOMPARE(model.rowCount(), 10);
|
||||
|
||||
QSignalSpy modelResetSpy(&model, SIGNAL(modelReset()));
|
||||
QSignalSpy layoutChangedSpy(&model, SIGNAL(layoutChanged()));
|
||||
QSignalSpy rowsRemovedSpy(&model, SIGNAL(rowsRemoved(QModelIndex,int,int)));
|
||||
QSignalSpy modelResetSpy(&model, &QStandardItemModel::modelReset);
|
||||
QSignalSpy layoutChangedSpy(&model, &QStandardItemModel::layoutChanged);
|
||||
QSignalSpy rowsRemovedSpy(&model, &QStandardItemModel::rowsRemoved);
|
||||
|
||||
QAbstractItemModelTester mt(&model);
|
||||
|
||||
@ -806,129 +792,35 @@ void tst_QStandardItemModel::clear()
|
||||
|
||||
void tst_QStandardItemModel::sort_data()
|
||||
{
|
||||
QTest::addColumn<int>("sortOrder");
|
||||
QTest::addColumn<Qt::SortOrder>("sortOrder");
|
||||
QTest::addColumn<QStringList>("initial");
|
||||
QTest::addColumn<QStringList>("expected");
|
||||
|
||||
QTest::newRow("flat descending") << static_cast<int>(Qt::DescendingOrder)
|
||||
<< (QStringList()
|
||||
<< "delta"
|
||||
<< "yankee"
|
||||
<< "bravo"
|
||||
<< "lima"
|
||||
<< "charlie"
|
||||
<< "juliet"
|
||||
<< "tango"
|
||||
<< "hotel"
|
||||
<< "uniform"
|
||||
<< "alpha"
|
||||
<< "echo"
|
||||
<< "golf"
|
||||
<< "quebec"
|
||||
<< "foxtrot"
|
||||
<< "india"
|
||||
<< "romeo"
|
||||
<< "november"
|
||||
<< "oskar"
|
||||
<< "zulu"
|
||||
<< "kilo"
|
||||
<< "whiskey"
|
||||
<< "mike"
|
||||
<< "papa"
|
||||
<< "sierra"
|
||||
<< "xray"
|
||||
<< "viktor")
|
||||
<< (QStringList()
|
||||
<< "zulu"
|
||||
<< "yankee"
|
||||
<< "xray"
|
||||
<< "whiskey"
|
||||
<< "viktor"
|
||||
<< "uniform"
|
||||
<< "tango"
|
||||
<< "sierra"
|
||||
<< "romeo"
|
||||
<< "quebec"
|
||||
<< "papa"
|
||||
<< "oskar"
|
||||
<< "november"
|
||||
<< "mike"
|
||||
<< "lima"
|
||||
<< "kilo"
|
||||
<< "juliet"
|
||||
<< "india"
|
||||
<< "hotel"
|
||||
<< "golf"
|
||||
<< "foxtrot"
|
||||
<< "echo"
|
||||
<< "delta"
|
||||
<< "charlie"
|
||||
<< "bravo"
|
||||
<< "alpha");
|
||||
QTest::newRow("flat ascending") << static_cast<int>(Qt::AscendingOrder)
|
||||
<< (QStringList()
|
||||
<< "delta"
|
||||
<< "yankee"
|
||||
<< "bravo"
|
||||
<< "lima"
|
||||
<< "charlie"
|
||||
<< "juliet"
|
||||
<< "tango"
|
||||
<< "hotel"
|
||||
<< "uniform"
|
||||
<< "alpha"
|
||||
<< "echo"
|
||||
<< "golf"
|
||||
<< "quebec"
|
||||
<< "foxtrot"
|
||||
<< "india"
|
||||
<< "romeo"
|
||||
<< "november"
|
||||
<< "oskar"
|
||||
<< "zulu"
|
||||
<< "kilo"
|
||||
<< "whiskey"
|
||||
<< "mike"
|
||||
<< "papa"
|
||||
<< "sierra"
|
||||
<< "xray"
|
||||
<< "viktor")
|
||||
<< (QStringList()
|
||||
<< "alpha"
|
||||
<< "bravo"
|
||||
<< "charlie"
|
||||
<< "delta"
|
||||
<< "echo"
|
||||
<< "foxtrot"
|
||||
<< "golf"
|
||||
<< "hotel"
|
||||
<< "india"
|
||||
<< "juliet"
|
||||
<< "kilo"
|
||||
<< "lima"
|
||||
<< "mike"
|
||||
<< "november"
|
||||
<< "oskar"
|
||||
<< "papa"
|
||||
<< "quebec"
|
||||
<< "romeo"
|
||||
<< "sierra"
|
||||
<< "tango"
|
||||
<< "uniform"
|
||||
<< "viktor"
|
||||
<< "whiskey"
|
||||
<< "xray"
|
||||
<< "yankee"
|
||||
<< "zulu");
|
||||
const QStringList unsorted(
|
||||
{"delta", "yankee", "bravo", "lima", "charlie", "juliet",
|
||||
"tango", "hotel", "uniform", "alpha", "echo", "golf",
|
||||
"quebec", "foxtrot", "india", "romeo", "november",
|
||||
"oskar", "zulu", "kilo", "whiskey", "mike", "papa",
|
||||
"sierra", "xray" , "viktor"});
|
||||
QStringList sorted = unsorted;
|
||||
|
||||
std::sort(sorted.begin(), sorted.end());
|
||||
QTest::newRow("flat ascending") << Qt::AscendingOrder
|
||||
<< unsorted
|
||||
<< sorted;
|
||||
std::reverse(sorted.begin(), sorted.end());
|
||||
QTest::newRow("flat descending") << Qt::DescendingOrder
|
||||
<< unsorted
|
||||
<< sorted;
|
||||
QStringList list;
|
||||
for (int i=1000; i < 2000; ++i)
|
||||
for (int i = 1000; i < 2000; ++i)
|
||||
list.append(QStringLiteral("Number: ") + QString::number(i));
|
||||
QTest::newRow("large set ascending") << static_cast<int>(Qt::AscendingOrder) << list << list;
|
||||
QTest::newRow("large set ascending") << Qt::AscendingOrder << list << list;
|
||||
}
|
||||
|
||||
void tst_QStandardItemModel::sort()
|
||||
{
|
||||
QFETCH(int, sortOrder);
|
||||
QFETCH(Qt::SortOrder, sortOrder);
|
||||
QFETCH(QStringList, initial);
|
||||
QFETCH(QStringList, expected);
|
||||
// prepare model
|
||||
@ -943,12 +835,12 @@ void tst_QStandardItemModel::sort()
|
||||
}
|
||||
|
||||
QSignalSpy layoutAboutToBeChangedSpy(
|
||||
&model, SIGNAL(layoutAboutToBeChanged()));
|
||||
&model, &QStandardItemModel::layoutAboutToBeChanged);
|
||||
QSignalSpy layoutChangedSpy(
|
||||
&model, SIGNAL(layoutChanged()));
|
||||
&model, &QStandardItemModel::layoutChanged);
|
||||
|
||||
// sort
|
||||
model.sort(0, static_cast<Qt::SortOrder>(sortOrder));
|
||||
model.sort(0, sortOrder);
|
||||
|
||||
QCOMPARE(layoutAboutToBeChangedSpy.count(), 1);
|
||||
QCOMPARE(layoutChangedSpy.count(), 1);
|
||||
@ -964,23 +856,23 @@ void tst_QStandardItemModel::sortRole_data()
|
||||
{
|
||||
QTest::addColumn<QStringList>("initialText");
|
||||
QTest::addColumn<QVariantList>("initialData");
|
||||
QTest::addColumn<int>("sortRole");
|
||||
QTest::addColumn<int>("sortOrder");
|
||||
QTest::addColumn<Qt::ItemDataRole>("sortRole");
|
||||
QTest::addColumn<Qt::SortOrder>("sortOrder");
|
||||
QTest::addColumn<QStringList>("expectedText");
|
||||
QTest::addColumn<QVariantList>("expectedData");
|
||||
|
||||
QTest::newRow("sort ascending with Qt::DisplayRole")
|
||||
<< (QStringList() << "b" << "a" << "c")
|
||||
<< (QVariantList() << 2 << 3 << 1)
|
||||
<< static_cast<int>(Qt::DisplayRole)
|
||||
<< static_cast<int>(Qt::AscendingOrder)
|
||||
<< Qt::DisplayRole
|
||||
<< Qt::AscendingOrder
|
||||
<< (QStringList() << "a" << "b" << "c")
|
||||
<< (QVariantList() << 3 << 2 << 1);
|
||||
QTest::newRow("sort ascending with Qt::UserRole")
|
||||
<< (QStringList() << "a" << "b" << "c")
|
||||
<< (QVariantList() << 3 << 2 << 1)
|
||||
<< static_cast<int>(Qt::UserRole)
|
||||
<< static_cast<int>(Qt::AscendingOrder)
|
||||
<< Qt::UserRole
|
||||
<< Qt::AscendingOrder
|
||||
<< (QStringList() << "c" << "b" << "a")
|
||||
<< (QVariantList() << 1 << 2 << 3);
|
||||
}
|
||||
@ -989,8 +881,8 @@ void tst_QStandardItemModel::sortRole()
|
||||
{
|
||||
QFETCH(QStringList, initialText);
|
||||
QFETCH(QVariantList, initialData);
|
||||
QFETCH(int, sortRole);
|
||||
QFETCH(int, sortOrder);
|
||||
QFETCH(Qt::ItemDataRole, sortRole);
|
||||
QFETCH(Qt::SortOrder, sortOrder);
|
||||
QFETCH(QStringList, expectedText);
|
||||
QFETCH(QVariantList, expectedData);
|
||||
|
||||
@ -1002,7 +894,7 @@ void tst_QStandardItemModel::sortRole()
|
||||
model.appendRow(item);
|
||||
}
|
||||
model.setSortRole(sortRole);
|
||||
model.sort(0, static_cast<Qt::SortOrder>(sortOrder));
|
||||
model.sort(0, sortOrder);
|
||||
for (int i = 0; i < expectedText.count(); ++i) {
|
||||
QStandardItem *item = model.item(i);
|
||||
QCOMPARE(item->text(), expectedText.at(i));
|
||||
@ -1033,23 +925,23 @@ void tst_QStandardItemModel::getSetHeaderItem()
|
||||
{
|
||||
QStandardItemModel model;
|
||||
|
||||
QCOMPARE(model.horizontalHeaderItem(0), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(model.horizontalHeaderItem(0), nullptr);
|
||||
QStandardItem *hheader = new QStandardItem();
|
||||
model.setHorizontalHeaderItem(0, hheader);
|
||||
QCOMPARE(model.columnCount(), 1);
|
||||
QCOMPARE(model.horizontalHeaderItem(0), hheader);
|
||||
QCOMPARE(hheader->model(), &model);
|
||||
model.setHorizontalHeaderItem(0, 0);
|
||||
QCOMPARE(model.horizontalHeaderItem(0), static_cast<QStandardItem*>(0));
|
||||
model.setHorizontalHeaderItem(0, nullptr);
|
||||
QCOMPARE(model.horizontalHeaderItem(0), nullptr);
|
||||
|
||||
QCOMPARE(model.verticalHeaderItem(0), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(model.verticalHeaderItem(0), nullptr);
|
||||
QStandardItem *vheader = new QStandardItem();
|
||||
model.setVerticalHeaderItem(0, vheader);
|
||||
QCOMPARE(model.rowCount(), 1);
|
||||
QCOMPARE(model.verticalHeaderItem(0), vheader);
|
||||
QCOMPARE(vheader->model(), &model);
|
||||
model.setVerticalHeaderItem(0, 0);
|
||||
QCOMPARE(model.verticalHeaderItem(0), static_cast<QStandardItem*>(0));
|
||||
model.setVerticalHeaderItem(0, nullptr);
|
||||
QCOMPARE(model.verticalHeaderItem(0), nullptr);
|
||||
}
|
||||
|
||||
void tst_QStandardItemModel::indexFromItem()
|
||||
@ -1066,7 +958,7 @@ void tst_QStandardItemModel::indexFromItem()
|
||||
QCOMPARE(itemIndex.row(), 10);
|
||||
QCOMPARE(itemIndex.column(), 20);
|
||||
QCOMPARE(itemIndex.parent(), QModelIndex());
|
||||
QCOMPARE(itemIndex.model(), (const QAbstractItemModel*)(&model));
|
||||
QCOMPARE(itemIndex.model(), &model);
|
||||
|
||||
QStandardItem *child = new QStandardItem;
|
||||
item->setChild(4, 2, child);
|
||||
@ -1081,7 +973,7 @@ void tst_QStandardItemModel::indexFromItem()
|
||||
QVERIFY(!noSuchIndex.isValid());
|
||||
delete dummy;
|
||||
|
||||
noSuchIndex = model.indexFromItem(0);
|
||||
noSuchIndex = model.indexFromItem(nullptr);
|
||||
QVERIFY(!noSuchIndex.isValid());
|
||||
}
|
||||
|
||||
@ -1089,7 +981,7 @@ void tst_QStandardItemModel::itemFromIndex()
|
||||
{
|
||||
QStandardItemModel model;
|
||||
|
||||
QCOMPARE(model.itemFromIndex(QModelIndex()), (QStandardItem*)0);
|
||||
QCOMPARE(model.itemFromIndex(QModelIndex()), nullptr);
|
||||
|
||||
QStandardItem *item = new QStandardItem;
|
||||
model.setItem(10, 20, item);
|
||||
@ -1110,35 +1002,31 @@ void tst_QStandardItemModel::itemFromIndex()
|
||||
class CustomItem : public QStandardItem
|
||||
{
|
||||
public:
|
||||
CustomItem() : QStandardItem() { }
|
||||
~CustomItem() { }
|
||||
int type() const {
|
||||
return UserType;
|
||||
}
|
||||
QStandardItem *clone() const {
|
||||
return new CustomItem;
|
||||
}
|
||||
using QStandardItem::QStandardItem;
|
||||
|
||||
int type() const override { return UserType; }
|
||||
QStandardItem *clone() const override { return new CustomItem; }
|
||||
};
|
||||
|
||||
void tst_QStandardItemModel::getSetItemPrototype()
|
||||
{
|
||||
QStandardItemModel model;
|
||||
QCOMPARE(model.itemPrototype(), static_cast<const QStandardItem*>(0));
|
||||
QCOMPARE(model.itemPrototype(), nullptr);
|
||||
|
||||
const CustomItem *proto = new CustomItem;
|
||||
model.setItemPrototype(proto);
|
||||
QCOMPARE(model.itemPrototype(), (const QStandardItem*)proto);
|
||||
QCOMPARE(model.itemPrototype(), proto);
|
||||
|
||||
model.setRowCount(1);
|
||||
model.setColumnCount(1);
|
||||
QModelIndex index = model.index(0, 0, QModelIndex());
|
||||
model.setData(index, "foo");
|
||||
QStandardItem *item = model.itemFromIndex(index);
|
||||
QVERIFY(item != 0);
|
||||
QVERIFY(item != nullptr);
|
||||
QCOMPARE(item->type(), static_cast<int>(QStandardItem::UserType));
|
||||
|
||||
model.setItemPrototype(0);
|
||||
QCOMPARE(model.itemPrototype(), static_cast<const QStandardItem*>(0));
|
||||
model.setItemPrototype(nullptr);
|
||||
QCOMPARE(model.itemPrototype(), nullptr);
|
||||
}
|
||||
|
||||
void tst_QStandardItemModel::getSetItemData()
|
||||
@ -1175,7 +1063,7 @@ void tst_QStandardItemModel::getSetItemData()
|
||||
QModelIndex idx = model.index(0, 0, QModelIndex());
|
||||
|
||||
QSignalSpy modelDataChangedSpy(
|
||||
&model, SIGNAL(dataChanged(QModelIndex,QModelIndex)));
|
||||
&model, &QStandardItemModel::dataChanged);
|
||||
QVERIFY(model.setItemData(idx, roles));
|
||||
QCOMPARE(modelDataChangedSpy.count(), 1);
|
||||
QVERIFY(model.setItemData(idx, roles));
|
||||
@ -1187,44 +1075,44 @@ void tst_QStandardItemModel::setHeaderLabels_data()
|
||||
{
|
||||
QTest::addColumn<int>("rows");
|
||||
QTest::addColumn<int>("columns");
|
||||
QTest::addColumn<int>("orientation");
|
||||
QTest::addColumn<Qt::Orientation>("orientation");
|
||||
QTest::addColumn<QStringList>("labels");
|
||||
QTest::addColumn<QStringList>("expectedLabels");
|
||||
|
||||
QTest::newRow("horizontal labels")
|
||||
<< 1
|
||||
<< 4
|
||||
<< int(Qt::Horizontal)
|
||||
<< Qt::Horizontal
|
||||
<< (QStringList() << "a" << "b" << "c" << "d")
|
||||
<< (QStringList() << "a" << "b" << "c" << "d");
|
||||
QTest::newRow("vertical labels")
|
||||
<< 4
|
||||
<< 1
|
||||
<< int(Qt::Vertical)
|
||||
<< Qt::Vertical
|
||||
<< (QStringList() << "a" << "b" << "c" << "d")
|
||||
<< (QStringList() << "a" << "b" << "c" << "d");
|
||||
QTest::newRow("too few (horizontal)")
|
||||
<< 1
|
||||
<< 4
|
||||
<< int(Qt::Horizontal)
|
||||
<< Qt::Horizontal
|
||||
<< (QStringList() << "a" << "b")
|
||||
<< (QStringList() << "a" << "b" << "3" << "4");
|
||||
QTest::newRow("too few (vertical)")
|
||||
<< 4
|
||||
<< 1
|
||||
<< int(Qt::Vertical)
|
||||
<< Qt::Vertical
|
||||
<< (QStringList() << "a" << "b")
|
||||
<< (QStringList() << "a" << "b" << "3" << "4");
|
||||
QTest::newRow("too many (horizontal)")
|
||||
<< 1
|
||||
<< 2
|
||||
<< int(Qt::Horizontal)
|
||||
<< Qt::Horizontal
|
||||
<< (QStringList() << "a" << "b" << "c" << "d")
|
||||
<< (QStringList() << "a" << "b" << "c" << "d");
|
||||
QTest::newRow("too many (vertical)")
|
||||
<< 2
|
||||
<< 1
|
||||
<< int(Qt::Vertical)
|
||||
<< Qt::Vertical
|
||||
<< (QStringList() << "a" << "b" << "c" << "d")
|
||||
<< (QStringList() << "a" << "b" << "c" << "d");
|
||||
}
|
||||
@ -1233,20 +1121,18 @@ void tst_QStandardItemModel::setHeaderLabels()
|
||||
{
|
||||
QFETCH(int, rows);
|
||||
QFETCH(int, columns);
|
||||
QFETCH(int, orientation);
|
||||
QFETCH(Qt::Orientation, orientation);
|
||||
QFETCH(QStringList, labels);
|
||||
QFETCH(QStringList, expectedLabels);
|
||||
QStandardItemModel model(rows, columns);
|
||||
QSignalSpy columnsInsertedSpy(
|
||||
&model, SIGNAL(columnsInserted(QModelIndex,int,int)));
|
||||
QSignalSpy rowsInsertedSpy(
|
||||
&model, SIGNAL(rowsInserted(QModelIndex,int,int)));
|
||||
QSignalSpy columnsInsertedSpy(&model, &QAbstractItemModel::columnsInserted);
|
||||
QSignalSpy rowsInsertedSpy(&model, &QAbstractItemModel::rowsInserted);
|
||||
if (orientation == Qt::Horizontal)
|
||||
model.setHorizontalHeaderLabels(labels);
|
||||
else
|
||||
model.setVerticalHeaderLabels(labels);
|
||||
for (int i = 0; i < expectedLabels.count(); ++i)
|
||||
QCOMPARE(model.headerData(i, Qt::Orientation(orientation)).toString(), expectedLabels.at(i));
|
||||
QCOMPARE(model.headerData(i, orientation).toString(), expectedLabels.at(i));
|
||||
QCOMPARE(columnsInsertedSpy.count(),
|
||||
(orientation == Qt::Vertical) ? 0 : labels.count() > columns);
|
||||
QCOMPARE(rowsInsertedSpy.count(),
|
||||
@ -1257,10 +1143,8 @@ void tst_QStandardItemModel::itemDataChanged()
|
||||
{
|
||||
QStandardItemModel model(6, 4);
|
||||
QStandardItem item;
|
||||
QSignalSpy dataChangedSpy(
|
||||
&model, SIGNAL(dataChanged(QModelIndex,QModelIndex)));
|
||||
QSignalSpy itemChangedSpy(
|
||||
&model, SIGNAL(itemChanged(QStandardItem*)));
|
||||
QSignalSpy dataChangedSpy(&model, &QStandardItemModel::dataChanged);
|
||||
QSignalSpy itemChangedSpy(&model, &QStandardItemModel::itemChanged);
|
||||
|
||||
model.setItem(0, &item);
|
||||
QCOMPARE(dataChangedSpy.count(), 1);
|
||||
@ -1304,19 +1188,17 @@ void tst_QStandardItemModel::takeHeaderItem()
|
||||
{
|
||||
QStandardItemModel model;
|
||||
// set header items
|
||||
QStandardItem *hheader = new QStandardItem();
|
||||
model.setHorizontalHeaderItem(0, hheader);
|
||||
QStandardItem *vheader = new QStandardItem();
|
||||
model.setVerticalHeaderItem(0, vheader);
|
||||
QScopedPointer<QStandardItem> hheader(new QStandardItem());
|
||||
model.setHorizontalHeaderItem(0, hheader.get());
|
||||
QScopedPointer<QStandardItem> vheader(new QStandardItem());
|
||||
model.setVerticalHeaderItem(0, vheader.get());
|
||||
// take header items
|
||||
QCOMPARE(model.takeHorizontalHeaderItem(0), hheader);
|
||||
QCOMPARE(model.takeVerticalHeaderItem(0), vheader);
|
||||
QCOMPARE(hheader->model(), static_cast<QStandardItemModel*>(0));
|
||||
QCOMPARE(vheader->model(), static_cast<QStandardItemModel*>(0));
|
||||
QCOMPARE(model.takeHorizontalHeaderItem(0), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(model.takeVerticalHeaderItem(0), static_cast<QStandardItem*>(0));
|
||||
delete hheader;
|
||||
delete vheader;
|
||||
QCOMPARE(model.takeHorizontalHeaderItem(0), hheader.get());
|
||||
QCOMPARE(model.takeVerticalHeaderItem(0), vheader.get());
|
||||
QCOMPARE(hheader->model(), nullptr);
|
||||
QCOMPARE(vheader->model(), nullptr);
|
||||
QCOMPARE(model.takeHorizontalHeaderItem(0), nullptr);
|
||||
QCOMPARE(model.takeVerticalHeaderItem(0), nullptr);
|
||||
}
|
||||
|
||||
void tst_QStandardItemModel::useCase1()
|
||||
@ -1326,7 +1208,7 @@ void tst_QStandardItemModel::useCase1()
|
||||
QStandardItemModel model(rows, columns);
|
||||
for (int i = 0; i < model.rowCount(); ++i) {
|
||||
for (int j = 0; j < model.columnCount(); ++j) {
|
||||
QCOMPARE(model.item(i, j), static_cast<QStandardItem*>(0));
|
||||
QCOMPARE(model.item(i, j), nullptr);
|
||||
|
||||
QStandardItem *item = new QStandardItem();
|
||||
model.setItem(i, j, item);
|
||||
@ -1361,7 +1243,7 @@ static void createChildren(QStandardItemModel *model, QStandardItem *parent, int
|
||||
QStandardItem *theItem = model->itemFromIndex(index);
|
||||
QCOMPARE(theItem, item);
|
||||
QStandardItem *theParent = model->itemFromIndex(parentIndex);
|
||||
QCOMPARE(theParent, (level == 0) ? (QStandardItem*)0 : parent);
|
||||
QCOMPARE(theParent, (level == 0) ? static_cast<QStandardItem *>(nullptr) : parent);
|
||||
}
|
||||
|
||||
{
|
||||
@ -1382,7 +1264,7 @@ void tst_QStandardItemModel::useCase2()
|
||||
void tst_QStandardItemModel::useCase3()
|
||||
{
|
||||
// create the tree structure first
|
||||
QStandardItem *childItem = 0;
|
||||
QStandardItem *childItem = nullptr;
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
QStandardItem *item = new QStandardItem(QStringLiteral("item ") + QString::number(i));
|
||||
if (childItem)
|
||||
@ -1395,7 +1277,7 @@ void tst_QStandardItemModel::useCase3()
|
||||
model.appendRow(childItem);
|
||||
|
||||
// make sure each item has the correct model and parent
|
||||
QStandardItem *parentItem = 0;
|
||||
QStandardItem *parentItem = nullptr;
|
||||
while (childItem) {
|
||||
QCOMPARE(childItem->model(), &model);
|
||||
QCOMPARE(childItem->parent(), parentItem);
|
||||
@ -1406,10 +1288,10 @@ void tst_QStandardItemModel::useCase3()
|
||||
// take the item, make sure model is set to 0, but that parents are the same
|
||||
childItem = model.takeItem(0);
|
||||
{
|
||||
parentItem = 0;
|
||||
parentItem = nullptr;
|
||||
QStandardItem *item = childItem;
|
||||
while (item) {
|
||||
QCOMPARE(item->model(), static_cast<QStandardItemModel*>(0));
|
||||
QCOMPARE(item->model(), nullptr);
|
||||
QCOMPARE(item->parent(), parentItem);
|
||||
parentItem = item;
|
||||
item = item->child(0);
|
||||
@ -1424,7 +1306,7 @@ void tst_QStandardItemModel::setNullChild()
|
||||
model.setColumnCount(2);
|
||||
createChildren(&model, model.invisibleRootItem(), 0);
|
||||
QStandardItem *item = model.item(0);
|
||||
QSignalSpy spy(&model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)));
|
||||
QSignalSpy spy(&model, &QAbstractItemModel::dataChanged);
|
||||
item->setChild(0, nullptr);
|
||||
QCOMPARE(item->child(0), nullptr);
|
||||
QCOMPARE(spy.count(), 1);
|
||||
@ -1436,7 +1318,7 @@ void tst_QStandardItemModel::deleteChild()
|
||||
model.setColumnCount(2);
|
||||
createChildren(&model, model.invisibleRootItem(), 0);
|
||||
QStandardItem *item = model.item(0);
|
||||
QSignalSpy spy(&model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)));
|
||||
QSignalSpy spy(&model, &QAbstractItemModel::dataChanged);
|
||||
delete item->child(0);
|
||||
QCOMPARE(item->child(0), nullptr);
|
||||
QCOMPARE(spy.count(), 1);
|
||||
@ -1471,7 +1353,7 @@ bool tst_QStandardItemModel::compareItems(QStandardItem *item1, QStandardItem *i
|
||||
return true;
|
||||
if (!item1 || !item2)
|
||||
return false;
|
||||
if (item1->text() != item2->text()){
|
||||
if (item1->text() != item2->text()) {
|
||||
qDebug() << item1->text() << item2->text();
|
||||
return false;
|
||||
}
|
||||
@ -1483,39 +1365,36 @@ bool tst_QStandardItemModel::compareItems(QStandardItem *item1, QStandardItem *i
|
||||
// qDebug() << "ColumnCount" << item1->text() << item1->columnCount() << item2->columnCount();
|
||||
return false;
|
||||
}
|
||||
for (int row = 0; row < item1->columnCount(); row++)
|
||||
for (int row = 0; row < item1->columnCount(); row++) {
|
||||
for (int col = 0; col < item1->columnCount(); col++) {
|
||||
|
||||
if (!compareItems(item1->child(row, col), item2->child(row, col)))
|
||||
return false;
|
||||
if (!compareItems(item1->child(row, col), item2->child(row, col)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static QStandardItem *itemFromText(QStandardItem *parent, const QString &text)
|
||||
{
|
||||
QStandardItem *item = 0;
|
||||
for(int i = 0; i < parent->columnCount(); i++)
|
||||
for(int j = 0; j < parent->rowCount(); j++) {
|
||||
QStandardItem *item = nullptr;
|
||||
for (int i = 0; i < parent->columnCount(); i++) {
|
||||
for (int j = 0; j < parent->rowCount(); j++) {
|
||||
QStandardItem *child = parent->child(j, i);
|
||||
if (!child)
|
||||
continue;
|
||||
|
||||
QStandardItem *child = parent->child(j, i);
|
||||
|
||||
if(!child)
|
||||
continue;
|
||||
|
||||
if (child->text() == text) {
|
||||
if (item) {
|
||||
return 0;
|
||||
if (child->text() == text) {
|
||||
if (item)
|
||||
return nullptr;
|
||||
item = child;
|
||||
}
|
||||
item = child;
|
||||
}
|
||||
|
||||
QStandardItem *candidate = itemFromText(child, text);
|
||||
if(candidate) {
|
||||
if (item) {
|
||||
return 0;
|
||||
QStandardItem *candidate = itemFromText(child, text);
|
||||
if (candidate) {
|
||||
if (item)
|
||||
return nullptr;
|
||||
item = candidate;
|
||||
}
|
||||
item = candidate;
|
||||
}
|
||||
}
|
||||
return item;
|
||||
|
@ -506,29 +506,67 @@ void tst_QGuiApplication::keyboardModifiers()
|
||||
window->close();
|
||||
}
|
||||
|
||||
/*
|
||||
Compare actual against expected but ignore unset roles.
|
||||
|
||||
Comparing palettes via operator== will compare all roles.
|
||||
*/
|
||||
static bool palettesMatch(const QPalette &actual, const QPalette &expected)
|
||||
{
|
||||
if (actual.resolve() != expected.resolve())
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < QPalette::NColorGroups; i++) {
|
||||
for (int j = 0; j < QPalette::NColorRoles; j++) {
|
||||
const auto g = QPalette::ColorGroup(i);
|
||||
const auto r = QPalette::ColorRole(j);
|
||||
if (expected.isBrushSet(g, r)) {
|
||||
if (actual.brush(g, r) != expected.brush(g, r))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void tst_QGuiApplication::palette()
|
||||
{
|
||||
// Getting the palette before application construction should work
|
||||
QPalette paletteBeforeAppConstruction = QGuiApplication::palette();
|
||||
// And should be reflected in the default constructed palette
|
||||
QCOMPARE(paletteBeforeAppConstruction, QPalette());
|
||||
|
||||
int argc = 1;
|
||||
char *argv[] = { const_cast<char*>("tst_qguiapplication") };
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
// The same should be true after application construction
|
||||
QCOMPARE(QGuiApplication::palette(), QPalette());
|
||||
|
||||
// The default application palette is not resolved
|
||||
QVERIFY(!QGuiApplication::palette().resolve());
|
||||
|
||||
QSignalSpy signalSpy(&app, SIGNAL(paletteChanged(QPalette)));
|
||||
|
||||
QPalette oldPalette = QGuiApplication::palette();
|
||||
QPalette newPalette = QPalette(Qt::red);
|
||||
|
||||
QGuiApplication::setPalette(newPalette);
|
||||
QCOMPARE(QGuiApplication::palette(), newPalette);
|
||||
QVERIFY(palettesMatch(QGuiApplication::palette(), newPalette));
|
||||
QCOMPARE(signalSpy.count(), 1);
|
||||
QCOMPARE(signalSpy.at(0).at(0), QVariant(newPalette));
|
||||
QVERIFY(palettesMatch(signalSpy.at(0).at(0).value<QPalette>(), newPalette));
|
||||
QCOMPARE(QGuiApplication::palette(), QPalette());
|
||||
|
||||
QGuiApplication::setPalette(oldPalette);
|
||||
QCOMPARE(QGuiApplication::palette(), oldPalette);
|
||||
QVERIFY(palettesMatch(QGuiApplication::palette(), oldPalette));
|
||||
QCOMPARE(signalSpy.count(), 2);
|
||||
QCOMPARE(signalSpy.at(1).at(0), QVariant(oldPalette));
|
||||
QVERIFY(palettesMatch(signalSpy.at(1).at(0).value<QPalette>(), oldPalette));
|
||||
QCOMPARE(QGuiApplication::palette(), QPalette());
|
||||
|
||||
QGuiApplication::setPalette(oldPalette);
|
||||
QCOMPARE(QGuiApplication::palette(), oldPalette);
|
||||
QVERIFY(palettesMatch(QGuiApplication::palette(), oldPalette));
|
||||
QCOMPARE(signalSpy.count(), 2);
|
||||
QCOMPARE(QGuiApplication::palette(), QPalette());
|
||||
}
|
||||
|
||||
void tst_QGuiApplication::font()
|
||||
@ -1073,6 +1111,9 @@ void tst_QGuiApplication::testSetPaletteAttribute()
|
||||
QGuiApplication::setPalette(palette);
|
||||
|
||||
QVERIFY(QCoreApplication::testAttribute(Qt::AA_SetPalette));
|
||||
|
||||
QGuiApplication::setPalette(QPalette());
|
||||
QVERIFY(!QCoreApplication::testAttribute(Qt::AA_SetPalette));
|
||||
}
|
||||
|
||||
// Test that static functions do not crash if there is no application instance.
|
||||
|
BIN
tests/auto/gui/rhi/qshader/data/texture_all_v4.frag.qsb
Normal file
BIN
tests/auto/gui/rhi/qshader/data/texture_all_v4.frag.qsb
Normal file
Binary file not shown.
@ -43,6 +43,8 @@ private slots:
|
||||
void mslResourceMapping();
|
||||
void loadV3();
|
||||
void serializeShaderDesc();
|
||||
void comparison();
|
||||
void loadV4();
|
||||
};
|
||||
|
||||
static QShader getShader(const QString &name)
|
||||
@ -353,36 +355,63 @@ void tst_QShader::serializeShaderDesc()
|
||||
QShaderDescription desc;
|
||||
QVERIFY(!desc.isValid());
|
||||
|
||||
const QByteArray data = desc.toCbor();
|
||||
QByteArray data;
|
||||
{
|
||||
QBuffer buf(&data);
|
||||
QDataStream ds(&buf);
|
||||
QVERIFY(buf.open(QIODevice::WriteOnly));
|
||||
desc.serialize(&ds);
|
||||
}
|
||||
QVERIFY(!data.isEmpty());
|
||||
|
||||
QShaderDescription desc2 = QShaderDescription::fromCbor(data);
|
||||
QVERIFY(!desc2.isValid());
|
||||
{
|
||||
QBuffer buf(&data);
|
||||
QDataStream ds(&buf);
|
||||
QVERIFY(buf.open(QIODevice::ReadOnly));
|
||||
QShaderDescription desc2 = QShaderDescription::deserialize(&ds);
|
||||
QVERIFY(!desc2.isValid());
|
||||
}
|
||||
}
|
||||
|
||||
// a QShaderDescription with inputs, outputs, uniform block and combined image sampler
|
||||
{
|
||||
QShader s = getShader(QLatin1String(":/data/texture_all_v3.frag.qsb"));
|
||||
QShader s = getShader(QLatin1String(":/data/texture_all_v4.frag.qsb"));
|
||||
QVERIFY(s.isValid());
|
||||
const QShaderDescription desc = s.description();
|
||||
QVERIFY(desc.isValid());
|
||||
|
||||
const QByteArray data = desc.toCbor();
|
||||
QByteArray data;
|
||||
{
|
||||
QBuffer buf(&data);
|
||||
QDataStream ds(&buf);
|
||||
QVERIFY(buf.open(QIODevice::WriteOnly));
|
||||
desc.serialize(&ds);
|
||||
}
|
||||
QVERIFY(!data.isEmpty());
|
||||
|
||||
QShaderDescription desc2;
|
||||
QVERIFY(!desc2.isValid());
|
||||
QVERIFY(!(desc == desc2));
|
||||
QVERIFY(desc != desc2);
|
||||
{
|
||||
QShaderDescription desc2;
|
||||
QVERIFY(!desc2.isValid());
|
||||
QVERIFY(!(desc == desc2));
|
||||
QVERIFY(desc != desc2);
|
||||
}
|
||||
|
||||
desc2 = QShaderDescription::fromCbor(data);
|
||||
QVERIFY(desc2.isValid());
|
||||
QCOMPARE(desc, desc2);
|
||||
{
|
||||
QBuffer buf(&data);
|
||||
QDataStream ds(&buf);
|
||||
QVERIFY(buf.open(QIODevice::ReadOnly));
|
||||
QShaderDescription desc2 = QShaderDescription::deserialize(&ds);
|
||||
QVERIFY(desc2.isValid());
|
||||
QCOMPARE(desc, desc2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QShader::comparison()
|
||||
{
|
||||
// exercise QShader and QShaderDescription comparisons
|
||||
{
|
||||
QShader s1 = getShader(QLatin1String(":/data/texture_all_v3.frag.qsb"));
|
||||
QShader s1 = getShader(QLatin1String(":/data/texture_all_v4.frag.qsb"));
|
||||
QVERIFY(s1.isValid());
|
||||
QShader s2 = getShader(QLatin1String(":/data/color_all_v1.vert.qsb"));
|
||||
QVERIFY(s2.isValid());
|
||||
@ -393,6 +422,93 @@ void tst_QShader::serializeShaderDesc()
|
||||
QVERIFY(s1 != s2);
|
||||
QVERIFY(s1.description() != s2.description());
|
||||
}
|
||||
|
||||
{
|
||||
QShader s1 = getShader(QLatin1String(":/data/texture_all_v4.frag.qsb"));
|
||||
QVERIFY(s1.isValid());
|
||||
QShader s2 = getShader(QLatin1String(":/data/texture_all_v4.frag.qsb"));
|
||||
QVERIFY(s2.isValid());
|
||||
|
||||
QVERIFY(s1.description().isValid());
|
||||
QVERIFY(s2.description().isValid());
|
||||
|
||||
QVERIFY(s1 == s2);
|
||||
QVERIFY(s1.description() == s2.description());
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QShader::loadV4()
|
||||
{
|
||||
// qsb version 4: QShaderDescription is serialized via QDataStream. Ensure the deserialized data is as expected.
|
||||
QShader s = getShader(QLatin1String(":/data/texture_all_v4.frag.qsb"));
|
||||
QVERIFY(s.isValid());
|
||||
QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 4);
|
||||
|
||||
const QVector<QShaderKey> availableShaders = s.availableShaders();
|
||||
QCOMPARE(availableShaders.count(), 7);
|
||||
QVERIFY(availableShaders.contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
|
||||
QVERIFY(availableShaders.contains(QShaderKey(QShader::MslShader, QShaderVersion(12))));
|
||||
QVERIFY(availableShaders.contains(QShaderKey(QShader::HlslShader, QShaderVersion(50))));
|
||||
QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs))));
|
||||
QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(120))));
|
||||
QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(150))));
|
||||
QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(330))));
|
||||
|
||||
const QShaderDescription desc = s.description();
|
||||
QVERIFY(desc.isValid());
|
||||
QCOMPARE(desc.inputVariables().count(), 1);
|
||||
for (const QShaderDescription::InOutVariable &v : desc.inputVariables()) {
|
||||
switch (v.location) {
|
||||
case 0:
|
||||
QCOMPARE(v.name, QLatin1String("qt_TexCoord"));
|
||||
QCOMPARE(v.type, QShaderDescription::Vec2);
|
||||
break;
|
||||
default:
|
||||
QVERIFY(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
QCOMPARE(desc.outputVariables().count(), 1);
|
||||
for (const QShaderDescription::InOutVariable &v : desc.outputVariables()) {
|
||||
switch (v.location) {
|
||||
case 0:
|
||||
QCOMPARE(v.name, QLatin1String("fragColor"));
|
||||
QCOMPARE(v.type, QShaderDescription::Vec4);
|
||||
break;
|
||||
default:
|
||||
QVERIFY(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
QCOMPARE(desc.uniformBlocks().count(), 1);
|
||||
const QShaderDescription::UniformBlock blk = desc.uniformBlocks().first();
|
||||
QCOMPARE(blk.blockName, QLatin1String("buf"));
|
||||
QCOMPARE(blk.structName, QLatin1String("ubuf"));
|
||||
QCOMPARE(blk.size, 68);
|
||||
QCOMPARE(blk.binding, 0);
|
||||
QCOMPARE(blk.descriptorSet, 0);
|
||||
QCOMPARE(blk.members.count(), 2);
|
||||
for (int i = 0; i < blk.members.count(); ++i) {
|
||||
const QShaderDescription::BlockVariable v = blk.members[i];
|
||||
switch (i) {
|
||||
case 0:
|
||||
QCOMPARE(v.offset, 0);
|
||||
QCOMPARE(v.size, 64);
|
||||
QCOMPARE(v.name, QLatin1String("qt_Matrix"));
|
||||
QCOMPARE(v.type, QShaderDescription::Mat4);
|
||||
QCOMPARE(v.matrixStride, 16);
|
||||
break;
|
||||
case 1:
|
||||
QCOMPARE(v.offset, 64);
|
||||
QCOMPARE(v.size, 4);
|
||||
QCOMPARE(v.name, QLatin1String("opacity"));
|
||||
QCOMPARE(v.type, QShaderDescription::Float);
|
||||
break;
|
||||
default:
|
||||
QVERIFY(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <tst_qshader.moc>
|
||||
|
@ -279,7 +279,7 @@ void tst_Http2::singleRequest()
|
||||
QVERIFY(prefaceOK);
|
||||
QVERIFY(serverGotSettingsACK);
|
||||
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->networkError(), QNetworkReply::NoError);
|
||||
QVERIFY(reply->isFinished());
|
||||
}
|
||||
|
||||
@ -444,7 +444,7 @@ void tst_Http2::pushPromise()
|
||||
QVERIFY(prefaceOK);
|
||||
QVERIFY(serverGotSettingsACK);
|
||||
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->networkError(), QNetworkReply::NoError);
|
||||
QVERIFY(reply->isFinished());
|
||||
|
||||
// Now, the most interesting part!
|
||||
@ -466,7 +466,7 @@ void tst_Http2::pushPromise()
|
||||
QCOMPARE(nSentRequests, 0);
|
||||
// Decreased by replyFinished():
|
||||
QCOMPARE(nRequests, 0);
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->networkError(), QNetworkReply::NoError);
|
||||
QVERIFY(reply->isFinished());
|
||||
}
|
||||
|
||||
@ -511,7 +511,7 @@ void tst_Http2::goaway()
|
||||
QNetworkRequest request(url);
|
||||
request.setAttribute(QNetworkRequest::Http2AllowedAttribute, QVariant(true));
|
||||
replies[i] = manager->get(request);
|
||||
QCOMPARE(replies[i]->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(replies[i]->networkError(), QNetworkReply::NoError);
|
||||
void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) =
|
||||
&QNetworkReply::error;
|
||||
connect(replies[i], errorSignal, this, &tst_Http2::replyFinishedWithError);
|
||||
@ -671,7 +671,7 @@ void tst_Http2::connectToHost()
|
||||
connect(reply, &QNetworkReply::finished, [this, reply]() {
|
||||
--nRequests;
|
||||
eventLoop.exitLoop();
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->networkError(), QNetworkReply::NoError);
|
||||
QVERIFY(reply->isFinished());
|
||||
// Nothing received back:
|
||||
QVERIFY(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).isNull());
|
||||
@ -698,7 +698,7 @@ void tst_Http2::connectToHost()
|
||||
QVERIFY(prefaceOK);
|
||||
QVERIFY(serverGotSettingsACK);
|
||||
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->networkError(), QNetworkReply::NoError);
|
||||
QVERIFY(reply->isFinished());
|
||||
}
|
||||
|
||||
@ -927,10 +927,10 @@ void tst_Http2::replyFinished()
|
||||
QVERIFY(nRequests);
|
||||
|
||||
if (const auto reply = qobject_cast<QNetworkReply *>(sender())) {
|
||||
if (reply->error() != QNetworkReply::NoError)
|
||||
if (reply->networkError() != QNetworkReply::NoError)
|
||||
stopEventLoop();
|
||||
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->networkError(), QNetworkReply::NoError);
|
||||
|
||||
const QVariant http2Used(reply->attribute(QNetworkRequest::Http2WasUsedAttribute));
|
||||
if (!http2Used.isValid() || !http2Used.toBool())
|
||||
@ -960,9 +960,9 @@ void tst_Http2::replyFinishedWithError()
|
||||
if (const auto reply = qobject_cast<QNetworkReply *>(sender())) {
|
||||
// For now this is a 'generic' code, it just verifies some error was
|
||||
// reported without testing its type.
|
||||
if (reply->error() == QNetworkReply::NoError)
|
||||
if (reply->networkError() == QNetworkReply::NoError)
|
||||
stopEventLoop();
|
||||
QVERIFY(reply->error() != QNetworkReply::NoError);
|
||||
QVERIFY(reply->networkError() != QNetworkReply::NoError);
|
||||
}
|
||||
|
||||
--nRequests;
|
||||
|
@ -322,10 +322,10 @@ void tst_QAbstractNetworkCache::runTest()
|
||||
|
||||
QByteArray secondData = reply2->readAll();
|
||||
if (!fetchFromCache && cacheLoadControl == QNetworkRequest::AlwaysCache) {
|
||||
QCOMPARE(reply2->error(), QNetworkReply::ContentNotFoundError);
|
||||
QCOMPARE(reply2->networkError(), QNetworkReply::ContentNotFoundError);
|
||||
QCOMPARE(secondData, QByteArray());
|
||||
} else {
|
||||
QCOMPARE(reply2->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply2->networkError(), QNetworkReply::NoError);
|
||||
QCOMPARE(QString(secondData), QString(goodData));
|
||||
QCOMPARE(secondData, goodData);
|
||||
QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
|
||||
@ -375,12 +375,12 @@ void tst_QAbstractNetworkCache::checkSynchronous()
|
||||
|
||||
QByteArray secondData = reply2->readAll();
|
||||
if (!fetchFromCache && cacheLoadControl == QNetworkRequest::AlwaysCache) {
|
||||
QCOMPARE(reply2->error(), QNetworkReply::ContentNotFoundError);
|
||||
QCOMPARE(reply2->networkError(), QNetworkReply::ContentNotFoundError);
|
||||
QCOMPARE(secondData, QByteArray());
|
||||
} else {
|
||||
if (reply2->error() != QNetworkReply::NoError)
|
||||
if (reply2->networkError() != QNetworkReply::NoError)
|
||||
qDebug() << reply2->errorString();
|
||||
QCOMPARE(reply2->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply2->networkError(), QNetworkReply::NoError);
|
||||
QCOMPARE(QString(secondData), QString(goodData));
|
||||
QCOMPARE(secondData, goodData);
|
||||
QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -149,7 +149,7 @@ public slots:
|
||||
|
||||
void requestFinished(QNetworkReply *reply)
|
||||
{
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->networkError(), QNetworkReply::NoError);
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
|
@ -536,7 +536,7 @@ void tst_qnetworkreply::echoPerformance()
|
||||
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
|
||||
QTestEventLoop::instance().enterLoop(5);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QVERIFY(reply->error() == QNetworkReply::NoError);
|
||||
QVERIFY(reply->networkError() == QNetworkReply::NoError);
|
||||
delete reply;
|
||||
}
|
||||
}
|
||||
@ -561,7 +561,7 @@ void tst_qnetworkreply::preConnectEncrypted()
|
||||
QPair<QNetworkReply *, qint64> normalResult = runGetRequest(&manager, request);
|
||||
QNetworkReply *normalReply = normalResult.first;
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QVERIFY(normalReply->error() == QNetworkReply::NoError);
|
||||
QVERIFY(normalReply->networkError() == QNetworkReply::NoError);
|
||||
qint64 normalElapsed = normalResult.second;
|
||||
|
||||
// clear all caches again
|
||||
@ -580,7 +580,7 @@ void tst_qnetworkreply::preConnectEncrypted()
|
||||
QPair<QNetworkReply *, qint64> preConnectResult = runGetRequest(&manager, request);
|
||||
QNetworkReply *preConnectReply = normalResult.first;
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QVERIFY(preConnectReply->error() == QNetworkReply::NoError);
|
||||
QVERIFY(preConnectReply->networkError() == QNetworkReply::NoError);
|
||||
qint64 preConnectElapsed = preConnectResult.second;
|
||||
qDebug() << request.url().toString() << "full request:" << normalElapsed
|
||||
<< "ms, pre-connect request:" << preConnectElapsed << "ms, difference:"
|
||||
@ -635,7 +635,7 @@ void tst_qnetworkreply::uploadPerformance()
|
||||
QTimer::singleShot(5000, &generator, SLOT(stop()));
|
||||
|
||||
QTestEventLoop::instance().enterLoop(30);
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->networkError(), QNetworkReply::NoError);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
}
|
||||
|
||||
@ -661,7 +661,7 @@ void tst_qnetworkreply::httpUploadPerformance()
|
||||
reader.exit();
|
||||
reader.wait();
|
||||
QVERIFY(reply->isFinished());
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->networkError(), QNetworkReply::NoError);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
|
||||
qDebug() << "tst_QNetworkReply::httpUploadPerformance" << elapsed << "msec, "
|
||||
@ -722,7 +722,7 @@ void tst_qnetworkreply::httpDownloadPerformance()
|
||||
QTime time;
|
||||
time.start();
|
||||
QTestEventLoop::instance().enterLoop(40);
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->networkError(), QNetworkReply::NoError);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
|
||||
qint64 elapsed = time.elapsed();
|
||||
@ -804,7 +804,7 @@ void tst_qnetworkreply::httpDownloadPerformanceDownloadBuffer()
|
||||
|
||||
QBENCHMARK_ONCE {
|
||||
QTestEventLoop::instance().enterLoop(40);
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->networkError(), QNetworkReply::NoError);
|
||||
QVERIFY(reply->isFinished());
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
}
|
||||
@ -839,7 +839,7 @@ public slots:
|
||||
}
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
|
||||
if (reply) {
|
||||
QVERIFY(reply->error() == QNetworkReply::NoError);
|
||||
QVERIFY(reply->networkError() == QNetworkReply::NoError);
|
||||
qDebug() << "time =" << timeOneRequest.elapsed() << "ms";
|
||||
timeList.append(timeOneRequest.elapsed());
|
||||
}
|
||||
@ -894,7 +894,7 @@ void tst_qnetworkreply::runHttpsUploadRequest(const QByteArray &data, const QNet
|
||||
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
QTestEventLoop::instance().enterLoop(15);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->networkError(), QNetworkReply::NoError);
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
@ -934,7 +934,7 @@ void tst_qnetworkreply::preConnect()
|
||||
QPair<QNetworkReply *, qint64> normalResult = runGetRequest(&manager, request);
|
||||
QNetworkReply *normalReply = normalResult.first;
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QVERIFY(normalReply->error() == QNetworkReply::NoError);
|
||||
QVERIFY(normalReply->networkError() == QNetworkReply::NoError);
|
||||
qint64 normalElapsed = normalResult.second;
|
||||
|
||||
// clear all caches again
|
||||
@ -954,7 +954,7 @@ void tst_qnetworkreply::preConnect()
|
||||
QPair<QNetworkReply *, qint64> preConnectResult = runGetRequest(&manager, request);
|
||||
QNetworkReply *preConnectReply = normalResult.first;
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QVERIFY(preConnectReply->error() == QNetworkReply::NoError);
|
||||
QVERIFY(preConnectReply->networkError() == QNetworkReply::NoError);
|
||||
qint64 preConnectElapsed = preConnectResult.second;
|
||||
qDebug() << request.url().toString() << "full request:" << normalElapsed
|
||||
<< "ms, pre-connect request:" << preConnectElapsed << "ms, difference:"
|
||||
|
6
tests/manual/rhi/cubemap_render/buildshader.bat
Executable file
6
tests/manual/rhi/cubemap_render/buildshader.bat
Executable file
@ -0,0 +1,6 @@
|
||||
qsb --glsl "300 es,120" --hlsl 50 --msl 12 cubemap_oneface.vert -o cubemap_oneface.vert.qsb
|
||||
qsb --glsl "300 es,120" --hlsl 50 --msl 12 cubemap_oneface.frag -o cubemap_oneface.frag.qsb
|
||||
qsb --glsl "300 es,120" --hlsl 50 --msl 12 cubemap_mrt.vert -o cubemap_mrt.vert.qsb
|
||||
qsb --glsl "300 es,120" --hlsl 50 --msl 12 cubemap_mrt.frag -o cubemap_mrt.frag.qsb
|
||||
qsb --glsl "300 es,120" --hlsl 50 --msl 12 cubemap_sample.vert -o cubemap_sample.vert.qsb
|
||||
qsb --glsl "300 es,120" --hlsl 50 --msl 12 cubemap_sample.frag -o cubemap_sample.frag.qsb
|
28
tests/manual/rhi/cubemap_render/cubemap_mrt.frag
Normal file
28
tests/manual/rhi/cubemap_render/cubemap_mrt.frag
Normal file
@ -0,0 +1,28 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) out vec4 c0;
|
||||
layout(location = 1) out vec4 c1;
|
||||
layout(location = 2) out vec4 c2;
|
||||
layout(location = 3) out vec4 c3;
|
||||
layout(location = 4) out vec4 c4;
|
||||
layout(location = 5) out vec4 c5;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 mvp;
|
||||
vec3 color0;
|
||||
vec3 color1;
|
||||
vec3 color2;
|
||||
vec3 color3;
|
||||
vec3 color4;
|
||||
vec3 color5;
|
||||
} ubuf;
|
||||
|
||||
void main()
|
||||
{
|
||||
c0 = vec4(ubuf.color0, 1.0);
|
||||
c1 = vec4(ubuf.color1, 1.0);
|
||||
c2 = vec4(ubuf.color2, 1.0);
|
||||
c3 = vec4(ubuf.color3, 1.0);
|
||||
c4 = vec4(ubuf.color4, 1.0);
|
||||
c5 = vec4(ubuf.color5, 1.0);
|
||||
}
|
BIN
tests/manual/rhi/cubemap_render/cubemap_mrt.frag.qsb
Normal file
BIN
tests/manual/rhi/cubemap_render/cubemap_mrt.frag.qsb
Normal file
Binary file not shown.
20
tests/manual/rhi/cubemap_render/cubemap_mrt.vert
Normal file
20
tests/manual/rhi/cubemap_render/cubemap_mrt.vert
Normal file
@ -0,0 +1,20 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) in vec4 position;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 mvp;
|
||||
vec3 color0;
|
||||
vec3 color1;
|
||||
vec3 color2;
|
||||
vec3 color3;
|
||||
vec3 color4;
|
||||
vec3 color5;
|
||||
} ubuf;
|
||||
|
||||
out gl_PerVertex { vec4 gl_Position; };
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = ubuf.mvp * position;
|
||||
}
|
BIN
tests/manual/rhi/cubemap_render/cubemap_mrt.vert.qsb
Normal file
BIN
tests/manual/rhi/cubemap_render/cubemap_mrt.vert.qsb
Normal file
Binary file not shown.
13
tests/manual/rhi/cubemap_render/cubemap_oneface.frag
Normal file
13
tests/manual/rhi/cubemap_render/cubemap_oneface.frag
Normal file
@ -0,0 +1,13 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 mvp;
|
||||
vec3 color;
|
||||
} ubuf;
|
||||
|
||||
void main()
|
||||
{
|
||||
fragColor = vec4(ubuf.color, 1.0);
|
||||
}
|
BIN
tests/manual/rhi/cubemap_render/cubemap_oneface.frag.qsb
Normal file
BIN
tests/manual/rhi/cubemap_render/cubemap_oneface.frag.qsb
Normal file
Binary file not shown.
15
tests/manual/rhi/cubemap_render/cubemap_oneface.vert
Normal file
15
tests/manual/rhi/cubemap_render/cubemap_oneface.vert
Normal file
@ -0,0 +1,15 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) in vec4 position;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 mvp;
|
||||
vec3 color;
|
||||
} ubuf;
|
||||
|
||||
out gl_PerVertex { vec4 gl_Position; };
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = ubuf.mvp * position;
|
||||
}
|
BIN
tests/manual/rhi/cubemap_render/cubemap_oneface.vert.qsb
Normal file
BIN
tests/manual/rhi/cubemap_render/cubemap_oneface.vert.qsb
Normal file
Binary file not shown.
466
tests/manual/rhi/cubemap_render/cubemap_render.cpp
Normal file
466
tests/manual/rhi/cubemap_render/cubemap_render.cpp
Normal file
@ -0,0 +1,466 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** BSD License Usage
|
||||
** Alternatively, you may use this file under the terms of the BSD license
|
||||
** as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// Demonstrates rendering to two cubemaps in two different ways:
|
||||
// - one by one, to each face,
|
||||
// - if the supported max number of color attachments is greater than 4: in
|
||||
// one go with all 6 faces attached as render targets.
|
||||
//
|
||||
// Finally, show what we got in a skybox-ish thing. Press the arrow keys to
|
||||
// switch between the two cubemaps. (the only difference should be their
|
||||
// background clear color)
|
||||
|
||||
#define EXAMPLEFW_KEYPRESS_EVENTS
|
||||
#include "../shared/examplefw.h"
|
||||
#include "../shared/cube.h"
|
||||
|
||||
// each face is 512x512
|
||||
static const QSize cubemapSize(512, 512);
|
||||
|
||||
// each cubemap face gets a 256x256 quad in the center
|
||||
static float halfQuadVertexData[] =
|
||||
{ // Y up, CCW
|
||||
-0.5f, 0.5f,
|
||||
-0.5f, -0.5f,
|
||||
0.5f, -0.5f,
|
||||
0.5f, 0.5f,
|
||||
};
|
||||
|
||||
static quint16 halfQuadIndexData[] =
|
||||
{
|
||||
0, 1, 2, 0, 2, 3
|
||||
};
|
||||
|
||||
struct {
|
||||
QVector<QRhiResource *> releasePool;
|
||||
|
||||
QRhiTexture *cubemap1 = nullptr;
|
||||
QRhiTexture *cubemap2 = nullptr;
|
||||
bool canDoMrt = false;
|
||||
|
||||
QRhiBuffer *half_quad_vbuf = nullptr;
|
||||
QRhiBuffer *half_quad_ibuf = nullptr;
|
||||
|
||||
QRhiBuffer *oneface_ubuf = nullptr;
|
||||
int ubufSizePerFace;
|
||||
QRhiTextureRenderTarget *oneface_rt[6];
|
||||
QRhiRenderPassDescriptor *oneface_rp = nullptr;
|
||||
QRhiShaderResourceBindings *oneface_srb = nullptr;
|
||||
QRhiGraphicsPipeline *oneface_ps = nullptr;
|
||||
|
||||
QRhiBuffer *mrt_ubuf = nullptr;
|
||||
QRhiTextureRenderTarget *mrt_rt = nullptr;
|
||||
QRhiRenderPassDescriptor *mrt_rp = nullptr;
|
||||
QRhiShaderResourceBindings *mrt_srb = nullptr;
|
||||
QRhiGraphicsPipeline *mrt_ps = nullptr;
|
||||
|
||||
QRhiBuffer *vbuf = nullptr;
|
||||
QRhiBuffer *ubuf = nullptr;
|
||||
QRhiSampler *sampler = nullptr;
|
||||
QRhiShaderResourceBindings *srb = nullptr;
|
||||
QRhiGraphicsPipeline *ps = nullptr;
|
||||
|
||||
QRhiResourceUpdateBatch *initialUpdates = nullptr;
|
||||
QMatrix4x4 winProj;
|
||||
float rx = 0;
|
||||
} d;
|
||||
|
||||
void initializePerFaceRendering(QRhi *rhi)
|
||||
{
|
||||
d.cubemap1 = rhi->newTexture(QRhiTexture::RGBA8, cubemapSize, 1, QRhiTexture::CubeMap | QRhiTexture::RenderTarget);
|
||||
d.cubemap1->build();
|
||||
d.releasePool << d.cubemap1;
|
||||
|
||||
d.ubufSizePerFace = rhi->ubufAligned(64 + 12);
|
||||
d.oneface_ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, d.ubufSizePerFace * 6);
|
||||
d.oneface_ubuf->build();
|
||||
d.releasePool << d.oneface_ubuf;
|
||||
|
||||
for (int face = 0; face < 6; ++face) {
|
||||
QRhiColorAttachment att(d.cubemap1);
|
||||
att.setLayer(face);
|
||||
QRhiTextureRenderTargetDescription rtDesc(att);
|
||||
d.oneface_rt[face] = rhi->newTextureRenderTarget(rtDesc);
|
||||
if (face == 0) {
|
||||
d.oneface_rp = d.oneface_rt[0]->newCompatibleRenderPassDescriptor();
|
||||
d.releasePool << d.oneface_rp;
|
||||
}
|
||||
d.oneface_rt[face]->setRenderPassDescriptor(d.oneface_rp);
|
||||
d.oneface_rt[face]->build();
|
||||
d.releasePool << d.oneface_rt[face];
|
||||
}
|
||||
|
||||
d.oneface_srb = rhi->newShaderResourceBindings();
|
||||
const QRhiShaderResourceBinding::StageFlags visibility =
|
||||
QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage;
|
||||
d.oneface_srb->setBindings({
|
||||
QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(0, visibility, d.oneface_ubuf, 64 + 12)
|
||||
});
|
||||
d.oneface_srb->build();
|
||||
d.releasePool << d.oneface_srb;
|
||||
|
||||
d.oneface_ps = rhi->newGraphicsPipeline();
|
||||
d.oneface_ps->setShaderStages({
|
||||
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/cubemap_oneface.vert.qsb")) },
|
||||
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/cubemap_oneface.frag.qsb")) }
|
||||
});
|
||||
QRhiVertexInputLayout inputLayout;
|
||||
inputLayout.setBindings({
|
||||
{ 2 * sizeof(float) }
|
||||
});
|
||||
inputLayout.setAttributes({
|
||||
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
|
||||
});
|
||||
d.oneface_ps->setVertexInputLayout(inputLayout);
|
||||
d.oneface_ps->setShaderResourceBindings(d.oneface_srb);
|
||||
d.oneface_ps->setRenderPassDescriptor(d.oneface_rp);
|
||||
d.oneface_ps->build();
|
||||
d.releasePool << d.oneface_ps;
|
||||
|
||||
// wasteful to duplicate the mvp as well but will do for now
|
||||
for (int face = 0; face < 6; ++face) {
|
||||
const int offset = d.ubufSizePerFace * face;
|
||||
QMatrix4x4 identity;
|
||||
d.initialUpdates->updateDynamicBuffer(d.oneface_ubuf, offset, 64, identity.constData());
|
||||
// will use a different color for each face
|
||||
QColor c;
|
||||
switch (face) {
|
||||
case 0:
|
||||
c = Qt::red;
|
||||
break;
|
||||
case 1:
|
||||
c = Qt::green;
|
||||
break;
|
||||
case 2:
|
||||
c = Qt::blue;
|
||||
break;
|
||||
case 3:
|
||||
c = Qt::yellow;
|
||||
break;
|
||||
case 4:
|
||||
c = Qt::lightGray;
|
||||
break;
|
||||
case 5:
|
||||
c = Qt::cyan;
|
||||
break;
|
||||
}
|
||||
float color[] = { float(c.redF()), float(c.greenF()), float(c.blueF()) };
|
||||
d.initialUpdates->updateDynamicBuffer(d.oneface_ubuf, offset + 64, 12, color);
|
||||
}
|
||||
}
|
||||
|
||||
// 6 render passes, 1 draw call each, targeting one cubemap face at a time
|
||||
void renderPerFace(QRhiCommandBuffer *cb)
|
||||
{
|
||||
for (int face = 0; face < 6; ++face) {
|
||||
cb->beginPass(d.oneface_rt[face], Qt::black, { 1.0f, 0 });
|
||||
cb->setGraphicsPipeline(d.oneface_ps);
|
||||
cb->setViewport({ 0, 0,
|
||||
float(d.oneface_rt[face]->pixelSize().width()),
|
||||
float(d.oneface_rt[face]->pixelSize().height()) });
|
||||
const QRhiCommandBuffer::DynamicOffset dynamicOffset(0, face * d.ubufSizePerFace);
|
||||
cb->setShaderResources(nullptr, 1, &dynamicOffset);
|
||||
QRhiCommandBuffer::VertexInput vbufBinding(d.half_quad_vbuf, 0);
|
||||
cb->setVertexInput(0, 1, &vbufBinding, d.half_quad_ibuf, 0, QRhiCommandBuffer::IndexUInt16);
|
||||
cb->drawIndexed(6);
|
||||
cb->endPass();
|
||||
}
|
||||
}
|
||||
|
||||
void initializeMrtRendering(QRhi *rhi)
|
||||
{
|
||||
d.cubemap2 = rhi->newTexture(QRhiTexture::RGBA8, cubemapSize, 1, QRhiTexture::CubeMap | QRhiTexture::RenderTarget);
|
||||
d.cubemap2->build();
|
||||
d.releasePool << d.cubemap2;
|
||||
|
||||
d.mrt_ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 6 * 16); // note that vec3 is aligned to 16 bytes
|
||||
d.mrt_ubuf->build();
|
||||
d.releasePool << d.mrt_ubuf;
|
||||
|
||||
QVarLengthArray<QRhiColorAttachment, 6> attachments;
|
||||
for (int face = 0; face < 6; ++face) {
|
||||
QRhiColorAttachment att(d.cubemap2);
|
||||
att.setLayer(face);
|
||||
attachments.append(att);
|
||||
}
|
||||
QRhiTextureRenderTargetDescription rtDesc;
|
||||
rtDesc.setColorAttachments(attachments.cbegin(), attachments.cend());
|
||||
d.mrt_rt = rhi->newTextureRenderTarget(rtDesc);
|
||||
d.mrt_rp = d.mrt_rt->newCompatibleRenderPassDescriptor();
|
||||
d.releasePool << d.mrt_rp;
|
||||
d.mrt_rt->setRenderPassDescriptor(d.mrt_rp);
|
||||
d.mrt_rt->build();
|
||||
d.releasePool << d.mrt_rt;
|
||||
|
||||
d.mrt_srb = rhi->newShaderResourceBindings();
|
||||
const QRhiShaderResourceBinding::StageFlags visibility =
|
||||
QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage;
|
||||
d.mrt_srb->setBindings({
|
||||
QRhiShaderResourceBinding::uniformBuffer(0, visibility, d.mrt_ubuf)
|
||||
});
|
||||
d.mrt_srb->build();
|
||||
d.releasePool << d.mrt_srb;
|
||||
|
||||
d.mrt_ps = rhi->newGraphicsPipeline();
|
||||
d.mrt_ps->setShaderStages({
|
||||
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/cubemap_mrt.vert.qsb")) },
|
||||
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/cubemap_mrt.frag.qsb")) }
|
||||
});
|
||||
QVarLengthArray<QRhiGraphicsPipeline::TargetBlend, 6> targetBlends;
|
||||
for (int face = 0; face < 6; ++face)
|
||||
targetBlends.append({}); // default to blend = false, color write = all, which is good
|
||||
d.mrt_ps->setTargetBlends(targetBlends.cbegin(), targetBlends.cend());
|
||||
QRhiVertexInputLayout inputLayout;
|
||||
inputLayout.setBindings({
|
||||
{ 2 * sizeof(float) }
|
||||
});
|
||||
inputLayout.setAttributes({
|
||||
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
|
||||
});
|
||||
d.mrt_ps->setVertexInputLayout(inputLayout);
|
||||
d.mrt_ps->setShaderResourceBindings(d.mrt_srb);
|
||||
d.mrt_ps->setRenderPassDescriptor(d.mrt_rp);
|
||||
d.mrt_ps->build();
|
||||
d.releasePool << d.mrt_ps;
|
||||
|
||||
QMatrix4x4 identity;
|
||||
d.initialUpdates->updateDynamicBuffer(d.mrt_ubuf, 0, 64, identity.constData());
|
||||
for (int face = 0; face < 6; ++face) {
|
||||
const int offset = 64 + face * 16;
|
||||
// will use a different color for each face
|
||||
QColor c;
|
||||
switch (face) {
|
||||
case 0:
|
||||
c = Qt::red;
|
||||
break;
|
||||
case 1:
|
||||
c = Qt::green;
|
||||
break;
|
||||
case 2:
|
||||
c = Qt::blue;
|
||||
break;
|
||||
case 3:
|
||||
c = Qt::yellow;
|
||||
break;
|
||||
case 4:
|
||||
c = Qt::lightGray;
|
||||
break;
|
||||
case 5:
|
||||
c = Qt::cyan;
|
||||
break;
|
||||
}
|
||||
float color[] = { float(c.redF()), float(c.greenF()), float(c.blueF()) };
|
||||
d.initialUpdates->updateDynamicBuffer(d.mrt_ubuf, offset, 12, color);
|
||||
}
|
||||
}
|
||||
|
||||
// 1 render pass, 1 draw call, with all 6 faces attached and written to
|
||||
void renderWithMrt(QRhiCommandBuffer *cb)
|
||||
{
|
||||
// use a different clear color to differentiate from cubemap1 (because the
|
||||
// results are expected to be identical otherwise)
|
||||
cb->beginPass(d.mrt_rt, Qt::magenta, { 1.0f, 0 });
|
||||
cb->setGraphicsPipeline(d.mrt_ps);
|
||||
cb->setViewport({ 0, 0,
|
||||
float(d.mrt_rt->pixelSize().width()),
|
||||
float(d.mrt_rt->pixelSize().height()) });
|
||||
cb->setShaderResources();
|
||||
QRhiCommandBuffer::VertexInput vbufBinding(d.half_quad_vbuf, 0);
|
||||
cb->setVertexInput(0, 1, &vbufBinding, d.half_quad_ibuf, 0, QRhiCommandBuffer::IndexUInt16);
|
||||
cb->drawIndexed(6);
|
||||
cb->endPass();
|
||||
}
|
||||
|
||||
void Window::customInit()
|
||||
{
|
||||
d.half_quad_vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(halfQuadVertexData));
|
||||
d.half_quad_vbuf->build();
|
||||
d.releasePool << d.half_quad_vbuf;
|
||||
|
||||
d.half_quad_ibuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(halfQuadIndexData));
|
||||
d.half_quad_ibuf->build();
|
||||
d.releasePool << d.half_quad_ibuf;
|
||||
|
||||
d.initialUpdates = m_r->nextResourceUpdateBatch();
|
||||
d.initialUpdates->uploadStaticBuffer(d.half_quad_vbuf, 0, sizeof(halfQuadVertexData), halfQuadVertexData);
|
||||
d.initialUpdates->uploadStaticBuffer(d.half_quad_ibuf, halfQuadIndexData);
|
||||
|
||||
initializePerFaceRendering(m_r);
|
||||
|
||||
d.canDoMrt = m_r->resourceLimit(QRhi::MaxColorAttachments) >= 6;
|
||||
if (d.canDoMrt)
|
||||
initializeMrtRendering(m_r);
|
||||
else
|
||||
qWarning("Not enough color attachments (need 6, supports %d)", m_r->resourceLimit(QRhi::MaxColorAttachments));
|
||||
|
||||
|
||||
// onscreen stuff
|
||||
d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube));
|
||||
d.vbuf->build();
|
||||
d.releasePool << d.vbuf;
|
||||
d.initialUpdates->uploadStaticBuffer(d.vbuf, cube);
|
||||
|
||||
d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64);
|
||||
d.ubuf->build();
|
||||
d.releasePool << d.ubuf;
|
||||
|
||||
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
|
||||
QRhiSampler::Repeat, QRhiSampler::Repeat);
|
||||
d.sampler->build();
|
||||
d.releasePool << d.sampler;
|
||||
|
||||
d.srb = m_r->newShaderResourceBindings();
|
||||
d.srb->setBindings({
|
||||
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf),
|
||||
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.cubemap1, d.sampler)
|
||||
});
|
||||
d.srb->build();
|
||||
d.releasePool << d.srb;
|
||||
|
||||
d.ps = m_r->newGraphicsPipeline();
|
||||
d.ps->setDepthTest(true);
|
||||
d.ps->setDepthWrite(true);
|
||||
d.ps->setDepthOp(QRhiGraphicsPipeline::LessOrEqual);
|
||||
d.ps->setCullMode(QRhiGraphicsPipeline::Front); // we are inside the cube so cull front, not back
|
||||
d.ps->setFrontFace(QRhiGraphicsPipeline::CCW); // front is ccw in the cube data
|
||||
QShader vs = getShader(QLatin1String(":/cubemap_sample.vert.qsb"));
|
||||
Q_ASSERT(vs.isValid());
|
||||
QShader fs = getShader(QLatin1String(":/cubemap_sample.frag.qsb"));
|
||||
Q_ASSERT(fs.isValid());
|
||||
d.ps->setShaderStages({
|
||||
{ QRhiShaderStage::Vertex, vs },
|
||||
{ QRhiShaderStage::Fragment, fs }
|
||||
});
|
||||
QRhiVertexInputLayout inputLayout;
|
||||
inputLayout.setBindings({
|
||||
{ 3 * sizeof(float) }
|
||||
});
|
||||
inputLayout.setAttributes({
|
||||
{ 0, 0, QRhiVertexInputAttribute::Float3, 0 }
|
||||
});
|
||||
d.ps->setVertexInputLayout(inputLayout);
|
||||
d.ps->setShaderResourceBindings(d.srb);
|
||||
d.ps->setRenderPassDescriptor(m_rp);
|
||||
d.ps->build();
|
||||
d.releasePool << d.ps;
|
||||
|
||||
if (d.canDoMrt)
|
||||
qDebug("Use the arrow keys to switch between the two generated cubemaps");
|
||||
}
|
||||
|
||||
void Window::customRelease()
|
||||
{
|
||||
qDeleteAll(d.releasePool);
|
||||
d.releasePool.clear();
|
||||
}
|
||||
|
||||
void Window::customRender()
|
||||
{
|
||||
const QSize outputSizeInPixels = m_sc->currentPixelSize();
|
||||
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
|
||||
QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch();
|
||||
if (d.initialUpdates) {
|
||||
u->merge(d.initialUpdates);
|
||||
d.initialUpdates->release();
|
||||
d.initialUpdates = nullptr;
|
||||
}
|
||||
|
||||
QMatrix4x4 mvp = m_r->clipSpaceCorrMatrix();
|
||||
mvp.perspective(90.0f, outputSizeInPixels.width() / (float) outputSizeInPixels.height(), 0.01f, 1000.0f);
|
||||
mvp.scale(10);
|
||||
mvp.rotate(d.rx, 1, 0, 0);
|
||||
d.rx += 0.5f;
|
||||
u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData());
|
||||
|
||||
cb->resourceUpdate(u);
|
||||
|
||||
renderPerFace(cb);
|
||||
|
||||
if (d.canDoMrt)
|
||||
renderWithMrt(cb);
|
||||
|
||||
cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 });
|
||||
cb->setGraphicsPipeline(d.ps);
|
||||
cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()));
|
||||
cb->setShaderResources();
|
||||
const QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, 0);
|
||||
cb->setVertexInput(0, 1, &vbufBinding);
|
||||
cb->draw(36);
|
||||
cb->endPass();
|
||||
}
|
||||
|
||||
void Window::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
switch (e->key()) {
|
||||
case Qt::Key_Left:
|
||||
case Qt::Key_Up:
|
||||
qDebug("Showing first cubemap (generated by rendering to the faces one by one; black background)");
|
||||
d.srb->setBindings({
|
||||
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf),
|
||||
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.cubemap1, d.sampler)
|
||||
});
|
||||
d.srb->build();
|
||||
break;
|
||||
case Qt::Key_Right:
|
||||
case Qt::Key_Down:
|
||||
if (d.canDoMrt) {
|
||||
qDebug("Showing second cubemap (generated with multiple render targets; magenta background)");
|
||||
d.srb->setBindings({
|
||||
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf),
|
||||
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.cubemap2, d.sampler)
|
||||
});
|
||||
d.srb->build();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
e->ignore();
|
||||
break;
|
||||
}
|
||||
}
|
8
tests/manual/rhi/cubemap_render/cubemap_render.pro
Normal file
8
tests/manual/rhi/cubemap_render/cubemap_render.pro
Normal file
@ -0,0 +1,8 @@
|
||||
TEMPLATE = app
|
||||
|
||||
QT += gui-private
|
||||
|
||||
SOURCES = \
|
||||
cubemap_render.cpp
|
||||
|
||||
RESOURCES = cubemap_render.qrc
|
10
tests/manual/rhi/cubemap_render/cubemap_render.qrc
Normal file
10
tests/manual/rhi/cubemap_render/cubemap_render.qrc
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>cubemap_oneface.vert.qsb</file>
|
||||
<file>cubemap_oneface.frag.qsb</file>
|
||||
<file>cubemap_mrt.vert.qsb</file>
|
||||
<file>cubemap_mrt.frag.qsb</file>
|
||||
<file>cubemap_sample.vert.qsb</file>
|
||||
<file>cubemap_sample.frag.qsb</file>
|
||||
</qresource>
|
||||
</RCC>
|
10
tests/manual/rhi/cubemap_render/cubemap_sample.frag
Normal file
10
tests/manual/rhi/cubemap_render/cubemap_sample.frag
Normal file
@ -0,0 +1,10 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) in vec3 v_coord;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(binding = 1) uniform samplerCube tex;
|
||||
|
||||
void main()
|
||||
{
|
||||
fragColor = vec4(texture(tex, v_coord).rgb, 1.0);
|
||||
}
|
BIN
tests/manual/rhi/cubemap_render/cubemap_sample.frag.qsb
Normal file
BIN
tests/manual/rhi/cubemap_render/cubemap_sample.frag.qsb
Normal file
Binary file not shown.
16
tests/manual/rhi/cubemap_render/cubemap_sample.vert
Normal file
16
tests/manual/rhi/cubemap_render/cubemap_sample.vert
Normal file
@ -0,0 +1,16 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) in vec4 position;
|
||||
layout(location = 0) out vec3 v_coord;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 mvp;
|
||||
} ubuf;
|
||||
|
||||
out gl_PerVertex { vec4 gl_Position; };
|
||||
|
||||
void main()
|
||||
{
|
||||
v_coord = position.xyz;
|
||||
gl_Position = ubuf.mvp * position;
|
||||
}
|
BIN
tests/manual/rhi/cubemap_render/cubemap_sample.vert.qsb
Normal file
BIN
tests/manual/rhi/cubemap_render/cubemap_sample.vert.qsb
Normal file
Binary file not shown.
3
tests/manual/rhi/float16texture_with_compute/buildshaders.sh
Executable file
3
tests/manual/rhi/float16texture_with_compute/buildshaders.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
qsb --glsl "430,310 es" --hlsl 50 --msl 12 load.comp -o load.comp.qsb
|
||||
qsb --glsl "430,310 es" --hlsl 50 --msl 12 prefilter.comp -o prefilter.comp.qsb
|
@ -0,0 +1,312 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** BSD License Usage
|
||||
** Alternatively, you may use this file under the terms of the BSD license
|
||||
** as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// An advanced version of floattexture. Instead of RGBA32F, we use RGBA16F, and
|
||||
// also generate the floating point data from rgba with compute. Then there's a
|
||||
// compute pass using the BSDF prefiltering taken from Qt Quick 3D, which
|
||||
// generates all the mip levels.
|
||||
|
||||
// Why do we animate the scale of the quad rendered to the window? To have
|
||||
// different mip levels used, to prove that all of them are generated
|
||||
// correctly, without artifacts (which would occur if memory barriers were not
|
||||
// correctly generated by QRhi). For full verification use RenderDoc or similar.
|
||||
|
||||
#include "../shared/examplefw.h"
|
||||
#include <qmath.h>
|
||||
|
||||
static float vertexData[] =
|
||||
{ // Y up, CCW
|
||||
-0.5f, 0.5f, 0.0f, 0.0f,
|
||||
-0.5f, -0.5f, 0.0f, 1.0f,
|
||||
0.5f, -0.5f, 1.0f, 1.0f,
|
||||
0.5f, 0.5f, 1.0f, 0.0f
|
||||
};
|
||||
|
||||
static quint16 indexData[] =
|
||||
{
|
||||
0, 1, 2, 0, 2, 3
|
||||
};
|
||||
|
||||
static const int MAX_MIP_LEVELS = 20;
|
||||
|
||||
struct {
|
||||
QVector<QRhiResource *> releasePool;
|
||||
|
||||
QRhiBuffer *vbuf = nullptr;
|
||||
QRhiBuffer *ibuf = nullptr;
|
||||
QRhiBuffer *ubuf = nullptr;
|
||||
QRhiTexture *texRgba = nullptr;
|
||||
QRhiTexture *texFloat16 = nullptr;
|
||||
QRhiSampler *sampler = nullptr;
|
||||
QRhiShaderResourceBindings *srb = nullptr;
|
||||
QRhiGraphicsPipeline *ps = nullptr;
|
||||
|
||||
QRhiBuffer *computeUBuf_load = nullptr;
|
||||
QRhiShaderResourceBindings *computeBindings_load = nullptr;
|
||||
QRhiComputePipeline *computePipeline_load = nullptr;
|
||||
QRhiBuffer *computeUBuf_prefilter = nullptr;
|
||||
QRhiShaderResourceBindings *computeBindings_prefilter[MAX_MIP_LEVELS];
|
||||
QRhiComputePipeline *computePipeline_prefilter = nullptr;
|
||||
|
||||
QRhiResourceUpdateBatch *initialUpdates = nullptr;
|
||||
bool computeDone = false;
|
||||
int mipCount;
|
||||
int prefilterUBufElemSize;
|
||||
quint32 prefilterNumWorkGroups[MAX_MIP_LEVELS][3];
|
||||
float scale = 2.5f;
|
||||
int scale_dir = -1;
|
||||
} d;
|
||||
|
||||
void recordUploadThenFilterFloat16TextureWithCompute(QRhiCommandBuffer *cb)
|
||||
{
|
||||
const int w = d.texRgba->pixelSize().width() / 16;
|
||||
const int h = d.texRgba->pixelSize().height() / 16;
|
||||
|
||||
cb->beginComputePass();
|
||||
|
||||
cb->setComputePipeline(d.computePipeline_load);
|
||||
cb->setShaderResources();
|
||||
cb->dispatch(w, h, 1);
|
||||
|
||||
cb->setComputePipeline(d.computePipeline_prefilter);
|
||||
for (int level = 1; level < d.mipCount; ++level) {
|
||||
const int i = level - 1;
|
||||
const int mipW = d.prefilterNumWorkGroups[i][0];
|
||||
const int mipH = d.prefilterNumWorkGroups[i][1];
|
||||
QPair<int, quint32> dynamicOffset = { 0, quint32(d.prefilterUBufElemSize * i) };
|
||||
cb->setShaderResources(d.computeBindings_prefilter[i], 1, &dynamicOffset);
|
||||
cb->dispatch(mipW, mipH, 1);
|
||||
}
|
||||
|
||||
cb->endComputePass();
|
||||
}
|
||||
|
||||
void Window::customInit()
|
||||
{
|
||||
if (!m_r->isFeatureSupported(QRhi::Compute))
|
||||
qFatal("Compute is not supported");
|
||||
|
||||
if (!m_r->isTextureFormatSupported(QRhiTexture::RGBA16F))
|
||||
qFatal("RGBA16F texture format is not supported");
|
||||
|
||||
d.initialUpdates = m_r->nextResourceUpdateBatch();
|
||||
|
||||
// load rgba8 image data
|
||||
|
||||
QImage image;
|
||||
image.load(QLatin1String(":/qt256.png"));
|
||||
image = image.convertToFormat(QImage::Format_RGBA8888);
|
||||
Q_ASSERT(!image.isNull());
|
||||
d.texRgba = m_r->newTexture(QRhiTexture::RGBA8, image.size(), 1, QRhiTexture::UsedWithLoadStore);
|
||||
d.texRgba->build();
|
||||
d.releasePool << d.texRgba;
|
||||
|
||||
d.initialUpdates->uploadTexture(d.texRgba, image);
|
||||
|
||||
d.mipCount = m_r->mipLevelsForSize(image.size());
|
||||
Q_ASSERT(d.mipCount <= MAX_MIP_LEVELS);
|
||||
|
||||
d.texFloat16 = m_r->newTexture(QRhiTexture::RGBA16F, image.size(), 1, QRhiTexture::UsedWithLoadStore | QRhiTexture::MipMapped);
|
||||
d.releasePool << d.texFloat16;
|
||||
d.texFloat16->build();
|
||||
|
||||
// compute
|
||||
|
||||
d.computeUBuf_load = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 12);
|
||||
d.computeUBuf_load->build();
|
||||
d.releasePool << d.computeUBuf_load;
|
||||
|
||||
quint32 numWorkGroups[3] = { quint32(image.width()), quint32(image.height()), 0 };
|
||||
d.initialUpdates->updateDynamicBuffer(d.computeUBuf_load, 0, 12, numWorkGroups);
|
||||
|
||||
d.computeBindings_load = m_r->newShaderResourceBindings();
|
||||
d.computeBindings_load->setBindings({
|
||||
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::ComputeStage, d.computeUBuf_load),
|
||||
QRhiShaderResourceBinding::imageLoad(1, QRhiShaderResourceBinding::ComputeStage, d.texRgba, 0),
|
||||
QRhiShaderResourceBinding::imageStore(2, QRhiShaderResourceBinding::ComputeStage, d.texFloat16, 0)
|
||||
});
|
||||
d.computeBindings_load->build();
|
||||
d.releasePool << d.computeBindings_load;
|
||||
|
||||
d.computePipeline_load = m_r->newComputePipeline();
|
||||
d.computePipeline_load->setShaderResourceBindings(d.computeBindings_load);
|
||||
d.computePipeline_load->setShaderStage({ QRhiShaderStage::Compute, getShader(QLatin1String(":/load.comp.qsb")) });
|
||||
d.computePipeline_load->build();
|
||||
d.releasePool << d.computePipeline_load;
|
||||
|
||||
d.prefilterUBufElemSize = m_r->ubufAligned(12);
|
||||
d.computeUBuf_prefilter = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, d.prefilterUBufElemSize * d.mipCount);
|
||||
d.computeUBuf_prefilter->build();
|
||||
d.releasePool << d.computeUBuf_prefilter;
|
||||
|
||||
int mipW = image.width() >> 1;
|
||||
int mipH = image.height() >> 1;
|
||||
for (int level = 1; level < d.mipCount; ++level) {
|
||||
const int i = level - 1;
|
||||
d.prefilterNumWorkGroups[i][0] = quint32(mipW);
|
||||
d.prefilterNumWorkGroups[i][1] = quint32(mipH);
|
||||
d.prefilterNumWorkGroups[i][2] = 0;
|
||||
d.initialUpdates->updateDynamicBuffer(d.computeUBuf_prefilter, d.prefilterUBufElemSize * i, 12, d.prefilterNumWorkGroups[i]);
|
||||
mipW = mipW > 2 ? mipW >> 1 : 1;
|
||||
mipH = mipH > 2 ? mipH >> 1 : 1;
|
||||
|
||||
d.computeBindings_prefilter[i] = m_r->newShaderResourceBindings();
|
||||
d.computeBindings_prefilter[i]->setBindings({
|
||||
QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(0, QRhiShaderResourceBinding::ComputeStage, d.computeUBuf_prefilter, 12),
|
||||
QRhiShaderResourceBinding::imageLoad(1, QRhiShaderResourceBinding::ComputeStage, d.texFloat16, level - 1),
|
||||
QRhiShaderResourceBinding::imageStore(2, QRhiShaderResourceBinding::ComputeStage, d.texFloat16, level)
|
||||
});
|
||||
d.computeBindings_prefilter[i]->build();
|
||||
d.releasePool << d.computeBindings_prefilter[i];
|
||||
}
|
||||
|
||||
d.computePipeline_prefilter = m_r->newComputePipeline();
|
||||
d.computePipeline_prefilter->setShaderResourceBindings(d.computeBindings_prefilter[0]); // just need a layout compatible one
|
||||
d.computePipeline_prefilter->setShaderStage({ QRhiShaderStage::Compute, getShader(QLatin1String(":/prefilter.comp.qsb")) });
|
||||
d.computePipeline_prefilter->build();
|
||||
d.releasePool << d.computePipeline_prefilter;
|
||||
|
||||
// graphics
|
||||
|
||||
d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData));
|
||||
d.vbuf->build();
|
||||
d.releasePool << d.vbuf;
|
||||
|
||||
d.ibuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indexData));
|
||||
d.ibuf->build();
|
||||
d.releasePool << d.ibuf;
|
||||
|
||||
d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68);
|
||||
d.ubuf->build();
|
||||
d.releasePool << d.ubuf;
|
||||
|
||||
// enable mipmaps
|
||||
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear,
|
||||
QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
|
||||
d.releasePool << d.sampler;
|
||||
d.sampler->build();
|
||||
|
||||
d.srb = m_r->newShaderResourceBindings();
|
||||
d.releasePool << d.srb;
|
||||
d.srb->setBindings({
|
||||
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf),
|
||||
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.texFloat16, d.sampler)
|
||||
});
|
||||
d.srb->build();
|
||||
|
||||
d.ps = m_r->newGraphicsPipeline();
|
||||
d.releasePool << d.ps;
|
||||
d.ps->setShaderStages({
|
||||
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
||||
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
||||
});
|
||||
QRhiVertexInputLayout inputLayout;
|
||||
inputLayout.setBindings({
|
||||
{ 4 * sizeof(float) }
|
||||
});
|
||||
inputLayout.setAttributes({
|
||||
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
|
||||
{ 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) }
|
||||
});
|
||||
d.ps->setVertexInputLayout(inputLayout);
|
||||
d.ps->setShaderResourceBindings(d.srb);
|
||||
d.ps->setRenderPassDescriptor(m_rp);
|
||||
d.ps->build();
|
||||
|
||||
d.initialUpdates->uploadStaticBuffer(d.vbuf, vertexData);
|
||||
d.initialUpdates->uploadStaticBuffer(d.ibuf, indexData);
|
||||
|
||||
qint32 flip = 0;
|
||||
d.initialUpdates->updateDynamicBuffer(d.ubuf, 64, 4, &flip);
|
||||
}
|
||||
|
||||
void Window::customRelease()
|
||||
{
|
||||
qDeleteAll(d.releasePool);
|
||||
d.releasePool.clear();
|
||||
}
|
||||
|
||||
void Window::customRender()
|
||||
{
|
||||
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
|
||||
QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch();
|
||||
if (d.initialUpdates) {
|
||||
u->merge(d.initialUpdates);
|
||||
d.initialUpdates->release();
|
||||
d.initialUpdates = nullptr;
|
||||
}
|
||||
|
||||
QMatrix4x4 mvp = m_proj;
|
||||
mvp.scale(d.scale);
|
||||
d.scale += d.scale_dir * 0.01f;
|
||||
if (qFuzzyIsNull(d.scale) || d.scale >= 2.5f)
|
||||
d.scale_dir *= -1;
|
||||
u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData());
|
||||
|
||||
cb->resourceUpdate(u);
|
||||
|
||||
// If not yet done, then do a compute pass that uploads level 0, doing an
|
||||
// rgba8 -> float16 conversion. Follow that with another compute pass to do
|
||||
// the filtering and generate all the mip levels.
|
||||
if (!d.computeDone) {
|
||||
recordUploadThenFilterFloat16TextureWithCompute(cb);
|
||||
d.computeDone = true;
|
||||
}
|
||||
|
||||
const QSize outputSizeInPixels = m_sc->currentPixelSize();
|
||||
cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 });
|
||||
cb->setGraphicsPipeline(d.ps);
|
||||
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
|
||||
cb->setShaderResources();
|
||||
const QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, 0);
|
||||
cb->setVertexInput(0, 1, &vbufBinding, d.ibuf, 0, QRhiCommandBuffer::IndexUInt16);
|
||||
cb->drawIndexed(6);
|
||||
cb->endPass();
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
TEMPLATE = app
|
||||
|
||||
QT += gui-private
|
||||
|
||||
SOURCES = \
|
||||
float16texture_with_compute.cpp
|
||||
|
||||
RESOURCES = float16texture_with_compute.qrc
|
@ -0,0 +1,9 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>load.comp.qsb</file>
|
||||
<file>prefilter.comp.qsb</file>
|
||||
<file alias="texture.vert.qsb">../shared/texture.vert.qsb</file>
|
||||
<file alias="texture.frag.qsb">../shared/texture.frag.qsb</file>
|
||||
<file alias="qt256.png">../shared/qt256.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
19
tests/manual/rhi/float16texture_with_compute/load.comp
Normal file
19
tests/manual/rhi/float16texture_with_compute/load.comp
Normal file
@ -0,0 +1,19 @@
|
||||
#version 440
|
||||
|
||||
layout(local_size_x = 16, local_size_y = 16) in;
|
||||
layout(rgba8, binding = 1) readonly uniform image2D inputImage;
|
||||
layout(rgba16f, binding = 2) writeonly uniform image2D outputImage;
|
||||
|
||||
// There is no equivalent of gl_NumWorkGroups in HLSL. So instead pass the
|
||||
// values in in a uniform buffer.
|
||||
layout(std140, binding = 0) uniform numWorkGroupsBuf {
|
||||
uvec3 numWorkGroups;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
if (gl_GlobalInvocationID.x >= numWorkGroups.x || gl_GlobalInvocationID.y >= numWorkGroups.y)
|
||||
return;
|
||||
vec4 value = imageLoad(inputImage, ivec2(gl_GlobalInvocationID.xy));
|
||||
imageStore(outputImage, ivec2(gl_GlobalInvocationID.xy), value);
|
||||
}
|
BIN
tests/manual/rhi/float16texture_with_compute/load.comp.qsb
Normal file
BIN
tests/manual/rhi/float16texture_with_compute/load.comp.qsb
Normal file
Binary file not shown.
50
tests/manual/rhi/float16texture_with_compute/prefilter.comp
Normal file
50
tests/manual/rhi/float16texture_with_compute/prefilter.comp
Normal file
@ -0,0 +1,50 @@
|
||||
#version 440
|
||||
|
||||
layout(local_size_x = 16, local_size_y = 16) in;
|
||||
layout(rgba16f, binding = 1) readonly uniform image2D inputImage;
|
||||
layout(rgba16f, binding = 2) writeonly uniform image2D outputImage;
|
||||
|
||||
// There is no equivalent of gl_NumWorkGroups in HLSL. So instead pass the
|
||||
// values in in a uniform buffer.
|
||||
layout(std140, binding = 0) uniform numWorkGroupsBuf {
|
||||
uvec3 numWorkGroups;
|
||||
};
|
||||
|
||||
int wrapMod( in int a, in int base )
|
||||
{
|
||||
return ( a >= 0 ) ? a % base : -(a % base) + base;
|
||||
}
|
||||
|
||||
void getWrappedCoords( inout int sX, inout int sY, in int width, in int height )
|
||||
{
|
||||
if (sY < 0) { sX -= width >> 1; sY = -sY; }
|
||||
if (sY >= height) { sX += width >> 1; sY = height - sY; }
|
||||
sX = wrapMod( sX, width );
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int prevWidth = int(numWorkGroups.x) << 1;
|
||||
int prevHeight = int(numWorkGroups.y) << 1;
|
||||
if (gl_GlobalInvocationID.x >= numWorkGroups.x || gl_GlobalInvocationID.y >= numWorkGroups.y)
|
||||
return;
|
||||
vec4 accumVal = vec4(0.0);
|
||||
for (int sy = -2; sy <= 2; ++sy) {
|
||||
for (int sx = -2; sx <= 2; ++sx) {
|
||||
int sampleX = sx + (int(gl_GlobalInvocationID.x) << 1);
|
||||
int sampleY = sy + (int(gl_GlobalInvocationID.y) << 1);
|
||||
getWrappedCoords(sampleX, sampleY, prevWidth, prevHeight);
|
||||
if ((sampleY * prevWidth + sampleX) < 0 )
|
||||
sampleY = prevHeight + sampleY;
|
||||
ivec2 pos = ivec2(sampleX, sampleY);
|
||||
vec4 value = imageLoad(inputImage, pos);
|
||||
float filterPdf = 1.0 / ( 1.0 + float(sx*sx + sy*sy)*2.0 );
|
||||
filterPdf /= 4.71238898;
|
||||
accumVal[0] += filterPdf * value.r;
|
||||
accumVal[1] += filterPdf * value.g;
|
||||
accumVal[2] += filterPdf * value.b;
|
||||
accumVal[3] += filterPdf * value.a;
|
||||
}
|
||||
}
|
||||
imageStore(outputImage, ivec2(gl_GlobalInvocationID.xy), accumVal);
|
||||
}
|
BIN
tests/manual/rhi/float16texture_with_compute/prefilter.comp.qsb
Normal file
BIN
tests/manual/rhi/float16texture_with_compute/prefilter.comp.qsb
Normal file
Binary file not shown.
@ -9,11 +9,13 @@ SUBDIRS += \
|
||||
msaarenderbuffer \
|
||||
cubemap \
|
||||
cubemap_scissor \
|
||||
cubemap_render \
|
||||
multiwindow \
|
||||
multiwindow_threaded \
|
||||
triquadcube \
|
||||
offscreen \
|
||||
floattexture \
|
||||
float16texture_with_compute \
|
||||
mrt \
|
||||
shadowmap \
|
||||
computebuffer \
|
||||
|
@ -148,6 +148,9 @@ protected:
|
||||
|
||||
void exposeEvent(QExposeEvent *) override;
|
||||
bool event(QEvent *) override;
|
||||
#ifdef EXAMPLEFW_KEYPRESS_EVENTS
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
#endif
|
||||
|
||||
bool m_running = false;
|
||||
bool m_notExposed = false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user