Backport fix for software cursors artifacts

Resolves: RHEL-58079
Resolves: RHEL-81897
This commit is contained in:
Jonas Ådahl 2025-03-12 23:00:37 +08:00
parent 7d87e29721
commit efbeeeb09a
3 changed files with 448 additions and 0 deletions

View File

@ -0,0 +1,178 @@
From cedeee4eb0c252d2450b7174b35f47ff5c27fc8e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 12 Mar 2025 11:35:17 +0800
Subject: [PATCH 1/2] backends: Update stage views and stage dimension from
MetaStage
This reduces the amount of code duplication between the native and
nested backend.
---
src/backends/meta-stage-impl-private.h | 2 ++
src/backends/meta-stage-impl.c | 12 ++++++++++++
src/backends/meta-stage-private.h | 2 ++
src/backends/meta-stage.c | 16 ++++++++++++++++
src/backends/native/meta-backend-native.c | 5 +----
src/backends/native/meta-stage-native.c | 12 ------------
src/backends/native/meta-stage-native.h | 2 --
.../x11/nested/meta-backend-x11-nested.c | 11 ++---------
8 files changed, 35 insertions(+), 27 deletions(-)
diff --git a/src/backends/meta-stage-impl-private.h b/src/backends/meta-stage-impl-private.h
index 766c283488..93b8bbad2f 100644
--- a/src/backends/meta-stage-impl-private.h
+++ b/src/backends/meta-stage-impl-private.h
@@ -64,4 +64,6 @@ MetaBackend * meta_stage_impl_get_backend (MetaStageImpl *stage_impl);
void meta_stage_impl_add_onscreen_frame_info (MetaStageImpl *stage_impl,
ClutterStageView *view);
+void meta_stage_impl_rebuild_views (MetaStageImpl *stage_impl);
+
G_END_DECLS
diff --git a/src/backends/meta-stage-impl.c b/src/backends/meta-stage-impl.c
index 945e95ff2b..804d77f25d 100644
--- a/src/backends/meta-stage-impl.c
+++ b/src/backends/meta-stage-impl.c
@@ -34,6 +34,7 @@
#include <stdlib.h>
#include <math.h>
+#include "backends/meta-renderer.h"
#include "backends/meta-stage-view-private.h"
#include "clutter/clutter-mutter.h"
#include "cogl/cogl.h"
@@ -907,3 +908,14 @@ meta_stage_impl_get_backend (MetaStageImpl *stage_impl)
return priv->backend;
}
+
+void
+meta_stage_impl_rebuild_views (MetaStageImpl *stage_impl)
+{
+ MetaBackend *backend = meta_stage_impl_get_backend (stage_impl);
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ ClutterActor *stage = meta_backend_get_stage (backend);
+
+ meta_renderer_rebuild_views (renderer);
+ clutter_stage_clear_stage_views (CLUTTER_STAGE (stage));
+}
diff --git a/src/backends/meta-stage-private.h b/src/backends/meta-stage-private.h
index 5546cc8ccf..e59ea35c6c 100644
--- a/src/backends/meta-stage-private.h
+++ b/src/backends/meta-stage-private.h
@@ -68,4 +68,6 @@ META_EXPORT_TEST
void meta_stage_remove_watch (MetaStage *stage,
MetaStageWatch *watch);
+void meta_stage_rebuild_views (MetaStage *stage);
+
G_END_DECLS
diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c
index 96224a03b5..32f681c8c5 100644
--- a/src/backends/meta-stage.c
+++ b/src/backends/meta-stage.c
@@ -494,3 +494,19 @@ meta_stage_remove_watch (MetaStage *stage,
g_assert (removed);
}
+
+void
+meta_stage_rebuild_views (MetaStage *stage)
+{
+ ClutterStageWindow *stage_window =
+ _clutter_stage_get_window (CLUTTER_STAGE (stage));
+ MetaStageImpl *stage_impl = META_STAGE_IMPL (stage_window);
+ MetaMonitorManager *monitor_manager =
+ meta_backend_get_monitor_manager (stage->backend);
+ int width, height;
+
+ meta_stage_impl_rebuild_views (stage_impl);
+
+ meta_monitor_manager_get_screen_size (monitor_manager, &width, &height);
+ clutter_actor_set_size (CLUTTER_ACTOR (stage), width, height);
+}
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index ee02b2783a..85bfeb7810 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -399,14 +399,11 @@ static void
meta_backend_native_update_stage (MetaBackend *backend)
{
ClutterActor *stage = meta_backend_get_stage (backend);
- ClutterStageWindow *stage_window =
- _clutter_stage_get_window (CLUTTER_STAGE (stage));
- MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
int width, height;
- meta_stage_native_rebuild_views (stage_native);
+ meta_stage_rebuild_views (META_STAGE (stage));
meta_monitor_manager_get_screen_size (monitor_manager, &width, &height);
clutter_actor_set_size (stage, width, height);
diff --git a/src/backends/native/meta-stage-native.c b/src/backends/native/meta-stage-native.c
index 80d869b920..34849e5b9c 100644
--- a/src/backends/native/meta-stage-native.c
+++ b/src/backends/native/meta-stage-native.c
@@ -54,18 +54,6 @@ G_DEFINE_TYPE_WITH_CODE (MetaStageNative, meta_stage_native,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init))
-void
-meta_stage_native_rebuild_views (MetaStageNative *stage_native)
-{
- MetaStageImpl *stage_impl = META_STAGE_IMPL (stage_native);
- MetaBackend *backend = meta_stage_impl_get_backend (stage_impl);
- MetaRenderer *renderer = meta_backend_get_renderer (backend);
- ClutterActor *stage = meta_backend_get_stage (backend);
-
- meta_renderer_rebuild_views (renderer);
- clutter_stage_clear_stage_views (CLUTTER_STAGE (stage));
-}
-
static gboolean
meta_stage_native_can_clip_redraws (ClutterStageWindow *stage_window)
{
diff --git a/src/backends/native/meta-stage-native.h b/src/backends/native/meta-stage-native.h
index 18ce3b14bb..cf081a32ea 100644
--- a/src/backends/native/meta-stage-native.h
+++ b/src/backends/native/meta-stage-native.h
@@ -28,5 +28,3 @@
#define META_TYPE_STAGE_NATIVE (meta_stage_native_get_type ())
G_DECLARE_FINAL_TYPE (MetaStageNative, meta_stage_native,
META, STAGE_NATIVE, MetaStageImpl)
-
-void meta_stage_native_rebuild_views (MetaStageNative *stage_native);
diff --git a/src/backends/x11/nested/meta-backend-x11-nested.c b/src/backends/x11/nested/meta-backend-x11-nested.c
index ec82f1d1a9..09d2a91cb6 100644
--- a/src/backends/x11/nested/meta-backend-x11-nested.c
+++ b/src/backends/x11/nested/meta-backend-x11-nested.c
@@ -21,6 +21,7 @@
#include "backends/meta-input-settings-dummy.h"
#include "backends/meta-monitor-manager-dummy.h"
+#include "backends/meta-stage-private.h"
#include "backends/x11/nested/meta-backend-x11-nested.h"
#include "backends/x11/nested/meta-cursor-renderer-x11-nested.h"
#include "backends/x11/nested/meta-renderer-x11-nested.h"
@@ -107,16 +108,8 @@ static void
meta_backend_x11_nested_update_stage (MetaBackend *backend)
{
ClutterActor *stage = meta_backend_get_stage (backend);
- MetaRenderer *renderer = meta_backend_get_renderer (backend);
- MetaMonitorManager *monitor_manager =
- meta_backend_get_monitor_manager (backend);
- int width, height;
- meta_renderer_rebuild_views (renderer);
- clutter_stage_clear_stage_views (CLUTTER_STAGE (stage));
-
- meta_monitor_manager_get_screen_size (monitor_manager, &width, &height);
- clutter_actor_set_size (stage, width, height);
+ meta_stage_rebuild_views (META_STAGE (stage));
}
static void
--
2.44.0.501.g19981daefd.dirty

View File

@ -0,0 +1,266 @@
From 3e09a7f1717d8c4b0a815fd9673471a52d6328b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 12 Mar 2025 11:56:46 +0800
Subject: [PATCH 2/2] stage: Track overlay damage per view
The previously painted rectangle of an overlay is not a global state,
but depends on what view it was painted on. There was also an issue
where an overlay being updated but not changing position, e.g. due to a
0,0 pointer movement or an absolute pointer movement with the position
not changing, not properly triggering damage of the old position when it
eventually actually moved.
Fix this by tracking damage per view, while also fixing the state
tracking to handle unchanged positions.
---
src/backends/meta-stage.c | 163 +++++++++++++++++++++++++-------------
1 file changed, 107 insertions(+), 56 deletions(-)
diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c
index 32f681c8c5..58f15bbb33 100644
--- a/src/backends/meta-stage.c
+++ b/src/backends/meta-stage.c
@@ -38,6 +38,12 @@ struct _MetaStageWatch
gpointer user_data;
};
+typedef struct _MetaOverlayViewState
+{
+ graphene_rect_t painted_rect;
+ gboolean has_painted_rect;
+} MetaOverlayViewState;
+
struct _MetaOverlay
{
MetaStage *stage;
@@ -49,8 +55,8 @@ struct _MetaOverlay
graphene_matrix_t transform;
graphene_rect_t current_rect;
- graphene_rect_t previous_rect;
- gboolean previous_is_valid;
+
+ GHashTable *view_states;
};
struct _MetaStage
@@ -77,6 +83,7 @@ meta_overlay_new (MetaStage *stage)
overlay = g_new0 (MetaOverlay, 1);
overlay->stage = stage;
overlay->pipeline = cogl_pipeline_new (ctx);
+ overlay->view_states = g_hash_table_new_full (NULL, NULL, NULL, g_free);
return overlay;
}
@@ -86,6 +93,7 @@ meta_overlay_free (MetaOverlay *overlay)
{
if (overlay->pipeline)
g_object_unref (overlay->pipeline);
+ g_hash_table_unref (overlay->view_states);
g_free (overlay);
}
@@ -115,19 +123,57 @@ meta_overlay_set (MetaOverlay *overlay,
overlay->current_rect = *dst_rect;
}
+static MetaOverlayViewState *
+get_view_state (MetaOverlay *overlay,
+ ClutterStageView *view)
+{
+ return g_hash_table_lookup (overlay->view_states, view);
+}
+
+static MetaOverlayViewState *
+ensure_view_state (MetaOverlay *overlay,
+ ClutterStageView *view)
+{
+ MetaOverlayViewState *view_state;
+
+ view_state = get_view_state (overlay, view);
+
+ if (!view_state)
+ {
+ view_state = g_new0 (MetaOverlayViewState, 1);
+ g_hash_table_insert (overlay->view_states, view, view_state);
+ }
+
+ return view_state;
+}
+
+static void
+meta_overlay_invalidate_views (MetaOverlay *overlay)
+{
+ g_hash_table_remove_all (overlay->view_states);
+}
+
static void
meta_overlay_paint (MetaOverlay *overlay,
ClutterPaintContext *paint_context)
{
+ ClutterStageView *view;
+ MetaOverlayViewState *view_state = NULL;
CoglFramebuffer *framebuffer;
- if (!overlay->texture)
- return;
+ view = clutter_paint_context_get_stage_view (paint_context);
+ if (view)
+ view_state = ensure_view_state (overlay, view);
- if (!overlay->is_visible &&
+ if ((!overlay->texture ||
+ !overlay->is_visible) &&
!(clutter_paint_context_get_paint_flags (paint_context) &
CLUTTER_PAINT_FLAG_FORCE_CURSORS))
- return;
+ {
+ if (view_state)
+ view_state->has_painted_rect = FALSE;
+ return;
+ }
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
cogl_framebuffer_draw_rectangle (framebuffer,
@@ -139,10 +185,10 @@ meta_overlay_paint (MetaOverlay *overlay,
(overlay->current_rect.origin.y +
overlay->current_rect.size.height));
- if (!graphene_rect_equal (&overlay->previous_rect, &overlay->current_rect))
+ if (view_state)
{
- overlay->previous_rect = overlay->current_rect;
- overlay->previous_is_valid = TRUE;
+ view_state->painted_rect = overlay->current_rect;
+ view_state->has_painted_rect = TRUE;
}
}
@@ -343,67 +389,68 @@ meta_stage_new (MetaBackend *backend)
}
static void
-queue_cursor_overlay_redraw_clutter_rect (MetaStage *stage,
- MetaOverlay *overlay,
- graphene_rect_t *rect)
+intersect_and_queue_redraw (ClutterStageView *view,
+ const MtkRectangle *clip)
{
- MtkRectangle clip = {
- .x = (int) floorf (rect->origin.x),
- .y = (int) floorf (rect->origin.y),
- .width = (int) ceilf (rect->size.width),
- .height = (int) ceilf (rect->size.height)
- };
- GList *l;
+ MtkRectangle view_layout;
+ MtkRectangle view_clip;
- /* Since we're flooring the coordinates, we need to enlarge the clip by the
- * difference between the actual coordinate and the floored value */
- clip.width += (int) ceilf (rect->origin.x - clip.x) * 2;
- clip.height += (int) ceilf (rect->origin.y - clip.y) * 2;
+ clutter_stage_view_get_layout (view, &view_layout);
- for (l = clutter_stage_peek_stage_views (CLUTTER_STAGE (stage));
- l;
- l = l->next)
+ if (mtk_rectangle_intersect (clip, &view_layout, &view_clip))
{
- ClutterStageView *view = l->data;
- MtkRectangle view_layout;
- MtkRectangle view_clip;
-
- if (clutter_stage_view_get_default_paint_flags (view) &
- CLUTTER_PAINT_FLAG_NO_CURSORS)
- continue;
-
- if (meta_stage_view_is_cursor_overlay_inhibited (META_STAGE_VIEW (view)))
- return;
+ clutter_stage_view_add_redraw_clip (view, &view_clip);
+ clutter_stage_view_schedule_update (view);
+ }
+}
- clutter_stage_view_get_layout (view, &view_layout);
+static void
+cursor_rect_to_clip (const graphene_rect_t *cursor_rect,
+ MtkRectangle *clip_rect)
+{
+ mtk_rectangle_from_graphene_rect (cursor_rect,
+ MTK_ROUNDING_STRATEGY_GROW,
+ clip_rect);
- if (mtk_rectangle_intersect (&clip, &view_layout, &view_clip))
- {
- clutter_stage_view_add_redraw_clip (view, &view_clip);
- clutter_stage_view_schedule_update (view);
- }
- }
+ /* Since we're flooring the coordinates, we need to enlarge the clip by the
+ * difference between the actual coordinate and the floored value */
+ clip_rect->width += (int) ceilf (cursor_rect->origin.x - clip_rect->x) * 2;
+ clip_rect->height += (int) ceilf (cursor_rect->origin.y - clip_rect->y) * 2;
}
static void
queue_redraw_for_cursor_overlay (MetaStage *stage,
MetaOverlay *overlay)
{
- /* Clear the location the overlay was at before, if we need to. */
- if (overlay->previous_is_valid)
- {
- queue_cursor_overlay_redraw_clutter_rect (stage,
- overlay,
- &overlay->previous_rect);
- overlay->previous_is_valid = FALSE;
- }
+ GList *l;
- /* Draw the overlay at the new position */
- if (overlay->is_visible && overlay->texture)
+ for (l = clutter_stage_peek_stage_views (CLUTTER_STAGE (stage));
+ l;
+ l = l->next)
{
- queue_cursor_overlay_redraw_clutter_rect (stage,
- overlay,
- &overlay->current_rect);
+ ClutterStageView *view = CLUTTER_STAGE_VIEW (l->data);
+ MetaOverlayViewState *view_state;
+
+ view_state = ensure_view_state (overlay, view);
+ if (view_state->has_painted_rect)
+ {
+ MtkRectangle clip;
+
+ cursor_rect_to_clip (&view_state->painted_rect, &clip);
+ intersect_and_queue_redraw (view, &clip);
+ }
+
+ if (overlay->is_visible &&
+ overlay->texture &&
+ !(clutter_stage_view_get_default_paint_flags (view) &
+ CLUTTER_PAINT_FLAG_NO_CURSORS) &&
+ !meta_stage_view_is_cursor_overlay_inhibited (META_STAGE_VIEW (view)))
+ {
+ MtkRectangle clip;
+
+ cursor_rect_to_clip (&overlay->current_rect, &clip);
+ intersect_and_queue_redraw (view, &clip);
+ }
}
}
@@ -509,4 +556,8 @@ meta_stage_rebuild_views (MetaStage *stage)
meta_monitor_manager_get_screen_size (monitor_manager, &width, &height);
clutter_actor_set_size (CLUTTER_ACTOR (stage), width, height);
+
+ g_list_foreach (stage->overlays,
+ (GFunc) meta_overlay_invalidate_views,
+ NULL);
}
--
2.44.0.501.g19981daefd.dirty

View File

@ -65,6 +65,10 @@ Patch: 0003-monitor-manager-Configure-for-lease-monitors-in-Appl.patch
Patch: 0001-wayland-Fix-refresh-interval-reporting-in-presentati.patch
Patch: 0002-input-capture-session-Disconnect-on_keymap_changed-o.patch
# Overlay cursor damage fix: RHEL-58079, RHEL-81897
Patch: 0001-backends-Update-stage-views-and-stage-dimension-from.patch
Patch: 0002-stage-Track-overlay-damage-per-view.patch
BuildRequires: pkgconfig(gobject-introspection-1.0) >= 1.41.0
BuildRequires: pkgconfig(sm)
BuildRequires: pkgconfig(libwacom)