summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2021-11-10 13:18:30 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-12-21 11:04:21 +0000
commitb529ae8b8e70104da6ac4a7587dc3aa6dfe5dd56 (patch)
tree67bd2fd1e3a4e18b564ba896713e6bf1a76f2d71
parentacffc4c669d215bf6ad0b2d6a6fe4731a34bec55 (diff)
client: Fix crash on shutdown on Mesa driver
On Wayland, then the mesa driver is in use, calling eglDestroySurface() while OpenGL commands are being executed may crash. While this means the driver does not operate by the specs in this case, the driver is so popular that it makes sense to work around it. To work around this, we read-lock the surface while rendering and wait for a write-lock before we destroy the EGL surface. [ChangeLog][QtWaylandClient] Fixed a crash on shutdown that could happen with some graphics-heavy applications when running on Mesa drivers. Fixes: QTBUG-92249 Change-Id: I8b8461066cc9f948dc44ddeeddaa6e7d92b76f04 Reviewed-by: Liang Qi <liang.qi@qt.io> (cherry picked from commit dff579147b07cd15888a47c303e36684e9930f9f) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/client/qwaylandwindow.cpp13
-rw-r--r--src/client/qwaylandwindow_p.h3
-rw-r--r--src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp34
-rw-r--r--src/hardwareintegration/client/wayland-egl/qwaylandglcontext_p.h6
4 files changed, 43 insertions, 13 deletions
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index 3481a8fa2..0b4347a88 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -77,6 +77,7 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
: QPlatformWindow(window)
, mDisplay(display)
, mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP"))
+ , mSurfaceLock(QReadWriteLock::Recursive)
{
{
bool ok;
@@ -235,6 +236,16 @@ bool QWaylandWindow::shouldCreateSubSurface() const
return QPlatformWindow::parent() != nullptr;
}
+void QWaylandWindow::beginFrame()
+{
+ mSurfaceLock.lockForRead();
+}
+
+void QWaylandWindow::endFrame()
+{
+ mSurfaceLock.unlock();
+}
+
void QWaylandWindow::reset()
{
delete mShellSurface;
@@ -242,10 +253,10 @@ void QWaylandWindow::reset()
delete mSubSurfaceWindow;
mSubSurfaceWindow = nullptr;
- invalidateSurface();
if (mSurface) {
emit wlSurfaceDestroyed();
QWriteLocker lock(&mSurfaceLock);
+ invalidateSurface();
mSurface.reset();
}
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index 4eecdd861..d64c80c41 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -233,6 +233,9 @@ public:
void setXdgActivationToken(const QString &token);
void requestXdgActivationToken(uint serial);
+ void beginFrame();
+ void endFrame();
+
public slots:
void applyConfigure();
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
index 65ec22f1f..e9b290a76 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
@@ -300,6 +300,18 @@ QWaylandGLContext::~QWaylandGLContext()
eglDestroyContext(eglDisplay(), m_decorationsContext);
}
+void QWaylandGLContext::beginFrame()
+{
+ Q_ASSERT(m_currentWindow != nullptr);
+ m_currentWindow->beginFrame();
+}
+
+void QWaylandGLContext::endFrame()
+{
+ Q_ASSERT(m_currentWindow != nullptr);
+ m_currentWindow->endFrame();
+}
+
bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface)
{
// in QWaylandGLContext() we called eglBindAPI with the correct value. However,
@@ -311,10 +323,10 @@ bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface)
eglBindAPI(m_api);
}
- QWaylandEglWindow *window = static_cast<QWaylandEglWindow *>(surface);
- EGLSurface eglSurface = window->eglSurface();
+ m_currentWindow = static_cast<QWaylandEglWindow *>(surface);
+ EGLSurface eglSurface = m_currentWindow->eglSurface();
- if (!window->needToUpdateContentFBO() && (eglSurface != EGL_NO_SURFACE)) {
+ if (!m_currentWindow->needToUpdateContentFBO() && (eglSurface != EGL_NO_SURFACE)) {
if (!eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext())) {
qWarning("QWaylandGLContext::makeCurrent: eglError: %x, this: %p \n", eglGetError(), this);
return false;
@@ -322,26 +334,26 @@ bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface)
return true;
}
- if (window->isExposed())
- window->setCanResize(false);
- if (m_decorationsContext != EGL_NO_CONTEXT && !window->decoration())
- window->createDecoration();
+ if (m_currentWindow->isExposed())
+ m_currentWindow->setCanResize(false);
+ if (m_decorationsContext != EGL_NO_CONTEXT && !m_currentWindow->decoration())
+ m_currentWindow->createDecoration();
if (eglSurface == EGL_NO_SURFACE) {
- window->updateSurface(true);
- eglSurface = window->eglSurface();
+ m_currentWindow->updateSurface(true);
+ eglSurface = m_currentWindow->eglSurface();
}
if (!eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext())) {
qWarning("QWaylandGLContext::makeCurrent: eglError: %x, this: %p \n", eglGetError(), this);
- window->setCanResize(true);
+ m_currentWindow->setCanResize(true);
return false;
}
//### setCurrentContext will be called in QOpenGLContext::makeCurrent after this function
// returns, but that's too late, as we need a current context in order to bind the content FBO.
QOpenGLContextPrivate::setCurrentContext(context());
- window->bindContentFBO();
+ m_currentWindow->bindContentFBO();
return true;
}
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext_p.h b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext_p.h
index 678a7695e..e43bc653d 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext_p.h
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext_p.h
@@ -64,7 +64,7 @@ class QOpenGLTextureCache;
namespace QtWaylandClient {
-class QWaylandWindow;
+class QWaylandEglWindow;
class DecorationsBlitter;
class Q_WAYLAND_CLIENT_EXPORT QWaylandGLContext : public QEGLPlatformContext
@@ -77,6 +77,9 @@ public:
bool makeCurrent(QPlatformSurface *surface) override;
void doneCurrent() override;
+ void beginFrame() override;
+ void endFrame() override;
+
GLuint defaultFramebufferObject(QPlatformSurface *surface) const override;
QFunctionPointer getProcAddress(const char *procName) override;
@@ -94,6 +97,7 @@ private:
EGLenum m_api;
wl_surface *m_wlSurface = nullptr;
wl_egl_window *m_eglWindow = nullptr;
+ QWaylandEglWindow *m_currentWindow = nullptr;
};
}