diff --git a/src/meson.build b/src/meson.build index fec9d541c..4b015e620 100644 --- a/src/meson.build +++ b/src/meson.build @@ -562,6 +562,8 @@ if have_wayland 'wayland/meta-wayland-pointer.h', 'wayland/meta-wayland-popup.c', 'wayland/meta-wayland-popup.h', + 'wayland/meta-wayland-presentation-time.c', + 'wayland/meta-wayland-presentation-time-private.h', 'wayland/meta-wayland-private.h', 'wayland/meta-wayland-region.c', 'wayland/meta-wayland-region.h', diff --git a/src/wayland/meta-wayland-presentation-time-private.h b/src/wayland/meta-wayland-presentation-time-private.h new file mode 100644 index 000000000..e8e5bbf79 --- /dev/null +++ b/src/wayland/meta-wayland-presentation-time-private.h @@ -0,0 +1,42 @@ +/* + * presentation-time protocol + * + * Copyright (C) 2020 Ivan Molodetskikh + * + * 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_WAYLAND_PRESENTATION_TIME_PRIVATE_H +#define META_WAYLAND_PRESENTATION_TIME_PRIVATE_H + +#include + +#include "wayland/meta-wayland-types.h" + +typedef struct _MetaWaylandPresentationFeedback +{ + struct wl_list link; + struct wl_resource *resource; + + MetaWaylandSurface *surface; +} MetaWaylandPresentationFeedback; + +void meta_wayland_init_presentation_time (MetaWaylandCompositor *compositor); + +void meta_wayland_presentation_feedback_discard (MetaWaylandPresentationFeedback *feedback); + +#endif /* META_WAYLAND_PRESENTATION_TIME_PRIVATE_H */ diff --git a/src/wayland/meta-wayland-presentation-time.c b/src/wayland/meta-wayland-presentation-time.c new file mode 100644 index 000000000..d54e1e50c --- /dev/null +++ b/src/wayland/meta-wayland-presentation-time.c @@ -0,0 +1,129 @@ +/* + * presentation-time protocol + * + * Copyright (C) 2020 Ivan Molodetskikh + * + * 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 "meta-wayland-presentation-time-private.h" + +#include + +#include "wayland/meta-wayland-private.h" +#include "wayland/meta-wayland-surface.h" +#include "wayland/meta-wayland-versions.h" + +#include "presentation-time-server-protocol.h" + +static void +wp_presentation_feedback_destructor (struct wl_resource *resource) +{ + MetaWaylandPresentationFeedback *feedback = + wl_resource_get_user_data (resource); + + wl_list_remove (&feedback->link); + g_free (feedback); +} + +static void +wp_presentation_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +wp_presentation_feedback (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *surface_resource, + uint32_t callback_id) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWaylandSurfaceState *pending; + MetaWaylandPresentationFeedback *feedback; + + feedback = g_new0 (MetaWaylandPresentationFeedback, 1); + wl_list_init (&feedback->link); + feedback->resource = wl_resource_create (client, + &wp_presentation_feedback_interface, + wl_resource_get_version (resource), + callback_id); + wl_resource_set_implementation (feedback->resource, + NULL, + feedback, + wp_presentation_feedback_destructor); + + if (surface == NULL) + { + g_warn_if_reached (); + meta_wayland_presentation_feedback_discard (feedback); + return; + } + + pending = meta_wayland_surface_get_pending_state (surface); + wl_list_insert (&pending->presentation_feedback_list, &feedback->link); + + feedback->surface = surface; +} + +static const struct wp_presentation_interface +meta_wayland_presentation_interface = { + wp_presentation_destroy, + wp_presentation_feedback, +}; + +static void +wp_presentation_bind (struct wl_client *client, + void *data, + uint32_t version, + uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, + &wp_presentation_interface, + version, + id); + wl_resource_set_implementation (resource, + &meta_wayland_presentation_interface, + NULL, + NULL); + + /* Presentation timestamps in Mutter are guaranteed to be CLOCK_MONOTONIC. */ + wp_presentation_send_clock_id (resource, CLOCK_MONOTONIC); +} + +void +meta_wayland_init_presentation_time (MetaWaylandCompositor *compositor) +{ + if (wl_global_create (compositor->wayland_display, + &wp_presentation_interface, + META_WP_PRESENTATION_VERSION, + NULL, + wp_presentation_bind) == NULL) + g_error ("Failed to register a global wp_presentation object"); +} + +void +meta_wayland_presentation_feedback_discard (MetaWaylandPresentationFeedback *feedback) +{ + wp_presentation_feedback_send_discarded (feedback->resource); + wl_resource_destroy (feedback->resource); +} diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 66275055f..db0d7f2f3 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -46,6 +46,7 @@ #include "wayland/meta-wayland-legacy-xdg-shell.h" #include "wayland/meta-wayland-outputs.h" #include "wayland/meta-wayland-pointer.h" +#include "wayland/meta-wayland-presentation-time-private.h" #include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-region.h" #include "wayland/meta-wayland-seat.h" @@ -466,6 +467,20 @@ meta_wayland_surface_state_set_default (MetaWaylandSurfaceState *state) state->has_new_buffer_transform = FALSE; state->has_new_viewport_src_rect = FALSE; state->has_new_viewport_dst_size = FALSE; + + wl_list_init (&state->presentation_feedback_list); +} + +static void +meta_wayland_surface_state_discard_presentation_feedback (MetaWaylandSurfaceState *state) +{ + while (!wl_list_empty (&state->presentation_feedback_list)) + { + MetaWaylandPresentationFeedback *feedback = + wl_container_of (state->presentation_feedback_list.next, feedback, link); + + meta_wayland_presentation_feedback_discard (feedback); + } } static void @@ -483,6 +498,8 @@ meta_wayland_surface_state_clear (MetaWaylandSurfaceState *state) wl_list_for_each_safe (cb, next, &state->frame_callback_list, link) wl_resource_destroy (cb->resource); + + meta_wayland_surface_state_discard_presentation_feedback (state); } static void @@ -592,6 +609,10 @@ meta_wayland_surface_state_merge_into (MetaWaylandSurfaceState *from, to); } + wl_list_insert_list (&to->presentation_feedback_list, + &from->presentation_feedback_list); + wl_list_init (&from->presentation_feedback_list); + meta_wayland_surface_state_reset (from); } @@ -627,6 +648,19 @@ meta_wayland_surface_state_class_init (MetaWaylandSurfaceStateClass *klass) G_TYPE_NONE, 0); } +static void +meta_wayland_surface_discard_presentation_feedback (MetaWaylandSurface *surface) +{ + while (!wl_list_empty (&surface->presentation_time.feedback_list)) + { + MetaWaylandPresentationFeedback *feedback = + wl_container_of (surface->presentation_time.feedback_list.next, + feedback, link); + + meta_wayland_presentation_feedback_discard (feedback); + } +} + static void meta_wayland_surface_apply_state (MetaWaylandSurface *surface, MetaWaylandSurfaceState *state) @@ -755,6 +789,16 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface, surface->input_region = NULL; } + /* + * A new commit indicates a new content update, so any previous + * content update did not go on screen and needs to be discarded. + */ + meta_wayland_surface_discard_presentation_feedback (surface); + + wl_list_insert_list (&surface->presentation_time.feedback_list, + &state->presentation_feedback_list); + wl_list_init (&state->presentation_feedback_list); + if (surface->role) { meta_wayland_surface_role_apply_state (surface->role, state); @@ -870,6 +914,13 @@ meta_wayland_surface_commit (MetaWaylandSurface *surface) MetaWaylandSurfaceState *cached_state; cached_state = meta_wayland_surface_ensure_cached_state (surface); + + /* + * A new commit indicates a new content update, so any previous + * cached content update did not go on screen and needs to be discarded. + */ + meta_wayland_surface_state_discard_presentation_feedback (cached_state); + meta_wayland_surface_state_merge_into (pending, cached_state); } else @@ -1350,6 +1401,8 @@ wl_surface_destructor (struct wl_resource *resource) link) wl_resource_destroy (cb->resource); + meta_wayland_surface_discard_presentation_feedback (surface); + if (surface->resource) wl_resource_set_user_data (surface->resource, NULL); @@ -1397,6 +1450,8 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor, surface->outputs = g_hash_table_new (NULL, NULL); surface->shortcut_inhibited_seats = g_hash_table_new (NULL, NULL); + wl_list_init (&surface->presentation_time.feedback_list); + meta_wayland_compositor_notify_surface_id (compositor, id, surface); return surface; diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index 0c7298886..1fabd57dd 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -120,6 +120,9 @@ struct _MetaWaylandSurfaceState gboolean has_new_viewport_dst_size; int viewport_dst_width; int viewport_dst_height; + + /* presentation-time */ + struct wl_list presentation_feedback_list; }; struct _MetaWaylandDragDestFuncs @@ -227,6 +230,11 @@ struct _MetaWaylandSurface /* table of seats for which shortcuts are inhibited */ GHashTable *shortcut_inhibited_seats; + + /* presentation-time */ + struct { + struct wl_list feedback_list; + } presentation_time; }; void meta_wayland_shell_init (MetaWaylandCompositor *compositor); diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h index bf891d99a..8f71c19dc 100644 --- a/src/wayland/meta-wayland-versions.h +++ b/src/wayland/meta-wayland-versions.h @@ -57,5 +57,6 @@ #define META_WP_VIEWPORTER_VERSION 1 #define META_GTK_PRIMARY_SELECTION_VERSION 1 #define META_ZWP_PRIMARY_SELECTION_V1_VERSION 1 +#define META_WP_PRESENTATION_VERSION 1 #endif diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index ef7a495b5..45bc7ace0 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -39,6 +39,7 @@ #include "wayland/meta-wayland-inhibit-shortcuts-dialog.h" #include "wayland/meta-wayland-inhibit-shortcuts.h" #include "wayland/meta-wayland-outputs.h" +#include "wayland/meta-wayland-presentation-time-private.h" #include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-region.h" #include "wayland/meta-wayland-seat.h" @@ -444,6 +445,7 @@ meta_wayland_compositor_setup (MetaWaylandCompositor *compositor) meta_wayland_surface_inhibit_shortcuts_dialog_init (); meta_wayland_text_input_init (compositor); meta_wayland_gtk_text_input_init (compositor); + meta_wayland_init_presentation_time (compositor); /* Xwayland specific protocol, needs to be filtered out for all other clients */ if (meta_xwayland_grab_keyboard_init (compositor))