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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
|
changeset: 553676:ca48ea0dfb91
tag: tip
parent: 553673:a42aa9514794
user: stransky <stransky@redhat.com>
date: Mon Oct 05 15:06:55 2020 +0200
files: widget/gtk/WindowSurfaceWayland.cpp widget/gtk/WindowSurfaceWayland.h
description:
Bug 1656727 [Wayland] Track delayed commits globally, r?jhorak
Track delayed commits in a global list and don't store them in actual wayland surfaces.
When a delayed commit is called, check that the associated wayland surface is still valid.
Differential Revision: https://phabricator.services.mozilla.com/D92432
diff --git a/widget/gtk/WindowSurfaceWayland.cpp b/widget/gtk/WindowSurfaceWayland.cpp
--- a/widget/gtk/WindowSurfaceWayland.cpp
+++ b/widget/gtk/WindowSurfaceWayland.cpp
@@ -159,7 +159,6 @@ We allocate shared memory (shm) by mmap(
between us and wayland compositor. We draw our graphics data to the shm and
handle to wayland compositor by WindowBackBuffer/WindowSurfaceWayland
(wl_buffer/wl_surface).
-
*/
#define EVENT_LOOP_DELAY (1000 / 240)
@@ -167,6 +166,44 @@ handle to wayland compositor by WindowBa
#define BUFFER_BPP 4
gfx::SurfaceFormat WindowBackBuffer::mFormat = gfx::SurfaceFormat::B8G8R8A8;
+static mozilla::Mutex* gDelayedCommitLock = nullptr;
+static GList* gDelayedCommits = nullptr;
+
+static void DelayedCommitsEnsureMutext() {
+ if (!gDelayedCommitLock) {
+ gDelayedCommitLock = new mozilla::Mutex("DelayedCommit lock");
+ }
+}
+
+static bool DelayedCommitsCheckAndRemoveSurface(
+ WindowSurfaceWayland* aSurface) {
+ MutexAutoLock lock(*gDelayedCommitLock);
+ GList* foundCommit = g_list_find(gDelayedCommits, aSurface);
+ if (foundCommit) {
+ gDelayedCommits = g_list_delete_link(gDelayedCommits, foundCommit);
+ }
+ return foundCommit != nullptr;
+}
+
+static bool DelayedCommitsCheckAndAddSurface(WindowSurfaceWayland* aSurface) {
+ MutexAutoLock lock(*gDelayedCommitLock);
+ GList* foundCommit = g_list_find(gDelayedCommits, aSurface);
+ if (!foundCommit) {
+ gDelayedCommits = g_list_prepend(gDelayedCommits, aSurface);
+ }
+ return foundCommit == nullptr;
+}
+
+// When a new window is created we may not have a valid wl_surface
+// for drawing (Gtk haven't created it yet). All commits are queued
+// and CommitWaylandBuffer() is called by timer when wl_surface is ready
+// for drawing.
+static void WaylandBufferDelayCommitHandler(WindowSurfaceWayland* aSurface) {
+ if (DelayedCommitsCheckAndRemoveSurface(aSurface)) {
+ aSurface->CommitWaylandBuffer();
+ }
+}
+
RefPtr<nsWaylandDisplay> WindowBackBuffer::GetWaylandDisplay() {
return mWindowSurfaceWayland->GetWaylandDisplay();
}
@@ -400,7 +437,6 @@ WindowSurfaceWayland::WindowSurfaceWayla
mWaylandFullscreenDamage(false),
mFrameCallback(nullptr),
mLastCommittedSurface(nullptr),
- mDelayedCommitHandle(nullptr),
mLastCommitTime(0),
mDrawToWaylandBufferDirectly(true),
mCanSwitchWaylandBuffer(true),
@@ -412,6 +448,7 @@ WindowSurfaceWayland::WindowSurfaceWayla
for (int i = 0; i < BACK_BUFFER_NUM; i++) {
mShmBackupBuffer[i] = nullptr;
}
+ DelayedCommitsEnsureMutext();
}
WindowSurfaceWayland::~WindowSurfaceWayland() {
@@ -419,12 +456,9 @@ WindowSurfaceWayland::~WindowSurfaceWayl
NS_WARNING("Deleted WindowSurfaceWayland with a pending commit!");
}
- if (mDelayedCommitHandle) {
- // Delete reference to this to prevent WaylandBufferDelayCommitHandler()
- // operate on released this. mDelayedCommitHandle itself will
- // be released at WaylandBufferDelayCommitHandler().
- *mDelayedCommitHandle = nullptr;
- }
+ // Delete reference to this to prevent WaylandBufferDelayCommitHandler()
+ // operate on released this.
+ DelayedCommitsCheckAndRemoveSurface(this);
if (mFrameCallback) {
wl_callback_destroy(mFrameCallback);
@@ -865,23 +899,11 @@ bool WindowSurfaceWayland::CommitImageCa
return true;
}
-static void WaylandBufferDelayCommitHandler(WindowSurfaceWayland** aSurface) {
- if (*aSurface) {
- (*aSurface)->DelayedCommitHandler();
- } else {
- // Referenced WindowSurfaceWayland is already deleted.
- // Do nothing but just release the mDelayedCommitHandle allocated at
- // WindowSurfaceWayland::CommitWaylandBuffer().
- free(aSurface);
- }
-}
-
void WindowSurfaceWayland::CommitWaylandBuffer() {
LOGWAYLAND(("WindowSurfaceWayland::CommitWaylandBuffer [%p]\n", (void*)this));
LOGWAYLAND(
(" mDrawToWaylandBufferDirectly = %d\n", mDrawToWaylandBufferDirectly));
LOGWAYLAND((" mCanSwitchWaylandBuffer = %d\n", mCanSwitchWaylandBuffer));
- LOGWAYLAND((" mDelayedCommitHandle = %p\n", mDelayedCommitHandle));
LOGWAYLAND((" mFrameCallback = %p\n", mFrameCallback));
LOGWAYLAND((" mLastCommittedSurface = %p\n", mLastCommittedSurface));
LOGWAYLAND((" mBufferPendingCommit = %d\n", mBufferPendingCommit));
@@ -917,16 +939,10 @@ void WindowSurfaceWayland::CommitWayland
MOZ_ASSERT(!mFrameCallback || waylandSurface != mLastCommittedSurface,
"Missing wayland surface at frame callback!");
- // Do nothing if there's already mDelayedCommitHandle pending.
- if (!mDelayedCommitHandle) {
- mDelayedCommitHandle = static_cast<WindowSurfaceWayland**>(
- moz_xmalloc(sizeof(*mDelayedCommitHandle)));
- *mDelayedCommitHandle = this;
-
+ if (DelayedCommitsCheckAndAddSurface(this)) {
MessageLoop::current()->PostDelayedTask(
NewRunnableFunction("WaylandBackBufferCommit",
- &WaylandBufferDelayCommitHandler,
- mDelayedCommitHandle),
+ &WaylandBufferDelayCommitHandler, this),
EVENT_LOOP_DELAY);
}
return;
@@ -1039,24 +1055,5 @@ void WindowSurfaceWayland::FrameCallback
CommitWaylandBuffer();
}
-void WindowSurfaceWayland::DelayedCommitHandler() {
- MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
- MOZ_ASSERT(mDelayedCommitHandle != nullptr, "Missing mDelayedCommitHandle!");
-
- LOGWAYLAND(
- ("WindowSurfaceWayland::DelayedCommitHandler [%p]\n", (void*)this));
-
- if (!mDelayedCommitHandle) {
- LOGWAYLAND((" We're missing mDelayedCommitHandle!\n"));
- return;
- }
-
- *mDelayedCommitHandle = nullptr;
- free(mDelayedCommitHandle);
- mDelayedCommitHandle = nullptr;
-
- CommitWaylandBuffer();
-}
-
} // namespace widget
} // namespace mozilla
diff --git a/widget/gtk/WindowSurfaceWayland.h b/widget/gtk/WindowSurfaceWayland.h
--- a/widget/gtk/WindowSurfaceWayland.h
+++ b/widget/gtk/WindowSurfaceWayland.h
@@ -161,7 +161,7 @@ class WindowSurfaceWayland : public Wind
// If we fail (wayland compositor is busy,
// wl_surface is not created yet) we queue the painting
// and we send it to wayland compositor in FrameCallbackHandler()/
- // DelayedCommitHandler/CommitWaylandBuffer().
+ // CommitWaylandBuffer().
already_AddRefed<gfx::DrawTarget> Lock(
const LayoutDeviceIntRegion& aRegion) override;
void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final;
@@ -171,12 +171,6 @@ class WindowSurfaceWayland : public Wind
// queued commits.
void FrameCallbackHandler();
- // When a new window is created we may not have a valid wl_surface
- // for drawing (Gtk haven't created it yet). All commits are queued
- // and DelayedCommitHandler() is called by timer when wl_surface is ready
- // for drawing.
- void DelayedCommitHandler();
-
// Try to commit all queued drawings to Wayland compositor. This is usually
// called from other routines but can be used to explicitly flush
// all drawings as we do when wl_buffer is released
@@ -249,17 +243,14 @@ class WindowSurfaceWayland : public Wind
wl_callback* mFrameCallback;
wl_surface* mLastCommittedSurface;
- // Registered reference to pending DelayedCommitHandler() call.
- WindowSurfaceWayland** mDelayedCommitHandle;
-
// Cached drawings. If we can't get WaylandBuffer (wl_buffer) at
// WindowSurfaceWayland::Lock() we direct gecko rendering to
// mImageSurface.
// If we can't get WaylandBuffer at WindowSurfaceWayland::Commit()
// time, mImageSurface is moved to mDelayedImageCommits which
// holds all cached drawings.
- // mDelayedImageCommits can be drawn by FrameCallbackHandler(),
- // DelayedCommitHandler() or when WaylandBuffer is detached.
+ // mDelayedImageCommits can be drawn by FrameCallbackHandler()
+ // or when WaylandBuffer is detached.
RefPtr<gfxImageSurface> mImageSurface;
AutoTArray<WindowImageSurface, 30> mDelayedImageCommits;
@@ -282,8 +273,8 @@ class WindowSurfaceWayland : public Wind
// We can't send WaylandBuffer (wl_buffer) to compositor when gecko
// is rendering into it (i.e. between WindowSurfaceWayland::Lock() /
// WindowSurfaceWayland::Commit()).
- // Thus we use mBufferCommitAllowed to disable commit by callbacks
- // (FrameCallbackHandler(), DelayedCommitHandler())
+ // Thus we use mBufferCommitAllowed to disable commit by
+ // CommitWaylandBuffer().
bool mBufferCommitAllowed;
// We need to clear WaylandBuffer when entire transparent window is repainted.
|