summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/widgets/kernel/qwidgetrepaintmanager.cpp31
-rw-r--r--tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp60
2 files changed, 85 insertions, 6 deletions
diff --git a/src/widgets/kernel/qwidgetrepaintmanager.cpp b/src/widgets/kernel/qwidgetrepaintmanager.cpp
index 718f904f93..3cc043ca42 100644
--- a/src/widgets/kernel/qwidgetrepaintmanager.cpp
+++ b/src/widgets/kernel/qwidgetrepaintmanager.cpp
@@ -1033,7 +1033,36 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion &region, QPlatf
if (widget != tlw)
offset += widget->mapTo(tlw, QPoint());
- if (tlw->d_func()->usesRhiFlush) {
+ // Use a condition that tries to keep both QTBUG-108344 and QTBUG-113557
+ // happy, i.e. support both (A) "native rhi-based child in a rhi-based
+ // toplevel" and (B) "native raster child in a rhi-based toplevel".
+ //
+ // If the tlw and the backingstore are RHI-based, then there are two cases
+ // to consider:
+ //
+ // (1) widget is not a native child, i.e. the QWindow for widget and tlw are
+ // the same,
+ //
+ // (2) widget is a native child which we now attempt to flush with tlw's
+ // backingstore to widget's native window. This is the interesting one.
+ //
+ // Using the condition tlw->usesRhiFlush on its own is insufficient since
+ // it fails to capture the case of a raster-based native child widget
+ // within tlw. (which must hit the non-rhi flush path)
+ //
+ // Extending the condition with tlw->windowHandle() == widget->windowHandle()
+ // would be logical but wrong, when it comes to (A) since flushing a
+ // RHI-based native child with a given 3D API using a RHI-based
+ // tlw/backingstore with the same 3D API needs to be supported still. (this
+ // happens when e.g. someone calls winId() on a QOpenGLWidget)
+ //
+ // Different 3D APIs do not need to be supported since we do not allow to
+ // do things like having a QQuickWidget with Vulkan and a QOpenGLWidget in
+ // the same toplevel, regardless of the widgets being native children or
+ // not. Hence comparing the surfaceType() instead. This satisfies both (A)
+ // and (B) given that an RHI-based toplevel cannot be RasterSurface.
+ //
+ if (tlw->d_func()->usesRhiFlush && tlw->windowHandle()->surfaceType() == widget->windowHandle()->surfaceType()) {
QRhi *rhi = store->handle()->rhi();
qCDebug(lcWidgetPainting) << "Flushing" << region << "of" << widget
<< "with QRhi" << rhi
diff --git a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp
index d4d5d9d583..bd0b62f3dd 100644
--- a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp
+++ b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp
@@ -573,6 +573,21 @@ void tst_QOpenGLWidget::showHide()
QVERIFY(image.pixel(30, 40) == qRgb(0, 0, 255));
}
+QtMessageHandler oldHandler = nullptr;
+
+void nativeWindowMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+{
+ if (oldHandler)
+ oldHandler(type, context, msg);
+
+ if (type == QtWarningMsg
+ && (msg.contains("QOpenGLContext::makeCurrent() called with non-opengl surface")
+ || msg.contains("Failed to make context current")))
+ {
+ QFAIL("Unexpected warning got printed");
+ }
+}
+
void tst_QOpenGLWidget::nativeWindow()
{
#ifdef Q_OS_ANDROID
@@ -584,6 +599,10 @@ void tst_QOpenGLWidget::nativeWindow()
// presented correctly as we can only do verification with
// grabFramebuffer() here which only exercises a part of the pipeline.
+ // Install a message handler that looks for some typical warnings from
+ // QRhi/QOpenGLConext that occur when the RHI-related logic in widgets goes wrong.
+ oldHandler = qInstallMessageHandler(nativeWindowMessageHandler);
+
{
QScopedPointer<ClearWidget> w(new ClearWidget(nullptr, 800, 600));
w->resize(800, 600);
@@ -599,7 +618,33 @@ void tst_QOpenGLWidget::nativeWindow()
QVERIFY(w->internalWinId());
}
- // Now as a native child
+ // QTBUG-113557: a plain _raster_ QWidget that is a _native_ child in a toplevel
+ // combined with a RHI-based (non-native) widget (QOpenGLWidget in this case)
+ // in the same toplevel.
+ {
+ QWidget topLevel;
+ topLevel.resize(800, 600);
+
+ ClearWidget *child = new ClearWidget(&topLevel, 800, 600);
+ child->setClearColor(1, 0, 0);
+ child->resize(400, 400);
+ child->move(23, 34);
+
+ QWidget *raster = new QWidget(&topLevel);
+ raster->setGeometry(23, 240, 120, 120);
+ raster->setStyleSheet("QWidget { background-color: yellow; }");
+
+ raster->winId();
+
+ topLevel.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
+
+ // Do not bother checking the output, i.e. if the yellow raster native child
+ // shows up as it should, but rather rely on the message handler catching the
+ // qWarnings if they occur.
+ }
+
+ // Now with the QOpenGLWidget being a native child
{
QWidget topLevel;
topLevel.resize(800, 600);
@@ -665,7 +710,7 @@ void tst_QOpenGLWidget::nativeWindow()
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->setClearColor(0, 0, 1);
child->resize(400, 400);
child->move(23, 34);
@@ -679,7 +724,7 @@ void tst_QOpenGLWidget::nativeWindow()
QImage image = child->grabFramebuffer();
QCOMPARE(image.width(), child->width());
QCOMPARE(image.height(), child->height());
- QVERIFY(image.pixel(30, 40) == qRgb(0, 255, 0));
+ QVERIFY(image.pixel(30, 40) == qRgb(0, 0, 255));
}
// Again as a child of a native child, but this time specifying the parent
@@ -691,7 +736,7 @@ void tst_QOpenGLWidget::nativeWindow()
container->winId();
// parent it right away
ClearWidget *child = new ClearWidget(container, 800, 600);
- child->setClearColor(0, 1, 0);
+ child->setClearColor(0, 0, 1);
child->resize(400, 400);
child->move(23, 34);
topLevel.show();
@@ -702,7 +747,12 @@ void tst_QOpenGLWidget::nativeWindow()
QImage image = child->grabFramebuffer();
QCOMPARE(image.width(), child->width());
QCOMPARE(image.height(), child->height());
- QVERIFY(image.pixel(30, 40) == qRgb(0, 255, 0));
+ QVERIFY(image.pixel(30, 40) == qRgb(0, 0, 255));
+ }
+
+ if (oldHandler) {
+ qInstallMessageHandler(oldHandler);
+ oldHandler = nullptr;
}
}