summaryrefslogtreecommitdiffstats
path: root/tests/auto
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2022-11-11 08:54:37 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2022-11-14 11:05:48 +0100
commit244daf4cfc44587c8c7c87e481688e840cc21c77 (patch)
treede974040d011604ff9a1a07f8d24a5c792017a0f /tests/auto
parent092bbc9ad30c6cd7389053dc4b332cc762693676 (diff)
Fix rhi flush eval perf. and native window problems
This effectively reverts a4a51f6a641f4bf0a863251d6d3e026d81de6280 while solving the problem that change intended to fix by an alternative approach: Swap the order of checks for rhi-based flushing. Checking the widgets' wishes first was a mistake. We should first check what is forced, e.g. via the env.vars. Then only move on investigating the child widget hierarchy if there was nothing specific requested. This way having a QOpenGLWidget in a window and running with QT_WIDGETS_RHI=1 QT_WIDGETS_RHI_BACKEND=vulkan will prioritize the forced request (Vulkan) and so the QOpenGLWidget will gracefully not render anything while printing the expected warning to tell what's going on. The expensive recursion plaguing the construction of larger widget hierarchies is now avoided, that should no longer take seconds due to walking the entire widget hierarchy of the top-level window every time a new widget is added to it. However, this then uncovered a set of problems concerning native child widgets. The repaint manager seems to have an obvious mistake where the usage of rhi (and so textures and whatnot) is decided based on 'widget' (which is either a top-level or a native child) instead of 'tlw' (which is the top-level with the backingstore). The usesRhiFlush flag only really matters for a real top-level, not for native child widgets. The rhi-based flushing is tied to the backingstore, and the backingstore comes from the top-level widget. Finally, make the qopenglwidget autotest to actually exercise something when it comes to QOpenGLWidgets (or their ancestors) turned native. The original code from a long time ago does not really test native child widgets, because it turns the top-level into native which is quite superfluous since the toplevel is backed by a native window (and a backingstore) anyway. Pick-to: 6.4 Task-number: QTBUG-105017 Fixes: QTBUG-108344 Fixes: QTBUG-108277 Change-Id: I1785b0ca627cf151aad06a5489f63874d787f087 Reviewed-by: Andy Nichols <andy.nichols@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'tests/auto')
-rw-r--r--tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp157
1 files changed, 125 insertions, 32 deletions
diff --git a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp
index 523984e751..4d3699009f 100644
--- a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp
+++ b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp
@@ -529,39 +529,132 @@ void tst_QOpenGLWidget::nativeWindow()
#ifdef Q_OS_ANDROID
QSKIP("Crashes on Android, figure out why (QTBUG-102043)");
#endif
- QScopedPointer<ClearWidget> w(new ClearWidget(0, 800, 600));
- w->resize(800, 600);
- w->show();
- w->winId();
- QVERIFY(QTest::qWaitForWindowExposed(w.data()));
- QImage image = w->grabFramebuffer();
- QVERIFY(!image.isNull());
- QCOMPARE(image.width(), w->width());
- QCOMPARE(image.height(), w->height());
- QVERIFY(image.pixel(30, 40) == qRgb(255, 0, 0));
- QVERIFY(w->internalWinId());
-
- // Now as a native child.
- QWidget nativeParent;
- nativeParent.resize(800, 600);
- nativeParent.setAttribute(Qt::WA_NativeWindow);
- ClearWidget *child = new ClearWidget(0, 800, 600);
- child->setClearColor(0, 1, 0);
- child->setParent(&nativeParent);
- child->resize(400, 400);
- child->move(23, 34);
- nativeParent.show();
- QVERIFY(QTest::qWaitForWindowExposed(&nativeParent));
-
- QVERIFY(nativeParent.internalWinId());
- QVERIFY(!child->internalWinId());
-
- image = child->grabFramebuffer();
- QVERIFY(!image.isNull());
- QCOMPARE(image.width(), child->width());
- QCOMPARE(image.height(), child->height());
- QVERIFY(image.pixel(30, 40) == qRgb(0, 255, 0));
+ // NB these tests do not fully verify that native child widgets are fully
+ // functional since there is no guarantee that the content is composed and
+ // presented correctly as we can only do verification with
+ // grabFramebuffer() here which only exercises a part of the pipeline.
+
+ {
+ QScopedPointer<ClearWidget> w(new ClearWidget(nullptr, 800, 600));
+ w->resize(800, 600);
+ w->show();
+ w->winId();
+ QVERIFY(QTest::qWaitForWindowExposed(w.data()));
+
+ QImage image = w->grabFramebuffer();
+ QVERIFY(!image.isNull());
+ QCOMPARE(image.width(), w->width());
+ QCOMPARE(image.height(), w->height());
+ QVERIFY(image.pixel(30, 40) == qRgb(255, 0, 0));
+ QVERIFY(w->internalWinId());
+ }
+
+ // Now as a native child
+ {
+ QWidget topLevel;
+ topLevel.resize(800, 600);
+
+ ClearWidget *child = new ClearWidget(nullptr, 800, 600);
+ child->setParent(&topLevel);
+
+ // make it a native child (native window, but not top-level -> no backingstore)
+ child->winId();
+
+ child->setClearColor(0, 1, 0);
+ child->resize(400, 400);
+ child->move(23, 34);
+
+ topLevel.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
+
+ QVERIFY(topLevel.internalWinId());
+ QVERIFY(child->internalWinId());
+
+ QImage image = child->grabFramebuffer();
+ QVERIFY(!image.isNull());
+ QCOMPARE(image.width(), child->width());
+ QCOMPARE(image.height(), child->height());
+ QVERIFY(image.pixel(30, 40) == qRgb(0, 255, 0));
+ }
+
+ // Now the same with WA_NativeWindow instead
+ {
+ QWidget topLevel;
+ topLevel.resize(800, 600);
+
+ ClearWidget *child = new ClearWidget(nullptr, 800, 600);
+ child->setParent(&topLevel);
+
+ // make it a native child (native window, but not top-level -> no backingstore)
+ child->setAttribute(Qt::WA_NativeWindow);
+
+ child->setClearColor(0, 1, 0);
+ child->resize(400, 400);
+ child->move(23, 34);
+
+ topLevel.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
+
+ QVERIFY(child->internalWinId());
+
+ QImage image = child->grabFramebuffer();
+ QCOMPARE(image.width(), child->width());
+ QCOMPARE(image.height(), child->height());
+ QVERIFY(image.pixel(30, 40) == qRgb(0, 255, 0));
+ }
+
+ // Now as a child of a native child
+ {
+ QWidget topLevel;
+ topLevel.resize(800, 600);
+
+ QWidget *container = new QWidget(&topLevel);
+ // make it a native child (native window, but not top-level -> no backingstore)
+ container->winId();
+
+ ClearWidget *child = new ClearWidget(nullptr, 800, 600);
+ // set the parent separately, this is important, see next test case
+ child->setParent(container);
+ child->setClearColor(0, 1, 0);
+ child->resize(400, 400);
+ child->move(23, 34);
+
+ topLevel.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
+
+ QVERIFY(topLevel.internalWinId());
+ QVERIFY(container->internalWinId());
+ QVERIFY(!child->internalWinId());
+
+ QImage image = child->grabFramebuffer();
+ QCOMPARE(image.width(), child->width());
+ QCOMPARE(image.height(), child->height());
+ QVERIFY(image.pixel(30, 40) == qRgb(0, 255, 0));
+ }
+
+ // Again as a child of a native child, but this time specifying the parent
+ // upon construction, not with an explicit setParent() call afterwards.
+ {
+ QWidget topLevel;
+ topLevel.resize(800, 600);
+ QWidget *container = new QWidget(&topLevel);
+ container->winId();
+ // parent it right away
+ ClearWidget *child = new ClearWidget(container, 800, 600);
+ child->setClearColor(0, 1, 0);
+ child->resize(400, 400);
+ child->move(23, 34);
+ topLevel.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
+ QVERIFY(topLevel.internalWinId());
+ QVERIFY(container->internalWinId());
+ QVERIFY(!child->internalWinId());
+ QImage image = child->grabFramebuffer();
+ QCOMPARE(image.width(), child->width());
+ QCOMPARE(image.height(), child->height());
+ QVERIFY(image.pixel(30, 40) == qRgb(0, 255, 0));
+ }
}
static inline QString msgRgbMismatch(unsigned actual, unsigned expected)