diff --git a/src/gui/painting/qbackingstoredefaultcompositor.cpp b/src/gui/painting/qbackingstoredefaultcompositor.cpp index 1dd116ac81..383fb651dd 100644 --- a/src/gui/painting/qbackingstoredefaultcompositor.cpp +++ b/src/gui/painting/qbackingstoredefaultcompositor.cpp @@ -17,6 +17,7 @@ QBackingStoreDefaultCompositor::~QBackingStoreDefaultCompositor() void QBackingStoreDefaultCompositor::reset() { + m_rhi = nullptr; delete m_psNoBlend; m_psNoBlend = nullptr; delete m_psBlend; diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index 82e7778b86..f7c4df40c8 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -379,6 +379,7 @@ void QPlatformBackingStore::graphicsDeviceReportedLost() return; qWarning("Rhi backingstore: graphics device lost, attempting to reinitialize"); + d_ptr->compositor.reset(); d_ptr->rhiSupport.reset(); d_ptr->rhiSupport.create(); if (!d_ptr->rhiSupport.rhi()) diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index f3905dff81..0659cf9fc4 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -877,8 +877,10 @@ QPlatformBackingStore::FlushResult QXcbBackingStore::rhiFlush(QWindow *window, m_image->flushScrolledRegion(true); - QPlatformBackingStore::rhiFlush(window, sourceDevicePixelRatio, region, offset, textures, translucentBackground); - + auto result = QPlatformBackingStore::rhiFlush(window, sourceDevicePixelRatio, region, offset, + textures, translucentBackground); + if (result != FlushSuccess) + return result; QXcbWindow *platformWindow = static_cast(window->handle()); if (platformWindow->needsSync()) { platformWindow->updateSyncRequestCounter(); diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 38957e9b46..08acae00c7 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -10602,7 +10602,7 @@ void QWidget::setParent(QWidget *parent) setParent((QWidget*)parent, windowFlags() & ~Qt::WindowType_Mask); } -static void sendWindowChangeToTextureChildrenRecursively(QWidget *widget, QEvent::Type eventType) +void qSendWindowChangeToTextureChildrenRecursively(QWidget *widget, QEvent::Type eventType) { QWidgetPrivate *d = QWidgetPrivate::get(widget); if (d->renderToTexture) { @@ -10613,7 +10613,7 @@ static void sendWindowChangeToTextureChildrenRecursively(QWidget *widget, QEvent for (int i = 0; i < d->children.size(); ++i) { QWidget *w = qobject_cast(d->children.at(i)); if (w && !w->isWindow() && QWidgetPrivate::get(w)->textureChildSeen) - sendWindowChangeToTextureChildrenRecursively(w, eventType); + qSendWindowChangeToTextureChildrenRecursively(w, eventType); } } @@ -10675,7 +10675,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) // texture-based widgets need a pre-notification when their associated top-level window changes // This is not under the wasCreated/newParent conditions above in order to also play nice with QDockWidget. if (d->textureChildSeen && ((!parent && parentWidget()) || (parent && parent->window() != oldtlw))) - sendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowAboutToChangeInternal); + qSendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowAboutToChangeInternal); // If we get parented into another window, children will be folded // into the new parent's focus chain, so clear focus now. @@ -10756,7 +10756,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) // texture-based widgets need another event when their top-level window // changes (more precisely, has already changed at this point) if (d->textureChildSeen && oldtlw != window()) - sendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowChangeInternal); + qSendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowChangeInternal); if (!wasCreated) { if (isWindow() || parentWidget()->isVisible()) diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index d9d9825b6f..2e1c4030f8 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -65,6 +65,7 @@ class QUnifiedToolbarSurface; // implemented in qshortcut.cpp bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context); +void qSendWindowChangeToTextureChildrenRecursively(QWidget *widget, QEvent::Type eventType); class QUpdateLaterEvent : public QEvent { diff --git a/src/widgets/kernel/qwidgetrepaintmanager.cpp b/src/widgets/kernel/qwidgetrepaintmanager.cpp index 16db49f95e..718f904f93 100644 --- a/src/widgets/kernel/qwidgetrepaintmanager.cpp +++ b/src/widgets/kernel/qwidgetrepaintmanager.cpp @@ -1058,7 +1058,11 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion ®ion, QPlatf translucentBackground); widgetWindowPrivate->sendComposeStatus(widget->window(), true); if (flushResult == QPlatformBackingStore::FlushFailedDueToLostDevice) { + qSendWindowChangeToTextureChildrenRecursively(widget->window(), + QEvent::WindowAboutToChangeInternal); store->handle()->graphicsDeviceReportedLost(); + qSendWindowChangeToTextureChildrenRecursively(widget->window(), + QEvent::WindowChangeInternal); widget->update(); } } else { diff --git a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp index ca1deb6094..07cce4cdc3 100644 --- a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp +++ b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -21,7 +22,10 @@ #include #include #include +#include #include +#include +#include class tst_QOpenGLWidget : public QObject { @@ -33,6 +37,9 @@ private slots: void clearAndGrab(); void clearAndResizeAndGrab(); void createNonTopLevel(); +#if QT_CONFIG(egl) + void deviceLoss(); +#endif void painter(); void reparentToAlreadyCreated(); void reparentToNotYetCreated(); @@ -189,6 +196,45 @@ void tst_QOpenGLWidget::createNonTopLevel() QVERIFY(QOpenGLContext::currentContext() == glw->context() && glw->context()); } +#if QT_CONFIG(egl) +void tst_QOpenGLWidget::deviceLoss() +{ + QScopedPointer w(new ClearWidget(0, 640, 480)); + + w->resize(640, 480); + w->show(); + + auto rhi = w->backingStore()->handle()->rhi(); + QNativeInterface::QEGLContext *rhiContext = nullptr; + if (rhi->backend() == QRhi::OpenGLES2) { + auto rhiHandles = static_cast(rhi->nativeHandles()); + rhiContext = rhiHandles->context->nativeInterface(); + } + if (!rhiContext) + QSKIP("deviceLoss needs EGL"); + + 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)); + + rhiContext->invalidateContext(); + + w->resize(600, 600); + QSignalSpy frameSwappedSpy(w.get(), &QOpenGLWidget::resized); + QTRY_VERIFY(frameSwappedSpy.size() > 0); + + 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)); +} +#endif + class PainterWidget : public QOpenGLWidget, protected QOpenGLFunctions { public: