wayland: Send presentation feedbacks to cursors

This commit assumes that cursor surfaces work in a "mailbox" fashion. If
they are painted multiple times before a successful flip, all commits
but the last get discarded, and the last commit gets presented after the
flip succeeds. This is more or less how it works in the atomic backend,
and also more or less how it works in other backends, with the exception
that the cursor painting might fail without any way of knowing. This
assumption is still better than unconditionally discarding all cursor
surface feedbacks as if the cursor painting always fails.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1484>
This commit is contained in:
Ivan Molodetskikh 2021-02-02 16:51:34 +03:00 committed by Marge Bot
parent cd9ae13465
commit 82af1fb87e
3 changed files with 69 additions and 9 deletions

View File

@ -30,6 +30,7 @@
#include "core/boxes-private.h"
#include "wayland/meta-cursor-sprite-wayland.h"
#include "wayland/meta-wayland-buffer.h"
#include "wayland/meta-wayland-presentation-time-private.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-xwayland.h"
@ -340,6 +341,9 @@ on_cursor_painted (MetaCursorRenderer *renderer,
MetaWaylandCursorSurfacePrivate *priv =
meta_wayland_cursor_surface_get_instance_private (cursor_surface);
guint32 time = (guint32) (g_get_monotonic_time () / 1000);
MetaBackend *backend = meta_get_backend ();
MetaWaylandCompositor *compositor =
meta_backend_get_wayland_compositor (backend);
if (displayed_sprite != META_CURSOR_SPRITE (priv->cursor_sprite))
return;
@ -352,6 +356,10 @@ on_cursor_painted (MetaCursorRenderer *renderer,
wl_callback_send_done (callback->resource, time);
wl_resource_destroy (callback->resource);
}
meta_wayland_presentation_time_cursor_painted (&compositor->presentation_time,
stage_view,
cursor_surface);
}
void

View File

@ -26,6 +26,7 @@
#include <wayland-server.h>
#include "clutter/clutter.h"
#include "wayland/meta-wayland-cursor-surface.h"
#include "wayland/meta-wayland-types.h"
typedef struct _MetaWaylandPresentationFeedback
@ -59,4 +60,8 @@ void meta_wayland_presentation_feedback_present (MetaWaylandPresentationFeedback
struct wl_list * meta_wayland_presentation_time_ensure_feedbacks (MetaWaylandPresentationTime *presentation_time,
ClutterStageView *stage_view);
void meta_wayland_presentation_time_cursor_painted (MetaWaylandPresentationTime *presentation_time,
ClutterStageView *stage_view,
MetaWaylandCursorSurface *cursor_surface);
#endif /* META_WAYLAND_PRESENTATION_TIME_PRIVATE_H */

View File

@ -27,6 +27,7 @@
#include <glib.h>
#include "compositor/meta-surface-actor-wayland.h"
#include "wayland/meta-wayland-cursor-surface.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-surface.h"
#include "wayland/meta-wayland-outputs.h"
@ -113,12 +114,14 @@ wp_presentation_bind (struct wl_client *client,
}
static void
discard_feedbacks (struct wl_list *feedbacks)
discard_non_cursor_feedbacks (struct wl_list *feedbacks)
{
while (!wl_list_empty (feedbacks))
MetaWaylandPresentationFeedback *feedback, *next;
wl_list_for_each_safe (feedback, next, feedbacks, link)
{
MetaWaylandPresentationFeedback *feedback =
wl_container_of (feedbacks->next, feedback, link);
if (META_IS_WAYLAND_CURSOR_SURFACE (feedback->surface->role))
continue;
meta_wayland_presentation_feedback_discard (feedback);
}
@ -133,14 +136,19 @@ on_after_paint (ClutterStage *stage,
GList *l;
/*
* We just painted this stage view, which means that all feedbacks that didn't
* fire (e.g. due to page flip failing) are now obsolete and should be
* discarded.
* We just painted this stage view, which means that all non-cursor feedbacks
* that didn't fire (e.g. due to page flip failing) are now obsolete and
* should be discarded.
*
* Cursor feedbacks have a similar mechanism done separately, mainly because
* they are painted earlier, in prepare_frame(). This means that the feedbacks
* list currently contains stale non-cursor feedbacks and up-to-date cursor
* feedbacks.
*/
feedbacks =
meta_wayland_presentation_time_ensure_feedbacks (&compositor->presentation_time,
stage_view);
discard_feedbacks (feedbacks);
discard_non_cursor_feedbacks (feedbacks);
l = compositor->presentation_time.feedback_surfaces;
while (l)
@ -182,7 +190,14 @@ destroy_feedback_list (gpointer data)
{
struct wl_list *feedbacks = data;
discard_feedbacks (feedbacks);
while (!wl_list_empty (feedbacks))
{
MetaWaylandPresentationFeedback *feedback =
wl_container_of (feedbacks->next, feedback, link);
meta_wayland_presentation_feedback_discard (feedback);
}
g_free (feedbacks);
}
@ -367,3 +382,35 @@ meta_wayland_presentation_time_ensure_feedbacks (MetaWaylandPresentationTime *pr
return g_hash_table_lookup (presentation_time->feedbacks, stage_view);
}
void
meta_wayland_presentation_time_cursor_painted (MetaWaylandPresentationTime *presentation_time,
ClutterStageView *stage_view,
MetaWaylandCursorSurface *cursor_surface)
{
struct wl_list *feedbacks;
MetaWaylandPresentationFeedback *feedback, *next;
MetaWaylandSurfaceRole *role = META_WAYLAND_SURFACE_ROLE (cursor_surface);
MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (role);
feedbacks =
meta_wayland_presentation_time_ensure_feedbacks (presentation_time,
stage_view);
/* Discard previous feedbacks for this cursor as now it has gone stale. */
wl_list_for_each_safe (feedback, next, feedbacks, link)
{
if (feedback->surface->role == role)
meta_wayland_presentation_feedback_discard (feedback);
}
/* Add new feedbacks. */
if (!wl_list_empty (&surface->presentation_time.feedback_list))
{
wl_list_insert_list (feedbacks,
&surface->presentation_time.feedback_list);
wl_list_init (&surface->presentation_time.feedback_list);
surface->presentation_time.needs_sequence_update = TRUE;
}
}