Handle device loss for texture widgets
Previously the widget stayed black and we printed "QBackingStoreDefaultCompositor: the QRhi has changed unexpectedly, this should not happen". To make it work the compositor is recreated in addition to the rhi and the widgets are informed with the internal events. Change-Id: I982d08bd3530478fe0f827080154c008a92a812e Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
parent
b538a53a9d
commit
141d626029
@ -17,6 +17,7 @@ QBackingStoreDefaultCompositor::~QBackingStoreDefaultCompositor()
|
|||||||
|
|
||||||
void QBackingStoreDefaultCompositor::reset()
|
void QBackingStoreDefaultCompositor::reset()
|
||||||
{
|
{
|
||||||
|
m_rhi = nullptr;
|
||||||
delete m_psNoBlend;
|
delete m_psNoBlend;
|
||||||
m_psNoBlend = nullptr;
|
m_psNoBlend = nullptr;
|
||||||
delete m_psBlend;
|
delete m_psBlend;
|
||||||
|
@ -379,6 +379,7 @@ void QPlatformBackingStore::graphicsDeviceReportedLost()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
qWarning("Rhi backingstore: graphics device lost, attempting to reinitialize");
|
qWarning("Rhi backingstore: graphics device lost, attempting to reinitialize");
|
||||||
|
d_ptr->compositor.reset();
|
||||||
d_ptr->rhiSupport.reset();
|
d_ptr->rhiSupport.reset();
|
||||||
d_ptr->rhiSupport.create();
|
d_ptr->rhiSupport.create();
|
||||||
if (!d_ptr->rhiSupport.rhi())
|
if (!d_ptr->rhiSupport.rhi())
|
||||||
|
@ -877,8 +877,10 @@ QPlatformBackingStore::FlushResult QXcbBackingStore::rhiFlush(QWindow *window,
|
|||||||
|
|
||||||
m_image->flushScrolledRegion(true);
|
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<QXcbWindow *>(window->handle());
|
QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle());
|
||||||
if (platformWindow->needsSync()) {
|
if (platformWindow->needsSync()) {
|
||||||
platformWindow->updateSyncRequestCounter();
|
platformWindow->updateSyncRequestCounter();
|
||||||
|
@ -10602,7 +10602,7 @@ void QWidget::setParent(QWidget *parent)
|
|||||||
setParent((QWidget*)parent, windowFlags() & ~Qt::WindowType_Mask);
|
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);
|
QWidgetPrivate *d = QWidgetPrivate::get(widget);
|
||||||
if (d->renderToTexture) {
|
if (d->renderToTexture) {
|
||||||
@ -10613,7 +10613,7 @@ static void sendWindowChangeToTextureChildrenRecursively(QWidget *widget, QEvent
|
|||||||
for (int i = 0; i < d->children.size(); ++i) {
|
for (int i = 0; i < d->children.size(); ++i) {
|
||||||
QWidget *w = qobject_cast<QWidget *>(d->children.at(i));
|
QWidget *w = qobject_cast<QWidget *>(d->children.at(i));
|
||||||
if (w && !w->isWindow() && QWidgetPrivate::get(w)->textureChildSeen)
|
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
|
// 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.
|
// 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)))
|
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
|
// If we get parented into another window, children will be folded
|
||||||
// into the new parent's focus chain, so clear focus now.
|
// 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
|
// texture-based widgets need another event when their top-level window
|
||||||
// changes (more precisely, has already changed at this point)
|
// changes (more precisely, has already changed at this point)
|
||||||
if (d->textureChildSeen && oldtlw != window())
|
if (d->textureChildSeen && oldtlw != window())
|
||||||
sendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowChangeInternal);
|
qSendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowChangeInternal);
|
||||||
|
|
||||||
if (!wasCreated) {
|
if (!wasCreated) {
|
||||||
if (isWindow() || parentWidget()->isVisible())
|
if (isWindow() || parentWidget()->isVisible())
|
||||||
|
@ -65,6 +65,7 @@ class QUnifiedToolbarSurface;
|
|||||||
|
|
||||||
// implemented in qshortcut.cpp
|
// implemented in qshortcut.cpp
|
||||||
bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context);
|
bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context);
|
||||||
|
void qSendWindowChangeToTextureChildrenRecursively(QWidget *widget, QEvent::Type eventType);
|
||||||
|
|
||||||
class QUpdateLaterEvent : public QEvent
|
class QUpdateLaterEvent : public QEvent
|
||||||
{
|
{
|
||||||
|
@ -1058,7 +1058,11 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion ®ion, QPlatf
|
|||||||
translucentBackground);
|
translucentBackground);
|
||||||
widgetWindowPrivate->sendComposeStatus(widget->window(), true);
|
widgetWindowPrivate->sendComposeStatus(widget->window(), true);
|
||||||
if (flushResult == QPlatformBackingStore::FlushFailedDueToLostDevice) {
|
if (flushResult == QPlatformBackingStore::FlushFailedDueToLostDevice) {
|
||||||
|
qSendWindowChangeToTextureChildrenRecursively(widget->window(),
|
||||||
|
QEvent::WindowAboutToChangeInternal);
|
||||||
store->handle()->graphicsDeviceReportedLost();
|
store->handle()->graphicsDeviceReportedLost();
|
||||||
|
qSendWindowChangeToTextureChildrenRecursively(widget->window(),
|
||||||
|
QEvent::WindowChangeInternal);
|
||||||
widget->update();
|
widget->update();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <QtOpenGLWidgets/QOpenGLWidget>
|
#include <QtOpenGLWidgets/QOpenGLWidget>
|
||||||
#include <QtGui/QOpenGLFunctions>
|
#include <QtGui/QOpenGLFunctions>
|
||||||
#include <QtGui/QPainter>
|
#include <QtGui/QPainter>
|
||||||
|
#include <QtGui/QBackingStore>
|
||||||
#include <QtGui/QScreen>
|
#include <QtGui/QScreen>
|
||||||
#include <QtGui/QStaticText>
|
#include <QtGui/QStaticText>
|
||||||
#include <QtWidgets/QGraphicsView>
|
#include <QtWidgets/QGraphicsView>
|
||||||
@ -21,7 +22,10 @@
|
|||||||
#include <private/qopengltextureglyphcache_p.h>
|
#include <private/qopengltextureglyphcache_p.h>
|
||||||
#include <qpa/qplatformintegration.h>
|
#include <qpa/qplatformintegration.h>
|
||||||
#include <private/qguiapplication_p.h>
|
#include <private/qguiapplication_p.h>
|
||||||
|
#include <qpa/qplatformbackingstore.h>
|
||||||
#include <qpa/qplatformintegration.h>
|
#include <qpa/qplatformintegration.h>
|
||||||
|
#include <private/qrhi_p.h>
|
||||||
|
#include <private/qrhigles2_p.h>
|
||||||
|
|
||||||
class tst_QOpenGLWidget : public QObject
|
class tst_QOpenGLWidget : public QObject
|
||||||
{
|
{
|
||||||
@ -33,6 +37,9 @@ private slots:
|
|||||||
void clearAndGrab();
|
void clearAndGrab();
|
||||||
void clearAndResizeAndGrab();
|
void clearAndResizeAndGrab();
|
||||||
void createNonTopLevel();
|
void createNonTopLevel();
|
||||||
|
#if QT_CONFIG(egl)
|
||||||
|
void deviceLoss();
|
||||||
|
#endif
|
||||||
void painter();
|
void painter();
|
||||||
void reparentToAlreadyCreated();
|
void reparentToAlreadyCreated();
|
||||||
void reparentToNotYetCreated();
|
void reparentToNotYetCreated();
|
||||||
@ -189,6 +196,45 @@ void tst_QOpenGLWidget::createNonTopLevel()
|
|||||||
QVERIFY(QOpenGLContext::currentContext() == glw->context() && glw->context());
|
QVERIFY(QOpenGLContext::currentContext() == glw->context() && glw->context());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if QT_CONFIG(egl)
|
||||||
|
void tst_QOpenGLWidget::deviceLoss()
|
||||||
|
{
|
||||||
|
QScopedPointer<QOpenGLWidget> 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<const QRhiGles2NativeHandles *>(rhi->nativeHandles());
|
||||||
|
rhiContext = rhiHandles->context->nativeInterface<QNativeInterface::QEGLContext>();
|
||||||
|
}
|
||||||
|
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
|
class PainterWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Loading…
Reference in New Issue
Block a user