229 lines
8.9 KiB
Diff
229 lines
8.9 KiB
Diff
|
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.
|
||
|
|