diff options
-rw-r--r-- | src/widgets/kernel/qwidgetrepaintmanager.cpp | 31 | ||||
-rw-r--r-- | tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp | 60 |
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 ®ion, 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; } } |