From 2c6918f72392da5b71735c318e26dbd94503dd84 Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Mon, 18 Aug 2025 16:46:36 +0400 Subject: [PATCH 01/27] 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 bf92b7c00..4e0ff5225 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 38e41fadb..8dbe22422 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -123,6 +123,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, @@ -358,30 +374,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); } @@ -645,7 +661,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); @@ -752,7 +768,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); } @@ -800,7 +817,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, @@ -1349,7 +1366,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); @@ -1611,6 +1629,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); @@ -1891,7 +1912,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 4a54afe78..9e577ec68 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 80a41cc46..fdfc2ae87 100644 --- a/src/wayland/meta-wayland-xdg-shell.c +++ b/src/wayland/meta-wayland-xdg-shell.c @@ -805,7 +805,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, @@ -1211,7 +1211,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); @@ -1222,7 +1222,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, @@ -1253,7 +1253,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); @@ -1661,7 +1661,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; } @@ -1730,7 +1730,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, @@ -2436,7 +2436,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 0f289674f8711148061e4ba3d18fadbb3db9be8a Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 20:01:16 +0400 Subject: [PATCH 02/27] 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 790da1a58..f54551b78 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 efae29fdd5c14009d6618609ccf02314c4e5b513 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 20:21:25 +0400 Subject: [PATCH 03/27] 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 1f52aa097..47450992f 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 8415dcfc7..09daaed21 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 fae6a930635da36fb467530598fb141212d182ee Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 20:41:51 +0400 Subject: [PATCH 04/27] 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 09f920845..4cfc428cf 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 09daaed21..993c8d494 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 469ddbb09f8969ff858713c58c887dc85d502f06 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 20:50:06 +0400 Subject: [PATCH 05/27] 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 c6a98b33df64338df9c386a854f549478038ca82 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 20:59:17 +0400 Subject: [PATCH 06/27] 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 8dbe22422..b297e848d 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -129,14 +129,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 @@ -1366,8 +1372,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 9e577ec68..b72b7e15c 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 09066db5315dae57781558e5229a75ddc7b03baf Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 22:29:16 +0400 Subject: [PATCH 07/27] 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 b297e848d..854c3324d 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -145,6 +145,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, @@ -386,25 +409,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 b9839b6eacf9a7d288c10f0fb385244b4edd3c9c Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Mon, 18 Aug 2025 23:38:37 +0400 Subject: [PATCH 08/27] 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 f54551b78..542715278 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); @@ -2243,6 +2258,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) @@ -2966,6 +3025,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 6f5cddba13c1134e419e5ca13197cd57d63912cf Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 00:39:45 +0400 Subject: [PATCH 09/27] 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 | 3 ++- 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(+), 3 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 12a069b87..407193cff 100644 --- a/clutter/clutter/clutter-stage-view-private.h +++ b/clutter/clutter/clutter-stage-view-private.h @@ -54,11 +54,12 @@ const cairo_region_t * clutter_stage_view_peek_redraw_clip (ClutterStageView *vi cairo_region_t * clutter_stage_view_take_redraw_clip (ClutterStageView *view); - void clutter_stage_view_transform_rect_to_onscreen (ClutterStageView *view, const cairo_rectangle_int_t *src_rect, int dst_width, int dst_height, cairo_rectangle_int_t *dst_rect); +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 d3a8f375a..7021a8996 100644 --- a/clutter/clutter/clutter-stage-view.c +++ b/clutter/clutter/clutter-stage-view.c @@ -25,6 +25,8 @@ #include "clutter/clutter-damage-history.h" #include "clutter/clutter-private.h" +#include "clutter/clutter-muffin.h" +#include "cogl/cogl.h" enum { @@ -64,6 +66,8 @@ typedef struct _ClutterStageViewPrivate CoglOffscreen *framebuffer; } shadow; + CoglScanout *next_scanout; + gboolean has_redraw_clip; cairo_region_t *redraw_clip; @@ -923,6 +927,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 c931855bd..2f5097f2d 100644 --- a/clutter/clutter/cogl/clutter-stage-cogl.c +++ b/clutter/clutter/cogl/clutter-stage-cogl.c @@ -793,6 +793,20 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window, return res; } +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) { @@ -820,11 +834,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 d054eb27a479a3d0a89b4e3c0eb9bd2f4a6a2320 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 00:50:05 +0400 Subject: [PATCH 10/27] 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 542715278..e2ed01c12 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 ba9706cbded2324dc40b404d019098fad883f080 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 18:59:26 +0400 Subject: [PATCH 11/27] 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 e2ed01c12..9d335990a 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -2264,6 +2264,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 d65bb6472815b494d5c32eb0fcb89e7c0d183028 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 19:09:23 +0400 Subject: [PATCH 12/27] 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 3236dd255716aa5f12acfec12a2d4d1b1ce1cae4 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 19:12:11 +0400 Subject: [PATCH 13/27] 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 d8481e04f509687dfaa20428a2da5ae87e70c1e2 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 23:13:48 +0400 Subject: [PATCH 14/27] 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 | 49 ++++++++++++ src/wayland/meta-wayland-surface.h | 3 + 6 files changed, 266 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 854c3324d..7c9a711d8 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -134,6 +134,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) { @@ -678,6 +685,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) @@ -2038,6 +2051,42 @@ meta_wayland_surface_get_height (MetaWaylandSurface *surface) } } +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; + +} + void meta_wayland_surface_notify_actor_changed (MetaWaylandSurface *surface) { diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index b72b7e15c..8bb7116f8 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -343,6 +343,9 @@ void meta_wayland_surface_notify_actor_changed (MetaWaylandSurfac 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 f0de49a8e495415348b33b6241835d2e421ab2c8 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Tue, 19 Aug 2025 23:33:42 +0400 Subject: [PATCH 15/27] 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 e40d74c37..5d8d32944 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 6056fb6bdfc746c3e1159868a754ed94cfc2eaa9 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Wed, 20 Aug 2025 20:53:21 +0400 Subject: [PATCH 16/27] 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 f715ff4ec..c6ecbbe1b 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 58ffc4e3a80a6bc79020141c740edc45ef68aec9 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Wed, 20 Aug 2025 21:45:55 +0400 Subject: [PATCH 17/27] 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 f48bc604a6e3f2cc112f933cb6baa5400db20441 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Wed, 20 Aug 2025 22:02:53 +0400 Subject: [PATCH 18/27] 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 88e6bdaf38687aa5d0cbe54ed740f6b70b987a27 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Wed, 20 Aug 2025 22:46:56 +0400 Subject: [PATCH 19/27] 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 7021a8996..99cc2cd72 100644 --- a/clutter/clutter/clutter-stage-view.c +++ b/clutter/clutter/clutter-stage-view.c @@ -934,8 +934,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 c6ecbbe1b..91a5c548e 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 5d8d32944..2ea93bd97 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', @@ -699,6 +699,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 bfd97cb89ebcb550e67e913328aed89b63a9edea Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Thu, 21 Aug 2025 16:14:16 +0400 Subject: [PATCH 20/27] 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 1ccb69f21..dee3e3926 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 @@ -1780,6 +1782,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 @@ -1914,6 +1917,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 @@ -2697,8 +2701,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 3b066b3e507b74e0f45e745faac3a9b024d1b751 Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Sat, 20 Sep 2025 21:15:45 +0400 Subject: [PATCH 21/27] 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 fdfc2ae87..988123857 100644 --- a/src/wayland/meta-wayland-xdg-shell.c +++ b/src/wayland/meta-wayland-xdg-shell.c @@ -864,7 +864,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 d895b01edf0989616c136bd07f82b71ab58b13e9 Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Sat, 20 Sep 2025 21:49:25 +0400 Subject: [PATCH 22/27] 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 3c9b5c73c6e81ff3e773992417b041bb84788a86 Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Sun, 28 Sep 2025 11:01:22 +0400 Subject: [PATCH 23/27] 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, From 05b81e6a756ef3d45ca80cfa1d5c57d27c991499 Mon Sep 17 00:00:00 2001 From: Sunderland93 Date: Mon, 2 Feb 2026 18:54:26 +0400 Subject: [PATCH 24/27] Use custom page flip function when retrying failed flips When using its EGLStream-based presentation path with the proprietary NVIDIA driver, mutter will use a different function to process page flips - custom_egl_stream_page_flip. If that fails due to an EBUSY error, it will attempt to retry the flip. However, when retrying, it unconditionally uses the libdrm-based path. In practice, this causes a segfault when attempting to access plane_assignments->fb_id, since plane_assignments will be NULL in the EGLStream case. This patch has muffin also use the custom page flip function when retrying the failed flip. --- src/backends/native/meta-kms-impl-simple.c | 46 ++++++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/backends/native/meta-kms-impl-simple.c b/src/backends/native/meta-kms-impl-simple.c index 0ddabf3c2..a687d78c6 100644 --- a/src/backends/native/meta-kms-impl-simple.c +++ b/src/backends/native/meta-kms-impl-simple.c @@ -319,6 +319,8 @@ typedef struct _RetryPageFlipData MetaKmsPageFlipData *page_flip_data; float refresh_rate; uint64_t retry_time_us; + MetaKmsCustomPageFlipFunc custom_page_flip_func; + gpointer custom_page_flip_user_data; } RetryPageFlipData; static void @@ -370,6 +372,7 @@ retry_page_flips (gpointer user_data) int fd; int ret; MetaKmsPageFlipData *page_flip_data; + MetaKmsCustomPageFlipFunc custom_page_flip_func; if (is_timestamp_earlier_than (now_us, retry_page_flip_data->retry_time_us)) @@ -378,12 +381,22 @@ retry_page_flips (gpointer user_data) continue; } - fd = meta_kms_impl_device_get_fd (impl_device); - ret = drmModePageFlip (fd, - meta_kms_crtc_get_id (crtc), - retry_page_flip_data->fb_id, - DRM_MODE_PAGE_FLIP_EVENT, - retry_page_flip_data->page_flip_data); + custom_page_flip_func = retry_page_flip_data->custom_page_flip_func; + if (custom_page_flip_func) + { + ret = custom_page_flip_func (retry_page_flip_data->custom_page_flip_user_data, + retry_page_flip_data->page_flip_data); + } + else + { + fd = meta_kms_impl_device_get_fd (impl_device); + ret = drmModePageFlip (fd, + meta_kms_crtc_get_id (crtc), + retry_page_flip_data->fb_id, + DRM_MODE_PAGE_FLIP_EVENT, + retry_page_flip_data->page_flip_data); + } + if (ret == -EBUSY) { float refresh_rate; @@ -451,11 +464,13 @@ retry_page_flips (gpointer user_data) } static void -schedule_retry_page_flip (MetaKmsImplSimple *impl_simple, - MetaKmsCrtc *crtc, - uint32_t fb_id, - float refresh_rate, - MetaKmsPageFlipData *page_flip_data) +schedule_retry_page_flip (MetaKmsImplSimple *impl_simple, + MetaKmsCrtc *crtc, + uint32_t fb_id, + float refresh_rate, + MetaKmsPageFlipData *page_flip_data, + MetaKmsCustomPageFlipFunc custom_page_flip_func, + gpointer custom_page_flip_user_data) { RetryPageFlipData *retry_page_flip_data; uint64_t now_us; @@ -471,6 +486,8 @@ schedule_retry_page_flip (MetaKmsImplSimple *impl_simple, .page_flip_data = meta_kms_page_flip_data_ref (page_flip_data), .refresh_rate = refresh_rate, .retry_time_us = retry_time_us, + .custom_page_flip_func = custom_page_flip_func, + .custom_page_flip_user_data = custom_page_flip_user_data, }; if (!impl_simple->retry_page_flips_source) @@ -677,9 +694,12 @@ process_page_flip (MetaKmsImpl *impl, refresh_rate = meta_calculate_drm_mode_refresh_rate (drm_mode); schedule_retry_page_flip (impl_simple, crtc, - plane_assignment->fb_id, + plane_assignment ? + plane_assignment->fb_id : 0, refresh_rate, - page_flip_data); + page_flip_data, + custom_page_flip_func, + page_flip->custom_page_flip_user_data); } else { From 48634803ce964fa5ed35b60e57a7d91085d9b691 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Sun, 15 Feb 2026 20:46:43 +0400 Subject: [PATCH 25/27] backends: force enable modifiers on tagged devices Some devices can't scanout to linear buffers directly as the hw is not capable of eg rendering into a linear depth buffer. Add code to force kms-modifiers on udev taged devices. --- data/61-muffin.rules | 1 + data/meson.build | 6 ++++++ meson.build | 5 +++++ meson_options.txt | 6 ++++++ src/backends/native/meta-backend-native.c | 3 +++ src/backends/native/meta-gpu-kms.c | 9 +++++++++ src/backends/native/meta-gpu-kms.h | 1 + src/backends/native/meta-kms-types.h | 1 + src/backends/native/meta-renderer-native.c | 9 +++++++++ src/backends/native/meta-renderer-native.h | 2 ++ src/backends/native/meta-udev.c | 21 +++++++++++++++++++++ src/backends/native/meta-udev.h | 2 ++ src/wayland/meta-wayland-dma-buf.c | 9 +++++++++ 13 files changed, 75 insertions(+) create mode 100644 data/61-muffin.rules diff --git a/data/61-muffin.rules b/data/61-muffin.rules new file mode 100644 index 000000000..4f50cf1b0 --- /dev/null +++ b/data/61-muffin.rules @@ -0,0 +1 @@ +DRIVER=="tegra-host1x", SUBSYSTEM=="platform", TAG+="muffin-device-requires-kms-modifiers" diff --git a/data/meson.build b/data/meson.build index aba5c8e9c..00cafcb34 100644 --- a/data/meson.build +++ b/data/meson.build @@ -44,3 +44,9 @@ configure_file( install_dir: schemadir ) +if have_libgudev + install_data(['61-muffin.rules'], + install_dir: join_paths(udev_dir, 'rules.d'), + ) +endif + diff --git a/meson.build b/meson.build index aebefe68f..41366236e 100644 --- a/meson.build +++ b/meson.build @@ -175,6 +175,11 @@ have_libgudev = get_option('udev') if have_libgudev libudev_dep = dependency('libudev', version: udev_req) gudev_dep = dependency('gudev-1.0', version: gudev_req) + udev_dep = dependency('udev') + udev_dir = get_option('udev_dir') + if udev_dir == '' + udev_dir = udev_dep.get_variable('udevdir') + endif endif have_native_backend = get_option('native_backend') diff --git a/meson_options.txt b/meson_options.txt index 9b6fb1fb8..c11d483f4 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -69,6 +69,12 @@ option('udev', description: 'Enable udev support when using the X11 backend' ) +option('udev_dir', + type: 'string', + value: '', + description: 'Absolute path of the udev base directory' +) + option('libwacom', type: 'boolean', value: true, diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c index d5dd674bb..9d8eb4842 100644 --- a/src/backends/native/meta-backend-native.c +++ b/src/backends/native/meta-backend-native.c @@ -523,6 +523,9 @@ create_gpu_from_udev_device (MetaBackendNative *native, if (meta_is_udev_device_boot_vga (device)) flags |= META_KMS_DEVICE_FLAG_BOOT_VGA; + if (meta_is_udev_device_requires_modifiers (device)) + flags |= META_KMS_DEVICE_FLAG_REQUIRES_MODIFIERS; + device_path = g_udev_device_get_device_file (device); kms_device = meta_kms_create_device (native->kms, device_path, flags, diff --git a/src/backends/native/meta-gpu-kms.c b/src/backends/native/meta-gpu-kms.c index a475933ad..2e2ed3ccf 100644 --- a/src/backends/native/meta-gpu-kms.c +++ b/src/backends/native/meta-gpu-kms.c @@ -274,6 +274,15 @@ meta_gpu_kms_is_platform_device (MetaGpuKms *gpu_kms) return !!(flags & META_KMS_DEVICE_FLAG_PLATFORM_DEVICE); } +gboolean +meta_gpu_kms_requires_modifiers (MetaGpuKms *gpu_kms) +{ + MetaKmsDeviceFlag flags; + + flags = meta_kms_device_get_flags (gpu_kms->kms_device); + return !!(flags & META_KMS_DEVICE_FLAG_REQUIRES_MODIFIERS); +} + static int compare_outputs (gconstpointer one, gconstpointer two) diff --git a/src/backends/native/meta-gpu-kms.h b/src/backends/native/meta-gpu-kms.h index f14e385b7..bc2c43665 100644 --- a/src/backends/native/meta-gpu-kms.h +++ b/src/backends/native/meta-gpu-kms.h @@ -47,6 +47,7 @@ gboolean meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms, gboolean meta_gpu_kms_is_boot_vga (MetaGpuKms *gpu_kms); gboolean meta_gpu_kms_is_platform_device (MetaGpuKms *gpu_kms); +gboolean meta_gpu_kms_requires_modifiers (MetaGpuKms *gpu_kms); gboolean meta_gpu_kms_wait_for_flip (MetaGpuKms *gpu_kms, GError **error); diff --git a/src/backends/native/meta-kms-types.h b/src/backends/native/meta-kms-types.h index ec36d226a..1fed7e332 100644 --- a/src/backends/native/meta-kms-types.h +++ b/src/backends/native/meta-kms-types.h @@ -56,6 +56,7 @@ typedef enum _MetaKmsDeviceFlag META_KMS_DEVICE_FLAG_NONE = 0, META_KMS_DEVICE_FLAG_BOOT_VGA = 1 << 0, META_KMS_DEVICE_FLAG_PLATFORM_DEVICE = 1 << 1, + META_KMS_DEVICE_FLAG_REQUIRES_MODIFIERS = 1 << 2, } MetaKmsDeviceFlag; typedef enum _MetaKmsPlaneType MetaKmsPlaneType; diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index 9d335990a..fd2272df3 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -333,6 +333,12 @@ meta_renderer_native_get_egl (MetaRendererNative *renderer_native) return meta_backend_get_egl (meta_renderer_get_backend (renderer)); } +gboolean +meta_renderer_native_use_modifiers (MetaRendererNative *renderer_native) +{ + return renderer_native->use_modifiers; +} + static MetaEgl * meta_onscreen_native_get_egl (MetaOnscreenNative *onscreen_native) { @@ -4019,6 +4025,9 @@ meta_renderer_native_initable_init (GInitable *initable, if (!renderer_native->primary_gpu_kms) return FALSE; + if (meta_gpu_kms_requires_modifiers (renderer_native->primary_gpu_kms)) + renderer_native->use_modifiers = TRUE; + return TRUE; } diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h index 04260486a..c75356843 100644 --- a/src/backends/native/meta-renderer-native.h +++ b/src/backends/native/meta-renderer-native.h @@ -55,6 +55,8 @@ MetaGpuKms * meta_renderer_native_get_primary_gpu (MetaRendererNative *renderer_ void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native); +gboolean meta_renderer_native_use_modifiers (MetaRendererNative *renderer_native); + int64_t meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_native); void meta_renderer_native_reset_modes (MetaRendererNative *renderer_native); diff --git a/src/backends/native/meta-udev.c b/src/backends/native/meta-udev.c index 2f19c8c9c..1c8851102 100644 --- a/src/backends/native/meta-udev.c +++ b/src/backends/native/meta-udev.c @@ -74,6 +74,27 @@ meta_is_udev_device_boot_vga (GUdevDevice *device) return g_udev_device_get_sysfs_attr_as_int (pci_device, "boot_vga") == 1; } +gboolean +meta_is_udev_device_requires_modifiers (GUdevDevice *device) +{ + g_autoptr (GUdevDevice) platform_device = NULL; + const char * const * tags; + + platform_device = g_udev_device_get_parent_with_subsystem (device, + "platform", + NULL); + + if (!platform_device) + return FALSE; + + tags = g_udev_device_get_tags (platform_device); + + if (!tags) + return FALSE; + + return g_strv_contains (tags, "muffin-device-requires-kms-modifiers"); +} + gboolean meta_udev_is_drm_device (MetaUdev *udev, GUdevDevice *device) diff --git a/src/backends/native/meta-udev.h b/src/backends/native/meta-udev.h index cf72acd1b..eb90abb09 100644 --- a/src/backends/native/meta-udev.h +++ b/src/backends/native/meta-udev.h @@ -32,6 +32,8 @@ gboolean meta_is_udev_device_platform_device (GUdevDevice *device); gboolean meta_is_udev_device_boot_vga (GUdevDevice *device); +gboolean meta_is_udev_device_requires_modifiers (GUdevDevice *device); + gboolean meta_udev_is_drm_device (MetaUdev *udev, GUdevDevice *device); diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c index 36e55cab2..b1c503c89 100644 --- a/src/wayland/meta-wayland-dma-buf.c +++ b/src/wayland/meta-wayland-dma-buf.c @@ -600,6 +600,15 @@ should_send_modifiers (MetaBackend *backend) { MetaSettings *settings = meta_backend_get_settings (backend); + #ifdef HAVE_NATIVE_BACKEND + if (META_IS_BACKEND_NATIVE (backend)) + { + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); + return meta_renderer_native_use_modifiers (renderer_native); + } + #endif + return meta_settings_is_experimental_feature_enabled ( settings, META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS); } From 76854a0c0e27e3b8a0be51139682bc566d262e1f Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Sun, 15 Feb 2026 21:06:26 +0400 Subject: [PATCH 26/27] add missing systemd-dev dependency --- debian/control | 1 + debian/libmuffin0.install | 1 + 2 files changed, 2 insertions(+) diff --git a/debian/control b/debian/control index dfb38956d..f9f5fdeb3 100644 --- a/debian/control +++ b/debian/control @@ -60,6 +60,7 @@ Build-Depends: libxt-dev, meson (>= 1.0.0), pkg-config (>= 0.22), + systemd-dev [linux-any], udev [linux-any], wayland-protocols (>= 1.23) [linux-any], xauth , diff --git a/debian/libmuffin0.install b/debian/libmuffin0.install index e66f14384..af222b1b4 100644 --- a/debian/libmuffin0.install +++ b/debian/libmuffin0.install @@ -1,3 +1,4 @@ usr/lib/*/libmuffin.so.* usr/lib/*/muffin/*.so.* +usr/lib/udev/rules.d/61-muffin.rules usr/libexec/muffin-restart-helper From bbfa8ecca75f6cb1fb56594df50c02892e6e3909 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Wed, 18 Feb 2026 20:31:18 +0400 Subject: [PATCH 27/27] compositor/native: fix parent class --- src/compositor/meta-compositor-native.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compositor/meta-compositor-native.h b/src/compositor/meta-compositor-native.h index d276a5905..60ec7992b 100644 --- a/src/compositor/meta-compositor-native.h +++ b/src/compositor/meta-compositor-native.h @@ -25,7 +25,7 @@ #define META_TYPE_COMPOSITOR_NATIVE (meta_compositor_native_get_type ()) G_DECLARE_FINAL_TYPE (MetaCompositorNative, meta_compositor_native, - META, COMPOSITOR_NATIVE, MetaCompositor) + META, COMPOSITOR_NATIVE, MetaCompositorServer) MetaCompositorNative * meta_compositor_native_new (MetaDisplay *display);