From db65a511cba4744fe9e90e07c8618ad0d33760b0 Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Mon, 18 Aug 2025 16:46:36 +0400 Subject: [PATCH 01/23] wayland/surface: Put buffer reference on heap Currently a buffer use count always reaches zero before it is replaced. This is due to the fact that at the point a new buffer is attached, the last potential user releases it (the stage) since the currently displayed frame has a composited copy of the buffer. This may however change, if a buffer is scanned out directly, meaning it should not be released until the page flip callback is invoked. Prepare for this by making the buffer reference a heap allocated struct, enabling us to keep a pointer to it longer than the buffer is attached. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=47002bf0cd9983cb5e45121d566d203baef71103 --- src/wayland/meta-wayland-actor-surface.c | 2 +- src/wayland/meta-wayland-shell-surface.c | 4 +- src/wayland/meta-wayland-subsurface.c | 2 +- src/wayland/meta-wayland-surface.c | 47 +++++++++++++++++------- src/wayland/meta-wayland-surface.h | 12 +++--- src/wayland/meta-wayland-xdg-shell.c | 14 +++---- src/wayland/meta-xwayland-surface.c | 2 +- 7 files changed, 53 insertions(+), 30 deletions(-) diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c index 0ce5bbb6c..8987f03a0 100644 --- a/src/wayland/meta-wayland-actor-surface.c +++ b/src/wayland/meta-wayland-actor-surface.c @@ -181,7 +181,7 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor surface_actor = priv->actor; stex = meta_surface_actor_get_texture (surface_actor); - buffer = surface->buffer_ref.buffer; + buffer = surface->buffer_ref->buffer; if (buffer) { CoglSnippet *snippet; diff --git a/src/wayland/meta-wayland-shell-surface.c b/src/wayland/meta-wayland-shell-surface.c index a1f5f36af..12d291043 100644 --- a/src/wayland/meta-wayland-shell-surface.c +++ b/src/wayland/meta-wayland-shell-surface.c @@ -245,7 +245,7 @@ meta_wayland_shell_surface_surface_pre_apply_state (MetaWaylandSurfaceRole *sur meta_wayland_surface_role_get_surface (surface_role); if (pending->newly_attached && - !surface->buffer_ref.buffer && + !surface->buffer_ref->buffer && priv->window) meta_window_queue (priv->window, META_QUEUE_CALC_SHOWING); } @@ -271,7 +271,7 @@ meta_wayland_shell_surface_surface_apply_state (MetaWaylandSurfaceRole *surface META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_shell_surface_parent_class); surface_role_class->apply_state (surface_role, pending); - buffer = surface->buffer_ref.buffer; + buffer = surface->buffer_ref->buffer; if (!buffer) return; diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c index b9c2e7079..741fbf6ae 100644 --- a/src/wayland/meta-wayland-subsurface.c +++ b/src/wayland/meta-wayland-subsurface.c @@ -74,7 +74,7 @@ sync_actor_subsurface_state (MetaWaylandSurface *surface) clutter_actor_set_position (actor, x, y); clutter_actor_set_reactive (actor, TRUE); - if (surface->buffer_ref.buffer) + if (surface->buffer_ref->buffer) clutter_actor_show (actor); else clutter_actor_hide (actor); diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 13d0f9184..f2941cb91 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -122,6 +122,22 @@ meta_wayland_surface_role_is_on_logical_monitor (MetaWaylandSurfaceRole *surface static MetaWaylandSurface * meta_wayland_surface_role_get_toplevel (MetaWaylandSurfaceRole *surface_role); +static MetaWaylandBufferRef * +meta_wayland_buffer_ref_new (void) +{ + MetaWaylandBufferRef *buffer_ref; + + buffer_ref = g_new0 (MetaWaylandBufferRef, 1); + + return buffer_ref; +} + +static void +meta_wayland_buffer_ref_free (MetaWaylandBufferRef *buffer_ref) +{ + g_free (buffer_ref); +} + static void role_assignment_valist_to_properties (GType role_type, const char *first_property_name, @@ -357,30 +373,30 @@ surface_process_damage (MetaWaylandSurface *surface, MetaWaylandBuffer * meta_wayland_surface_get_buffer (MetaWaylandSurface *surface) { - return surface->buffer_ref.buffer; + return surface->buffer_ref->buffer; } void meta_wayland_surface_ref_buffer_use_count (MetaWaylandSurface *surface) { - g_return_if_fail (surface->buffer_ref.buffer); - g_warn_if_fail (surface->buffer_ref.buffer->resource); + g_return_if_fail (surface->buffer_ref->buffer); + g_warn_if_fail (surface->buffer_ref->buffer->resource); - surface->buffer_ref.use_count++; + surface->buffer_ref->use_count++; } void meta_wayland_surface_unref_buffer_use_count (MetaWaylandSurface *surface) { - MetaWaylandBuffer *buffer = surface->buffer_ref.buffer; + MetaWaylandBuffer *buffer = surface->buffer_ref->buffer; - g_return_if_fail (surface->buffer_ref.use_count != 0); + g_return_if_fail (surface->buffer_ref->use_count != 0); - surface->buffer_ref.use_count--; + surface->buffer_ref->use_count--; g_return_if_fail (buffer); - if (surface->buffer_ref.use_count == 0 && buffer->resource) + if (surface->buffer_ref->use_count == 0 && buffer->resource) wl_buffer_send_release (buffer->resource); } @@ -644,7 +660,7 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface, if (surface->buffer_held) meta_wayland_surface_unref_buffer_use_count (surface); - g_set_object (&surface->buffer_ref.buffer, state->buffer); + g_set_object (&surface->buffer_ref->buffer, state->buffer); if (state->buffer) meta_wayland_surface_ref_buffer_use_count (surface); @@ -751,7 +767,8 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface, * role the surface is given. That means we need to also keep a use * count for wl_buffer's that are used by unassigned wl_surface's. */ - g_set_object (&surface->unassigned.buffer, surface->buffer_ref.buffer); + g_set_object (&surface->unassigned.buffer, + surface->buffer_ref->buffer); if (surface->unassigned.buffer) meta_wayland_surface_ref_buffer_use_count (surface); } @@ -799,7 +816,7 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface, * be released if no-one else has a use-reference to it. */ if (state->newly_attached && - !surface->buffer_held && surface->buffer_ref.buffer) + !surface->buffer_held && surface->buffer_ref->buffer) meta_wayland_surface_unref_buffer_use_count (surface); g_signal_emit (state, @@ -1348,7 +1365,8 @@ wl_surface_destructor (struct wl_resource *resource) if (surface->buffer_held) meta_wayland_surface_unref_buffer_use_count (surface); g_clear_pointer (&surface->texture, cogl_object_unref); - g_clear_object (&surface->buffer_ref.buffer); + g_clear_object (&surface->buffer_ref->buffer); + g_clear_pointer (&surface->buffer_ref, meta_wayland_buffer_ref_free); g_clear_object (&surface->cached_state); g_clear_object (&surface->pending_state); @@ -1610,6 +1628,9 @@ static void meta_wayland_surface_init (MetaWaylandSurface *surface) { surface->pending_state = g_object_new (META_TYPE_WAYLAND_SURFACE_STATE, NULL); + + surface->buffer_ref = meta_wayland_buffer_ref_new (); + surface->subsurface_branch_node = g_node_new (surface); surface->subsurface_leaf_node = g_node_prepend_data (surface->subsurface_branch_node, surface); @@ -1882,7 +1903,7 @@ meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface) cairo_region_t *region; cairo_rectangle_int_t buffer_rect; - if (!surface->buffer_ref.buffer) + if (!surface->buffer_ref->buffer) return NULL; buffer_rect = (cairo_rectangle_int_t) { diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index 7e8814c23..16deaaed2 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -140,6 +140,12 @@ struct _MetaWaylandDragDestFuncs MetaWaylandSurface *surface); }; +typedef struct _MetaWaylandBufferRef +{ + MetaWaylandBuffer *buffer; + unsigned int use_count; +} MetaWaylandBufferRef; + struct _MetaWaylandSurface { GObject parent; @@ -159,11 +165,7 @@ struct _MetaWaylandSurface CoglTexture *texture; - /* Buffer reference state. */ - struct { - MetaWaylandBuffer *buffer; - unsigned int use_count; - } buffer_ref; + MetaWaylandBufferRef *buffer_ref; /* Buffer renderer state. */ gboolean buffer_held; diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c index b87cb9aee..44ff6bfde 100644 --- a/src/wayland/meta-wayland-xdg-shell.c +++ b/src/wayland/meta-wayland-xdg-shell.c @@ -777,7 +777,7 @@ meta_wayland_xdg_toplevel_apply_state (MetaWaylandSurfaceRole *surface_role, return; } - if (!surface->buffer_ref.buffer && xdg_surface_priv->first_buffer_attached) + if (!surface->buffer_ref->buffer && xdg_surface_priv->first_buffer_attached) { meta_wayland_xdg_surface_reset (xdg_surface); meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, @@ -1183,7 +1183,7 @@ meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role, if (xdg_popup->setup.parent_surface) finish_popup_setup (xdg_popup); - if (!surface->buffer_ref.buffer && xdg_surface_priv->first_buffer_attached) + if (!surface->buffer_ref->buffer && xdg_surface_priv->first_buffer_attached) { meta_wayland_xdg_surface_reset (xdg_surface); meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending); @@ -1194,7 +1194,7 @@ meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role, META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_popup_parent_class); surface_role_class->apply_state (surface_role, pending); - if (xdg_popup->dismissed_by_client && surface->buffer_ref.buffer) + if (xdg_popup->dismissed_by_client && surface->buffer_ref->buffer) { wl_resource_post_error (xdg_popup->resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, @@ -1225,7 +1225,7 @@ meta_wayland_xdg_popup_post_apply_state (MetaWaylandSurfaceRole *surface_role, if (!pending->newly_attached) return; - if (!surface->buffer_ref.buffer) + if (!surface->buffer_ref->buffer) return; surface_role_class->post_apply_state (surface_role, pending); @@ -1633,7 +1633,7 @@ meta_wayland_xdg_surface_apply_state (MetaWaylandSurfaceRole *surface_role, if (!window) return; - if (surface->buffer_ref.buffer) + if (surface->buffer_ref->buffer) priv->first_buffer_attached = TRUE; } @@ -1702,7 +1702,7 @@ meta_wayland_xdg_surface_assigned (MetaWaylandSurfaceRole *surface_role) priv->configure_sent = FALSE; priv->first_buffer_attached = FALSE; - if (surface->buffer_ref.buffer) + if (surface->buffer_ref->buffer) { wl_resource_post_error (xdg_wm_base_resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, @@ -2408,7 +2408,7 @@ xdg_wm_base_get_xdg_surface (struct wl_client *client, return; } - if (surface->buffer_ref.buffer) + if (surface->buffer_ref->buffer) { wl_resource_post_error (resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, diff --git a/src/wayland/meta-xwayland-surface.c b/src/wayland/meta-xwayland-surface.c index 4a4615a2c..c8625f414 100644 --- a/src/wayland/meta-xwayland-surface.c +++ b/src/wayland/meta-xwayland-surface.c @@ -182,7 +182,7 @@ meta_xwayland_surface_pre_apply_state (MetaWaylandSurfaceRole *surface_role, MetaXwaylandSurface *xwayland_surface = META_XWAYLAND_SURFACE (surface_role); if (pending->newly_attached && - surface->buffer_ref.buffer && + surface->buffer_ref->buffer && xwayland_surface->window) meta_window_queue (xwayland_surface->window, META_QUEUE_CALC_SHOWING); } From 4f554bb0dab6ae77e06a950bbc0b8381f32f50dd Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 20:01:16 +0400 Subject: [PATCH 02/23] drm-buffer/gbm: Support both surface and standalone buffers Surface buffers are created with meta_drm_buffer_new_acquire(), taking a gbm_surface acquiring the gbm itself, and meta_drm_buffer_new_take() that takes over ownership of a passed gbm_bo. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=282aada13a5d744dd29eedf3255b6a9f6d0e370c --- src/backends/native/meta-drm-buffer-gbm.c | 77 +++++++++++++++------- src/backends/native/meta-drm-buffer-gbm.h | 14 ++-- src/backends/native/meta-renderer-native.c | 10 +-- 3 files changed, 69 insertions(+), 32 deletions(-) diff --git a/src/backends/native/meta-drm-buffer-gbm.c b/src/backends/native/meta-drm-buffer-gbm.c index b446d64e1..deb96ff11 100644 --- a/src/backends/native/meta-drm-buffer-gbm.c +++ b/src/backends/native/meta-drm-buffer-gbm.c @@ -53,22 +53,12 @@ meta_drm_buffer_gbm_get_bo (MetaDrmBufferGbm *buffer_gbm) } static gboolean -acquire_swapped_buffer (MetaDrmBufferGbm *buffer_gbm, - gboolean use_modifiers, - GError **error) +init_fb_id (MetaDrmBufferGbm *buffer_gbm, + struct gbm_bo *bo, + gboolean use_modifiers, + GError **error) { MetaGpuKmsFBArgs fb_args = { 0, }; - struct gbm_bo *bo; - - bo = gbm_surface_lock_front_buffer (buffer_gbm->surface); - if (!bo) - { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "gbm_surface_lock_front_buffer failed"); - return FALSE; - } if (gbm_bo_get_handle_for_plane (bo, 0).s32 == -1) { @@ -99,37 +89,71 @@ acquire_swapped_buffer (MetaDrmBufferGbm *buffer_gbm, use_modifiers, &fb_args, &buffer_gbm->fb_id, error)) + return FALSE; + return TRUE; +} + +static gboolean +lock_front_buffer (MetaDrmBufferGbm *buffer_gbm, + gboolean use_modifiers, + GError **error) +{ + buffer_gbm->bo = gbm_surface_lock_front_buffer (buffer_gbm->surface); + if (!buffer_gbm->bo) { - gbm_surface_release_buffer (buffer_gbm->surface, bo); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "gbm_surface_lock_front_buffer failed"); return FALSE; } + return init_fb_id (buffer_gbm, buffer_gbm->bo, use_modifiers, error); +} - buffer_gbm->bo = bo; +MetaDrmBufferGbm * +meta_drm_buffer_gbm_new_lock_front (MetaGpuKms *gpu_kms, + struct gbm_surface *gbm_surface, + gboolean use_modifiers, + GError **error) +{ + MetaDrmBufferGbm *buffer_gbm; - return TRUE; + buffer_gbm = g_object_new (META_TYPE_DRM_BUFFER_GBM, NULL); + buffer_gbm->gpu_kms = gpu_kms; + buffer_gbm->surface = gbm_surface; + + if (!lock_front_buffer (buffer_gbm, use_modifiers, error)) + { + g_object_unref (buffer_gbm); + return NULL; + } + + return buffer_gbm; } MetaDrmBufferGbm * -meta_drm_buffer_gbm_new (MetaGpuKms *gpu_kms, - struct gbm_surface *gbm_surface, - gboolean use_modifiers, - GError **error) +meta_drm_buffer_gbm_new_take (MetaGpuKms *gpu_kms, + struct gbm_bo *bo, + gboolean use_modifiers, + GError **error) { MetaDrmBufferGbm *buffer_gbm; buffer_gbm = g_object_new (META_TYPE_DRM_BUFFER_GBM, NULL); buffer_gbm->gpu_kms = gpu_kms; - buffer_gbm->surface = gbm_surface; - if (!acquire_swapped_buffer (buffer_gbm, use_modifiers, error)) + if (!init_fb_id (buffer_gbm, bo, use_modifiers, error)) { g_object_unref (buffer_gbm); return NULL; } + buffer_gbm->bo = bo; + return buffer_gbm; } + static uint32_t meta_drm_buffer_gbm_get_fb_id (MetaDrmBuffer *buffer) { @@ -150,7 +174,12 @@ meta_drm_buffer_gbm_finalize (GObject *object) } if (buffer_gbm->bo) - gbm_surface_release_buffer (buffer_gbm->surface, buffer_gbm->bo); + { + if (buffer_gbm->surface) + gbm_surface_release_buffer (buffer_gbm->surface, buffer_gbm->bo); + else + gbm_bo_destroy (buffer_gbm->bo); + } G_OBJECT_CLASS (meta_drm_buffer_gbm_parent_class)->finalize (object); } diff --git a/src/backends/native/meta-drm-buffer-gbm.h b/src/backends/native/meta-drm-buffer-gbm.h index b48cef06a..b46925ecc 100644 --- a/src/backends/native/meta-drm-buffer-gbm.h +++ b/src/backends/native/meta-drm-buffer-gbm.h @@ -33,10 +33,16 @@ G_DECLARE_FINAL_TYPE (MetaDrmBufferGbm, META, DRM_BUFFER_GBM, MetaDrmBuffer) -MetaDrmBufferGbm * meta_drm_buffer_gbm_new (MetaGpuKms *gpu_kms, - struct gbm_surface *gbm_surface, - gboolean use_modifiers, - GError **error); +MetaDrmBufferGbm * meta_drm_buffer_gbm_new_lock_front (MetaGpuKms *gpu_kms, + struct gbm_surface *gbm_surface, + gboolean use_modifiers, + GError **error); + + +MetaDrmBufferGbm * meta_drm_buffer_gbm_new_take (MetaGpuKms *gpu_kms, + struct gbm_bo *gbm_bo, + gboolean use_modifiers, + GError **error); struct gbm_bo * meta_drm_buffer_gbm_get_bo (MetaDrmBufferGbm *buffer_gbm); diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index 7e75ab9fd..65bfd40b1 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -1621,13 +1621,14 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, return; } - buffer_gbm = meta_drm_buffer_gbm_new (secondary_gpu_state->gpu_kms, + buffer_gbm = + meta_drm_buffer_gbm_new_lock_front (secondary_gpu_state->gpu_kms, secondary_gpu_state->gbm.surface, renderer_native->use_modifiers, &error); if (!buffer_gbm) { - g_warning ("meta_drm_buffer_gbm_new failed: %s", + g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s", error->message); g_error_free (error); return; @@ -2113,13 +2114,14 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, g_warn_if_fail (onscreen_native->gbm.next_fb == NULL); g_clear_object (&onscreen_native->gbm.next_fb); - buffer_gbm = meta_drm_buffer_gbm_new (render_gpu, + buffer_gbm = + meta_drm_buffer_gbm_new_lock_front (render_gpu, onscreen_native->gbm.surface, renderer_native->use_modifiers, &error); if (!buffer_gbm) { - g_warning ("meta_drm_buffer_gbm_new failed: %s", + g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s", error->message); return; } From 0bfecad752a81171d8773fa5225168af77cf2f35 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 20:21:25 +0400 Subject: [PATCH 03/23] window/x11: Use G_DECLARE_DERIVABLE_TYPE() This removes the MetaWindowX11::priv pointer. It is replaced with a meta_window_x11_get_private() helper function, and another method to get the client rect without going through MetaWindowX11Private. --- src/ui/frames.c | 16 ++++++++++------ src/x11/window-props.c | 14 +++++++------- src/x11/window-x11-private.h | 19 +++---------------- src/x11/window-x11.c | 15 ++++++++++++++- src/x11/window-x11.h | 24 +++++++++++++----------- 5 files changed, 47 insertions(+), 41 deletions(-) diff --git a/src/ui/frames.c b/src/ui/frames.c index 3c076b691..b49358847 100644 --- a/src/ui/frames.c +++ b/src/ui/frames.c @@ -421,7 +421,7 @@ meta_ui_frame_calc_geometry (MetaUIFrame *frame, MetaFrameType type; MetaButtonLayout button_layout; MetaWindowX11 *window_x11 = META_WINDOW_X11 (frame->meta_window); - MetaWindowX11Private *priv = window_x11->priv; + MetaRectangle client_rect; flags = meta_frame_get_flags (frame->meta_window->frame); type = meta_window_get_frame_type (frame->meta_window); @@ -430,13 +430,15 @@ meta_ui_frame_calc_geometry (MetaUIFrame *frame, meta_prefs_get_button_layout (&button_layout); + client_rect = meta_window_x11_get_client_rect (window_x11); + meta_theme_calc_geometry (meta_theme_get_default (), frame->style_info, type, frame->text_height, flags, - priv->client_rect.width, - priv->client_rect.height, + client_rect.width, + client_rect.height, &button_layout, fgeom); } @@ -1657,7 +1659,7 @@ meta_ui_frame_paint (MetaUIFrame *frame, int button_type = -1; MetaButtonLayout button_layout; MetaWindowX11 *window_x11 = META_WINDOW_X11 (frame->meta_window); - MetaWindowX11Private *priv = window_x11->priv; + MetaRectangle client_rect; for (i = 0; i < META_BUTTON_TYPE_LAST; i++) button_states[i] = META_BUTTON_STATE_NORMAL; @@ -1695,13 +1697,15 @@ meta_ui_frame_paint (MetaUIFrame *frame, meta_prefs_get_button_layout (&button_layout); + client_rect = meta_window_x11_get_client_rect (window_x11); + meta_theme_draw_frame (meta_theme_get_default (), frame->style_info, cr, type, flags, - priv->client_rect.width, - priv->client_rect.height, + client_rect.width, + client_rect.height, frame->text_layout, frame->text_height, &button_layout, diff --git a/src/x11/window-props.c b/src/x11/window-props.c index 6d06be225..ba7e7c126 100644 --- a/src/x11/window-props.c +++ b/src/x11/window-props.c @@ -249,7 +249,7 @@ reload_net_wm_window_type (MetaWindow *window, { MetaX11Display *x11_display = window->display->x11_display; MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); if (value->type != META_PROP_VALUE_INVALID) { @@ -291,7 +291,7 @@ reload_icon (MetaWindow *window, Atom atom) { MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); meta_icon_cache_property_changed (&priv->icon_cache, window->display->x11_display, @@ -604,7 +604,7 @@ set_window_title (MetaWindow *window, const char *title) { MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); char *new_title = NULL; @@ -627,7 +627,7 @@ reload_net_wm_name (MetaWindow *window, gboolean initial) { MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); if (value->type != META_PROP_VALUE_INVALID) { @@ -652,7 +652,7 @@ reload_wm_name (MetaWindow *window, gboolean initial) { MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); if (priv->using_net_wm_name) { @@ -792,7 +792,7 @@ reload_net_wm_state (MetaWindow *window, { MetaX11Display *x11_display = window->display->x11_display; MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); int i; @@ -1664,7 +1664,7 @@ reload_wm_hints (MetaWindow *window, gboolean initial) { MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); Window old_group_leader; gboolean urgent; diff --git a/src/x11/window-x11-private.h b/src/x11/window-x11-private.h index 906d44546..2ffaa85d4 100644 --- a/src/x11/window-x11-private.h +++ b/src/x11/window-x11-private.h @@ -25,27 +25,12 @@ #include "core/window-private.h" #include "x11/iconcache.h" +#include "x11/window-x11.h" G_BEGIN_DECLS typedef struct _MetaWindowX11Private MetaWindowX11Private; -struct _MetaWindowX11Class -{ - MetaWindowClass parent_class; - - void (*freeze_commits) (MetaWindow *window); - void (*thaw_commits) (MetaWindow *window); - gboolean (*always_update_shape) (MetaWindow *window); -}; - -struct _MetaWindowX11 -{ - MetaWindow parent; - - MetaWindowX11Private *priv; -}; - struct _MetaWindowX11Private { /* TRUE if the client forced these on */ @@ -81,6 +66,8 @@ struct _MetaWindowX11Private gboolean thaw_after_paint; }; +MetaWindowX11Private * meta_window_x11_get_private (MetaWindowX11 *window_x11); + G_END_DECLS #endif diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c index aa4435b7f..4ccccad2a 100644 --- a/src/x11/window-x11.c +++ b/src/x11/window-x11.c @@ -73,7 +73,12 @@ meta_window_x11_maybe_focus_delayed (MetaWindow *window, static void meta_window_x11_init (MetaWindowX11 *window_x11) { - window_x11->priv = meta_window_x11_get_instance_private (window_x11); +} + +MetaWindowX11Private * +meta_window_x11_get_private (MetaWindowX11 *window_x11) +{ + return meta_window_x11_get_instance_private (window_x11); } static void @@ -4133,3 +4138,11 @@ meta_window_x11_surface_rect_to_client_rect (MetaWindow *window, client_rect->width -= borders.total.left + borders.total.right; client_rect->height -= borders.total.top + borders.total.bottom; } + +MetaRectangle +meta_window_x11_get_client_rect (MetaWindowX11 *window_x11) +{ + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + + return priv->client_rect; +} diff --git a/src/x11/window-x11.h b/src/x11/window-x11.h index d41d0d156..2952c67d0 100644 --- a/src/x11/window-x11.h +++ b/src/x11/window-x11.h @@ -25,24 +25,24 @@ #include +#include "core/window-private.h" #include "meta/compositor.h" #include "meta/window.h" G_BEGIN_DECLS -#define META_TYPE_WINDOW_X11 (meta_window_x11_get_type()) -#define META_WINDOW_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW_X11, MetaWindowX11)) -#define META_WINDOW_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW_X11, MetaWindowX11Class)) -#define META_IS_WINDOW_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WINDOW_X11)) -#define META_IS_WINDOW_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WINDOW_X11)) -#define META_WINDOW_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WINDOW_X11, MetaWindowX11Class)) +#define META_TYPE_WINDOW_X11 (meta_window_x11_get_type()) +G_DECLARE_DERIVABLE_TYPE (MetaWindowX11, meta_window_x11, + META, WINDOW_X11, MetaWindow) -GType meta_window_x11_get_type (void); +struct _MetaWindowX11Class +{ + MetaWindowClass parent_class; -typedef struct _MetaWindowX11 MetaWindowX11; -typedef struct _MetaWindowX11Class MetaWindowX11Class; - -G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaWindowX11, g_object_unref) + void (*freeze_commits) (MetaWindow *window); + void (*thaw_commits) (MetaWindow *window); + gboolean (*always_update_shape) (MetaWindow *window); +}; MetaWindow * meta_window_x11_new (MetaDisplay *display, Window xwindow, @@ -95,4 +95,6 @@ void meta_window_x11_surface_rect_to_frame_rect (MetaWindow *window, void meta_window_x11_surface_rect_to_client_rect (MetaWindow *window, MetaRectangle *surface_rect, MetaRectangle *client_rect); + +MetaRectangle meta_window_x11_get_client_rect (MetaWindowX11 *window_x11); #endif From 99c5b74c6e398acc267edc6d9ab4d432651013f7 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 20:41:51 +0400 Subject: [PATCH 04/23] surface-actor-x11: Move window related unredirect logic to MetaWindowX11 Better to have the relevant object figure out whether it is a good position to be unredirectable other than the actor, which should be responsible for being composited. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=5dad87cfb9058a0be96d9ec1a530e09a6d418a6e --- src/compositor/meta-surface-actor-x11.c | 27 ++--------- src/compositor/meta-window-actor-x11.c | 7 +++ src/core/window-private.h | 10 ----- src/core/window.c | 24 ---------- src/meta/window.h | 6 --- src/x11/window-props.c | 19 +++++--- src/x11/window-x11-private.h | 16 +++++++ src/x11/window-x11.c | 59 +++++++++++++++++++++++++ src/x11/window-x11.h | 2 + 9 files changed, 100 insertions(+), 70 deletions(-) diff --git a/src/compositor/meta-surface-actor-x11.c b/src/compositor/meta-surface-actor-x11.c index 7b2a742fd..3b1a250d9 100644 --- a/src/compositor/meta-surface-actor-x11.c +++ b/src/compositor/meta-surface-actor-x11.c @@ -254,33 +254,14 @@ meta_surface_actor_x11_is_opaque (MetaSurfaceActor *actor) gboolean meta_surface_actor_x11_should_unredirect (MetaSurfaceActorX11 *self) { - MetaWindow *window = self->window; - - if (meta_window_requested_dont_bypass_compositor (window)) - return FALSE; - - if (window->opacity != 0xFF) - return FALSE; - - if (window->shape_region != NULL) - return FALSE; - - if (!meta_window_is_monitor_sized (window)) - return FALSE; - - if (meta_window_requested_bypass_compositor (window)) - return TRUE; - if (!meta_surface_actor_x11_is_opaque (META_SURFACE_ACTOR (self))) return FALSE; - if (meta_window_is_override_redirect (window)) - return TRUE; - - if (self->does_full_damage && meta_prefs_get_unredirect_fullscreen_windows ()) - return TRUE; + if (!self->does_full_damage && + !meta_window_is_override_redirect (self->window)) + return FALSE; - return FALSE; + return TRUE; } static void diff --git a/src/compositor/meta-window-actor-x11.c b/src/compositor/meta-window-actor-x11.c index 0952635f0..fd1293e7d 100644 --- a/src/compositor/meta-window-actor-x11.c +++ b/src/compositor/meta-window-actor-x11.c @@ -39,6 +39,7 @@ #include "meta/meta-window-actor.h" #include "meta/meta-x11-errors.h" #include "meta/window.h" +#include "x11/window-x11.h" #include "x11/meta-x11-display-private.h" #include "x11/window-x11.h" @@ -544,12 +545,18 @@ has_shadow (MetaWindowActorX11 *actor_x11) gboolean meta_window_actor_x11_should_unredirect (MetaWindowActorX11 *actor_x11) { + MetaWindow *window = + meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); MetaSurfaceActor *surface; MetaSurfaceActorX11 *surface_x11; if (meta_window_actor_is_destroyed (META_WINDOW_ACTOR (actor_x11))) return FALSE; + if (!meta_window_x11_can_unredirect (window_x11)) + return FALSE; + surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); if (!surface) return FALSE; diff --git a/src/core/window-private.h b/src/core/window-private.h index 72274a6cf..5fb5cabfc 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -65,13 +65,6 @@ typedef enum #define NUMBER_OF_QUEUES 3 -typedef enum -{ - _NET_WM_BYPASS_COMPOSITOR_HINT_AUTO = 0, - _NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1, - _NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2, -} MetaBypassCompositorHintValue; - typedef enum { META_MOVE_RESIZE_CONFIGURE_REQUEST = 1 << 0, @@ -552,9 +545,6 @@ struct _MetaWindow // MetaWindow *tile_match; - /* Bypass compositor hints */ - guint bypass_compositor; - struct { MetaPlacementRule *rule; MetaPlacementState state; diff --git a/src/core/window.c b/src/core/window.c index 1edb0fe59..04a514327 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -3176,30 +3176,6 @@ meta_window_is_on_primary_monitor (MetaWindow *window) return window->monitor->is_primary; } -/** - * meta_window_requested_bypass_compositor: - * @window: a #MetaWindow - * - * Return value: %TRUE if the window requested to bypass the compositor - */ -gboolean -meta_window_requested_bypass_compositor (MetaWindow *window) -{ - return window->bypass_compositor == _NET_WM_BYPASS_COMPOSITOR_HINT_ON; -} - -/** - * meta_window_requested_dont_bypass_compositor: - * @window: a #MetaWindow - * - * Return value: %TRUE if the window requested to opt out of unredirecting - */ -gboolean -meta_window_requested_dont_bypass_compositor (MetaWindow *window) -{ - return window->bypass_compositor == _NET_WM_BYPASS_COMPOSITOR_HINT_OFF; -} - static void get_default_tile_fractions (MetaTileMode for_mode, double *hfraction, diff --git a/src/meta/window.h b/src/meta/window.h index 7ed58f7da..8cd52b61b 100644 --- a/src/meta/window.h +++ b/src/meta/window.h @@ -283,12 +283,6 @@ gboolean meta_window_is_monitor_sized (MetaWindow *window); META_EXPORT gboolean meta_window_is_on_primary_monitor (MetaWindow *window); -META_EXPORT -gboolean meta_window_requested_bypass_compositor (MetaWindow *window); - -META_EXPORT -gboolean meta_window_requested_dont_bypass_compositor (MetaWindow *window); - META_EXPORT gboolean meta_window_get_icon_geometry (MetaWindow *window, MetaRectangle *rect); diff --git a/src/x11/window-props.c b/src/x11/window-props.c index ba7e7c126..b1d16ea89 100644 --- a/src/x11/window-props.c +++ b/src/x11/window-props.c @@ -1855,23 +1855,28 @@ reload_bypass_compositor (MetaWindow *window, MetaPropValue *value, gboolean initial) { - int requested_value = 0; - int current_value = window->bypass_compositor; + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); + MetaBypassCompositorHint requested_value; + MetaBypassCompositorHint current_value; if (value->type != META_PROP_VALUE_INVALID) - requested_value = (int) value->v.cardinal; + requested_value = (MetaBypassCompositorHint) value->v.cardinal; + else + requested_value = META_BYPASS_COMPOSITOR_HINT_AUTO; + current_value = priv->bypass_compositor; if (requested_value == current_value) return; - if (requested_value == _NET_WM_BYPASS_COMPOSITOR_HINT_ON) + if (requested_value == META_BYPASS_COMPOSITOR_HINT_ON) meta_verbose ("Request to bypass compositor for window %s.\n", window->desc); - else if (requested_value == _NET_WM_BYPASS_COMPOSITOR_HINT_OFF) + else if (requested_value == META_BYPASS_COMPOSITOR_HINT_OFF) meta_verbose ("Request to don't bypass compositor for window %s.\n", window->desc); - else if (requested_value != _NET_WM_BYPASS_COMPOSITOR_HINT_AUTO) + else if (requested_value != META_BYPASS_COMPOSITOR_HINT_AUTO) return; - window->bypass_compositor = requested_value; + priv->bypass_compositor = requested_value; } static void diff --git a/src/x11/window-x11-private.h b/src/x11/window-x11-private.h index 2ffaa85d4..e12f83be0 100644 --- a/src/x11/window-x11-private.h +++ b/src/x11/window-x11-private.h @@ -29,6 +29,16 @@ G_BEGIN_DECLS +/* + * Mirrors _NET_WM_BYPASS_COMPOSITOR preference values. + */ +typedef enum _MetaBypassCompositorHint +{ + META_BYPASS_COMPOSITOR_HINT_AUTO = 0, + META_BYPASS_COMPOSITOR_HINT_ON = 1, + META_BYPASS_COMPOSITOR_HINT_OFF = 2, +} MetaBypassCompositorHint; + typedef struct _MetaWindowX11Private MetaWindowX11Private; struct _MetaWindowX11Private @@ -64,10 +74,16 @@ struct _MetaWindowX11Private /* Freeze/thaw on resize (for Xwayland) */ gboolean thaw_after_paint; + + /* Bypass compositor hints */ + MetaBypassCompositorHint bypass_compositor; }; MetaWindowX11Private * meta_window_x11_get_private (MetaWindowX11 *window_x11); +void meta_window_x11_set_bypass_compositor_hint (MetaWindowX11 *window_x11, + MetaBypassCompositorHint requested_value); + G_END_DECLS #endif diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c index 4ccccad2a..b3ea18717 100644 --- a/src/x11/window-x11.c +++ b/src/x11/window-x11.c @@ -4146,3 +4146,62 @@ meta_window_x11_get_client_rect (MetaWindowX11 *window_x11) return priv->client_rect; } + +static gboolean +has_requested_bypass_compositor (MetaWindowX11 *window_x11) +{ + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + + return priv->bypass_compositor == META_BYPASS_COMPOSITOR_HINT_ON; +} + +static gboolean +has_requested_dont_bypass_compositor (MetaWindowX11 *window_x11) +{ + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + + return priv->bypass_compositor == META_BYPASS_COMPOSITOR_HINT_OFF; +} + +gboolean +meta_window_x11_can_unredirect (MetaWindowX11 *window_x11) +{ + MetaWindow *window = META_WINDOW (window_x11); + + if (has_requested_dont_bypass_compositor (window_x11)) + return FALSE; + + if (window->opacity != 0xFF) + return FALSE; + + if (window->shape_region != NULL) + return FALSE; + + if (!window->monitor) + return FALSE; + + if (window->fullscreen) + return TRUE; + + if (meta_window_is_screen_sized (window)) + return TRUE; + + if (has_requested_bypass_compositor (window_x11)) + return TRUE; + + if (window->override_redirect) + { + MetaRectangle window_rect; + MetaRectangle logical_monitor_layout; + MetaLogicalMonitor *logical_monitor = window->monitor; + + meta_window_get_frame_rect (window, &window_rect); + logical_monitor_layout = + meta_logical_monitor_get_layout (logical_monitor); + + if (meta_rectangle_equal (&window_rect, &logical_monitor_layout)) + return TRUE; + } + + return FALSE; +} diff --git a/src/x11/window-x11.h b/src/x11/window-x11.h index 2952c67d0..0223af781 100644 --- a/src/x11/window-x11.h +++ b/src/x11/window-x11.h @@ -97,4 +97,6 @@ void meta_window_x11_surface_rect_to_client_rect (MetaWindow *window, MetaRectangle *client_rect); MetaRectangle meta_window_x11_get_client_rect (MetaWindowX11 *window_x11); + +gboolean meta_window_x11_can_unredirect (MetaWindowX11 *window_x11); #endif From a829b5b650ec8222b0949f7db0105eef7f91592f Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 20:50:06 +0400 Subject: [PATCH 05/23] clutter/actor: Add semi-private API to check for transitions Transitions are used for animating actors when e.g. going from/to fullscreen, and the like. We need to know such things when deciding whether to avoid compositing a window actor, so make add API visible to mutter that checks whether there are any transitions active. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=bc178b711ffbd8db0b7cfecefb6f67edf4e0254f --- clutter/clutter/clutter-actor.c | 17 +++++++++++++++++ clutter/clutter/clutter-muffin.h | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c index 9d4d36ec3..4e8d53436 100644 --- a/clutter/clutter/clutter-actor.c +++ b/clutter/clutter/clutter-actor.c @@ -20020,6 +20020,23 @@ clutter_actor_get_transition (ClutterActor *self, return clos->transition; } +/** + * clutter_actor_has_transitions: (skip) + */ +gboolean +clutter_actor_has_transitions (ClutterActor *self) +{ + const ClutterAnimationInfo *info; + + g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); + + info = _clutter_actor_get_animation_info_or_defaults (self); + if (info->transitions == NULL) + return FALSE; + + return g_hash_table_size (info->transitions) > 0; +} + /** * clutter_actor_save_easing_state: * @self: a #ClutterActor diff --git a/clutter/clutter/clutter-muffin.h b/clutter/clutter/clutter-muffin.h index c0d9015d8..fe1233ad4 100644 --- a/clutter/clutter/clutter-muffin.h +++ b/clutter/clutter/clutter-muffin.h @@ -83,6 +83,10 @@ void clutter_stage_get_device_coords (ClutterStage *stage, ClutterInputDevice *device, ClutterEventSequence *sequence, graphene_point_t *coords); + +CLUTTER_EXPORT +gboolean clutter_actor_has_transitions (ClutterActor *actor); + #undef __CLUTTER_H_INSIDE__ #endif /* __CLUTTER_MUFFIN_H__ */ From 1def5051ba59a38bcb01cc6c292f4ec0cd490360 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 20:59:17 +0400 Subject: [PATCH 06/23] wayland: Make MetaWaylandBufferRef reference counted So that we can have a more dynamic ownership. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=f36120757f4de3eead9245335bc497c596ed88df --- src/wayland/meta-wayland-surface.c | 13 +++++++++---- src/wayland/meta-wayland-surface.h | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index f2941cb91..323bfa93f 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -128,14 +128,20 @@ meta_wayland_buffer_ref_new (void) MetaWaylandBufferRef *buffer_ref; buffer_ref = g_new0 (MetaWaylandBufferRef, 1); + g_ref_count_init (&buffer_ref->ref_count); return buffer_ref; } static void -meta_wayland_buffer_ref_free (MetaWaylandBufferRef *buffer_ref) +meta_wayland_buffer_ref_unref (MetaWaylandBufferRef *buffer_ref) { - g_free (buffer_ref); + if (g_ref_count_dec (&buffer_ref->ref_count)) + { + g_warn_if_fail (buffer_ref->use_count == 0); + g_clear_object (&buffer_ref->buffer); + g_free (buffer_ref); + } } static void @@ -1365,8 +1371,7 @@ wl_surface_destructor (struct wl_resource *resource) if (surface->buffer_held) meta_wayland_surface_unref_buffer_use_count (surface); g_clear_pointer (&surface->texture, cogl_object_unref); - g_clear_object (&surface->buffer_ref->buffer); - g_clear_pointer (&surface->buffer_ref, meta_wayland_buffer_ref_free); + g_clear_pointer (&surface->buffer_ref, meta_wayland_buffer_ref_unref); g_clear_object (&surface->cached_state); g_clear_object (&surface->pending_state); diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index 16deaaed2..cfc155978 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -142,6 +142,7 @@ struct _MetaWaylandDragDestFuncs typedef struct _MetaWaylandBufferRef { + grefcount ref_count; MetaWaylandBuffer *buffer; unsigned int use_count; } MetaWaylandBufferRef; From 20d4edd12cf39ae5c33d9d832a4cbaed9ea604fb Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 22:29:16 +0400 Subject: [PATCH 07/23] wayland/buffer-ref: Add helpers for use count tracking Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=f8ee974628504e5ca917cf03a9effdd810629332 --- src/wayland/meta-wayland-surface.c | 39 +++++++++++++++++++----------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 323bfa93f..19c590221 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -144,6 +144,29 @@ meta_wayland_buffer_ref_unref (MetaWaylandBufferRef *buffer_ref) } } +static void +meta_wayland_buffer_ref_inc_use_count (MetaWaylandBufferRef *buffer_ref) +{ + g_return_if_fail (buffer_ref->buffer); + g_warn_if_fail (buffer_ref->buffer->resource); + + buffer_ref->use_count++; +} + +static void +meta_wayland_buffer_ref_dec_use_count (MetaWaylandBufferRef *buffer_ref) +{ + MetaWaylandBuffer *buffer = buffer_ref->buffer; + + g_return_if_fail (buffer_ref->use_count > 0); + g_return_if_fail (buffer); + + buffer_ref->use_count--; + + if (buffer_ref->use_count == 0 && buffer->resource) + wl_buffer_send_release (buffer->resource); +} + static void role_assignment_valist_to_properties (GType role_type, const char *first_property_name, @@ -385,25 +408,13 @@ meta_wayland_surface_get_buffer (MetaWaylandSurface *surface) void meta_wayland_surface_ref_buffer_use_count (MetaWaylandSurface *surface) { - g_return_if_fail (surface->buffer_ref->buffer); - g_warn_if_fail (surface->buffer_ref->buffer->resource); - - surface->buffer_ref->use_count++; + meta_wayland_buffer_ref_inc_use_count (surface->buffer_ref); } void meta_wayland_surface_unref_buffer_use_count (MetaWaylandSurface *surface) { - MetaWaylandBuffer *buffer = surface->buffer_ref->buffer; - - g_return_if_fail (surface->buffer_ref->use_count != 0); - - surface->buffer_ref->use_count--; - - g_return_if_fail (buffer); - - if (surface->buffer_ref->use_count == 0 && buffer->resource) - wl_buffer_send_release (buffer->resource); + meta_wayland_buffer_ref_dec_use_count (surface->buffer_ref); } static void From 0e44b94348f06993a32b9c46745d0b07a6dcf9ec Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 23:38:37 +0400 Subject: [PATCH 08/23] cogl/onscreen: Add API to scanout a buffer directly Instead of always swapping buffers and flipping the back buffer, make it possible to scan out a provided buffer directly without swapping any EGL buffers. A buffer is passed as an object implementing the empty CoglScanout interface. It is only possible to do this in the native backend; and the interface is implemented by MetaDrmBufferGbm. When directly scanned out, instead of calling gbm_surface_lock_front_buffer() to get the gbm_bo and fbid, get it directly from the MetaDrmBufferGbm, and use that to create the page flip KMS update. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=3da8c1bfdc1fa486111c1e1dff363fb931612468 --- cogl/cogl/cogl-onscreen.c | 21 +++++ cogl/cogl/cogl-onscreen.h | 9 +++ cogl/cogl/cogl-scanout.c | 27 +++++++ cogl/cogl/cogl-scanout.h | 35 +++++++++ cogl/cogl/cogl.h | 1 + cogl/cogl/meson.build | 2 + cogl/cogl/winsys/cogl-winsys-private.h | 5 ++ src/backends/native/meta-drm-buffer-gbm.c | 12 ++- src/backends/native/meta-renderer-native.c | 90 ++++++++++++++++++---- 9 files changed, 186 insertions(+), 16 deletions(-) create mode 100644 cogl/cogl/cogl-scanout.c create mode 100644 cogl/cogl/cogl-scanout.h diff --git a/cogl/cogl/cogl-onscreen.c b/cogl/cogl/cogl-onscreen.c index 704e1c44b..892a0af3b 100644 --- a/cogl/cogl/cogl-onscreen.c +++ b/cogl/cogl/cogl-onscreen.c @@ -405,6 +405,27 @@ cogl_onscreen_get_buffer_age (CoglOnscreen *onscreen) return winsys->onscreen_get_buffer_age (onscreen); } +void +cogl_onscreen_direct_scanout (CoglOnscreen *onscreen, + CoglScanout *scanout) +{ + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); + const CoglWinsysVtable *winsys; + CoglFrameInfo *info; + + g_return_if_fail (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN); + g_return_if_fail (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT)); + + info = _cogl_frame_info_new (); + info->frame_counter = onscreen->frame_counter; + g_queue_push_tail (&onscreen->pending_frame_infos, info); + + winsys = _cogl_framebuffer_get_winsys (framebuffer); + winsys->onscreen_direct_scanout (onscreen, scanout); + + onscreen->frame_counter++; +} + #ifdef COGL_HAS_X11_SUPPORT uint32_t cogl_x11_onscreen_get_window_xid (CoglOnscreen *onscreen) diff --git a/cogl/cogl/cogl-onscreen.h b/cogl/cogl/cogl-onscreen.h index a7b50e2af..b0f04039c 100644 --- a/cogl/cogl/cogl-onscreen.h +++ b/cogl/cogl/cogl-onscreen.h @@ -50,6 +50,8 @@ G_BEGIN_DECLS typedef struct _CoglOnscreen CoglOnscreen; #define COGL_ONSCREEN(X) ((CoglOnscreen *)(X)) +typedef struct _CoglScanout CoglScanout; + /** * cogl_onscreen_get_gtype: * @@ -284,6 +286,13 @@ cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, const int *rectangles, int n_rectangles); +/** + * cogl_onscreen_direct_scanout: (skip) + */ +void +cogl_onscreen_direct_scanout (CoglOnscreen *onscreen, + CoglScanout *scanout); + /** * cogl_onscreen_swap_region: * @onscreen: A #CoglOnscreen framebuffer diff --git a/cogl/cogl/cogl-scanout.c b/cogl/cogl/cogl-scanout.c new file mode 100644 index 000000000..759cd62a4 --- /dev/null +++ b/cogl/cogl/cogl-scanout.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "cogl-config.h" + +#include "cogl-scanout.h" + +G_DEFINE_INTERFACE (CoglScanout, cogl_scanout, G_TYPE_OBJECT) + +static void +cogl_scanout_default_init (CoglScanoutInterface *iface) +{ +} diff --git a/cogl/cogl/cogl-scanout.h b/cogl/cogl/cogl-scanout.h new file mode 100644 index 000000000..63e1238f0 --- /dev/null +++ b/cogl/cogl/cogl-scanout.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef COGL_SCANOUT_H +#define COGL_SCANOUT_H + +#include "cogl/cogl-types.h" + +#include + +#define COGL_TYPE_SCANOUT (cogl_scanout_get_type ()) +COGL_EXPORT +G_DECLARE_INTERFACE (CoglScanout, cogl_scanout, + COGL, SCANOUT, GObject) + +struct _CoglScanoutInterface +{ + GTypeInterface parent_iface; +}; + +#endif /* COGL_SCANOUT_H */ diff --git a/cogl/cogl/cogl.h b/cogl/cogl/cogl.h index 3fd9b1c64..f3d3aaaae 100644 --- a/cogl/cogl/cogl.h +++ b/cogl/cogl/cogl.h @@ -122,6 +122,7 @@ #include #include #include +#include /* XXX: This will definitly go away once all the Clutter winsys * code has been migrated down into Cogl! */ #include diff --git a/cogl/cogl/meson.build b/cogl/cogl/meson.build index 55523dd3f..daea0df10 100644 --- a/cogl/cogl/meson.build +++ b/cogl/cogl/meson.build @@ -122,6 +122,7 @@ cogl_nonintrospected_headers = [ 'cogl-version.h', 'cogl-gtype-private.h', 'cogl-glib-source.h', + 'cogl-scanout.h', ] cogl_nodist_headers = [ @@ -347,6 +348,7 @@ cogl_sources = [ 'cogl-closure-list.c', 'cogl-fence.c', 'cogl-fence-private.h', + 'cogl-scanout.c', 'deprecated/cogl-material-compat.c', 'deprecated/cogl-program.c', 'deprecated/cogl-program-private.h', diff --git a/cogl/cogl/winsys/cogl-winsys-private.h b/cogl/cogl/winsys/cogl-winsys-private.h index 7781f9004..924cfc43c 100644 --- a/cogl/cogl/winsys/cogl-winsys-private.h +++ b/cogl/cogl/winsys/cogl-winsys-private.h @@ -33,6 +33,7 @@ #include "cogl-renderer.h" #include "cogl-onscreen.h" +#include "cogl-scanout.h" #ifdef COGL_HAS_XLIB_SUPPORT #include "cogl-texture-pixmap-x11-private.h" @@ -116,6 +117,10 @@ typedef struct _CoglWinsysVtable const int *rectangles, int n_rectangles); + void + (*onscreen_direct_scanout) (CoglOnscreen *onscreen, + CoglScanout *scanout); + void (*onscreen_set_visibility) (CoglOnscreen *onscreen, gboolean visibility); diff --git a/src/backends/native/meta-drm-buffer-gbm.c b/src/backends/native/meta-drm-buffer-gbm.c index deb96ff11..85f5ed598 100644 --- a/src/backends/native/meta-drm-buffer-gbm.c +++ b/src/backends/native/meta-drm-buffer-gbm.c @@ -44,7 +44,12 @@ struct _MetaDrmBufferGbm uint32_t fb_id; }; -G_DEFINE_TYPE (MetaDrmBufferGbm, meta_drm_buffer_gbm, META_TYPE_DRM_BUFFER) +static void +cogl_scanout_iface_init (CoglScanoutInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaDrmBufferGbm, meta_drm_buffer_gbm, META_TYPE_DRM_BUFFER, + G_IMPLEMENT_INTERFACE (COGL_TYPE_SCANOUT, + cogl_scanout_iface_init)) struct gbm_bo * meta_drm_buffer_gbm_get_bo (MetaDrmBufferGbm *buffer_gbm) @@ -160,6 +165,11 @@ meta_drm_buffer_gbm_get_fb_id (MetaDrmBuffer *buffer) return META_DRM_BUFFER_GBM (buffer)->fb_id; } +static void +cogl_scanout_iface_init (CoglScanoutInterface *iface) +{ +} + static void meta_drm_buffer_gbm_finalize (GObject *object) { diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index 65bfd40b1..a7102d5cf 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -2013,6 +2013,35 @@ update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen, } } +static void +ensure_crtc_modes (CoglOnscreen *onscreen, + MetaKmsUpdate *kms_update) +{ + CoglOnscreenEGL *onscreen_egl = onscreen->winsys; + MetaOnscreenNative *onscreen_native = onscreen_egl->platform; + CoglContext *cogl_context = COGL_FRAMEBUFFER (onscreen)->context; + CoglRenderer *cogl_renderer = cogl_context->display->renderer; + CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; + MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; + MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; + MetaRenderer *renderer = META_RENDERER (renderer_native); + MetaBackend *backend = meta_renderer_get_backend (renderer); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaPowerSave power_save_mode; + + power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager); + if (onscreen_native->pending_set_crtc && + power_save_mode == META_POWER_SAVE_ON) + { + meta_onscreen_native_set_crtc_mode (onscreen, + renderer_gpu_data, + kms_update); + onscreen_native->pending_set_crtc = FALSE; + } +} + + static MetaKmsUpdate * unset_disabled_crtcs (MetaBackend *backend, MetaKms *kms) @@ -2068,8 +2097,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; MetaRenderer *renderer = META_RENDERER (renderer_native); MetaBackend *backend = meta_renderer_get_backend (renderer); - MetaMonitorManager *monitor_manager = - meta_backend_get_monitor_manager (backend); MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); MetaKms *kms = meta_backend_native_get_kms (backend_native); CoglOnscreenEGL *onscreen_egl = onscreen->winsys; @@ -2078,7 +2105,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, CoglFrameInfo *frame_info; gboolean egl_context_changed = FALSE; MetaKmsUpdate *kms_update; - MetaPowerSave power_save_mode; g_autoptr (GError) error = NULL; MetaDrmBufferGbm *buffer_gbm; g_autoptr (MetaKmsFeedback) kms_feedback = NULL; @@ -2137,18 +2163,7 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed); - /* If this is the first framebuffer to be presented then we now setup the - * crtc modes, else we flip from the previous buffer */ - - power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager); - if (onscreen_native->pending_set_crtc && - power_save_mode == META_POWER_SAVE_ON) - { - meta_onscreen_native_set_crtc_mode (onscreen, - renderer_gpu_data, - kms_update); - onscreen_native->pending_set_crtc = FALSE; - } + ensure_crtc_modes (onscreen, kms_update); onscreen_native->pending_queue_swap_notify_frame_count = renderer_native->frame_counter; meta_onscreen_native_flip_crtcs (onscreen, kms_update); @@ -2239,6 +2254,50 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer, return NULL; } +static void +meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, + CoglScanout *scanout) +{ + CoglOnscreenEGL *onscreen_egl = onscreen->winsys; + MetaOnscreenNative *onscreen_native = onscreen_egl->platform; + MetaGpuKms *render_gpu = onscreen_native->render_gpu; + CoglContext *cogl_context = COGL_FRAMEBUFFER (onscreen)->context; + CoglRenderer *cogl_renderer = cogl_context->display->renderer; + CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; + MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; + MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; + MetaRenderer *renderer = META_RENDERER (renderer_native); + MetaBackend *backend = meta_renderer_get_backend (renderer); + MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); + MetaKms *kms = meta_backend_native_get_kms (backend_native); + CoglFrameInfo *frame_info; + MetaKmsUpdate *kms_update; + g_autoptr (GError) error = NULL; + + kms_update = meta_kms_ensure_pending_update (kms); + + wait_for_pending_flips (onscreen); + + frame_info = g_queue_peek_tail (&onscreen->pending_frame_infos); + frame_info->global_frame_counter = renderer_native->frame_counter; + + renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, + render_gpu); + + g_return_if_fail (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_GBM); + + g_warn_if_fail (!onscreen_native->gbm.next_fb); + g_set_object (&onscreen_native->gbm.next_fb, META_DRM_BUFFER (scanout)); + + ensure_crtc_modes (onscreen, kms_update); + + onscreen_native->pending_queue_swap_notify_frame_count = + renderer_native->frame_counter; + meta_onscreen_native_flip_crtcs (onscreen, kms_update); + + meta_kms_post_pending_update_sync (kms); +} + static gboolean meta_renderer_native_init_egl_context (CoglContext *cogl_context, GError **error) @@ -2962,6 +3021,7 @@ get_native_cogl_winsys_vtable (CoglRenderer *cogl_renderer) vtable.onscreen_swap_region = NULL; vtable.onscreen_swap_buffers_with_damage = meta_onscreen_native_swap_buffers_with_damage; + vtable.onscreen_direct_scanout = meta_onscreen_native_direct_scanout; vtable.context_get_clock_time = meta_renderer_native_get_clock_time; From a26316a1c00f35f9cdd6c097adf9c5e2dcbc1a20 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 00:39:45 +0400 Subject: [PATCH 09/23] clutter/view: Make it possible to assign a temporary direct scanout Make it possible to cause the next frame to scan out directly from the passed CoglScannout. This makes it possible to completely bypass compositing for the following frame. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=753066598ff83fa9bdbd1be23d1e22663ae59297 --- clutter/clutter/clutter-muffin.h | 4 +++ clutter/clutter/clutter-stage-view-private.h | 2 ++ clutter/clutter/clutter-stage-view.c | 24 +++++++++++++++++ clutter/clutter/cogl/clutter-stage-cogl.c | 28 +++++++++++++++++++- cogl/cogl/cogl-onscreen.h | 2 +- 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/clutter/clutter/clutter-muffin.h b/clutter/clutter/clutter-muffin.h index fe1233ad4..3cffda020 100644 --- a/clutter/clutter/clutter-muffin.h +++ b/clutter/clutter/clutter-muffin.h @@ -75,6 +75,10 @@ void clutter_stage_thaw_updates (ClutterStage *stage); CLUTTER_EXPORT void clutter_stage_update_resource_scales (ClutterStage *stage); +CLUTTER_EXPORT +void clutter_stage_view_assign_next_scanout (ClutterStageView *stage_view, + CoglScanout *scanout); + CLUTTER_EXPORT gboolean clutter_actor_has_damage (ClutterActor *actor); diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h index 3b0d419fc..2e5ad4c53 100644 --- a/clutter/clutter/clutter-stage-view-private.h +++ b/clutter/clutter/clutter-stage-view-private.h @@ -43,4 +43,6 @@ const cairo_region_t * clutter_stage_view_peek_redraw_clip (ClutterStageView *vi cairo_region_t * clutter_stage_view_take_redraw_clip (ClutterStageView *view); +CoglScanout * clutter_stage_view_take_scanout (ClutterStageView *view); + #endif /* __CLUTTER_STAGE_VIEW_PRIVATE_H__ */ diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c index d93cf573f..ad6252c2c 100644 --- a/clutter/clutter/clutter-stage-view.c +++ b/clutter/clutter/clutter-stage-view.c @@ -24,6 +24,8 @@ #include #include "clutter/clutter-private.h" +#include "clutter/clutter-muffin.h" +#include "cogl/cogl.h" enum { @@ -52,6 +54,8 @@ typedef struct _ClutterStageViewPrivate CoglOffscreen *shadowfb; CoglPipeline *shadowfb_pipeline; + CoglScanout *next_scanout; + gboolean has_redraw_clip; cairo_region_t *redraw_clip; @@ -407,6 +411,26 @@ clutter_stage_default_get_offscreen_transformation_matrix (ClutterStageView *vie cogl_matrix_init_identity (matrix); } +void +clutter_stage_view_assign_next_scanout (ClutterStageView *view, + CoglScanout *scanout) +{ + ClutterStageViewPrivate *priv = + clutter_stage_view_get_instance_private (view); + + g_clear_object (&priv->next_scanout); + priv->next_scanout = scanout; +} + +CoglScanout * +clutter_stage_view_take_scanout (ClutterStageView *view) +{ + ClutterStageViewPrivate *priv = + clutter_stage_view_get_instance_private (view); + + return g_steal_pointer (&priv->next_scanout); +} + static void clutter_stage_view_get_property (GObject *object, guint prop_id, diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c index bda49ee4d..172ac6014 100644 --- a/clutter/clutter/cogl/clutter-stage-cogl.c +++ b/clutter/clutter/cogl/clutter-stage-cogl.c @@ -989,6 +989,20 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window, } } +static void +clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl, + ClutterStageView *view, + CoglScanout *scanout) +{ + CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view); + CoglOnscreen *onscreen; + + g_return_if_fail (cogl_is_onscreen (framebuffer)); + + onscreen = COGL_ONSCREEN (framebuffer); + cogl_onscreen_direct_scanout (onscreen, scanout); +} + static void clutter_stage_cogl_redraw (ClutterStageWindow *stage_window) { @@ -1016,11 +1030,23 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window) for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next) { ClutterStageView *view = l->data; + g_autoptr (CoglScanout) scanout = NULL; if (!clutter_stage_view_has_redraw_clip (view)) continue; - swap_event |= clutter_stage_cogl_redraw_view (stage_window, view); + scanout = clutter_stage_view_take_scanout (view); + if (scanout) + { + clutter_stage_cogl_scanout_view (stage_cogl, + view, + scanout); + swap_event = TRUE; + } + else + { + swap_event |= clutter_stage_cogl_redraw_view (stage_window, view); + } } if (has_redraw_clip) diff --git a/cogl/cogl/cogl-onscreen.h b/cogl/cogl/cogl-onscreen.h index b0f04039c..e99d8d129 100644 --- a/cogl/cogl/cogl-onscreen.h +++ b/cogl/cogl/cogl-onscreen.h @@ -289,7 +289,7 @@ cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, /** * cogl_onscreen_direct_scanout: (skip) */ -void +COGL_EXPORT void cogl_onscreen_direct_scanout (CoglOnscreen *onscreen, CoglScanout *scanout); From d103bde9dd065ad79fd4cee3475cf931b135d260 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 00:50:05 +0400 Subject: [PATCH 10/23] renderer/native: Add API to get primary GPU Will be used when acquiring scanouts from Wayland buffers. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=3dd8861fbf51183fd69106f55095d444cd37cc34 --- src/backends/native/meta-renderer-native.c | 6 ++++++ src/backends/native/meta-renderer-native.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index a7102d5cf..b31702d4c 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -313,6 +313,12 @@ meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms) return renderer_gpu_data->gbm.device; } +MetaGpuKms * +meta_renderer_native_get_primary_gpu (MetaRendererNative *renderer_native) +{ + return renderer_native->primary_gpu_kms; +} + static MetaRendererNativeGpuData * meta_create_renderer_native_gpu_data (MetaGpuKms *gpu_kms) { diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h index 1f61e261f..29ab67df1 100644 --- a/src/backends/native/meta-renderer-native.h +++ b/src/backends/native/meta-renderer-native.h @@ -51,6 +51,8 @@ MetaRendererNative * meta_renderer_native_new (MetaBackendNative *backend_nativ struct gbm_device * meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms); +MetaGpuKms * meta_renderer_native_get_primary_gpu (MetaRendererNative *renderer_native); + void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native); int64_t meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_native); From 1bac0f251f87772c9df7b9af28b8c0ec79b7c842 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 18:59:26 +0400 Subject: [PATCH 11/23] onscreen/native: Add API to check whether buffer is scanout compatible While this is fairly incomplete, as to check things fully we need to use TEST_ONLY in atomic to try out a complete assignment on the device, but this works well enough for legacy non-modifier cases. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=b9fe9c736a3b7ef298bda5f785938275805a47f0 --- src/backends/native/meta-renderer-native.c | 42 ++++++++++++++++++++++ src/backends/native/meta-renderer-native.h | 5 +++ 2 files changed, 47 insertions(+) diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index b31702d4c..658053bdc 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -2260,6 +2260,48 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer, return NULL; } +gboolean +meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen, + uint32_t drm_format, + uint64_t drm_modifier, + uint32_t stride) +{ + CoglOnscreenEGL *onscreen_egl = onscreen->winsys; + MetaOnscreenNative *onscreen_native = onscreen_egl->platform; + MetaDrmBuffer *fb; + struct gbm_bo *gbm_bo; + + if (onscreen_native->crtc->config->transform != META_MONITOR_TRANSFORM_NORMAL) + return FALSE; + + if (onscreen_native->secondary_gpu_state) + return FALSE; + + if (!onscreen_native->gbm.surface) + return FALSE; + + fb = onscreen_native->gbm.current_fb ? onscreen_native->gbm.current_fb + : onscreen_native->gbm.next_fb; + if (!fb) + return FALSE; + + if (!META_IS_DRM_BUFFER_GBM (fb)) + return FALSE; + + gbm_bo = meta_drm_buffer_gbm_get_bo (META_DRM_BUFFER_GBM (fb)); + + if (gbm_bo_get_format (gbm_bo) != drm_format) + return FALSE; + + if (gbm_bo_get_modifier (gbm_bo) != drm_modifier) + return FALSE; + + if (gbm_bo_get_stride (gbm_bo) != stride) + return FALSE; + + return TRUE; +} + static void meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, CoglScanout *scanout) diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h index 29ab67df1..04260486a 100644 --- a/src/backends/native/meta-renderer-native.h +++ b/src/backends/native/meta-renderer-native.h @@ -59,4 +59,9 @@ int64_t meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_nat void meta_renderer_native_reset_modes (MetaRendererNative *renderer_native); +gboolean meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen, + uint32_t drm_format, + uint64_t drm_modifier, + uint32_t stride); + #endif /* META_RENDERER_NATIVE_H */ From 370213ff59d8f1f6730ca8ab534fbc8f2d38cb68 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 19:09:23 +0400 Subject: [PATCH 12/23] wayland/dma-buf: Don't advertise modifier support by default Advertising support for modifiers means we will most likely not not be able to scan out client buffers directly, meaning it just as likely that we won't be able to scan out even fullscreen windows without atomic KMS. When we have atomic support, we should advertise support for modifiers if atomic is used to drive the CRTCs, as we by then can check whether we can scan out directly, place in an overlay plane, etc. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=cb05b164140dc6934ff5a00cb4354a5dbf4593ef --- src/wayland/meta-wayland-dma-buf.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c index 31ed68a3c..7f8658cf0 100644 --- a/src/wayland/meta-wayland-dma-buf.c +++ b/src/wayland/meta-wayland-dma-buf.c @@ -471,6 +471,15 @@ static const struct zwp_linux_dmabuf_v1_interface dma_buf_implementation = dma_buf_handle_create_buffer_params, }; +static gboolean +should_send_modifiers (MetaBackend *backend) +{ + MetaSettings *settings = meta_backend_get_settings (backend); + + return meta_settings_is_experimental_feature_enabled ( + settings, META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS); +} + static void send_modifiers (struct wl_resource *resource, uint32_t format) @@ -493,6 +502,14 @@ send_modifiers (struct wl_resource *resource, if (wl_resource_get_version (resource) < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) return; + if (!should_send_modifiers (backend)) + { + zwp_linux_dmabuf_v1_send_modifier (resource, format, + DRM_FORMAT_MOD_INVALID >> 32, + DRM_FORMAT_MOD_INVALID & 0xffffffff); + return; + } + /* First query the number of available modifiers, then allocate an array, * then fill the array. */ ret = meta_egl_query_dma_buf_modifiers (egl, egl_display, format, 0, NULL, From 9f57ddf075d6d38310834bba9867571ee3b4eb7b Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 19:12:11 +0400 Subject: [PATCH 13/23] wayland/dma-buf: Handle getting dma-buf from detached buffer handle We might still have a MetaWaylandBuffer for a wl_buffer that was destroyed. Handle trying to fetch the MetaWaylandDmaBufBuffer from such a buffer gracefully. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=4b1805c3065eea293aefb1e3d1dc0ba685bcc1fc --- src/wayland/meta-wayland-dma-buf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c index 7f8658cf0..8c13a5359 100644 --- a/src/wayland/meta-wayland-dma-buf.c +++ b/src/wayland/meta-wayland-dma-buf.c @@ -299,9 +299,12 @@ static const struct wl_buffer_interface dma_buf_buffer_impl = MetaWaylandDmaBufBuffer * meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer) { + if (!buffer->resource) + return NULL; + if (wl_resource_instance_of (buffer->resource, &wl_buffer_interface, &dma_buf_buffer_impl)) - return wl_resource_get_user_data (buffer->resource); + return wl_resource_get_user_data (buffer->resource); return NULL; } From d983b45b81c7107045a1513a315f3bf99c726b13 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 23:13:48 +0400 Subject: [PATCH 14/23] wayland: Add API to acquire a CoglScanout from a surface This will check whether the current backing buffer is compatible with the primary plane of the passed CoglOnscreen. Since this will extend the time before a buffer is released, the MetaWaylandBufferRef is swapped and orphaned if a new buffer is committed before the previous one was released. It'll eventually be released, usually by the next page flip callback. Currently implemented for EGLImage and DMA-BUF buffer types. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=ff7a42b8bc25c24d3e0fc0a277b1d628f5ea599a --- src/wayland/meta-wayland-buffer.c | 92 +++++++++++++++++++++++ src/wayland/meta-wayland-buffer.h | 2 + src/wayland/meta-wayland-dma-buf.c | 116 +++++++++++++++++++++++++++++ src/wayland/meta-wayland-dma-buf.h | 4 + src/wayland/meta-wayland-surface.c | 48 ++++++++++++ src/wayland/meta-wayland-surface.h | 3 + 6 files changed, 265 insertions(+) diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c index d38084fbf..4774ccb2b 100644 --- a/src/wayland/meta-wayland-buffer.c +++ b/src/wayland/meta-wayland-buffer.c @@ -59,6 +59,11 @@ #include "wayland/meta-wayland-dma-buf.h" #include "wayland/meta-wayland-private.h" +#ifdef HAVE_NATIVE_BACKEND +#include "backends/native/meta-drm-buffer-gbm.h" +#include "backends/native/meta-renderer-native.h" +#endif + #ifndef DRM_FORMAT_MOD_INVALID #define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1) #endif @@ -640,6 +645,93 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer, } } +static CoglScanout * +try_acquire_egl_image_scanout (MetaWaylandBuffer *buffer, + CoglOnscreen *onscreen) +{ + #ifdef HAVE_NATIVE_BACKEND + MetaBackend *backend = meta_get_backend (); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); + MetaGpuKms *gpu_kms; + struct gbm_device *gbm_device; + struct gbm_bo *gbm_bo; + uint32_t drm_format; + uint64_t drm_modifier; + uint32_t stride; + MetaDrmBufferGbm *fb; + g_autoptr (GError) error = NULL; + + gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native); + gbm_device = meta_gbm_device_from_gpu (gpu_kms); + + gbm_bo = gbm_bo_import (gbm_device, + GBM_BO_IMPORT_WL_BUFFER, buffer->resource, + GBM_BO_USE_SCANOUT); + if (!gbm_bo) + return NULL; + + drm_format = gbm_bo_get_format (gbm_bo); + drm_modifier = gbm_bo_get_modifier (gbm_bo); + stride = gbm_bo_get_stride (gbm_bo); + if (!meta_onscreen_native_is_buffer_scanout_compatible (onscreen, + drm_format, + drm_modifier, + stride)) + { + gbm_bo_destroy (gbm_bo); + return NULL; + } + + fb = meta_drm_buffer_gbm_new_take (gpu_kms, gbm_bo, + drm_modifier != DRM_FORMAT_MOD_INVALID, + &error); + if (!fb) + { + g_debug ("Failed to create scanout buffer: %s", error->message); + gbm_bo_destroy (gbm_bo); + return NULL; + } + + return COGL_SCANOUT (fb); +#else + return NULL; +#endif +} + +CoglScanout * +meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer *buffer, + CoglOnscreen *onscreen) +{ + switch (buffer->type) + { + case META_WAYLAND_BUFFER_TYPE_SHM: + return NULL; + case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE: + return try_acquire_egl_image_scanout (buffer, onscreen); + #ifdef HAVE_WAYLAND_EGLSTREAM + case META_WAYLAND_BUFFER_TYPE_EGL_STREAM: + return NULL; + #endif + case META_WAYLAND_BUFFER_TYPE_DMA_BUF: + { + MetaWaylandDmaBufBuffer *dma_buf; + + dma_buf = meta_wayland_dma_buf_from_buffer (buffer); + if (!dma_buf) + return NULL; + + return meta_wayland_dma_buf_try_acquire_scanout (dma_buf, onscreen); + } + case META_WAYLAND_BUFFER_TYPE_UNKNOWN: + g_warn_if_reached (); + return NULL; + } + + g_assert_not_reached (); + return NULL; +} + static void meta_wayland_buffer_finalize (GObject *object) { diff --git a/src/wayland/meta-wayland-buffer.h b/src/wayland/meta-wayland-buffer.h index 83607a976..a489bbe5e 100644 --- a/src/wayland/meta-wayland-buffer.h +++ b/src/wayland/meta-wayland-buffer.h @@ -90,5 +90,7 @@ void meta_wayland_buffer_process_damage (MetaWaylandBuff cairo_region_t *region); void meta_wayland_init_shm (MetaWaylandCompositor *compositor); +CoglScanout * meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer *buffer, + CoglOnscreen *onscreen); #endif /* META_WAYLAND_BUFFER_H */ diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c index 8c13a5359..09ddf1df5 100644 --- a/src/wayland/meta-wayland-dma-buf.c +++ b/src/wayland/meta-wayland-dma-buf.c @@ -51,6 +51,11 @@ #include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-versions.h" +#ifdef HAVE_NATIVE_BACKEND +#include "backends/native/meta-drm-buffer-gbm.h" +#include "backends/native/meta-renderer-native.h" +#endif + #include "linux-dmabuf-unstable-v1-server-protocol.h" #ifndef DRM_FORMAT_MOD_INVALID @@ -195,6 +200,117 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer, return TRUE; } +#ifdef HAVE_NATIVE_BACKEND +static struct gbm_bo * +create_gbm_bo (MetaWaylandDmaBufBuffer *dma_buf, + MetaGpuKms *gpu_kms, + int n_planes, + gboolean *use_modifier) +{ + struct gbm_device *gbm_device; + + gbm_device = meta_gbm_device_from_gpu (gpu_kms); + + if (dma_buf->drm_modifier != DRM_FORMAT_MOD_INVALID || + n_planes > 1 || + dma_buf->offsets[0] > 0) + { + struct gbm_import_fd_modifier_data import_with_modifier; + + import_with_modifier = (struct gbm_import_fd_modifier_data) { + .width = dma_buf->width, + .height = dma_buf->height, + .format = dma_buf->drm_format, + .num_fds = n_planes, + .modifier = dma_buf->drm_modifier, + }; + memcpy (import_with_modifier.fds, + dma_buf->fds, + sizeof (dma_buf->fds)); + memcpy (import_with_modifier.strides, + dma_buf->strides, + sizeof (import_with_modifier.strides)); + memcpy (import_with_modifier.offsets, + dma_buf->offsets, + sizeof (import_with_modifier.offsets)); + + *use_modifier = TRUE; + return gbm_bo_import (gbm_device, GBM_BO_IMPORT_FD_MODIFIER, + &import_with_modifier, + GBM_BO_USE_SCANOUT); + } + else + { + struct gbm_import_fd_data import_legacy; + + import_legacy = (struct gbm_import_fd_data) { + .width = dma_buf->width, + .height = dma_buf->height, + .format = dma_buf->drm_format, + .stride = dma_buf->strides[0], + .fd = dma_buf->fds[0], + }; + + *use_modifier = FALSE; + return gbm_bo_import (gbm_device, GBM_BO_IMPORT_FD, + &import_legacy, + GBM_BO_USE_SCANOUT); + } +} +#endif + +CoglScanout * +meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf, + CoglOnscreen *onscreen) +{ + #ifdef HAVE_NATIVE_BACKEND + MetaBackend *backend = meta_get_backend (); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); + MetaGpuKms *gpu_kms; + int n_planes; + uint32_t drm_format; + uint64_t drm_modifier; + uint32_t stride; + struct gbm_bo *gbm_bo; + gboolean use_modifier; + g_autoptr (GError) error = NULL; + MetaDrmBufferGbm *fb; + + for (n_planes = 0; n_planes < META_WAYLAND_DMA_BUF_MAX_FDS; n_planes++) + { + if (dma_buf->fds[n_planes] < 0) + break; + } + + drm_format = dma_buf->drm_format; + drm_modifier = dma_buf->drm_modifier; + stride = dma_buf->strides[0]; + if (!meta_onscreen_native_is_buffer_scanout_compatible (onscreen, + drm_format, + drm_modifier, + stride)) + return NULL; + + gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native); + gbm_bo = create_gbm_bo (dma_buf, gpu_kms, n_planes, &use_modifier); + + fb = meta_drm_buffer_gbm_new_take (gpu_kms, gbm_bo, + use_modifier, + &error); + if (!fb) + { + g_debug ("Failed to create scanout buffer: %s", error->message); + gbm_bo_destroy (gbm_bo); + return NULL; + } + + return COGL_SCANOUT (fb); +#else + return NULL; +#endif +} + static void buffer_params_add (struct wl_client *client, struct wl_resource *resource, diff --git a/src/wayland/meta-wayland-dma-buf.h b/src/wayland/meta-wayland-dma-buf.h index b7f712d8d..cdc65aeb5 100644 --- a/src/wayland/meta-wayland-dma-buf.h +++ b/src/wayland/meta-wayland-dma-buf.h @@ -49,4 +49,8 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer, MetaWaylandDmaBufBuffer * meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer); +CoglScanout * +meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf, + CoglOnscreen *onscreen); + #endif /* META_WAYLAND_DMA_BUF_H */ diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 19c590221..36030e63d 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -133,6 +133,13 @@ meta_wayland_buffer_ref_new (void) return buffer_ref; } +static MetaWaylandBufferRef * +meta_wayland_buffer_ref_ref (MetaWaylandBufferRef *buffer_ref) +{ + g_ref_count_inc (&buffer_ref->ref_count); + return buffer_ref; +} + static void meta_wayland_buffer_ref_unref (MetaWaylandBufferRef *buffer_ref) { @@ -677,6 +684,12 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface, if (surface->buffer_held) meta_wayland_surface_unref_buffer_use_count (surface); + if (surface->buffer_ref->use_count > 0) + { + meta_wayland_buffer_ref_unref (surface->buffer_ref); + surface->buffer_ref = meta_wayland_buffer_ref_new (); + } + g_set_object (&surface->buffer_ref->buffer, state->buffer); if (state->buffer) @@ -2028,3 +2041,38 @@ meta_wayland_surface_get_height (MetaWaylandSurface *surface) return height / surface->scale; } } + +static void +scanout_destroyed (gpointer data, + GObject *where_the_object_was) +{ + MetaWaylandBufferRef *buffer_ref = data; + + meta_wayland_buffer_ref_dec_use_count (buffer_ref); + meta_wayland_buffer_ref_unref (buffer_ref); +} + +CoglScanout * +meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface, + CoglOnscreen *onscreen) +{ + CoglScanout *scanout; + MetaWaylandBufferRef *buffer_ref; + + if (!surface->buffer_ref->buffer) + return NULL; + + if (surface->buffer_ref->use_count == 0) + return NULL; + + scanout = meta_wayland_buffer_try_acquire_scanout (surface->buffer_ref->buffer, + onscreen); + if (!scanout) + return NULL; + + buffer_ref = meta_wayland_buffer_ref_ref (surface->buffer_ref); + meta_wayland_buffer_ref_inc_use_count (buffer_ref); + g_object_weak_ref (G_OBJECT (scanout), scanout_destroyed, buffer_ref); + + return scanout; +} diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index cfc155978..91497d2c8 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -341,6 +341,9 @@ void meta_wayland_surface_update_outputs_recursively (MetaWayland int meta_wayland_surface_get_width (MetaWaylandSurface *surface); int meta_wayland_surface_get_height (MetaWaylandSurface *surface); +CoglScanout * meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface, + CoglOnscreen *onscreen); + static inline GNode * meta_get_next_subsurface_sibling (GNode *n) { From 18e99f317aefea078a64998bdd9ff7130aac5cef Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 23:33:42 +0400 Subject: [PATCH 15/23] util: Move MetaLater to its own file While at it, fix some style inconsistencies, for now use a single singleton struct instead of multiple static variables, and other non-functional cleanups. Semantically, there is no changes introduced. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=d682cdb078f281b03084e3e0d7ab40d3ea382c1f --- src/compositor/meta-later.c | 321 ++++++++++++++++++++++++++++++++++++ src/core/util.c | 285 -------------------------------- src/meson.build | 1 + 3 files changed, 322 insertions(+), 285 deletions(-) create mode 100644 src/compositor/meta-later.c diff --git a/src/compositor/meta-later.c b/src/compositor/meta-later.c new file mode 100644 index 000000000..516fa07b6 --- /dev/null +++ b/src/compositor/meta-later.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2005 Elijah Newren + * Copyright (C) 2020 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "config.h" + +#include "cogl/cogl.h" +#include "meta/util.h" + +typedef struct _MetaLater +{ + unsigned int id; + unsigned int ref_count; + MetaLaterType when; + + GSourceFunc func; + gpointer user_data; + GDestroyNotify destroy_notify; + + guint source_id; + gboolean run_once; +} MetaLater; + +typedef struct _MetaLaters MetaLaters; + +#define META_LATER_N_TYPES (META_LATER_IDLE + 1) + +struct _MetaLaters +{ + unsigned int last_later_id; + + GSList *laters[META_LATER_N_TYPES]; + + ClutterTimeline *timeline; + guint repaint_func; +}; + +static MetaLaters _laters; + +static MetaLater * +meta_later_ref (MetaLater *later) +{ + later->ref_count++; + return later; +} + +static void +meta_later_unref (MetaLater *later) +{ + if (--later->ref_count == 0) + { + if (later->destroy_notify) + { + later->destroy_notify (later->user_data); + later->destroy_notify = NULL; + } + + g_slice_free (MetaLater, later); + } +} + +static void +meta_later_destroy (MetaLater *later) +{ + g_clear_handle_id (&later->source_id, g_source_remove); + later->func = NULL; + meta_later_unref (later); +} + +#ifdef COGL_HAS_TRACING +static const char * +later_type_to_string (MetaLaterType when) +{ + switch (when) + { + case META_LATER_RESIZE: + return "Later (resize)"; + case META_LATER_CALC_SHOWING: + return "Later (calc-showing)"; + case META_LATER_CHECK_FULLSCREEN: + return "Later (check-fullscreen)"; + case META_LATER_SYNC_STACK: + return "Later (sync-stack)"; + case META_LATER_BEFORE_REDRAW: + return "Later (before-redraw)"; + case META_LATER_IDLE: + return "Later (idle)"; + } + + return "unknown"; +} +#endif + +static gboolean +meta_later_invoke (MetaLater *later) +{ + COGL_TRACE_BEGIN_SCOPED (later, later_type_to_string (later->when)); + return later->func (later->user_data); +} + +static gboolean +remove_later_from_list (unsigned int later_id, + GSList **laters_list) +{ + GSList *l; + + for (l = *laters_list; l; l = l->next) + { + MetaLater *later = l->data; + + if (later->id == later_id) + { + *laters_list = g_slist_delete_link (*laters_list, l); + meta_later_destroy (later); + return TRUE; + } + } + + return FALSE; +} + +static void +run_repaint_laters (GSList **laters_list) +{ + g_autoptr (GSList) laters_copy = NULL; + GSList *l; + + for (l = *laters_list; l; l = l->next) + { + MetaLater *later = l->data; + + if (!later->source_id || + (later->when <= META_LATER_BEFORE_REDRAW && !later->run_once)) + laters_copy = g_slist_prepend (laters_copy, meta_later_ref (later)); + } + laters_copy = g_slist_reverse (laters_copy); + + for (l = laters_copy; l; l = l->next) + { + MetaLater *later = l->data; + + if (!later->func) + remove_later_from_list (later->id, laters_list); + else if (!meta_later_invoke (later)) + remove_later_from_list (later->id, laters_list); + + meta_later_unref (later); + } +} + +static gboolean +run_all_repaint_laters (gpointer data) +{ + MetaLaters *laters = data; + unsigned int i; + GSList *l; + gboolean keep_timeline_running = FALSE; + + for (i = 0; i < G_N_ELEMENTS (laters->laters); i++) + run_repaint_laters (&laters->laters[i]); + + for (i = 0; i < G_N_ELEMENTS (laters->laters); i++) + { + for (l = laters->laters[i]; l; l = l->next) + { + MetaLater *later = l->data; + + if (!later->source_id) + keep_timeline_running = TRUE; + } + } + + if (!keep_timeline_running) + clutter_timeline_stop (laters->timeline); + + return TRUE; +} + +static void +ensure_later_repaint_func (MetaLaters *laters) +{ + if (!laters->timeline) + laters->timeline = clutter_timeline_new (G_MAXUINT); + + if (laters->repaint_func == 0) + { + laters->repaint_func = + clutter_threads_add_repaint_func (run_all_repaint_laters, + laters, NULL); + } + + /* Make sure the repaint function gets run */ + clutter_timeline_start (laters->timeline); +} + +static gboolean +invoke_later_idle (gpointer data) +{ + MetaLater *later = data; + + if (!later->func (later->user_data)) + { + meta_later_remove (later->id); + return FALSE; + } + else + { + later->run_once = TRUE; + return TRUE; + } +} + +static unsigned int +meta_laters_add (MetaLaters *laters, + MetaLaterType when, + GSourceFunc func, + gpointer user_data, + GDestroyNotify notify) +{ + MetaLater *later = g_slice_new0 (MetaLater); + + later->id = ++laters->last_later_id; + later->ref_count = 1; + later->when = when; + later->func = func; + later->user_data = user_data; + later->destroy_notify = notify; + + laters->laters[when] = g_slist_prepend (laters->laters[when], later); + + switch (when) + { + case META_LATER_RESIZE: + later->source_id = g_idle_add_full (META_PRIORITY_RESIZE, + invoke_later_idle, + later, NULL); + g_source_set_name_by_id (later->source_id, "[muffin] invoke_later_idle"); + ensure_later_repaint_func (laters); + break; + case META_LATER_CALC_SHOWING: + case META_LATER_CHECK_FULLSCREEN: + case META_LATER_SYNC_STACK: + case META_LATER_BEFORE_REDRAW: + ensure_later_repaint_func (laters); + break; + case META_LATER_IDLE: + later->source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, + invoke_later_idle, + later, NULL); + g_source_set_name_by_id (later->source_id, "[muffin] invoke_later_idle"); + break; + } + + return later->id; +} + +/** + * meta_later_add: + * @when: enumeration value determining the phase at which to run the callback + * @func: callback to run later + * @data: data to pass to the callback + * @notify: function to call to destroy @data when it is no longer in use, or %NULL + * + * Sets up a callback to be called at some later time. @when determines the + * particular later occasion at which it is called. This is much like g_idle_add(), + * except that the functions interact properly with clutter event handling. + * If a "later" function is added from a clutter event handler, and is supposed + * to be run before the stage is redrawn, it will be run before that redraw + * of the stage, not the next one. + * + * Return value: an integer ID (guaranteed to be non-zero) that can be used + * to cancel the callback and prevent it from being run. + */ +unsigned int +meta_later_add (MetaLaterType when, + GSourceFunc func, + gpointer data, + GDestroyNotify notify) +{ + return meta_laters_add (&_laters, when, func, data, notify); +} + +static void +meta_laters_remove (MetaLaters *laters, + unsigned int later_id) +{ + unsigned int i; + + for (i = 0; i < G_N_ELEMENTS (laters->laters); i++) + { + if (remove_later_from_list (later_id, &laters->laters[i])) + return; + } +} + +/** + * meta_later_remove: + * @later_id: the integer ID returned from meta_later_add() + * + * Removes a callback added with meta_later_add() + */ +void +meta_later_remove (unsigned int later_id) +{ + meta_laters_remove (&_laters, later_id); +} diff --git a/src/core/util.c b/src/core/util.c index 3a7f94570..32c90d409 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -50,9 +50,6 @@ meta_topic_real_valist (MetaDebugTopic topic, va_list args) G_GNUC_PRINTF(2, 0); #endif -static gboolean -meta_later_remove_from_list (guint later_id, GSList **laters_list); - static gint verbose_topics = 0; static gboolean is_debugging = FALSE; static gboolean replace_current = FALSE; @@ -704,288 +701,6 @@ meta_show_dialog (const char *type, return child_pid; } -/*************************************************************************** - * Later functions: like idles but integrated with the Clutter repaint loop - ***************************************************************************/ - -static guint last_later_id = 0; - -typedef struct -{ - guint id; - guint ref_count; - MetaLaterType when; - GSourceFunc func; - gpointer data; - GDestroyNotify notify; - int source; - gboolean run_once; -} MetaLater; - -static GSList *laters[] = { - NULL, /* META_LATER_RESIZE */ - NULL, /* META_LATER_CALC_SHOWING */ - NULL, /* META_LATER_CHECK_FULLSCREEN */ - NULL, /* META_LATER_SYNC_STACK */ - NULL, /* META_LATER_BEFORE_REDRAW */ - NULL, /* META_LATER_IDLE */ -}; -/* This is a dummy timeline used to get the Clutter master clock running */ -static ClutterTimeline *later_timeline; -static guint later_repaint_func = 0; - -static void ensure_later_repaint_func (void); - -static void -unref_later (MetaLater *later) -{ - if (--later->ref_count == 0) - { - if (later->notify) - { - later->notify (later->data); - later->notify = NULL; - } - g_slice_free (MetaLater, later); - } -} - -static void -destroy_later (MetaLater *later) -{ - g_clear_handle_id (&later->source, g_source_remove); - later->func = NULL; - unref_later (later); -} - -#ifdef COGL_HAS_TRACING -static const char * -later_type_to_string (MetaLaterType when) -{ - switch (when) - { - case META_LATER_RESIZE: - return "Later (resize)"; - case META_LATER_CALC_SHOWING: - return "Later (calc-showing)"; - case META_LATER_CHECK_FULLSCREEN: - return "Later (check-fullscreen)"; - case META_LATER_SYNC_STACK: - return "Later (sync-stack)"; - case META_LATER_BEFORE_REDRAW: - return "Later (before-redraw)"; - case META_LATER_IDLE: - return "Later (idle)"; - } - - return "unknown"; -} -#endif - -static gboolean -call_later_func (MetaLater *later) -{ - COGL_TRACE_BEGIN_SCOPED (later, later_type_to_string (later->when)); - return later->func (later->data); -} - -static void -run_repaint_laters (GSList **laters_list) -{ - GSList *laters_copy; - GSList *l; - - laters_copy = NULL; - for (l = *laters_list; l; l = l->next) - { - MetaLater *later = l->data; - if (later->source == 0 || - (later->when <= META_LATER_BEFORE_REDRAW && !later->run_once)) - { - later->ref_count++; - laters_copy = g_slist_prepend (laters_copy, later); - } - } - laters_copy = g_slist_reverse (laters_copy); - - for (l = laters_copy; l; l = l->next) - { - MetaLater *later = l->data; - - if (!later->func || !call_later_func (later)) - meta_later_remove_from_list (later->id, laters_list); - unref_later (later); - } - - g_slist_free (laters_copy); -} - -static gboolean -run_all_repaint_laters (gpointer data) -{ - guint i; - GSList *l; - gboolean keep_timeline_running = FALSE; - - for (i = 0; i < G_N_ELEMENTS (laters); i++) - { - run_repaint_laters (&laters[i]); - } - - for (i = 0; i < G_N_ELEMENTS (laters); i++) - { - for (l = laters[i]; l; l = l->next) - { - MetaLater *later = l->data; - - if (later->source == 0) - keep_timeline_running = TRUE; - } - } - - if (!keep_timeline_running) - clutter_timeline_stop (later_timeline); - - /* Just keep the repaint func around - it's cheap if the lists are empty */ - return TRUE; -} - -static void -ensure_later_repaint_func (void) -{ - if (!later_timeline) - later_timeline = clutter_timeline_new (G_MAXUINT); - - if (later_repaint_func == 0) - later_repaint_func = clutter_threads_add_repaint_func (run_all_repaint_laters, - NULL, NULL); - - /* Make sure the repaint function gets run */ - clutter_timeline_start (later_timeline); -} - -static gboolean -call_idle_later (gpointer data) -{ - MetaLater *later = data; - - if (!later->func (later->data)) - { - meta_later_remove (later->id); - return FALSE; - } - else - { - later->run_once = TRUE; - return TRUE; - } -} - -/** - * meta_later_add: - * @when: enumeration value determining the phase at which to run the callback - * @func: callback to run later - * @data: data to pass to the callback - * @notify: function to call to destroy @data when it is no longer in use, or %NULL - * - * Sets up a callback to be called at some later time. @when determines the - * particular later occasion at which it is called. This is much like g_idle_add(), - * except that the functions interact properly with clutter event handling. - * If a "later" function is added from a clutter event handler, and is supposed - * to be run before the stage is redrawn, it will be run before that redraw - * of the stage, not the next one. - * - * Return value: an integer ID (guaranteed to be non-zero) that can be used - * to cancel the callback and prevent it from being run. - */ -guint -meta_later_add (MetaLaterType when, - GSourceFunc func, - gpointer data, - GDestroyNotify notify) -{ - MetaLater *later = g_slice_new0 (MetaLater); - - later->id = ++last_later_id; - later->ref_count = 1; - later->when = when; - later->func = func; - later->data = data; - later->notify = notify; - - laters[when] = g_slist_prepend (laters[when], later); - - switch (when) - { - case META_LATER_RESIZE: - /* We add this one two ways - as a high-priority idle and as a - * repaint func. If we are in a clutter event callback, the repaint - * handler will get hit first, and we'll take care of this function - * there so it gets called before the stage is redrawn, even if - * we haven't gotten back to the main loop. Otherwise, the idle - * handler will get hit first and we want to call this function - * there so it will happen before GTK+ repaints. - */ - later->source = g_idle_add_full (META_PRIORITY_RESIZE, call_idle_later, later, NULL); - g_source_set_name_by_id (later->source, "[muffin] call_idle_later"); - ensure_later_repaint_func (); - break; - case META_LATER_CALC_SHOWING: - case META_LATER_CHECK_FULLSCREEN: - case META_LATER_SYNC_STACK: - case META_LATER_BEFORE_REDRAW: - ensure_later_repaint_func (); - break; - case META_LATER_IDLE: - later->source = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, call_idle_later, later, NULL); - g_source_set_name_by_id (later->source, "[muffin] call_idle_later"); - break; - } - - return later->id; -} - -static gboolean -meta_later_remove_from_list (guint later_id, GSList **laters_list) -{ - GSList *l; - - for (l = *laters_list; l; l = l->next) - { - MetaLater *later = l->data; - - if (later->id == later_id) - { - *laters_list = g_slist_delete_link (*laters_list, l); - /* If this was a "repaint func" later, we just let the - * repaint func run and get removed - */ - destroy_later (later); - return TRUE; - } - } - - return FALSE; -} - -/** - * meta_later_remove: - * @later_id: the integer ID returned from meta_later_add() - * - * Removes a callback added with meta_later_add() - */ -void -meta_later_remove (guint later_id) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (laters); i++) - { - if (meta_later_remove_from_list (later_id, &laters[i])) - return; - } -} - MetaLocaleDirection meta_get_locale_direction (void) { diff --git a/src/meson.build b/src/meson.build index fa0e5c043..786463fd3 100644 --- a/src/meson.build +++ b/src/meson.build @@ -299,6 +299,7 @@ muffin_sources = [ 'compositor/meta-dnd.c', 'compositor/meta-feedback-actor.c', 'compositor/meta-feedback-actor-private.h', + 'compositor/meta-later.c', 'compositor/meta-module.c', 'compositor/meta-module.h', 'compositor/meta-plugin.c', From 5e812043ac05ce7a744c10bb0d950c3aa98a36dc Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Wed, 20 Aug 2025 20:53:21 +0400 Subject: [PATCH 16/23] display: Initialize MetaCompositor in two steps MetaCompositor is the place in muffin that manages the higher level state of compositing, such as handling what happens before and after paint. In order for other units that depend on having a compositor instance active, but should be initialized before the X11 implementation of MetaCompositor registers as a X11 compositing manager, split the initialization of compositing into two steps: 1) Instantiate the object - only construct the instance, making it possible for users to start listening to signals etc 2) Manage - this e.g. establishes the compositor as the X11 compositing manager and similar things. This will enable us to put compositing dependent scattered global variables into a MetaCompositor owned object. For now, compositor management is internally done by calling a new `meta_compositor_do_manage()`, as right now we can't change the API of `meta_compositor_manage()` as it is public. For the next version, manual management of compositing will removed from the public API, and only managed internally. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=dc4fe780f790c8fbd3624a7e75fd25c9a3918d0b --- src/compositor/compositor-private.h | 6 +++- src/compositor/compositor.c | 19 +++++++++-- src/compositor/meta-compositor-server.c | 7 +++-- src/compositor/meta-compositor-x11.c | 32 +++++++++++++++++-- src/core/display.c | 42 +++++-------------------- 5 files changed, 62 insertions(+), 44 deletions(-) diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h index 488a8cc4c..141b77ddf 100644 --- a/src/compositor/compositor-private.h +++ b/src/compositor/compositor-private.h @@ -18,7 +18,8 @@ struct _MetaCompositorClass { GObjectClass parent_class; - void (* manage) (MetaCompositor *compositor); + gboolean (* manage) (MetaCompositor *compositor, + GError **error); void (* unmanage) (MetaCompositor *compositor); void (* pre_paint) (MetaCompositor *compositor); void (* post_paint) (MetaCompositor *compositor); @@ -28,6 +29,9 @@ struct _MetaCompositorClass int64_t time_us); }; +gboolean meta_compositor_do_manage (MetaCompositor *compositor, + GError **error); + void meta_compositor_remove_window_actor (MetaCompositor *compositor, MetaWindowActor *window_actor); diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 66af08546..4f48445e2 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -567,8 +567,9 @@ meta_compositor_redirect_x11_windows (MetaCompositor *compositor) redirect_windows (display->x11_display); } -void -meta_compositor_manage (MetaCompositor *compositor) +gboolean +meta_compositor_do_manage (MetaCompositor *compositor, + GError **error) { MetaCompositorPrivate *priv = meta_compositor_get_instance_private (compositor); @@ -618,11 +619,23 @@ meta_compositor_manage (MetaCompositor *compositor) clutter_actor_add_child (priv->stage, priv->top_window_group); clutter_actor_add_child (priv->stage, priv->feedback_group); - META_COMPOSITOR_GET_CLASS (compositor)->manage (compositor); + if (!META_COMPOSITOR_GET_CLASS (compositor)->manage (compositor, error)) + return FALSE; priv->plugin_mgr = meta_plugin_manager_new (compositor); clutter_actor_show (priv->stage); + + return TRUE; +} + +void +meta_compositor_manage (MetaCompositor *compositor) +{ + GError *error = NULL; + + if (!meta_compositor_do_manage (compositor, &error)) + g_error ("Compositor failed to manage display: %s", error->message); } void diff --git a/src/compositor/meta-compositor-server.c b/src/compositor/meta-compositor-server.c index 1e1d977d5..e568d5f1d 100644 --- a/src/compositor/meta-compositor-server.c +++ b/src/compositor/meta-compositor-server.c @@ -19,6 +19,7 @@ */ #include "config.h" +#include #include "compositor/meta-compositor-server.h" @@ -29,9 +30,11 @@ struct _MetaCompositorServer G_DEFINE_TYPE (MetaCompositorServer, meta_compositor_server, META_TYPE_COMPOSITOR) -static void -meta_compositor_server_manage (MetaCompositor *compositor) +static gboolean +meta_compositor_server_manage (MetaCompositor *compositor, + GError **error) { + return TRUE; } static void diff --git a/src/compositor/meta-compositor-x11.c b/src/compositor/meta-compositor-x11.c index c3c96a5a1..c2ee7d745 100644 --- a/src/compositor/meta-compositor-x11.c +++ b/src/compositor/meta-compositor-x11.c @@ -154,15 +154,39 @@ determine_server_clock_source (MetaCompositorX11 *compositor_x11) compositor_x11->xserver_uses_monotonic_clock = FALSE; } -static void -meta_compositor_x11_manage (MetaCompositor *compositor) +static gboolean +meta_compositor_x11_manage (MetaCompositor *compositor, + GError **error) { MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); MetaDisplay *display = meta_compositor_get_display (compositor); - Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); + MetaX11Display *x11_display = display->x11_display; + Display *xdisplay = meta_x11_display_get_xdisplay (x11_display); + int composite_version; MetaBackend *backend = meta_get_backend (); Window xwindow; + if (!META_X11_DISPLAY_HAS_COMPOSITE (x11_display) || + !META_X11_DISPLAY_HAS_DAMAGE (x11_display)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing required extension %s", + !META_X11_DISPLAY_HAS_COMPOSITE (x11_display) ? + "composite" : "damage"); + return FALSE; + } + + composite_version = ((x11_display->composite_major_version * 10) + + x11_display->composite_minor_version); + if (composite_version < 3) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "COMPOSITE extension 3.0 required (found %d.%d)", + x11_display->composite_major_version, + x11_display->composite_minor_version); + return FALSE; + } + determine_server_clock_source (compositor_x11); meta_x11_display_set_cm_selection (display->x11_display); @@ -204,6 +228,8 @@ meta_compositor_x11_manage (MetaCompositor *compositor) compositor_x11->have_x11_sync_object = meta_sync_ring_init (xdisplay); meta_compositor_redirect_x11_windows (META_COMPOSITOR (compositor)); + + return TRUE; } static void diff --git a/src/core/display.c b/src/core/display.c index 0db2ab0a7..4620a2f21 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -629,39 +629,6 @@ create_compositor (MetaDisplay *display) return META_COMPOSITOR (meta_compositor_x11_new (display)); } -static void -enable_compositor (MetaDisplay *display) -{ - MetaX11Display *x11_display = display->x11_display; - - if (x11_display) - { - if (!META_X11_DISPLAY_HAS_COMPOSITE (x11_display) || - !META_X11_DISPLAY_HAS_DAMAGE (x11_display)) - { - meta_fatal ("Missing %s extension required for compositing", - !META_X11_DISPLAY_HAS_COMPOSITE (x11_display) ? - "composite" : "damage"); - return; - } - - int version = (x11_display->composite_major_version * 10) + - x11_display->composite_minor_version; - if (version < 3) - { - meta_fatal ("Your version of COMPOSITE (%d.%d) is too old. Version 3.0 or later required.", - x11_display->composite_major_version, - x11_display->composite_minor_version); - return; - } - } - - if (!display->compositor) - display->compositor = create_compositor (display); - - meta_compositor_manage (display->compositor); -} - static void meta_display_init (MetaDisplay *disp) { @@ -935,6 +902,8 @@ meta_display_open (void) g_signal_connect (settings, "ui-scaling-factor-changed", G_CALLBACK (on_ui_scaling_factor_changed), display); + display->compositor = create_compositor (display); + meta_display_set_cursor (display, META_CURSOR_DEFAULT); display->stack = meta_stack_new (display); @@ -972,7 +941,6 @@ meta_display_open (void) display->last_focus_time = timestamp; display->last_user_time = timestamp; - display->compositor = NULL; if (!meta_is_wayland_compositor ()) meta_prop_get_window (display->x11_display, @@ -980,7 +948,11 @@ meta_display_open (void) display->x11_display->atom__NET_ACTIVE_WINDOW, &old_active_xwindow); - enable_compositor (display); + if (!meta_compositor_do_manage (display->compositor, &error)) + { + g_error ("Compositor failed to manage display: %s", + error->message); + } if (display->x11_display) { From b2eea8f0d03173daf2bebaeabfac7c7b33919be5 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Wed, 20 Aug 2025 21:45:55 +0400 Subject: [PATCH 17/23] later: Make MetaCompositor the owner of the MetaLaters state Since the order of destruction during MetaDisplay tear down is a bit unordered, there are pieces that try to destruct its compositing dependent pieces (i.e. queued MetaLater callbacks) after MetaCompositor has been cleaned up, meaning we need to put some slightly awkward NULL checks to avoid crashing. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=2e7d02f1ce8cb8eba15968c7facd815a7ce43080 --- src/compositor/compositor-private.h | 4 +++ src/compositor/compositor.c | 16 +++++++++ src/compositor/meta-later-private.h | 27 +++++++++++++++ src/compositor/meta-later.c | 44 ++++++++++++++++++++---- src/meta/meson.build | 1 + src/meta/meta-later.h | 53 +++++++++++++++++++++++++++++ src/meta/util.h | 31 +---------------- 7 files changed, 139 insertions(+), 37 deletions(-) create mode 100644 src/compositor/meta-later-private.h create mode 100644 src/meta/meta-later.h diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h index 141b77ddf..42ca3f4a9 100644 --- a/src/compositor/compositor-private.h +++ b/src/compositor/compositor-private.h @@ -14,6 +14,8 @@ /* Wait 2ms after vblank before starting to draw next frame */ #define META_SYNC_DELAY 2 +typedef struct _MetaLaters MetaLaters; + struct _MetaCompositorClass { GObjectClass parent_class; @@ -73,6 +75,8 @@ ClutterStage * meta_compositor_get_stage (MetaCompositor *compositor); gboolean meta_compositor_is_switching_workspace (MetaCompositor *compositor); +MetaLaters * meta_compositor_get_laters (MetaCompositor *compositor); + void meta_update_desklet_stacking (MetaCompositor *compositor); static inline int64_t diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 4f48445e2..6011d39fc 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -62,6 +62,7 @@ #include "backends/x11/meta-stage-x11.h" #include "clutter/clutter-muffin.h" #include "cogl/cogl.h" +#include "compositor/meta-later-private.h" #include "compositor/meta-window-actor-x11.h" #include "compositor/meta-window-actor-private.h" #include "compositor/meta-window-group-private.h" @@ -132,6 +133,8 @@ typedef struct _MetaCompositorPrivate int switch_workspace_in_progress; MetaPluginManager *plugin_mgr; + + MetaLaters *laters; } MetaCompositorPrivate; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaCompositor, meta_compositor, @@ -1401,6 +1404,8 @@ meta_compositor_init (MetaCompositor *compositor) meta_post_paint_func, compositor, NULL); + + priv->laters = meta_laters_new (); } static void @@ -1410,6 +1415,8 @@ meta_compositor_dispose (GObject *object) MetaCompositorPrivate *priv = meta_compositor_get_instance_private (compositor); + g_clear_pointer (&priv->laters, meta_laters_free); + g_clear_signal_handler (&priv->stage_after_paint_id, priv->stage); g_clear_signal_handler (&priv->stage_presented_id, priv->stage); @@ -1745,6 +1752,15 @@ meta_compositor_is_switching_workspace (MetaCompositor *compositor) return priv->switch_workspace_in_progress > 0; } +MetaLaters * +meta_compositor_get_laters (MetaCompositor *compositor) +{ + MetaCompositorPrivate *priv = + meta_compositor_get_instance_private (compositor); + + return priv->laters; +} + /** * meta_get_x11_background_actor_for_display: * @display: a #MetaDisplay diff --git a/src/compositor/meta-later-private.h b/src/compositor/meta-later-private.h new file mode 100644 index 000000000..b1c88766f --- /dev/null +++ b/src/compositor/meta-later-private.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef META_LATER_PRIVATE_H +#define META_LATER_PRIVATE_H + +typedef struct _MetaLaters MetaLaters; + +MetaLaters * meta_laters_new (void); + +void meta_laters_free (MetaLaters *laters); + +#endif /* META_LATER_PRIVATE_H */ diff --git a/src/compositor/meta-later.c b/src/compositor/meta-later.c index 516fa07b6..a1654c7b3 100644 --- a/src/compositor/meta-later.c +++ b/src/compositor/meta-later.c @@ -19,8 +19,12 @@ #include "config.h" +#include "compositor/meta-later-private.h" + #include "cogl/cogl.h" -#include "meta/util.h" +#include "compositor/compositor-private.h" +#include "core/display-private.h" +#include "meta/meta-later.h" typedef struct _MetaLater { @@ -36,8 +40,6 @@ typedef struct _MetaLater gboolean run_once; } MetaLater; -typedef struct _MetaLaters MetaLaters; - #define META_LATER_N_TYPES (META_LATER_IDLE + 1) struct _MetaLaters @@ -50,8 +52,6 @@ struct _MetaLaters guint repaint_func; }; -static MetaLaters _laters; - static MetaLater * meta_later_ref (MetaLater *later) { @@ -292,7 +292,11 @@ meta_later_add (MetaLaterType when, gpointer data, GDestroyNotify notify) { - return meta_laters_add (&_laters, when, func, data, notify); + MetaDisplay *display = meta_get_display (); + MetaCompositor *compositor = display->compositor; + + return meta_laters_add (meta_compositor_get_laters (compositor), + when, func, data, notify); } static void @@ -317,5 +321,31 @@ meta_laters_remove (MetaLaters *laters, void meta_later_remove (unsigned int later_id) { - meta_laters_remove (&_laters, later_id); + MetaDisplay *display = meta_get_display (); + MetaCompositor *compositor = display->compositor; + + if (!compositor) + return; + + meta_laters_remove (meta_compositor_get_laters (compositor), later_id); +} + +MetaLaters * +meta_laters_new (void) +{ + return g_new0 (MetaLaters, 1); +} + +void +meta_laters_free (MetaLaters *laters) +{ + unsigned int i; + + for (i = 0; i < G_N_ELEMENTS (laters->laters); i++) + g_slist_free_full (laters->laters[i], (GDestroyNotify) meta_later_unref); + + g_clear_object (&laters->timeline); + if (laters->repaint_func) + clutter_threads_remove_repaint_func (laters->repaint_func); + g_free (laters); } diff --git a/src/meta/meson.build b/src/meta/meson.build index e3b18daf4..d895e88dc 100644 --- a/src/meta/meson.build +++ b/src/meta/meson.build @@ -19,6 +19,7 @@ muffin_public_headers = [ 'meta-idle-monitor.h', 'meta-inhibit-shortcuts-dialog.h', 'meta-launch-context.h', + 'meta-later.h', 'meta-monitor-manager.h', 'meta-plugin.h', 'meta-remote-access-controller.h', diff --git a/src/meta/meta-later.h b/src/meta/meta-later.h new file mode 100644 index 000000000..25b3f91a7 --- /dev/null +++ b/src/meta/meta-later.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2005 Elijah Newren + * Copyright (C) 2020 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef META_LATER_H +#define META_LATER_H + +/** + * MetaLaterType: + * @META_LATER_RESIZE: call in a resize processing phase that is done + * before GTK+ repainting (including window borders) is done. + * @META_LATER_CALC_SHOWING: used by Mutter to compute which windows should be mapped + * @META_LATER_CHECK_FULLSCREEN: used by Mutter to see if there's a fullscreen window + * @META_LATER_SYNC_STACK: used by Mutter to send it's idea of the stacking order to the server + * @META_LATER_BEFORE_REDRAW: call before the stage is redrawn + * @META_LATER_IDLE: call at a very low priority (can be blocked + * by running animations or redrawing applications) + **/ +typedef enum +{ + META_LATER_RESIZE, + META_LATER_CALC_SHOWING, + META_LATER_CHECK_FULLSCREEN, + META_LATER_SYNC_STACK, + META_LATER_BEFORE_REDRAW, + META_LATER_IDLE +} MetaLaterType; + +META_EXPORT +guint meta_later_add (MetaLaterType when, + GSourceFunc func, + gpointer data, + GDestroyNotify notify); + +META_EXPORT +void meta_later_remove (guint later_id); + +#endif /* META_LATER_H */ diff --git a/src/meta/util.h b/src/meta/util.h index 323898ee8..ea24b946d 100644 --- a/src/meta/util.h +++ b/src/meta/util.h @@ -27,6 +27,7 @@ #include #include +#include META_EXPORT gboolean meta_is_verbose (void); @@ -186,36 +187,6 @@ GPid meta_show_dialog (const char *type, #endif /* !WITH_VERBOSE_MODE */ -/** - * MetaLaterType: - * @META_LATER_RESIZE: call in a resize processing phase that is done - * before GTK+ repainting (including window borders) is done. - * @META_LATER_CALC_SHOWING: used by Mutter to compute which windows should be mapped - * @META_LATER_CHECK_FULLSCREEN: used by Mutter to see if there's a fullscreen window - * @META_LATER_SYNC_STACK: used by Mutter to send it's idea of the stacking order to the server - * @META_LATER_BEFORE_REDRAW: call before the stage is redrawn - * @META_LATER_IDLE: call at a very low priority (can be blocked - * by running animations or redrawing applications) - **/ -typedef enum -{ - META_LATER_RESIZE, - META_LATER_CALC_SHOWING, - META_LATER_CHECK_FULLSCREEN, - META_LATER_SYNC_STACK, - META_LATER_BEFORE_REDRAW, - META_LATER_IDLE -} MetaLaterType; - -META_EXPORT -guint meta_later_add (MetaLaterType when, - GSourceFunc func, - gpointer data, - GDestroyNotify notify); - -META_EXPORT -void meta_later_remove (guint later_id); - typedef enum { META_LOCALE_DIRECTION_LTR, From 6019359f7334a6da2a6a5b8d83af9b4c1333799e Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Wed, 20 Aug 2025 22:02:53 +0400 Subject: [PATCH 18/23] later: Listen to MetaCompositor signal instead of clutter We need to coordinate with MetaCompositor during pre-paint so that we have control over whether MetaLater callbacks happen first, or the MetaCompositor pre-paint logic. In order to do so, make MetaLater listen to a new signal "pre-paint" on MetaCompositor, that is called MetaCompositors own pre-paint handling. This fixes an issue where the top window actor was calculated after the MetaCompositor pre-paint handling, meaning the top actor being painted was out-of-date. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=b51c468c0facc3be5df597a6fe0c8c35b95a1fff --- src/compositor/compositor.c | 22 ++++++++++++-- src/compositor/meta-later-private.h | 3 +- src/compositor/meta-later.c | 46 ++++++++++++++--------------- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 6011d39fc..73ff31832 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -99,6 +99,15 @@ enum static GParamSpec *obj_props[N_PROPS] = { NULL, }; +enum +{ + PRE_PAINT, + + N_SIGNALS +}; + +static guint signals[N_SIGNALS]; + typedef struct _MetaCompositorPrivate { GObject parent; @@ -1277,7 +1286,8 @@ meta_compositor_pre_paint (MetaCompositor *compositor) { COGL_TRACE_BEGIN_SCOPED (MetaCompositorPrePaint, "Compositor (pre-paint)"); - META_COMPOSITOR_GET_CLASS (compositor)->pre_paint (compositor); + + g_signal_emit (compositor, signals[PRE_PAINT], 0); } static gboolean @@ -1405,7 +1415,7 @@ meta_compositor_init (MetaCompositor *compositor) compositor, NULL); - priv->laters = meta_laters_new (); + priv->laters = meta_laters_new (compositor); } static void @@ -1461,6 +1471,14 @@ meta_compositor_class_init (MetaCompositorClass *klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, obj_props); + + signals[PRE_PAINT] = + g_signal_new ("pre-paint", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MetaCompositorClass, pre_paint), + NULL, NULL, NULL, + G_TYPE_NONE, 0); } /** diff --git a/src/compositor/meta-later-private.h b/src/compositor/meta-later-private.h index b1c88766f..c8d0f80a8 100644 --- a/src/compositor/meta-later-private.h +++ b/src/compositor/meta-later-private.h @@ -19,8 +19,9 @@ #define META_LATER_PRIVATE_H typedef struct _MetaLaters MetaLaters; +typedef struct _MetaCompositor MetaCompositor; -MetaLaters * meta_laters_new (void); +MetaLaters * meta_laters_new (MetaCompositor *compositor); void meta_laters_free (MetaLaters *laters); diff --git a/src/compositor/meta-later.c b/src/compositor/meta-later.c index a1654c7b3..f51e43797 100644 --- a/src/compositor/meta-later.c +++ b/src/compositor/meta-later.c @@ -44,12 +44,14 @@ typedef struct _MetaLater struct _MetaLaters { + MetaCompositor *compositor; + unsigned int last_later_id; GSList *laters[META_LATER_N_TYPES]; ClutterTimeline *timeline; - guint repaint_func; + gulong pre_paint_handler_id; }; static MetaLater * @@ -163,10 +165,10 @@ run_repaint_laters (GSList **laters_list) } } -static gboolean -run_all_repaint_laters (gpointer data) +static void +on_pre_paint (MetaCompositor *compositor, + MetaLaters *laters) { - MetaLaters *laters = data; unsigned int i; GSList *l; gboolean keep_timeline_running = FALSE; @@ -187,24 +189,11 @@ run_all_repaint_laters (gpointer data) if (!keep_timeline_running) clutter_timeline_stop (laters->timeline); - - return TRUE; } static void -ensure_later_repaint_func (MetaLaters *laters) +ensure_timeline_running (MetaLaters *laters) { - if (!laters->timeline) - laters->timeline = clutter_timeline_new (G_MAXUINT); - - if (laters->repaint_func == 0) - { - laters->repaint_func = - clutter_threads_add_repaint_func (run_all_repaint_laters, - laters, NULL); - } - - /* Make sure the repaint function gets run */ clutter_timeline_start (laters->timeline); } @@ -250,13 +239,13 @@ meta_laters_add (MetaLaters *laters, invoke_later_idle, later, NULL); g_source_set_name_by_id (later->source_id, "[muffin] invoke_later_idle"); - ensure_later_repaint_func (laters); + ensure_timeline_running (laters); break; case META_LATER_CALC_SHOWING: case META_LATER_CHECK_FULLSCREEN: case META_LATER_SYNC_STACK: case META_LATER_BEFORE_REDRAW: - ensure_later_repaint_func (laters); + ensure_timeline_running (laters); break; case META_LATER_IDLE: later->source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, @@ -331,9 +320,19 @@ meta_later_remove (unsigned int later_id) } MetaLaters * -meta_laters_new (void) +meta_laters_new (MetaCompositor *compositor) { - return g_new0 (MetaLaters, 1); + MetaLaters *laters; + + laters = g_new0 (MetaLaters, 1); + laters->compositor = compositor; + laters->timeline = clutter_timeline_new (G_MAXUINT); + + laters->pre_paint_handler_id = g_signal_connect (compositor, "pre-paint", + G_CALLBACK (on_pre_paint), + laters); + + return laters; } void @@ -345,7 +344,6 @@ meta_laters_free (MetaLaters *laters) g_slist_free_full (laters->laters[i], (GDestroyNotify) meta_later_unref); g_clear_object (&laters->timeline); - if (laters->repaint_func) - clutter_threads_remove_repaint_func (laters->repaint_func); + g_clear_signal_handler (&laters->pre_paint_handler_id, laters->compositor); g_free (laters); } From 06ca96f899b7fdf44193cf1cbddc6cb8a8ba865d Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Wed, 20 Aug 2025 22:46:56 +0400 Subject: [PATCH 19/23] compositor: Add support for direct scanout of Wayland surfaces Try to bypass compositing if there is a fullscreen toplevel window with a buffer compatible with the primary plane of the monitor it is fullscreen on. Only non-mirrored is currently supported; as well as fullscreened on a single monitor. It should be possible to extend with more cases, but this starts small. It does this by introducing a new MetaCompositor sub type MetaCompositorNative specific to the native backend, which derives from MetaCompositorServer, containing functionality only relevant for when running on top of the native backend. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=65a6c4c361b7dad10b19f9bcabdcf7b576d7daa0 --- clutter/clutter/clutter-stage-view.c | 3 +- src/compositor/meta-compositor-native.c | 148 ++++++++++++++++++++ src/compositor/meta-compositor-native.h | 32 +++++ src/compositor/meta-compositor-server.c | 5 - src/compositor/meta-compositor-server.h | 9 +- src/compositor/meta-surface-actor-wayland.c | 15 ++ src/compositor/meta-surface-actor-wayland.h | 4 + src/core/display.c | 13 +- src/meson.build | 6 +- 9 files changed, 221 insertions(+), 14 deletions(-) create mode 100644 src/compositor/meta-compositor-native.c create mode 100644 src/compositor/meta-compositor-native.h diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c index ad6252c2c..2db98fa9e 100644 --- a/clutter/clutter/clutter-stage-view.c +++ b/clutter/clutter/clutter-stage-view.c @@ -418,8 +418,7 @@ clutter_stage_view_assign_next_scanout (ClutterStageView *view, ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); - g_clear_object (&priv->next_scanout); - priv->next_scanout = scanout; + g_set_object (&priv->next_scanout, scanout); } CoglScanout * diff --git a/src/compositor/meta-compositor-native.c b/src/compositor/meta-compositor-native.c new file mode 100644 index 000000000..0acb08c82 --- /dev/null +++ b/src/compositor/meta-compositor-native.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2019 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#include "config.h" + +#include "compositor/meta-compositor-native.h" + +#include "backends/meta-logical-monitor.h" +#include "compositor/meta-surface-actor-wayland.h" + +struct _MetaCompositorNative +{ + MetaCompositorServer parent; +}; + +G_DEFINE_TYPE (MetaCompositorNative, meta_compositor_native, + META_TYPE_COMPOSITOR_SERVER) + +static MetaRendererView * +get_window_view (MetaRenderer *renderer, + MetaWindow *window) +{ + GList *l; + MetaRendererView *view_found = NULL; + + for (l = meta_renderer_get_views (renderer); l; l = l->next) + { + ClutterStageView *stage_view = l->data; + MetaRectangle view_layout; + + clutter_stage_view_get_layout (stage_view, &view_layout); + + if (meta_rectangle_equal (&window->buffer_rect, + &view_layout)) + { + if (view_found) + return NULL; + view_found = META_RENDERER_VIEW (stage_view); + } + } + + return view_found; +} + +static void +maybe_assign_primary_plane (MetaCompositor *compositor) +{ + MetaBackend *backend = meta_get_backend (); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaWindowActor *window_actor; + MetaWindow *window; + MetaRendererView *view; + CoglFramebuffer *framebuffer; + CoglOnscreen *onscreen; + MetaSurfaceActor *surface_actor; + MetaSurfaceActorWayland *surface_actor_wayland; + g_autoptr (CoglScanout) scanout = NULL; + + if (meta_compositor_is_unredirect_inhibited (compositor)) + return; + + window_actor = meta_compositor_get_top_window_actor (compositor); + if (!window_actor) + return; + + if (meta_window_actor_effect_in_progress (window_actor)) + return; + + if (clutter_actor_has_transitions (CLUTTER_ACTOR (window_actor))) + return; + + if (clutter_actor_get_n_children (CLUTTER_ACTOR (window_actor)) != 1) + return; + + window = meta_window_actor_get_meta_window (window_actor); + if (!window) + return; + + view = get_window_view (renderer, window); + if (!view) + return; + + framebuffer = clutter_stage_view_get_framebuffer (CLUTTER_STAGE_VIEW (view)); + if (!cogl_is_onscreen (framebuffer)) + return; + + surface_actor = meta_window_actor_get_surface (window_actor); + if (!META_IS_SURFACE_ACTOR_WAYLAND (surface_actor)) + return; + + surface_actor_wayland = META_SURFACE_ACTOR_WAYLAND (surface_actor); + onscreen = COGL_ONSCREEN (framebuffer); + scanout = meta_surface_actor_wayland_try_acquire_scanout (surface_actor_wayland, + onscreen); + if (!scanout) + return; + + clutter_stage_view_assign_next_scanout (CLUTTER_STAGE_VIEW (view), scanout); +} + +static void +meta_compositor_native_pre_paint (MetaCompositor *compositor) +{ + MetaCompositorClass *parent_class; + + maybe_assign_primary_plane (compositor); + + parent_class = META_COMPOSITOR_CLASS (meta_compositor_native_parent_class); + parent_class->pre_paint (compositor); +} + +MetaCompositorNative * +meta_compositor_native_new (MetaDisplay *display) +{ + return g_object_new (META_TYPE_COMPOSITOR_NATIVE, + "display", display, + NULL); +} + +static void +meta_compositor_native_init (MetaCompositorNative *compositor_native) +{ +} + +static void +meta_compositor_native_class_init (MetaCompositorNativeClass *klass) +{ + MetaCompositorClass *compositor_class = META_COMPOSITOR_CLASS (klass); + + compositor_class->pre_paint = meta_compositor_native_pre_paint; +} diff --git a/src/compositor/meta-compositor-native.h b/src/compositor/meta-compositor-native.h new file mode 100644 index 000000000..d276a5905 --- /dev/null +++ b/src/compositor/meta-compositor-native.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#ifndef META_COMPOSITOR_NATIVE_H +#define META_COMPOSITOR_NATIVE_H + +#include "compositor/meta-compositor-server.h" + +#define META_TYPE_COMPOSITOR_NATIVE (meta_compositor_native_get_type ()) +G_DECLARE_FINAL_TYPE (MetaCompositorNative, meta_compositor_native, + META, COMPOSITOR_NATIVE, MetaCompositor) + +MetaCompositorNative * meta_compositor_native_new (MetaDisplay *display); + +#endif /* META_COMPOSITOR_NATIVE_H */ diff --git a/src/compositor/meta-compositor-server.c b/src/compositor/meta-compositor-server.c index e568d5f1d..6bfe447cf 100644 --- a/src/compositor/meta-compositor-server.c +++ b/src/compositor/meta-compositor-server.c @@ -23,11 +23,6 @@ #include "compositor/meta-compositor-server.h" -struct _MetaCompositorServer -{ - MetaCompositor parent; -}; - G_DEFINE_TYPE (MetaCompositorServer, meta_compositor_server, META_TYPE_COMPOSITOR) static gboolean diff --git a/src/compositor/meta-compositor-server.h b/src/compositor/meta-compositor-server.h index 8bff05e7b..7339105f5 100644 --- a/src/compositor/meta-compositor-server.h +++ b/src/compositor/meta-compositor-server.h @@ -24,8 +24,13 @@ #include "compositor/compositor-private.h" #define META_TYPE_COMPOSITOR_SERVER (meta_compositor_server_get_type ()) -G_DECLARE_FINAL_TYPE (MetaCompositorServer, meta_compositor_server, - META, COMPOSITOR_SERVER, MetaCompositor) +G_DECLARE_DERIVABLE_TYPE (MetaCompositorServer, meta_compositor_server, + META, COMPOSITOR_SERVER, MetaCompositor) + +struct _MetaCompositorServerClass +{ + MetaCompositorClass parent_class; +}; MetaCompositorServer * meta_compositor_server_new (MetaDisplay *display); diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c index e8d946e98..ce50da162 100644 --- a/src/compositor/meta-surface-actor-wayland.c +++ b/src/compositor/meta-surface-actor-wayland.c @@ -71,6 +71,21 @@ meta_surface_actor_wayland_is_opaque (MetaSurfaceActor *actor) return meta_shaped_texture_is_opaque (stex); } +CoglScanout * +meta_surface_actor_wayland_try_acquire_scanout (MetaSurfaceActorWayland *self, + CoglOnscreen *onscreen) +{ + MetaWaylandSurface *surface; + CoglScanout *scanout; + + surface = meta_surface_actor_wayland_get_surface (self); + scanout = meta_wayland_surface_try_acquire_scanout (surface, onscreen); + if (!scanout) + return NULL; + + return scanout; +} + static void meta_surface_actor_wayland_dispose (GObject *object) { diff --git a/src/compositor/meta-surface-actor-wayland.h b/src/compositor/meta-surface-actor-wayland.h index e1ad843f7..241217265 100644 --- a/src/compositor/meta-surface-actor-wayland.h +++ b/src/compositor/meta-surface-actor-wayland.h @@ -52,6 +52,10 @@ void meta_surface_actor_wayland_get_subsurface_rect (MetaSurfaceActorWayland *se void meta_surface_actor_wayland_add_frame_callbacks (MetaSurfaceActorWayland *self, struct wl_list *frame_callbacks); +CoglScanout * meta_surface_actor_wayland_try_acquire_scanout (MetaSurfaceActorWayland *self, + CoglOnscreen *onscreen); + G_END_DECLS #endif /* __META_SURFACE_ACTOR_WAYLAND_H__ */ + diff --git a/src/core/display.c b/src/core/display.c index 4620a2f21..da0134c4f 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -51,6 +51,7 @@ #include "backends/x11/meta-backend-x11.h" #include "backends/x11/meta-event-x11.h" #include "backends/x11/cm/meta-backend-x11-cm.h" +#include "backends/x11/nested/meta-backend-x11-nested.h" #include "clutter/x11/clutter-x11.h" #include "compositor/compositor-private.h" #include "compositor/meta-compositor-x11.h" @@ -81,6 +82,7 @@ #include "x11/xprops.h" #ifdef HAVE_WAYLAND +#include "compositor/meta-compositor-native.h" #include "compositor/meta-compositor-server.h" #include "wayland/meta-xwayland-private.h" #include "wayland/meta-wayland-tablet-seat.h" @@ -622,11 +624,16 @@ static MetaCompositor * create_compositor (MetaDisplay *display) { #ifdef HAVE_WAYLAND - if (meta_is_wayland_compositor ()) + MetaBackend *backend = meta_get_backend (); + +#ifdef HAVE_NATIVE_BACKEND + if (META_IS_BACKEND_NATIVE (backend)) + return META_COMPOSITOR (meta_compositor_native_new (display)); +#endif + if (META_IS_BACKEND_X11_NESTED (backend)) return META_COMPOSITOR (meta_compositor_server_new (display)); - else #endif - return META_COMPOSITOR (meta_compositor_x11_new (display)); + return META_COMPOSITOR (meta_compositor_x11_new (display)); } static void diff --git a/src/meson.build b/src/meson.build index 786463fd3..0fc308368 100644 --- a/src/meson.build +++ b/src/meson.build @@ -290,6 +290,8 @@ muffin_sources = [ 'compositor/meta-background-group.c', 'compositor/meta-background-image.c', 'compositor/meta-background-private.h', + 'compositor/meta-compositor-server.c', + 'compositor/meta-compositor-server.h', 'compositor/meta-compositor-x11.c', 'compositor/meta-compositor-x11.h', 'compositor/meta-cullable.c', @@ -482,8 +484,6 @@ if have_wayland 'compositor/meta-surface-actor-wayland.h', 'compositor/meta-window-actor-wayland.c', 'compositor/meta-window-actor-wayland.h', - 'compositor/meta-compositor-server.c', - 'compositor/meta-compositor-server.h', 'wayland/meta-cursor-sprite-wayland.c', 'wayland/meta-cursor-sprite-wayland.h', 'wayland/meta-pointer-confinement-wayland.c', @@ -697,6 +697,8 @@ if have_native_backend 'backends/native/meta-virtual-input-device-native.h', 'backends/native/meta-xkb-utils.c', 'backends/native/meta-xkb-utils.h', + 'compositor/meta-compositor-native.c', + 'compositor/meta-compositor-native.h', ] endif From 93d805ac6c099068c008f2628bfd074b9142d681 Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Thu, 21 Aug 2025 16:14:16 +0400 Subject: [PATCH 20/23] debian: update symbols for libmuffin0 --- debian/libmuffin0.symbols | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/debian/libmuffin0.symbols b/debian/libmuffin0.symbols index e81451b6e..1afaf1c76 100644 --- a/debian/libmuffin0.symbols +++ b/debian/libmuffin0.symbols @@ -217,6 +217,7 @@ libmuffin-clutter-0.so.0 libmuffin0 #MINVER# clutter_actor_has_mapped_clones@Base 5.3.0 clutter_actor_has_overlaps@Base 5.3.0 clutter_actor_has_pointer@Base 5.3.0 + clutter_actor_has_transitions@Base 6.4.1 clutter_actor_hide@Base 5.3.0 clutter_actor_inhibit_culling@Base 5.3.0 clutter_actor_insert_child_above@Base 5.3.0 @@ -1159,6 +1160,7 @@ libmuffin-clutter-0.so.0 libmuffin0 #MINVER# clutter_stage_state_get_type@Base 5.3.0 clutter_stage_thaw_updates@Base 5.3.0 clutter_stage_update_resource_scales@Base 5.3.0 + clutter_stage_view_assign_next_scanout@Base 6.4.1 clutter_stage_view_cogl_get_type@Base 5.3.0 clutter_stage_view_get_framebuffer@Base 5.3.0 clutter_stage_view_get_layout@Base 5.3.0 @@ -1772,6 +1774,7 @@ libmuffin-cogl-0.so.0 libmuffin0 #MINVER# cogl_onscreen_add_dirty_callback@Base 5.3.0 cogl_onscreen_add_frame_callback@Base 5.3.0 cogl_onscreen_add_resize_callback@Base 5.3.0 + cogl_onscreen_direct_scanout@Base 6.4.1 cogl_onscreen_dirty_closure_get_gtype@Base 5.3.0 cogl_onscreen_get_buffer_age@Base 5.3.0 cogl_onscreen_get_frame_counter@Base 5.3.0 @@ -1906,6 +1909,7 @@ libmuffin-cogl-0.so.0 libmuffin0 #MINVER# cogl_renderer_set_custom_winsys@Base 5.3.0 cogl_renderer_set_driver@Base 5.3.0 cogl_renderer_set_winsys_id@Base 5.3.0 + cogl_scanout_get_type@Base 6.4.1 cogl_set_backface_culling_enabled@Base 5.3.0 cogl_set_depth_test_enabled@Base 5.3.0 cogl_set_tracing_disabled_on_thread@Base 5.3.0 @@ -2688,8 +2692,6 @@ libmuffin.so.0 libmuffin0 #MINVER# meta_window_move_resize_frame@Base 5.3.0 meta_window_move_to_monitor@Base 5.3.0 meta_window_raise@Base 5.3.0 - meta_window_requested_bypass_compositor@Base 5.3.0 - meta_window_requested_dont_bypass_compositor@Base 5.3.0 meta_window_set_compositor_private@Base 5.3.0 meta_window_set_demands_attention@Base 5.3.0 meta_window_set_icon_geometry@Base 5.3.0 From 6578318f4f8d0d9b58bd3113e204b506cf01f607 Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Sat, 20 Sep 2025 21:15:45 +0400 Subject: [PATCH 21/23] Fix build --- src/wayland/meta-wayland-xdg-shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c index 44ff6bfde..abecd8ca0 100644 --- a/src/wayland/meta-wayland-xdg-shell.c +++ b/src/wayland/meta-wayland-xdg-shell.c @@ -836,7 +836,7 @@ meta_wayland_xdg_toplevel_post_apply_state (MetaWaylandSurfaceRole *surface_rol META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_toplevel_parent_class); surface_role_class->post_apply_state (surface_role, pending); - if (!surface->buffer_ref.buffer) + if (!surface->buffer_ref->buffer) return; window_geometry = meta_wayland_xdg_surface_get_window_geometry (xdg_surface); From e55d0a0faee9567ed376fc73b05efa1656eba698 Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Sat, 20 Sep 2025 21:49:25 +0400 Subject: [PATCH 22/23] Fix build --- src/wayland/meta-wayland-subsurface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c index 741fbf6ae..b2343ffff 100644 --- a/src/wayland/meta-wayland-subsurface.c +++ b/src/wayland/meta-wayland-subsurface.c @@ -147,7 +147,7 @@ meta_wayland_subsurface_union_geometry (MetaWaylandSubsurface *subsurface, .height = meta_wayland_surface_get_height (surface), }; - if (surface->buffer_ref.buffer) + if (surface->buffer_ref->buffer) meta_rectangle_union (out_geometry, &geometry, out_geometry); META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface) From c60db700cc27458caa893b63bf65bf223dd31fd1 Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Sun, 28 Sep 2025 11:01:22 +0400 Subject: [PATCH 23/23] wayland/dma-buf: Handle failing to import scanout DMA buffer --- src/wayland/meta-wayland-dma-buf.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c index 09ddf1df5..36e55cab2 100644 --- a/src/wayland/meta-wayland-dma-buf.c +++ b/src/wayland/meta-wayland-dma-buf.c @@ -202,10 +202,10 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer, #ifdef HAVE_NATIVE_BACKEND static struct gbm_bo * -create_gbm_bo (MetaWaylandDmaBufBuffer *dma_buf, - MetaGpuKms *gpu_kms, - int n_planes, - gboolean *use_modifier) +import_scanout_gbm_bo (MetaWaylandDmaBufBuffer *dma_buf, + MetaGpuKms *gpu_kms, + int n_planes, + gboolean *use_modifier) { struct gbm_device *gbm_device; @@ -293,7 +293,12 @@ meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf, return NULL; gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native); - gbm_bo = create_gbm_bo (dma_buf, gpu_kms, n_planes, &use_modifier); + gbm_bo = import_scanout_gbm_bo (dma_buf, gpu_kms, n_planes, &use_modifier); + if (!gbm_bo) + { + g_debug ("Failed to import scanout gbm_bo: %s", g_strerror (errno)); + return NULL; + } fb = meta_drm_buffer_gbm_new_take (gpu_kms, gbm_bo, use_modifier,