summaryrefslogtreecommitdiff
blob: 8bffa3e08b3e80e8eba5cc4acdcaf932bd20d2c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
From d7b34dbf072236cdfb3b64e5ad26d1ff29dfec5f Mon Sep 17 00:00:00 2001
From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Date: Thu, 22 Apr 2021 08:42:33 +0200
Subject: client: Gracefully handle shutdown and window hiding

When a window is hidden or destroyed, the render thread may already
be rendering. We need to properly read-lock the surface pointer
when it is in use and exit when it becomes null.

Note that there is also a potential crash in the Mesa GL driver
where it keeps a proxy to the wl_surface, so if we delete this
while we are still rendering, it can crash inside the driver.
This is not addressed by this patch, and has not been reproduced
on any other drivers so far.

[ChangeLog][Client] Fixed a crash that could happen when hiding
or closing windows while Qt Quick was actively rendering on
a different thread.

Pick-to: 6.0 6.1 5.15
Fixes: QTBUG-91264
Fixes: QTBUG-90037
Task-number: QTBUG-92249
Change-Id: I029b123b83c58740321e8b90a463ced748d8bcf4
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Reviewed-by: David Edmundson <davidedmundson@kde.org>
(cherry picked from commit b19b0fbaf775e8b8eda1e03c265a5393d618c6c0)
---
 src/client/qwaylandwindow.cpp                   | 17 ++++++++++++++++-
 src/client/qwaylandwindow_p.h                   |  2 +-
 .../client/wayland-egl/qwaylandglcontext.cpp    |  1 -
 3 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index 494911b3..0d849b57 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -414,6 +414,7 @@ void QWaylandWindow::closePopups(QWaylandWindow *parent)
 
 QPlatformScreen *QWaylandWindow::calculateScreenFromSurfaceEvents() const
 {
+    QReadLocker lock(&mSurfaceLock);
     if (mSurface) {
         if (auto *screen = mSurface->oldestEnteredScreen())
             return screen;
@@ -552,6 +553,10 @@ void QWaylandWindow::sendRecursiveExposeEvent()
 
 void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y)
 {
+    QReadLocker locker(&mSurfaceLock);
+    if (mSurface == nullptr)
+        return;
+
     if (buffer) {
         Q_ASSERT(!buffer->committed());
         handleUpdate();
@@ -571,6 +576,10 @@ void QWaylandWindow::attachOffset(QWaylandBuffer *buffer)
 
 void QWaylandWindow::damage(const QRect &rect)
 {
+    QReadLocker locker(&mSurfaceLock);
+    if (mSurface == nullptr)
+        return;
+
     const int s = scale();
     if (mDisplay->compositorVersion() >= 4)
         mSurface->damage_buffer(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height());
@@ -605,6 +614,8 @@ void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage)
         qCDebug(lcWaylandBackingstore) << "Buffer already committed, ignoring.";
         return;
     }
+
+    QReadLocker locker(&mSurfaceLock);
     if (!mSurface)
         return;
 
@@ -624,7 +635,9 @@ void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage)
 
 void QWaylandWindow::commit()
 {
-    mSurface->commit();
+    QReadLocker locker(&mSurfaceLock);
+    if (mSurface != nullptr)
+        mSurface->commit();
 }
 
 const wl_callback_listener QWaylandWindow::callbackListener = {
@@ -725,6 +738,7 @@ QPointF QWaylandWindow::mapFromWlSurface(const QPointF &surfacePosition) const
 
 wl_surface *QWaylandWindow::wlSurface()
 {
+    QReadLocker locker(&mSurfaceLock);
     return mSurface ? mSurface->object() : nullptr;
 }
 
@@ -749,6 +763,7 @@ QWaylandScreen *QWaylandWindow::waylandScreen() const
 
 void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation)
 {
+    QReadLocker locker(&mSurfaceLock);
     if (mDisplay->compositorVersion() < 2)
         return;
 
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index d45980a8..54ac67a9 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -288,7 +288,7 @@ private:
 
     static QWaylandWindow *mMouseGrab;
 
-    QReadWriteLock mSurfaceLock;
+    mutable QReadWriteLock mSurfaceLock;
 
     friend class QWaylandSubSurface;
 };
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
index 683fe123..8f12736d 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
@@ -192,7 +192,6 @@ public:
     }
     void blit(QWaylandEglWindow *window)
     {
-        Q_ASSERT(window->wlSurface());
         QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(m_context->context());
 
         QSize surfaceSize = window->surfaceSize();
-- 
2.35.0