diff options
author | Leander Beernaert <leander.beernaert@qt.io> | 2020-01-22 13:47:08 +0100 |
---|---|---|
committer | Leander Beernaert <leander.beernaert@qt.io> | 2020-01-24 13:17:33 +0100 |
commit | 502d3d6744913899da87acfda5ebdab42c40329e (patch) | |
tree | 16658a328503bfd5a62b4fd5d69ffb66e9854b18 /tests/manual | |
parent | d1be8b9ceb2c7b20bbe53a07154c79699540ea3d (diff) | |
parent | 06bb315beb6c2c398223cfe52cbc7f66e14a8557 (diff) |
Merge remote-tracking branch 'origin/dev' into merge-dev
Change-Id: I31b761cfd5ea01373c60d02a5da8c33398d34739
Diffstat (limited to 'tests/manual')
54 files changed, 1800 insertions, 174 deletions
diff --git a/tests/manual/diaglib/nativewindowdump_win.cpp b/tests/manual/diaglib/nativewindowdump_win.cpp index 55af49fd27..6334fcfedd 100644 --- a/tests/manual/diaglib/nativewindowdump_win.cpp +++ b/tests/manual/diaglib/nativewindowdump_win.cpp @@ -32,6 +32,7 @@ #include <QtCore/QTextStream> #include <QtCore/QSharedPointer> #include <QtCore/QDebug> +#include <QtCore/QRect> #include <QtCore/QVector> #include <QtCore/qt_windows.h> @@ -56,14 +57,76 @@ struct DumpContext { if (style & styleConstant) \ str << ' ' << #styleConstant; +static QTextStream &operator<<(QTextStream &str, const QPoint &p) +{ + str << p.x() << ", " << p.y(); + return str; +} + +static QTextStream &operator<<(QTextStream &str, const QSize &s) +{ + str << s.width() << 'x' << s.height(); + return str; +} + +static QTextStream &operator<<(QTextStream &str, const QRect &rect) +{ + str << rect.size() << forcesign << rect.x() << rect.y() << noforcesign; + return str; +} + +static inline QSize qsizeFromRECT(const RECT &rect) +{ + return QSize(rect.right -rect.left, rect.bottom - rect.top); +} + +static inline QRect qrectFromRECT(const RECT &rect) +{ + return QRect(QPoint(rect.left, rect.top), qsizeFromRECT(rect)); +} + +static QRect getFrameGeometry(HWND hwnd) +{ + RECT rect; + return GetWindowRect(hwnd, &rect) ? qrectFromRECT(rect) : QRect(); +} + +static QPoint getClientAreaScreenPos(HWND hwnd) +{ + POINT clientPos{0, 0}; + return ClientToScreen(hwnd, &clientPos) ? QPoint(clientPos.x, clientPos.y) : QPoint(); +} + +static QRect getClientAreaGeometry(HWND hwnd) +{ + RECT clientRect; + return GetClientRect(hwnd, &clientRect) + ? QRect(getClientAreaScreenPos(hwnd), qsizeFromRECT(clientRect)) : QRect(); +} + +static bool isTopLevel(HWND hwnd) +{ + auto parent = GetParent(hwnd); + return !parent || parent == GetDesktopWindow(); +} + static void formatNativeWindow(HWND hwnd, QTextStream &str) { str << hex << showbase << quintptr(hwnd) << noshowbase << dec; - RECT rect; - if (GetWindowRect(hwnd, &rect)) { - str << ' ' << (rect.right - rect.left) << 'x' << (rect.bottom - rect.top) - << forcesign << rect.left << rect.top << noforcesign; + + const bool topLevel = isTopLevel(hwnd); + if (topLevel) + str << " [top]"; + const auto frameGeometry = getFrameGeometry(hwnd); + const auto clientGeometry = getClientAreaGeometry(hwnd); + str << ' ' << frameGeometry; + if (!topLevel) + str << " local: " << (clientGeometry.topLeft() - getClientAreaScreenPos(GetParent(hwnd))); + if (clientGeometry != frameGeometry) { + str << " client: " << clientGeometry << " frame: " + << (clientGeometry.topLeft() - frameGeometry.topLeft()); } + if (IsWindowVisible(hwnd)) str << " [visible]"; diff --git a/tests/manual/dialogs/messageboxpanel.cpp b/tests/manual/dialogs/messageboxpanel.cpp index 3c6a042e19..6a305523ea 100644 --- a/tests/manual/dialogs/messageboxpanel.cpp +++ b/tests/manual/dialogs/messageboxpanel.cpp @@ -135,7 +135,7 @@ void MessageBoxPanel::setupMessageBox(QMessageBox &box) bool ok; QMessageBox::StandardButtons btns = (QMessageBox::StandardButtons) btnHexText.toUInt(&ok, 16); box.setStandardButtons((QMessageBox::StandardButtons) btns); - if (box.standardButtons() == (QMessageBox::StandardButtons) 0) + if (box.standardButtons() == QMessageBox::StandardButtons()) box.setStandardButtons(QMessageBox::Ok); // just to have something. #if QT_VERSION >= 0x050000 diff --git a/tests/manual/dialogs/wizardpanel.cpp b/tests/manual/dialogs/wizardpanel.cpp index 0e5a18fe8c..8e8af5f556 100644 --- a/tests/manual/dialogs/wizardpanel.cpp +++ b/tests/manual/dialogs/wizardpanel.cpp @@ -198,7 +198,7 @@ void WizardOptionsControl::setWizardOptions(int options) class Wizard : public QWizard { Q_OBJECT public: - explicit Wizard(QWidget *parent = 0, Qt::WindowFlags flags = 0); + explicit Wizard(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags()); public slots: void changeWizardStyle(int newStyle); diff --git a/tests/manual/highdpi/dragwidget.cpp b/tests/manual/highdpi/dragwidget.cpp index 11bbc1d127..8ad3d3ca47 100644 --- a/tests/manual/highdpi/dragwidget.cpp +++ b/tests/manual/highdpi/dragwidget.cpp @@ -42,7 +42,7 @@ public: }; DragWidget::DragWidget(QString text, QWidget *parent) - : QWidget(parent), otherWindow(nullptr) + : QWidget(parent) { int x = 5; int y = 5; @@ -52,9 +52,9 @@ DragWidget::DragWidget(QString text, QWidget *parent) text = "You can drag from this window and drop text here"; QStringList words = text.split(' '); - foreach (QString word, words) { + for (const QString &word : words) { if (!word.isEmpty()) { - FramedLabel *wordLabel = new FramedLabel(word, this); + auto wordLabel = new FramedLabel(word, this); wordLabel->move(x, y); wordLabel->show(); x += wordLabel->width() + 2; @@ -105,7 +105,6 @@ void DragWidget::dragLeaveEvent(QDragLeaveEvent *) update(); } - void DragWidget::dropEvent(QDropEvent *event) { if (event->mimeData()->hasText()) { @@ -141,9 +140,9 @@ void DragWidget::dropEvent(QDropEvent *event) } else { event->ignore(); } - foreach (QObject *child, children()) { - if (child->inherits("QWidget")) { - QWidget *widget = static_cast<QWidget *>(child); + for (QObject *child : children()) { + if (child->isWidgetType()) { + auto widget = static_cast<QWidget *>(child); if (!widget->isVisible()) widget->deleteLater(); } @@ -170,7 +169,7 @@ void DragWidget::mousePressEvent(QMouseEvent *event) pixmap.setDevicePixelRatio(dpr); child->render(&pixmap); - QDrag *drag = new QDrag(this); + auto drag = new QDrag(this); drag->setMimeData(mimeData); drag->setPixmap(pixmap); drag->setHotSpot(hotSpot); diff --git a/tests/manual/highdpi/dragwidget.h b/tests/manual/highdpi/dragwidget.h index 8b67b20410..06663fc74a 100644 --- a/tests/manual/highdpi/dragwidget.h +++ b/tests/manual/highdpi/dragwidget.h @@ -40,7 +40,7 @@ QT_END_NAMESPACE class DragWidget : public QWidget { public: - DragWidget(QString text = QString(), QWidget *parent = 0); + DragWidget(QString text = QString(), QWidget *parent = nullptr); protected: void dragEnterEvent(QDragEnterEvent *event) override; @@ -52,12 +52,13 @@ protected: void timerEvent(QTimerEvent *event) override; void showEvent(QShowEvent *event) override; void hideEvent(QHideEvent *event) override; + private: QPoint dragPos; QPoint dropPos; QBasicTimer dragTimer; QBasicTimer dropTimer; - QWidget *otherWindow; + QWidget *otherWindow = nullptr; }; #endif // DRAGWIDGET_H diff --git a/tests/manual/highdpi/main.cpp b/tests/manual/highdpi/main.cpp index 0329e62387..2a9fb6aa0c 100644 --- a/tests/manual/highdpi/main.cpp +++ b/tests/manual/highdpi/main.cpp @@ -30,6 +30,7 @@ #include <QMenuBar> #include <QLabel> #include <QHBoxLayout> +#include <QFormLayout> #include <QApplication> #include <QAction> #include <QStyle> @@ -38,6 +39,7 @@ #include <QButtonGroup> #include <QLineEdit> #include <QPlainTextEdit> +#include <QTabWidget> #include <QScrollBar> #include <QSlider> #include <QSpinBox> @@ -50,38 +52,57 @@ #include <QGraphicsView> #include <QGraphicsTextItem> #include <QFile> +#include <QFontMetrics> #include <QMouseEvent> #include <QTemporaryDir> #include <QTimer> #include <QCommandLineParser> #include <QCommandLineOption> #include <QDebug> +#include <QElapsedTimer> #include <private/qhighdpiscaling_p.h> #include <qpa/qplatformscreen.h> #include "dragwidget.h" +#include <utility> + +static QTextStream &operator<<(QTextStream &str, const QSizeF &s) +{ + str << s.width() << 'x' << s.height(); + return str; +} + static QTextStream &operator<<(QTextStream &str, const QRect &r) { str << r.width() << 'x' << r.height() << Qt::forcesign << r.x() << r.y() << Qt::noforcesign; return str; } +static QString formatWindowTitle(const QString &title) +{ + QString result; + QTextStream(&result) << title << ' ' << QT_VERSION_STR << " (" + << QGuiApplication::platformName() + << '/' << QApplication::style()->objectName() << ')'; + return result; +} + class DemoContainerBase { public: - DemoContainerBase() : m_widget(nullptr) {} - virtual ~DemoContainerBase() {} - QString name() { return option().names().first(); } + DemoContainerBase() = default; + virtual ~DemoContainerBase() = default; + QString name() { return option().names().constFirst(); } virtual QCommandLineOption &option() = 0; virtual void makeVisible(bool visible, QWidget *parent) = 0; - QWidget *widget() { return m_widget; } + QWidget *widget() const { return m_widget; } + protected: - QWidget *m_widget; + QWidget *m_widget = nullptr; }; -typedef QList<DemoContainerBase*> DemoContainerList ; - +using DemoContainerList = QVector<DemoContainerBase*>; template <class T> class DemoContainer : public DemoContainerBase @@ -93,16 +114,25 @@ public: } ~DemoContainer() { delete m_widget; } - QCommandLineOption &option() { return m_option; } + QCommandLineOption &option() override { return m_option; } - void makeVisible(bool visible, QWidget *parent) { + void makeVisible(bool visible, QWidget *parent) override + { if (visible && !m_widget) { m_widget = new T; + if (m_widget->windowTitle().isEmpty()) { + QString title = m_option.description(); + if (title.startsWith("Test ", Qt::CaseInsensitive)) + title.remove(0, 5); + title[0] = title.at(0).toUpper(); + m_widget->setWindowTitle(formatWindowTitle(title)); + } m_widget->installEventFilter(parent); } if (m_widget) m_widget->setVisible(visible); } + private: QCommandLineOption m_option; }; @@ -134,12 +164,15 @@ public: connect(m_slider, &QSlider::sliderMoved, this, &LabelSlider::updateLabel); connect(m_slider, &QSlider::valueChanged, this, &LabelSlider::valueChanged); } - void setValue(int scaleFactor) { + void setValue(int scaleFactor) + { m_slider->setValue(scaleFactor); updateLabel(scaleFactor); } + private slots: - void updateLabel(int scaleFactor) { + void updateLabel(int scaleFactor) + { // slider value is scale factor times ten; qreal scalefactorF = qreal(scaleFactor) / 10.0; @@ -149,8 +182,10 @@ private slots: number.append(".0"); m_label->setText(number); } + signals: void valueChanged(int scaleFactor); + private: QSlider *m_slider; QLabel *m_label; @@ -172,31 +207,35 @@ static inline qreal getGlobalScaleFactor() class DemoController : public QWidget { -Q_OBJECT + Q_OBJECT public: - DemoController(DemoContainerList *demos, QCommandLineParser *parser); + DemoController(DemoContainerList demos, QCommandLineParser *parser); ~DemoController(); + protected: - bool eventFilter(QObject *object, QEvent *event); - void closeEvent(QCloseEvent *) { qApp->quit(); } + bool eventFilter(QObject *object, QEvent *event) override; + void closeEvent(QCloseEvent *) override { QCoreApplication::quit(); } + private slots: void handleButton(int id, bool toggled); + private: - DemoContainerList *m_demos; + DemoContainerList m_demos; QButtonGroup *m_group; }; -DemoController::DemoController(DemoContainerList *demos, QCommandLineParser *parser) - : m_demos(demos) +DemoController::DemoController(DemoContainerList demos, QCommandLineParser *parser) + : m_demos(std::move(demos)) { - setWindowTitle("screen scale factors"); + setWindowTitle(formatWindowTitle("Screen Scale Factors")); setObjectName("controller"); // make WindowScaleFactorSetter skip this window - QGridLayout *layout = new QGridLayout; - setLayout(layout); + auto mainLayout = new QVBoxLayout(this); + auto scaleLayout = new QGridLayout; + mainLayout->addLayout(scaleLayout); int layoutRow = 0; - LabelSlider *globalScaleSlider = new LabelSlider(this, "Global scale factor", layout, layoutRow++); + LabelSlider *globalScaleSlider = new LabelSlider(this, "Global scale factor", scaleLayout, layoutRow++); globalScaleSlider->setValue(int(getGlobalScaleFactor() * 10)); connect(globalScaleSlider, &LabelSlider::valueChanged, [](int scaleFactor){ // slider value is scale factor times ten; @@ -205,13 +244,13 @@ DemoController::DemoController(DemoContainerList *demos, QCommandLineParser *par }); // set up one scale control line per screen - QList<QScreen *> screens = QGuiApplication::screens(); - foreach (QScreen *screen, screens) { + const auto screens = QGuiApplication::screens(); + for (QScreen *screen : screens) { // create scale control line QSize screenSize = screen->geometry().size(); QString screenId = screen->name() + QLatin1Char(' ') + QString::number(screenSize.width()) + QLatin1Char(' ') + QString::number(screenSize.height()); - LabelSlider *slider = new LabelSlider(this, screenId, layout, layoutRow++); + LabelSlider *slider = new LabelSlider(this, screenId, scaleLayout, layoutRow++); slider->setValue(getScreenFactorWithoutPixelDensity(screen) * 10); // handle slider value change @@ -228,15 +267,18 @@ DemoController::DemoController(DemoContainerList *demos, QCommandLineParser *par }); } + auto demoLayout = new QFormLayout; + mainLayout->addLayout(demoLayout); m_group = new QButtonGroup(this); m_group->setExclusive(false); - for (int i = 0; i < m_demos->size(); ++i) { - DemoContainerBase *demo = m_demos->at(i); - QPushButton *button = new QPushButton(demo->name()); - button->setToolTip(demo->option().description()); + for (int i = 0; i < m_demos.size(); ++i) { + DemoContainerBase *demo = m_demos.at(i); + QString name = demo->name(); + name[0] = name.at(0).toUpper(); + auto button = new QPushButton(name); button->setCheckable(true); - layout->addWidget(button, layoutRow++, 0, 1, -1); + demoLayout->addRow(demo->option().description(), button); m_group->addButton(button, i); if (parser->isSet(demo->option())) { @@ -244,19 +286,20 @@ DemoController::DemoController(DemoContainerList *demos, QCommandLineParser *par button->setChecked(true); } } - connect(m_group, SIGNAL(buttonToggled(int, bool)), this, SLOT(handleButton(int, bool))); + connect(m_group, QOverload<int,bool>::of(&QButtonGroup::buttonToggled), + this, &DemoController::handleButton); } DemoController::~DemoController() { - qDeleteAll(*m_demos); + qDeleteAll(m_demos); } bool DemoController::eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::Close) { - for (int i = 0; i < m_demos->size(); ++i) { - DemoContainerBase *demo = m_demos->at(i); + for (int i = 0; i < m_demos.size(); ++i) { + DemoContainerBase *demo = m_demos.at(i); if (demo->widget() == object) { m_group->button(i)->setChecked(false); break; @@ -268,15 +311,17 @@ bool DemoController::eventFilter(QObject *object, QEvent *event) void DemoController::handleButton(int id, bool toggled) { - m_demos->at(id)->makeVisible(toggled, this); + m_demos.at(id)->makeVisible(toggled, this); } class PixmapPainter : public QWidget { public: PixmapPainter(); - void paintEvent(QPaintEvent *event); + void paintEvent(QPaintEvent *event) override; + +private: QPixmap pixmap1X; QPixmap pixmap2X; QPixmap pixmapLarge; @@ -348,12 +393,14 @@ void PixmapPainter::paintEvent(QPaintEvent *) class TiledPixmapPainter : public QWidget { public: + TiledPixmapPainter(); + + void paintEvent(QPaintEvent *event) override; + +private: QPixmap pixmap1X; QPixmap pixmap2X; QPixmap pixmapLarge; - - TiledPixmapPainter(); - void paintEvent(QPaintEvent *event); }; TiledPixmapPainter::TiledPixmapPainter() @@ -404,6 +451,7 @@ class Labels : public QWidget public: Labels(); +private: QPixmap pixmap1X; QPixmap pixmap2X; QPixmap pixmapLarge; @@ -419,7 +467,7 @@ Labels::Labels() qtIcon.addFile(":/qticon32.png"); qtIcon.addFile(":/qticon32@2x.png"); setWindowIcon(qtIcon); - setWindowTitle("Labels"); + setWindowTitle(formatWindowTitle("Labels")); QLabel *label1x = new QLabel(); label1x->setPixmap(pixmap1X); @@ -454,18 +502,17 @@ private: QIcon qtIcon2x; QToolBar *fileToolBar; - int menuCount; QAction *m_maskAction; + int menuCount = 0; }; MainWindow::MainWindow() - :menuCount(0) { // beware that QIcon auto-loads the @2x versions. qtIcon1x.addFile(":/qticon16.png"); qtIcon2x.addFile(":/qticon32.png"); setWindowIcon(qtIcon); - setWindowTitle("MainWindow"); + setWindowTitle(formatWindowTitle("MainWindow")); fileToolBar = addToolBar(tr("File")); // fileToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); @@ -484,7 +531,6 @@ MainWindow::MainWindow() addNewMenu("&Help", 2); } - QMenu *MainWindow::addNewMenu(const QString &title, int itemCount) { QMenu *menu = menuBar()->addMenu(title); @@ -516,7 +562,7 @@ void MainWindow::maskActionToggled(bool t) class StandardIcons : public QWidget { public: - void paintEvent(QPaintEvent *) + void paintEvent(QPaintEvent *) override { int x = 10; int y = 10; @@ -538,7 +584,7 @@ public: class Caching : public QWidget { public: - void paintEvent(QPaintEvent *) + void paintEvent(QPaintEvent *) override { QSize layoutSize(75, 75); @@ -576,16 +622,12 @@ public: } }; -class Style : public QWidget { +class Style : public QWidget +{ public: - QPushButton *button; - QLineEdit *lineEdit; - QSlider *slider; - QHBoxLayout *row1; - - Style() { - row1 = new QHBoxLayout(); - setLayout(row1); + Style() + { + row1 = new QHBoxLayout(this); button = new QPushButton(); button->setText("Test Button"); @@ -601,17 +643,23 @@ public: row1->addWidget(new QSpinBox); row1->addWidget(new QScrollBar); - QTabBar *tab = new QTabBar(); + auto tab = new QTabBar(); tab->addTab("Foo"); tab->addTab("Bar"); row1->addWidget(tab); } + +private: + QPushButton *button; + QLineEdit *lineEdit; + QSlider *slider; + QHBoxLayout *row1; }; class Fonts : public QWidget { public: - void paintEvent(QPaintEvent *) + void paintEvent(QPaintEvent *) override { QPainter painter(this); @@ -690,7 +738,7 @@ public: iconNormalDpi.reset(new QIcon(path32_2)); // does not have a 2x version. } - void paintEvent(QPaintEvent *) + void paintEvent(QPaintEvent *) override { int x = 10; int y = 10; @@ -782,7 +830,7 @@ public: tab->move(10, 100); tab->show(); - QToolBar *toolBar = new QToolBar(this); + auto toolBar = new QToolBar(this); toolBar->addAction(QIcon(":/qticon16.png"), "16"); toolBar->addAction(QIcon(":/qticon16@2x.png"), "16@2x"); toolBar->addAction(QIcon(":/qticon32.png"), "32"); @@ -796,11 +844,12 @@ public: class LinePainter : public QWidget { public: - void paintEvent(QPaintEvent *event); - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); + void paintEvent(QPaintEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; +private: QPoint lastMousePoint; QVector<QPoint> linePoints; }; @@ -855,17 +904,15 @@ void LinePainter::mouseMoveEvent(QMouseEvent *event) class CursorTester : public QWidget { public: - CursorTester() - :moveLabel(nullptr), moving(false) - { - } + CursorTester() = default; inline QRect getRect(int idx) const { int h = height() / 2; return QRect(10, 10 + h * (idx - 1), width() - 20, h - 20); } - void paintEvent(QPaintEvent *) + + void paintEvent(QPaintEvent *) override { QPainter p(this); QRect r1 = getRect(1); @@ -899,7 +946,7 @@ public: } } - void mousePressEvent(QMouseEvent *e) + void mousePressEvent(QMouseEvent *e) override { if (moving) return; @@ -923,7 +970,7 @@ public: moveLabel->show(); } - void mouseReleaseEvent(QMouseEvent *) + void mouseReleaseEvent(QMouseEvent *) override { if (moveLabel) moveLabel->hide(); @@ -931,7 +978,7 @@ public: moving = false; } - void mouseMoveEvent(QMouseEvent *e) + void mouseMoveEvent(QMouseEvent *e) override { if (!moving) return; @@ -943,32 +990,32 @@ public: } private: - QLabel *moveLabel; - bool useCursorPos; - bool moving; + QLabel *moveLabel = nullptr; QPoint mousePos; + bool useCursorPos = false; + bool moving = false; }; - class ScreenDisplayer : public QWidget { public: - ScreenDisplayer() - : QWidget(), moveLabel(nullptr), scaleFactor(1.0) - { - } + ScreenDisplayer() = default; - void timerEvent(QTimerEvent *) { + void timerEvent(QTimerEvent *) override + { update(); } - void mousePressEvent(QMouseEvent *) { + void mousePressEvent(QMouseEvent *) override + { if (!moveLabel) moveLabel = new QLabel(this,Qt::BypassWindowManagerHint|Qt::FramelessWindowHint|Qt::Window ); moveLabel->setText("Hello, Qt this is a label\nwith some text"); moveLabel->show(); } - void mouseMoveEvent(QMouseEvent *e) { + + void mouseMoveEvent(QMouseEvent *e) override + { if (!moveLabel) return; moveLabel->move(e->pos() / scaleFactor); @@ -978,23 +1025,30 @@ public: dbg << moveLabel->geometry(); moveLabel->setText(str); } - void mouseReleaseEvent(QMouseEvent *) { + + void mouseReleaseEvent(QMouseEvent *) override + { if (moveLabel) moveLabel->hide(); } - void showEvent(QShowEvent *) { + + void showEvent(QShowEvent *) override + { refreshTimer.start(300, this); } - void hideEvent(QHideEvent *) { + + void hideEvent(QHideEvent *) override + { refreshTimer.stop(); } - void paintEvent(QPaintEvent *) { + + void paintEvent(QPaintEvent *) override + { QPainter p(this); QRectF total; - QList<QScreen*> screens = qApp->screens(); - foreach (QScreen *screen, screens) { + const auto screens = QGuiApplication::screens(); + for (const QScreen *screen : screens) total |= screen->geometry(); - } if (total.isEmpty()) return; @@ -1006,8 +1060,7 @@ public: p.setPen(QPen(Qt::white, 10)); p.setBrush(Qt::gray); - - foreach (QScreen *screen, screens) { + for (const QScreen *screen : screens) { p.drawRect(screen->geometry()); QFont f = font(); f.setPixelSize(screen->geometry().height() / 8); @@ -1015,7 +1068,9 @@ public: p.drawText(screen->geometry(), Qt::AlignCenter, screen->name()); } p.setBrush(QColor(200,220,255,127)); - foreach (QWidget *widget, QApplication::topLevelWidgets()) { + + const auto topLevels = QApplication::topLevelWidgets(); + for (QWidget *widget : topLevels) { if (!widget->isHidden()) p.drawRect(widget->geometry()); } @@ -1028,42 +1083,51 @@ public: cursorShape.translate(QCursor::pos()); p.drawPolygon(cursorShape); } + private: - QLabel *moveLabel; + QLabel *moveLabel = nullptr; + qreal scaleFactor = 1; QBasicTimer refreshTimer; - qreal scaleFactor; }; class PhysicalSizeTest : public QWidget { -Q_OBJECT + Q_OBJECT public: - PhysicalSizeTest() : QWidget(), m_ignoreResize(false) {} - void paintEvent(QPaintEvent *event); - void resizeEvent(QResizeEvent *) { + PhysicalSizeTest() = default; + + void paintEvent(QPaintEvent *event) override; + + void resizeEvent(QResizeEvent *) override + { qreal ppi = window()->windowHandle()->screen()->physicalDotsPerInchX(); QSizeF s = size(); if (!m_ignoreResize) m_physicalSize = s / ppi; } - bool event(QEvent *event) { + + bool event(QEvent *event) override + { if (event->type() == QEvent::ScreenChangeInternal) { // we will get resize events when the scale factor changes m_ignoreResize = true; - QTimer::singleShot(100, this, SLOT(handleScreenChange())); + QTimer::singleShot(100, this, &PhysicalSizeTest::handleScreenChange); } return QWidget::event(event); } + public slots: - void handleScreenChange() { + void handleScreenChange() + { qreal ppi = window()->windowHandle()->screen()->physicalDotsPerInchX(); QSizeF newSize = m_physicalSize * ppi; resize(newSize.toSize()); m_ignoreResize = false; } + private: QSizeF m_physicalSize; - bool m_ignoreResize; + bool m_ignoreResize = false; }; void PhysicalSizeTest::paintEvent(QPaintEvent *) @@ -1166,8 +1230,9 @@ void PhysicalSizeTest::paintEvent(QPaintEvent *) class GraphicsViewCaching : public QGraphicsView { public: - GraphicsViewCaching() { - QGraphicsScene *scene = new QGraphicsScene(0, 0, 400, 400); + GraphicsViewCaching() + { + auto scene = new QGraphicsScene(0, 0, 400, 400); QGraphicsTextItem *item = scene->addText("NoCache"); item->setCacheMode(QGraphicsItem::NoCache); @@ -1185,16 +1250,15 @@ public: } }; -class MetricsTest : public QWidget +class MetricsTest : public QTabWidget { - QPlainTextEdit *m_textEdit; - + Q_OBJECT public: MetricsTest() { - qDebug() << R"( -MetricsTest -Relevant environment variables are: + qDebug().noquote().nospace() << "MetricsTest " << QT_VERSION_STR + << ' ' << QGuiApplication::platformName() << '\n' +<< R"(Relevant environment variables are: QT_FONT_DPI=N QT_SCALE_FACTOR=n QT_ENABLE_HIGHDPI_SCALING=0|1 @@ -1203,14 +1267,36 @@ QT_SCREEN_SCALE_FACTORS=N;N;N or QT_SCREEN_SCALE_FACTORS=name:N QT_SCALE_FACTOR_ROUNDING_POLICY=Round|Ceil|Floor|RoundPreferFloor|PassThrough QT_DPI_ADJUSTMENT_POLICY=AdjustDpi|DontAdjustDpi|AdjustUpOnly)"; - resize(480, 360); + m_textEdit = addTextPage("Parameters"); + m_logEdit = addTextPage("Screen Change Log"); - QVBoxLayout *layout = new QVBoxLayout(); - setLayout(layout); + const auto screens = QGuiApplication::screens(); + for (auto screen : screens) + connectScreenChangeSignals(screen); + connect(qApp, &QGuiApplication::screenAdded, this, &MetricsTest::slotScreenAdded); + connect(qApp, &QGuiApplication::primaryScreenChanged, this, &MetricsTest::slotPrimaryScreenChanged); + connect(qApp, &QGuiApplication::screenRemoved, this, &MetricsTest::slotScreenRemoved); + + setWindowTitle(formatWindowTitle("Screens")); + m_logTimer.start(); + logMessage(briefFormatScreens()); + + // Resize to roughly match the metrics text. + const auto metrics = QFontMetrics(m_textEdit->font(), m_textEdit); + const int width = 10 + metrics.horizontalAdvance(QStringLiteral("X")) * 50; + const int height = 40 + metrics.height() * (10 + 8 * screens.size()); + resize(width, height); + } - m_textEdit = new QPlainTextEdit; - m_textEdit->setReadOnly(true); - layout->addWidget(m_textEdit); + void setVisible(bool visible) override + { + QWidget::setVisible(visible); + if (visible && !m_screenChangedConnected) { + m_screenChangedConnected = true; + QObject::connect(windowHandle(), &QWindow::screenChanged, + this, &MetricsTest::screenChanged); + updateMetrics(); + } } void updateMetrics() @@ -1254,24 +1340,145 @@ QT_DPI_ADJUSTMENT_POLICY=AdjustDpi|DontAdjustDpi|AdjustUpOnly)"; m_textEdit->setPlainText(text); } - void paintEvent(QPaintEvent *ev) +private slots: + void screenChanged() { - // We get a paint event on screen change, so this is a convenient place - // to update the metrics, at the possible risk of doing something else - // than painting in a paint event. + const QString message = QLatin1String("screenChanged ") + windowHandle()->screen()->name(); + qInfo("%s", qPrintable(message)); + logMessage(message); updateMetrics(); - QWidget::paintEvent(ev); } + + void slotScreenAdded(QScreen *); + void slotScreenRemoved(QScreen *); + void slotPrimaryScreenChanged(QScreen *); + void slotScreenGeometryChanged(const QRect &geometry) + { logScreenChangeSignal(sender(), "geometry", geometry); } + void slotScreenAvailableGeometryChanged(const QRect &geometry) + { logScreenChangeSignal(sender(), "availableGeometry", geometry); } + void slotScreenPhysicalSizeChanged(const QSizeF &size) + { logScreenChangeSignal(sender(), "physicalSize", size); } + void slotScreenPhysicalDotsPerInchChanged(qreal dpi) + { logScreenChangeSignal(sender(), "physicalDotsPerInch", dpi); } + void slotScreenLogicalDotsPerInchChanged(qreal dpi) + { logScreenChangeSignal(sender(), "logicalDotsPerInch", dpi); } + void slotScreenVirtualGeometryChanged(const QRect &rect) + { logScreenChangeSignal(sender(), "virtualGeometry", rect); } + void slotScreenPrimaryOrientationChanged(Qt::ScreenOrientation orientation) + { logScreenChangeSignal(sender(), "primaryOrientation", orientation); } + void slotScreenOrientationChanged(Qt::ScreenOrientation orientation) + { logScreenChangeSignal(sender(), "orientation", orientation); } + void slotScreenRefreshRateChanged(qreal refreshRate) + { logScreenChangeSignal(sender(), "refreshRate", refreshRate); } + +private: + QPlainTextEdit *addTextPage(const QString &title); + void logMessage(const QString &); + void connectScreenChangeSignals(QScreen *s); + static QString briefFormatScreens(); + template <class T> + void logScreenChangeSignal(const QObject *o, const char *name, const T &value); + + QPlainTextEdit *m_textEdit; + QPlainTextEdit *m_logEdit; + QElapsedTimer m_logTimer; + bool m_screenChangedConnected = false; }; +void MetricsTest::slotScreenAdded(QScreen *screen) +{ + logMessage(QLatin1String("Added ") + screen->name() + QLatin1Char(' ') + + briefFormatScreens()); + connectScreenChangeSignals(screen); +} + +void MetricsTest::slotScreenRemoved(QScreen *screen) +{ + logMessage(QLatin1String("Removed ") + screen->name() + QLatin1Char(' ') + + briefFormatScreens()); +} + +void MetricsTest::slotPrimaryScreenChanged(QScreen *screen) +{ + logMessage(QLatin1String("PrimaryScreenChanged ") + screen->name() + QLatin1Char(' ') + + briefFormatScreens()); +} + +QPlainTextEdit *MetricsTest::addTextPage(const QString &title) +{ + auto result = new QPlainTextEdit(this); + result->setReadOnly(true); + result->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); + addTab(result, title); + return result; +} + +void MetricsTest::logMessage(const QString &m) +{ + const QString timeStamp = + QStringLiteral("%1ms: %2").arg(m_logTimer.elapsed(), 6, 10, QLatin1Char('0')).arg(m); + m_logEdit->appendPlainText(timeStamp); +} + +void MetricsTest::connectScreenChangeSignals(QScreen *s) +{ + connect(s, &QScreen::geometryChanged, this, &MetricsTest::slotScreenGeometryChanged); + connect(s, &QScreen::availableGeometryChanged, this, &MetricsTest::slotScreenAvailableGeometryChanged); + connect(s, &QScreen::physicalSizeChanged, this, &MetricsTest::slotScreenPhysicalSizeChanged); + connect(s, &QScreen::physicalDotsPerInchChanged, this, &MetricsTest::slotScreenPhysicalDotsPerInchChanged); + connect(s, &QScreen::logicalDotsPerInchChanged, this, &MetricsTest::slotScreenLogicalDotsPerInchChanged); + connect(s, &QScreen::virtualGeometryChanged, this, &MetricsTest::slotScreenVirtualGeometryChanged); + connect(s, &QScreen::primaryOrientationChanged, this, &MetricsTest::slotScreenPrimaryOrientationChanged); + connect(s, &QScreen::orientationChanged, this, &MetricsTest::slotScreenOrientationChanged); + connect(s, &QScreen::refreshRateChanged, this, &MetricsTest::slotScreenRefreshRateChanged); +} + +QString MetricsTest::briefFormatScreens() +{ + QString message; + QTextStream str(&message); + const auto screens = QGuiApplication::screens(); + for (int i = 0, size = screens.size(); i < size; ++i) { + str << (i ? ", " : "("); + str << screens.at(i)->name() << " " << screens.at(i)->geometry(); + } + str << ')'; + return message; +} + +template <class T> +void MetricsTest::logScreenChangeSignal(const QObject *o, const char *name, const T &value) +{ + auto screen = qobject_cast<const QScreen *>(o); + QString message; + QTextStream(&message) << (screen ? screen->name() : QString()) << ' ' << name << " changed: " << value; + logMessage(message); +} + int main(int argc, char **argv) { +#define NOSCALINGOPTION "noscaling" +#define SCALINGOPTION "scaling" + + qInfo("High DPI tester %s", QT_VERSION_STR); + + int preAppOptionCount = 0; + for (int a = 1; a < argc; ++a) { + if (qstrcmp(argv[a], "--" NOSCALINGOPTION) == 0) { + QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); + preAppOptionCount++; + qInfo("AA_DisableHighDpiScaling"); + } else if (qstrcmp(argv[a], "--" SCALINGOPTION) == 0) { + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + preAppOptionCount++; + qInfo("AA_EnableHighDpiScaling"); + } + } + QApplication app(argc, argv); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QCoreApplication::setApplicationVersion(QT_VERSION_STR); - int argumentCount = QCoreApplication::arguments().count(); - QCommandLineParser parser; parser.setApplicationDescription("High DPI tester. Pass one or more of the options to\n" "test various high-dpi aspects. \n" @@ -1281,7 +1488,8 @@ int main(int argc, char **argv) parser.addVersionOption(); QCommandLineOption controllerOption("interactive", "Show configuration window."); parser.addOption(controllerOption); - + parser.addOption(QCommandLineOption(NOSCALINGOPTION, "Set AA_DisableHighDpiScaling")); + parser.addOption(QCommandLineOption(SCALINGOPTION, "Set AA_EnableHighDpiScaling")); DemoContainerList demoList; demoList << new DemoContainer<PixmapPainter>("pixmap", "Test pixmap painter"); @@ -1300,17 +1508,17 @@ int main(int argc, char **argv) demoList << new DemoContainer<ScreenDisplayer>("screens", "Test screen and window positioning"); demoList << new DemoContainer<PhysicalSizeTest>("physicalsize", "Test manual highdpi support using physicalDotsPerInch"); demoList << new DemoContainer<GraphicsViewCaching>("graphicsview", "Test QGraphicsView caching"); - demoList << new DemoContainer<MetricsTest>("metrics", "Show display metrics"); + demoList << new DemoContainer<MetricsTest>("metrics", "Show screen metrics"); - foreach (DemoContainerBase *demo, demoList) + for (DemoContainerBase *demo : qAsConst(demoList)) parser.addOption(demo->option()); parser.process(app); //controller takes ownership of all demos - DemoController controller(&demoList, &parser); + DemoController controller(demoList, &parser); - if (parser.isSet(controllerOption) || argumentCount <= 1) + if (parser.isSet(controllerOption) || (QCoreApplication::arguments().count() - preAppOptionCount) <= 1) controller.show(); if (QApplication::topLevelWidgets().isEmpty()) diff --git a/tests/manual/network_stresstest/tst_network_stresstest.cpp b/tests/manual/network_stresstest/tst_network_stresstest.cpp index 03df1633d5..5f2fd2b24e 100644 --- a/tests/manual/network_stresstest/tst_network_stresstest.cpp +++ b/tests/manual/network_stresstest/tst_network_stresstest.cpp @@ -123,7 +123,8 @@ void tst_NetworkStressTest::initTestCase_data() void tst_NetworkStressTest::initTestCase() { - QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); + if (!QtNetworkSettings::verifyTestNetworkSettings()) + QSKIP("No network test server available"); } void tst_NetworkStressTest::init() diff --git a/tests/manual/qgraphicslayout/flicker/window.h b/tests/manual/qgraphicslayout/flicker/window.h index c49b82704e..b2ebe60af4 100644 --- a/tests/manual/qgraphicslayout/flicker/window.h +++ b/tests/manual/qgraphicslayout/flicker/window.h @@ -74,7 +74,7 @@ class Window; class SlowWidget : public QGraphicsWidget { public: - SlowWidget(QGraphicsWidget *w = 0, Qt::WindowFlags wFlags = 0) : QGraphicsWidget(w, wFlags) + SlowWidget(QGraphicsWidget *w = nullptr, Qt::WindowFlags wFlags = {}) : QGraphicsWidget(w, wFlags) { m_window = 0; } diff --git a/tests/manual/qnetworkreply/main.cpp b/tests/manual/qnetworkreply/main.cpp index 01bd30a854..1086498553 100644 --- a/tests/manual/qnetworkreply/main.cpp +++ b/tests/manual/qnetworkreply/main.cpp @@ -105,7 +105,8 @@ protected: void tst_qnetworkreply::initTestCase() { qRegisterMetaType<QNetworkReply *>(); // for QSignalSpy - QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); + if (!QtNetworkSettings::verifyTestNetworkSettings()) + QSKIP("No network test server available"); } void tst_qnetworkreply::limiting_data() diff --git a/tests/manual/rhi/cubemap_render/buildshader.bat b/tests/manual/rhi/cubemap_render/buildshader.bat new file mode 100755 index 0000000000..3886c138d8 --- /dev/null +++ b/tests/manual/rhi/cubemap_render/buildshader.bat @@ -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 diff --git a/tests/manual/rhi/cubemap_render/cubemap_mrt.frag b/tests/manual/rhi/cubemap_render/cubemap_mrt.frag new file mode 100644 index 0000000000..06a08f6cd6 --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_mrt.frag @@ -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); +} diff --git a/tests/manual/rhi/cubemap_render/cubemap_mrt.frag.qsb b/tests/manual/rhi/cubemap_render/cubemap_mrt.frag.qsb Binary files differnew file mode 100644 index 0000000000..7a0be83a81 --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_mrt.frag.qsb diff --git a/tests/manual/rhi/cubemap_render/cubemap_mrt.vert b/tests/manual/rhi/cubemap_render/cubemap_mrt.vert new file mode 100644 index 0000000000..6d82feccc8 --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_mrt.vert @@ -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; +} diff --git a/tests/manual/rhi/cubemap_render/cubemap_mrt.vert.qsb b/tests/manual/rhi/cubemap_render/cubemap_mrt.vert.qsb Binary files differnew file mode 100644 index 0000000000..9358ac2792 --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_mrt.vert.qsb diff --git a/tests/manual/rhi/cubemap_render/cubemap_oneface.frag b/tests/manual/rhi/cubemap_render/cubemap_oneface.frag new file mode 100644 index 0000000000..8bafe689be --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_oneface.frag @@ -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); +} diff --git a/tests/manual/rhi/cubemap_render/cubemap_oneface.frag.qsb b/tests/manual/rhi/cubemap_render/cubemap_oneface.frag.qsb Binary files differnew file mode 100644 index 0000000000..a6187939a0 --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_oneface.frag.qsb diff --git a/tests/manual/rhi/cubemap_render/cubemap_oneface.vert b/tests/manual/rhi/cubemap_render/cubemap_oneface.vert new file mode 100644 index 0000000000..2db9076a74 --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_oneface.vert @@ -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; +} diff --git a/tests/manual/rhi/cubemap_render/cubemap_oneface.vert.qsb b/tests/manual/rhi/cubemap_render/cubemap_oneface.vert.qsb Binary files differnew file mode 100644 index 0000000000..58772179e5 --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_oneface.vert.qsb diff --git a/tests/manual/rhi/cubemap_render/cubemap_render.cpp b/tests/manual/rhi/cubemap_render/cubemap_render.cpp new file mode 100644 index 0000000000..a08e96f0c6 --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_render.cpp @@ -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; + } +} diff --git a/tests/manual/rhi/cubemap_render/cubemap_render.pro b/tests/manual/rhi/cubemap_render/cubemap_render.pro new file mode 100644 index 0000000000..71208cc01f --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_render.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + cubemap_render.cpp + +RESOURCES = cubemap_render.qrc diff --git a/tests/manual/rhi/cubemap_render/cubemap_render.qrc b/tests/manual/rhi/cubemap_render/cubemap_render.qrc new file mode 100644 index 0000000000..f6029d3f3a --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_render.qrc @@ -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> diff --git a/tests/manual/rhi/cubemap_render/cubemap_sample.frag b/tests/manual/rhi/cubemap_render/cubemap_sample.frag new file mode 100644 index 0000000000..13a365ed0c --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_sample.frag @@ -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); +} diff --git a/tests/manual/rhi/cubemap_render/cubemap_sample.frag.qsb b/tests/manual/rhi/cubemap_render/cubemap_sample.frag.qsb Binary files differnew file mode 100644 index 0000000000..f26e3985b6 --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_sample.frag.qsb diff --git a/tests/manual/rhi/cubemap_render/cubemap_sample.vert b/tests/manual/rhi/cubemap_render/cubemap_sample.vert new file mode 100644 index 0000000000..f1caf1a74f --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_sample.vert @@ -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; +} diff --git a/tests/manual/rhi/cubemap_render/cubemap_sample.vert.qsb b/tests/manual/rhi/cubemap_render/cubemap_sample.vert.qsb Binary files differnew file mode 100644 index 0000000000..0cbc144011 --- /dev/null +++ b/tests/manual/rhi/cubemap_render/cubemap_sample.vert.qsb diff --git a/tests/manual/rhi/float16texture_with_compute/buildshaders.sh b/tests/manual/rhi/float16texture_with_compute/buildshaders.sh new file mode 100755 index 0000000000..7d4d27741d --- /dev/null +++ b/tests/manual/rhi/float16texture_with_compute/buildshaders.sh @@ -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 diff --git a/tests/manual/rhi/float16texture_with_compute/float16texture_with_compute.cpp b/tests/manual/rhi/float16texture_with_compute/float16texture_with_compute.cpp new file mode 100644 index 0000000000..9d74fe797b --- /dev/null +++ b/tests/manual/rhi/float16texture_with_compute/float16texture_with_compute.cpp @@ -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(); +} diff --git a/tests/manual/rhi/float16texture_with_compute/float16texture_with_compute.pro b/tests/manual/rhi/float16texture_with_compute/float16texture_with_compute.pro new file mode 100644 index 0000000000..7708e845d0 --- /dev/null +++ b/tests/manual/rhi/float16texture_with_compute/float16texture_with_compute.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + float16texture_with_compute.cpp + +RESOURCES = float16texture_with_compute.qrc diff --git a/tests/manual/rhi/float16texture_with_compute/float16texture_with_compute.qrc b/tests/manual/rhi/float16texture_with_compute/float16texture_with_compute.qrc new file mode 100644 index 0000000000..ce3c52aac5 --- /dev/null +++ b/tests/manual/rhi/float16texture_with_compute/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> diff --git a/tests/manual/rhi/float16texture_with_compute/load.comp b/tests/manual/rhi/float16texture_with_compute/load.comp new file mode 100644 index 0000000000..eb7bc1ece4 --- /dev/null +++ b/tests/manual/rhi/float16texture_with_compute/load.comp @@ -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); +} diff --git a/tests/manual/rhi/float16texture_with_compute/load.comp.qsb b/tests/manual/rhi/float16texture_with_compute/load.comp.qsb Binary files differnew file mode 100644 index 0000000000..bfdd7f5446 --- /dev/null +++ b/tests/manual/rhi/float16texture_with_compute/load.comp.qsb diff --git a/tests/manual/rhi/float16texture_with_compute/prefilter.comp b/tests/manual/rhi/float16texture_with_compute/prefilter.comp new file mode 100644 index 0000000000..ba09ecb129 --- /dev/null +++ b/tests/manual/rhi/float16texture_with_compute/prefilter.comp @@ -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); +} diff --git a/tests/manual/rhi/float16texture_with_compute/prefilter.comp.qsb b/tests/manual/rhi/float16texture_with_compute/prefilter.comp.qsb Binary files differnew file mode 100644 index 0000000000..77618a12b9 --- /dev/null +++ b/tests/manual/rhi/float16texture_with_compute/prefilter.comp.qsb diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.cpp b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.cpp index ea1fefc308..9b03a48bfe 100644 --- a/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.cpp +++ b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.cpp @@ -77,7 +77,7 @@ #include <QtGui/private/qrhid3d11_p.h> #endif -#ifdef Q_OS_DARWIN +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) #include <QtGui/private/qrhimetal_p.h> #endif @@ -283,7 +283,7 @@ void Window::init() } #endif -#ifdef Q_OS_DARWIN +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) if (graphicsApi == Metal) { QRhiMetalInitParams params; m_r = QRhi::create(QRhi::Metal, ¶ms); @@ -483,7 +483,7 @@ int main(int argc, char **argv) // Defaults. #if defined(Q_OS_WIN) graphicsApi = D3D11; -#elif defined(Q_OS_DARWIN) +#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS) graphicsApi = Metal; #elif QT_CONFIG(vulkan) graphicsApi = Vulkan; diff --git a/tests/manual/rhi/multiwindow/multiwindow.cpp b/tests/manual/rhi/multiwindow/multiwindow.cpp index 4d5de16a58..5fb5bb22ab 100644 --- a/tests/manual/rhi/multiwindow/multiwindow.cpp +++ b/tests/manual/rhi/multiwindow/multiwindow.cpp @@ -78,7 +78,7 @@ #include <QtGui/private/qrhid3d11_p.h> #endif -#ifdef Q_OS_DARWIN +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) #include <QtGui/private/qrhimetal_p.h> #endif @@ -148,7 +148,7 @@ void createRhi() } #endif -#ifdef Q_OS_DARWIN +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) if (graphicsApi == Metal) { QRhiMetalInitParams params; r.r = QRhi::create(QRhi::Metal, ¶ms); @@ -530,7 +530,7 @@ int main(int argc, char **argv) #if defined(Q_OS_WIN) graphicsApi = D3D11; -#elif defined(Q_OS_DARWIN) +#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS) graphicsApi = Metal; #elif QT_CONFIG(vulkan) graphicsApi = Vulkan; diff --git a/tests/manual/rhi/multiwindow_threaded/multiwindow_threaded.cpp b/tests/manual/rhi/multiwindow_threaded/multiwindow_threaded.cpp index 37c6cd04c3..75a1590d94 100644 --- a/tests/manual/rhi/multiwindow_threaded/multiwindow_threaded.cpp +++ b/tests/manual/rhi/multiwindow_threaded/multiwindow_threaded.cpp @@ -82,7 +82,7 @@ #include <QtGui/private/qrhid3d11_p.h> #endif -#ifdef Q_OS_DARWIN +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) #include <QtGui/private/qrhimetal_p.h> #endif @@ -376,7 +376,7 @@ void Renderer::createRhi() } #endif -#ifdef Q_OS_DARWIN +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) if (graphicsApi == Metal) { QRhiMetalInitParams params; r = QRhi::create(QRhi::Metal, ¶ms, rhiFlags); @@ -730,7 +730,7 @@ int main(int argc, char **argv) #if defined(Q_OS_WIN) graphicsApi = D3D11; -#elif defined(Q_OS_DARWIN) +#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS) graphicsApi = Metal; #elif QT_CONFIG(vulkan) graphicsApi = Vulkan; diff --git a/tests/manual/rhi/offscreen/offscreen.cpp b/tests/manual/rhi/offscreen/offscreen.cpp index 79e50d3dd4..31c0632be1 100644 --- a/tests/manual/rhi/offscreen/offscreen.cpp +++ b/tests/manual/rhi/offscreen/offscreen.cpp @@ -72,7 +72,7 @@ #include <QtGui/private/qrhid3d11_p.h> #endif -#ifdef Q_OS_DARWIN +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) #include <QtGui/private/qrhimetal_p.h> #endif @@ -130,7 +130,7 @@ int main(int argc, char **argv) #if defined(Q_OS_WIN) graphicsApi = D3D11; -#elif defined(Q_OS_DARWIN) +#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS) graphicsApi = Metal; #elif QT_CONFIG(vulkan) graphicsApi = Vulkan; @@ -217,7 +217,7 @@ int main(int argc, char **argv) } #endif -#ifdef Q_OS_DARWIN +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) if (graphicsApi == Metal) { QRhiMetalInitParams params; r = QRhi::create(QRhi::Metal, ¶ms); diff --git a/tests/manual/rhi/rhi.pro b/tests/manual/rhi/rhi.pro index 4768ee1c6d..4bee164969 100644 --- a/tests/manual/rhi/rhi.pro +++ b/tests/manual/rhi/rhi.pro @@ -9,11 +9,13 @@ SUBDIRS += \ msaarenderbuffer \ cubemap \ cubemap_scissor \ + cubemap_render \ multiwindow \ multiwindow_threaded \ triquadcube \ offscreen \ floattexture \ + float16texture_with_compute \ mrt \ shadowmap \ computebuffer \ diff --git a/tests/manual/rhi/shared/examplefw.h b/tests/manual/rhi/shared/examplefw.h index d28bbea0a8..84895cf530 100644 --- a/tests/manual/rhi/shared/examplefw.h +++ b/tests/manual/rhi/shared/examplefw.h @@ -78,7 +78,7 @@ #include <QtGui/private/qrhid3d11_p.h> #endif -#ifdef Q_OS_DARWIN +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) #include <QtGui/private/qrhimetal_p.h> #endif @@ -123,9 +123,9 @@ QString graphicsApiName() QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers; int sampleCount = 1; -QRhiSwapChain::Flags scFlags = 0; -QRhi::BeginFrameFlags beginFrameFlags = 0; -QRhi::EndFrameFlags endFrameFlags = 0; +QRhiSwapChain::Flags scFlags; +QRhi::BeginFrameFlags beginFrameFlags; +QRhi::EndFrameFlags endFrameFlags; int framesUntilTdr = -1; bool transparentBackground = false; @@ -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; @@ -292,7 +295,7 @@ void Window::init() } #endif -#ifdef Q_OS_DARWIN +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) if (graphicsApi == Metal) { QRhiMetalInitParams params; m_r = QRhi::create(QRhi::Metal, ¶ms, rhiFlags); @@ -445,7 +448,7 @@ int main(int argc, char **argv) // Defaults. #if defined(Q_OS_WIN) graphicsApi = D3D11; -#elif defined(Q_OS_DARWIN) +#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS) graphicsApi = Metal; #elif QT_CONFIG(vulkan) graphicsApi = Vulkan; diff --git a/tests/manual/rhi/texuploads/texuploads.cpp b/tests/manual/rhi/texuploads/texuploads.cpp index 4c10a6b965..a6b7d87d3e 100644 --- a/tests/manual/rhi/texuploads/texuploads.cpp +++ b/tests/manual/rhi/texuploads/texuploads.cpp @@ -237,11 +237,11 @@ void Window::customRender() // Exercise texture object export/import. if (d.testStage == 6) { - const QRhiNativeHandles *h = d.tex->nativeHandles(); - if (h) { -#ifdef Q_OS_DARWIN + const QRhiTexture::NativeTexture nativeTexture = d.tex->nativeTexture(); + if (nativeTexture.object) { +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) if (graphicsApi == Metal) { - qDebug() << "Metal texture: " << static_cast<const QRhiMetalTextureNativeHandles *>(h)->texture; + qDebug() << "Metal texture: " << *(void**)nativeTexture.object; // Now could cast to id<MTLTexture> and do something with // it, keeping in mind that copy operations are only done // in beginPass, while rendering into a texture may only @@ -253,7 +253,7 @@ void Window::customRender() d.importedTex = m_r->newTexture(QRhiTexture::RGBA8, d.tex->pixelSize()); d.releasePool << d.importedTex; - if (!d.importedTex->buildFrom(h)) + if (!d.importedTex->buildFrom(nativeTexture)) qWarning("Texture import failed"); // now d.tex and d.importedTex use the same MTLTexture diff --git a/tests/manual/rhi/triquadcube/texturedcuberenderer.cpp b/tests/manual/rhi/triquadcube/texturedcuberenderer.cpp index 8c5845d4fc..d8dea6d91f 100644 --- a/tests/manual/rhi/triquadcube/texturedcuberenderer.cpp +++ b/tests/manual/rhi/triquadcube/texturedcuberenderer.cpp @@ -78,7 +78,7 @@ void TexturedCubeRenderer::initResources(QRhiRenderPassDescriptor *rp) m_ubuf->build(); m_image = QImage(QLatin1String(":/qt256.png")).convertToFormat(QImage::Format_RGBA8888); - QRhiTexture::Flags texFlags = 0; + QRhiTexture::Flags texFlags; if (MIPMAP) texFlags |= QRhiTexture::MipMapped; if (AUTOGENMIPMAP) diff --git a/tests/manual/rhi/triquadcube/triangleoncuberenderer.cpp b/tests/manual/rhi/triquadcube/triangleoncuberenderer.cpp index 250ae3a2ee..3a58eed6ce 100644 --- a/tests/manual/rhi/triquadcube/triangleoncuberenderer.cpp +++ b/tests/manual/rhi/triquadcube/triangleoncuberenderer.cpp @@ -158,7 +158,7 @@ void TriangleOnCubeRenderer::initResources(QRhiRenderPassDescriptor *rp) m_ps->build(); - QRhiTextureRenderTarget::Flags rtFlags = 0; + QRhiTextureRenderTarget::Flags rtFlags; if (IMAGE_UNDER_OFFSCREEN_RENDERING) rtFlags |= QRhiTextureRenderTarget::PreserveColorContents; diff --git a/tests/manual/wasm/cursors/MainWindow.cpp b/tests/manual/wasm/cursors/MainWindow.cpp new file mode 100644 index 0000000000..a850856ab3 --- /dev/null +++ b/tests/manual/wasm/cursors/MainWindow.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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$ +** +****************************************************************************/ +#include "MainWindow.h" +#include "ui_MainWindow.h" + +#include <QPushButton> +#include <QVariant> +#include <QApplication> + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + for (int i = 0; i <= Qt::LastCursor; i++) { + auto shape = Qt::CursorShape(i); + auto button = + new QPushButton(QVariant::fromValue(shape).toString(), this); + ui->buttonsLayout->addWidget(button); + QObject::connect(button, &QPushButton::clicked, + [this, shape]() { ui->cursorWidget->setCursor(shape); }); + } +} + +MainWindow::~MainWindow() +{ + delete ui; +} diff --git a/tests/manual/wasm/cursors/MainWindow.h b/tests/manual/wasm/cursors/MainWindow.h new file mode 100644 index 0000000000..cda4ef19ba --- /dev/null +++ b/tests/manual/wasm/cursors/MainWindow.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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$ +** +****************************************************************************/ +#pragma once + +#include <QMainWindow> + +QT_BEGIN_NAMESPACE +namespace Ui { +class MainWindow; +} +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +private: + Ui::MainWindow *ui; +}; diff --git a/tests/manual/wasm/cursors/MainWindow.ui b/tests/manual/wasm/cursors/MainWindow.ui new file mode 100644 index 0000000000..ef4bfab87d --- /dev/null +++ b/tests/manual/wasm/cursors/MainWindow.ui @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>700</width> + <height>520</height> + </rect> + </property> + <property name="windowTitle"> + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QWidget" name="buttons" native="true"> + <property name="maximumSize"> + <size> + <width>200</width> + <height>16777215</height> + </size> + </property> + <layout class="QVBoxLayout" name="buttonsLayout"/> + </widget> + </item> + <item> + <widget class="QWidget" name="cursorWidget" native="true"> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Push the button to activate cursor and move mouse th this area.</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="textInteractionFlags"> + <set>Qt::NoTextInteraction</set> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tests/manual/wasm/cursors/cursors.pro b/tests/manual/wasm/cursors/cursors.pro new file mode 100644 index 0000000000..501b6d1da3 --- /dev/null +++ b/tests/manual/wasm/cursors/cursors.pro @@ -0,0 +1,13 @@ +QT += core gui widgets + +SOURCES += \ + main.cpp \ + MainWindow.cpp + +HEADERS += \ + MainWindow.h + +FORMS += \ + MainWindow.ui + +LIBS += -lidbfs.js diff --git a/tests/manual/wasm/cursors/main.cpp b/tests/manual/wasm/cursors/main.cpp new file mode 100644 index 0000000000..c0b90f2c37 --- /dev/null +++ b/tests/manual/wasm/cursors/main.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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$ +** +****************************************************************************/ +#include "MainWindow.h" + +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.showFullScreen(); + return a.exec(); +} diff --git a/tests/manual/widgets/widgets/qtabbar/qtabbar.pro b/tests/manual/widgets/widgets/qtabbar/qtabbar.pro new file mode 100644 index 0000000000..b39c81493b --- /dev/null +++ b/tests/manual/widgets/widgets/qtabbar/qtabbar.pro @@ -0,0 +1 @@ +SUBDIRS = stylesheet diff --git a/tests/manual/widgets/widgets/qtabbar/stylesheet/main.cpp b/tests/manual/widgets/widgets/qtabbar/stylesheet/main.cpp new file mode 100644 index 0000000000..02393f66f9 --- /dev/null +++ b/tests/manual/widgets/widgets/qtabbar/stylesheet/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** + ** + ** Copyright (C) 2020 The Qt Company Ltd. + ** Contact: https://www.qt.io/licensing/ + ** + ** This file is part of the test suite 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$ + ** + ****************************************************************************/ + +// This test is for checking that when there is padding set on the stylesheet and the elide mode is +// set that it is correctly shown as elided and not clipped. + +#include <QApplication> +#include <QTabBar> +#include <QIcon> + +int main(int argc, char** argv) +{ + QApplication app(argc, argv); + app.setStyleSheet("QTabBar::tab { padding-left: 20px; }\n"); + QIcon icon(":/v.ico"); + + QTabBar b; + b.setElideMode(Qt::ElideRight); + b.addTab(icon, "some text"); + b.resize(80,32); + b.show(); + + return app.exec(); +} diff --git a/tests/manual/widgets/widgets/qtabbar/stylesheet/res.qrc b/tests/manual/widgets/widgets/qtabbar/stylesheet/res.qrc new file mode 100644 index 0000000000..9d0bb8e061 --- /dev/null +++ b/tests/manual/widgets/widgets/qtabbar/stylesheet/res.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>v.ico</file> + </qresource> +</RCC> diff --git a/tests/manual/widgets/widgets/qtabbar/stylesheet/stylesheet.pro b/tests/manual/widgets/widgets/qtabbar/stylesheet/stylesheet.pro new file mode 100644 index 0000000000..4957503abc --- /dev/null +++ b/tests/manual/widgets/widgets/qtabbar/stylesheet/stylesheet.pro @@ -0,0 +1,5 @@ +QT += widgets +TEMPLATE = app +TARGET = stylesheet +RESOURCES += res.qrc +SOURCES += main.cpp diff --git a/tests/manual/widgets/widgets/qtabbar/stylesheet/v.ico b/tests/manual/widgets/widgets/qtabbar/stylesheet/v.ico Binary files differnew file mode 100644 index 0000000000..90dfbc9f9b --- /dev/null +++ b/tests/manual/widgets/widgets/qtabbar/stylesheet/v.ico diff --git a/tests/manual/widgets/widgets/widgets.pro b/tests/manual/widgets/widgets/widgets.pro index 1fccb09d79..5a07e621e8 100644 --- a/tests/manual/widgets/widgets/widgets.pro +++ b/tests/manual/widgets/widgets/widgets.pro @@ -2,4 +2,5 @@ TEMPLATE = subdirs SUBDIRS = bigmenucreator \ defaultUpMenuBar \ multiscreen-menus \ - qtoolbutton/menuOnMultiScreens + qtoolbutton/menuOnMultiScreens \ + qtabbar diff --git a/tests/manual/windowflags/controls.cpp b/tests/manual/windowflags/controls.cpp index c167e5f8bf..b999a59abe 100644 --- a/tests/manual/windowflags/controls.cpp +++ b/tests/manual/windowflags/controls.cpp @@ -95,7 +95,7 @@ HintControl::HintControl(QWidget *parent) Qt::WindowFlags HintControl::hints() const { - Qt::WindowFlags flags = 0; + Qt::WindowFlags flags; if (msWindowsFixedSizeDialogCheckBox->isChecked()) flags |= Qt::MSWindowsFixedSizeDialogHint; if (x11BypassWindowManagerCheckBox->isChecked()) |