From daafa866dae8b00204f59d28a3ac3f533a254ad6 Mon Sep 17 00:00:00 2001 From: Robert Mader Date: Tue, 16 Feb 2021 09:04:47 +0000 Subject: [PATCH] Bug 1668805: Enable opaque region if new GDK API is availabe, r=stransky From GTK 3.24.25 on we have a new API that allows us to savely apply opaque regions to our own surfaces without risking to freeze GDK. Differential Revision: https://phabricator.services.mozilla.com/D102835 --- modules/libpref/init/StaticPrefList.yaml | 6 ++ modules/libpref/init/all.js | 1 - widget/gtk/MozContainerWayland.cpp | 85 +++++++++++++++++++++--- widget/gtk/MozContainerWayland.h | 4 +- widget/gtk/mozgtk/mozgtk.c | 1 + widget/gtk/nsWindow.cpp | 6 +- 6 files changed, 85 insertions(+), 18 deletions(-) diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 9630f0b03ced..3550b56d4cd9 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -10561,6 +10561,12 @@ type: RelaxedAtomicBool value: true mirror: always + +# Use opaque region for MozContainer wl_surface +- name: widget.wayland.opaque-region.enabled + type: RelaxedAtomicBool + value: true + mirror: always #endif # Enable the RemoteLookAndFeel in content processes, which will cause all diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index c712ae34d714..c7cde8917c9b 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -3785,7 +3785,6 @@ pref("network.psl.onUpdate_notify", false); #endif #ifdef MOZ_WAYLAND pref("widget.wayland_vsync.enabled", true); - pref("widget.wayland.use-opaque-region", false); pref("widget.use-xdg-desktop-portal", false); #endif diff --git a/widget/gtk/MozContainerWayland.cpp b/widget/gtk/MozContainerWayland.cpp index de93a613c28b..3d0ed90177db 100644 --- a/widget/gtk/MozContainerWayland.cpp +++ b/widget/gtk/MozContainerWayland.cpp @@ -50,14 +50,14 @@ #include "MozContainer.h" -#include -#include -#include -#include "nsWaylandDisplay.h" -#include "gfxPlatformGtk.h" -#include -#include #include +#include +#include +#include + +#include "gfxPlatformGtk.h" +#include "nsGtkUtils.h" +#include "nsWaylandDisplay.h" #undef LOG #ifdef MOZ_LOGGING @@ -167,8 +167,9 @@ void moz_container_wayland_init(MozContainerWayland* container) { container->eglwindow = nullptr; container->frame_callback_handler = nullptr; container->ready_to_draw = false; - container->opaque_region_updates = false; + container->opaque_region_needs_updates = false; container->opaque_region_subtract_corners = false; + container->opaque_region_used = false; container->surface_needs_clear = true; container->subsurface_dx = 0; container->subsurface_dy = 0; @@ -213,10 +214,65 @@ static void moz_container_wayland_frame_callback_handler( static const struct wl_callback_listener moz_container_frame_listener = { moz_container_wayland_frame_callback_handler}; +static void after_frame_clock_after_paint(GdkFrameClock* clock, + MozContainer* container) { + struct wl_surface* surface = moz_container_wayland_surface_lock(container); + if (surface) { + wl_surface_commit(surface); + moz_container_wayland_surface_unlock(container, &surface); + } +} + +static bool moz_gdk_wayland_window_add_frame_callback_surface_locked( + MozContainer* container) { + static auto sGdkWaylandWindowAddCallbackSurface = + (void (*)(GdkWindow*, struct wl_surface*))dlsym( + RTLD_DEFAULT, "gdk_wayland_window_add_frame_callback_surface"); + + if (!StaticPrefs::widget_wayland_opaque_region_enabled() || + !sGdkWaylandWindowAddCallbackSurface) { + return false; + } + + GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container)); + MozContainerWayland* wl_container = &container->wl_container; + + sGdkWaylandWindowAddCallbackSurface(window, wl_container->surface); + + GdkFrameClock* frame_clock = gdk_window_get_frame_clock(window); + g_signal_connect_after(frame_clock, "after-paint", + G_CALLBACK(after_frame_clock_after_paint), container); + return true; +} + +static void moz_gdk_wayland_window_remove_frame_callback_surface_locked( + MozContainer* container) { + static auto sGdkWaylandWindowRemoveCallbackSurface = + (void (*)(GdkWindow*, struct wl_surface*))dlsym( + RTLD_DEFAULT, "gdk_wayland_window_remove_frame_callback_surface"); + + if (!sGdkWaylandWindowRemoveCallbackSurface) { + return; + } + + GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container)); + MozContainerWayland* wl_container = &container->wl_container; + + sGdkWaylandWindowRemoveCallbackSurface(window, wl_container->surface); + + GdkFrameClock* frame_clock = gdk_window_get_frame_clock(window); + g_signal_handlers_disconnect_by_func( + frame_clock, FuncToGpointer(after_frame_clock_after_paint), container); +} + static void moz_container_wayland_unmap_internal(MozContainer* container) { MozContainerWayland* wl_container = &container->wl_container; MutexAutoLock lock(*wl_container->container_lock); + if (wl_container->opaque_region_used) { + moz_gdk_wayland_window_remove_frame_callback_surface_locked(container); + } + g_clear_pointer(&wl_container->eglwindow, wl_egl_window_destroy); g_clear_pointer(&wl_container->subsurface, wl_subsurface_destroy); g_clear_pointer(&wl_container->surface, wl_surface_destroy); @@ -336,7 +392,12 @@ static void moz_container_wayland_set_opaque_region_locked( MozContainer* container) { MozContainerWayland* wl_container = &container->wl_container; - if (!wl_container->opaque_region_updates) { + if (!wl_container->opaque_region_needs_updates) { + return; + } + + if (!wl_container->opaque_region_used) { + wl_container->opaque_region_needs_updates = false; return; } @@ -348,6 +409,7 @@ static void moz_container_wayland_set_opaque_region_locked( wl_container->opaque_region_subtract_corners); wl_surface_set_opaque_region(wl_container->surface, region); wl_region_destroy(region); + wl_container->opaque_region_needs_updates = false; } static void moz_container_wayland_set_opaque_region(MozContainer* container) { @@ -437,6 +499,9 @@ static bool moz_container_wayland_surface_create_locked( wl_surface_commit(wl_container->surface); wl_display_flush(WaylandDisplayGet()->GetDisplay()); + wl_container->opaque_region_used = + moz_gdk_wayland_window_add_frame_callback_surface_locked(container); + LOGWAYLAND((" created surface %p ID %d\n", (void*)wl_container->surface, wl_proxy_get_id((struct wl_proxy*)wl_container->surface))); return true; @@ -504,7 +569,7 @@ gboolean moz_container_wayland_surface_needs_clear(MozContainer* container) { void moz_container_wayland_update_opaque_region(MozContainer* container, bool aSubtractCorners) { MozContainerWayland* wl_container = &container->wl_container; - wl_container->opaque_region_updates = true; + wl_container->opaque_region_needs_updates = true; wl_container->opaque_region_subtract_corners = aSubtractCorners; // When GL compositor / WebRender is used, diff --git a/widget/gtk/MozContainerWayland.h b/widget/gtk/MozContainerWayland.h index 895c9133a793..ddc93170f91b 100644 --- a/widget/gtk/MozContainerWayland.h +++ b/widget/gtk/MozContainerWayland.h @@ -37,9 +37,9 @@ struct MozContainerWayland { int subsurface_dx, subsurface_dy; struct wl_egl_window* eglwindow; struct wl_callback* frame_callback_handler; - gboolean opaque_region_updates; + gboolean opaque_region_needs_updates; gboolean opaque_region_subtract_corners; - gboolean opaque_region_fullscreen; + gboolean opaque_region_used; gboolean surface_needs_clear; gboolean ready_to_draw; gboolean before_first_size_alloc; diff --git a/widget/gtk/mozgtk/mozgtk.c b/widget/gtk/mozgtk/mozgtk.c index 0b2e3fd49468..157e6b30856d 100644 --- a/widget/gtk/mozgtk/mozgtk.c +++ b/widget/gtk/mozgtk/mozgtk.c @@ -550,6 +550,7 @@ STUB(gdk_display_manager_open_display) STUB(gdk_error_trap_pop_ignored) STUB(gdk_event_get_source_device) STUB(gdk_screen_get_monitor_workarea) +STUB(gdk_window_get_frame_clock) STUB(gdk_window_get_type) STUB(gdk_window_set_opaque_region) STUB(gdk_x11_window_get_xid) diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 972cebf886b2..80cf6219f36f 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -379,7 +379,6 @@ static bool gBlockActivateEvent = false; static bool gGlobalsInitialized = false; static bool gRaiseWindows = true; static bool gUseWaylandVsync = true; -static bool gUseWaylandUseOpaqueRegion = true; static bool gUseAspectRatio = true; static GList* gVisibleWaylandPopupWindows = nullptr; static uint32_t gLastTouchID = 0; @@ -5662,8 +5661,7 @@ void nsWindow::UpdateTopLevelOpaqueRegion(void) { cairo_region_destroy(region); #ifdef MOZ_WAYLAND - // We don't set opaque region to mozContainer by default due to Bug 1615098. - if (!mIsX11Display && gUseWaylandUseOpaqueRegion) { + if (!mIsX11Display) { moz_container_wayland_update_opaque_region(mContainer, subtractCorners); } #endif @@ -7345,8 +7343,6 @@ static nsresult initialize_prefs(void) { Preferences::GetBool("mozilla.widget.raise-on-setfocus", true); gUseWaylandVsync = Preferences::GetBool("widget.wayland_vsync.enabled", false); - gUseWaylandUseOpaqueRegion = - Preferences::GetBool("widget.wayland.use-opaque-region", false); if (Preferences::HasUserValue("widget.use-aspect-ratio")) { gUseAspectRatio = Preferences::GetBool("widget.use-aspect-ratio", true);