wayland: Add support for FIFO commits
New protocol that allows a client to require that a previously flagged content update must be presented before a content update can be applied. Signed-off-by: Derek Foreman <derek.foreman@collabora.com> Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3355>
This commit is contained in:
parent
14c70c4f53
commit
fd39ca9f20
@ -607,6 +607,7 @@ if have_wayland
|
||||
'wayland/meta-wayland-color-management.c',
|
||||
'wayland/meta-wayland-color-management.h',
|
||||
'wayland/meta-wayland-commit-timing.c',
|
||||
'wayland/meta-wayland-fifo.c',
|
||||
'wayland/meta-wayland-cursor-surface.c',
|
||||
'wayland/meta-wayland-cursor-surface.h',
|
||||
'wayland/meta-wayland-data-device.c',
|
||||
@ -1130,6 +1131,7 @@ if have_wayland
|
||||
['color-management-v1', 'private', ],
|
||||
['session-management-v1', 'private', ],
|
||||
['commit-timing', 'staging', 'v1', ],
|
||||
['fifo', 'staging', 'v1', ],
|
||||
]
|
||||
if have_wayland_eglstream
|
||||
wayland_eglstream_protocols_dir = wayland_eglstream_protocols_dep.get_variable('pkgdatadir')
|
||||
|
@ -316,7 +316,8 @@ meta_wayland_actor_surface_apply_state (MetaWaylandSurfaceRole *surface_role,
|
||||
MetaWaylandActorSurfacePrivate *priv =
|
||||
meta_wayland_actor_surface_get_instance_private (actor_surface);
|
||||
|
||||
if (priv->actor && !wl_list_empty (&pending->frame_callback_list))
|
||||
if (priv->actor &&
|
||||
(!wl_list_empty (&pending->frame_callback_list) || pending->fifo_wait))
|
||||
meta_surface_actor_schedule_update (priv->actor);
|
||||
|
||||
meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);
|
||||
|
191
src/wayland/meta-wayland-fifo.c
Normal file
191
src/wayland/meta-wayland-fifo.c
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Valve Corporation
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <wayland-server.h>
|
||||
|
||||
#include "fifo-v1-server-protocol.h"
|
||||
#include "wayland/meta-wayland-fifo.h"
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
#include "wayland/meta-wayland-versions.h"
|
||||
|
||||
typedef struct _MetaWaylandFifoSurface
|
||||
{
|
||||
MetaWaylandSurface *surface;
|
||||
gulong destroy_handler_id;
|
||||
} MetaWaylandFifoSurface;
|
||||
|
||||
static void
|
||||
fifo_destructor (struct wl_resource *resource)
|
||||
{
|
||||
MetaWaylandFifoSurface *fifo = wl_resource_get_user_data (resource);
|
||||
|
||||
if (fifo->surface)
|
||||
{
|
||||
g_object_set_data (G_OBJECT (fifo->surface), "-meta-wayland-fifo", NULL);
|
||||
|
||||
g_clear_signal_handler (&fifo->destroy_handler_id, fifo->surface);
|
||||
}
|
||||
|
||||
g_free (fifo);
|
||||
}
|
||||
|
||||
static void
|
||||
fifo_destroy (struct wl_client *client,
|
||||
struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy (resource);
|
||||
}
|
||||
|
||||
static void
|
||||
set_barrier (struct wl_client *client,
|
||||
struct wl_resource *resource)
|
||||
{
|
||||
MetaWaylandFifoSurface *fifo = wl_resource_get_user_data (resource);
|
||||
MetaWaylandSurface *surface = fifo->surface;
|
||||
MetaWaylandSurfaceState *pending;
|
||||
|
||||
if (!surface)
|
||||
{
|
||||
wl_resource_post_error (resource,
|
||||
WP_FIFO_V1_ERROR_SURFACE_DESTROYED,
|
||||
"surface destroyed");
|
||||
return;
|
||||
}
|
||||
|
||||
pending = meta_wayland_surface_get_pending_state (surface);
|
||||
pending->fifo_barrier = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
wait_barrier (struct wl_client *client,
|
||||
struct wl_resource *resource)
|
||||
{
|
||||
MetaWaylandFifoSurface *fifo = wl_resource_get_user_data (resource);
|
||||
MetaWaylandSurface *surface = fifo->surface;
|
||||
MetaWaylandSurfaceState *pending;
|
||||
|
||||
if (!surface)
|
||||
{
|
||||
wl_resource_post_error (resource,
|
||||
WP_FIFO_V1_ERROR_SURFACE_DESTROYED,
|
||||
"surface destroyed");
|
||||
return;
|
||||
}
|
||||
|
||||
pending = meta_wayland_surface_get_pending_state (surface);
|
||||
pending->fifo_wait = TRUE;
|
||||
}
|
||||
|
||||
static const struct wp_fifo_v1_interface meta_wayland_fifo_interface =
|
||||
{
|
||||
set_barrier,
|
||||
wait_barrier,
|
||||
fifo_destroy,
|
||||
};
|
||||
|
||||
static void
|
||||
fifo_manager_destroy (struct wl_client *client,
|
||||
struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy (resource);
|
||||
}
|
||||
|
||||
static void
|
||||
on_surface_destroyed (MetaWaylandSurface *surface,
|
||||
MetaWaylandFifoSurface *fifo)
|
||||
{
|
||||
fifo->surface = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
fifo_manager_get_queue (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t id,
|
||||
struct wl_resource *surface_resource)
|
||||
{
|
||||
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
||||
MetaWaylandFifoSurface *fifo;
|
||||
struct wl_resource *fifo_resource;
|
||||
|
||||
fifo = g_object_get_data (G_OBJECT (surface), "-meta-wayland-fifo");
|
||||
|
||||
if (fifo)
|
||||
{
|
||||
wl_resource_post_error (resource,
|
||||
WP_FIFO_MANAGER_V1_ERROR_ALREADY_EXISTS,
|
||||
"Fifo resource already exists on surface");
|
||||
return;
|
||||
}
|
||||
|
||||
fifo_resource = wl_resource_create (client,
|
||||
&wp_fifo_v1_interface,
|
||||
wl_resource_get_version (resource),
|
||||
id);
|
||||
|
||||
fifo = g_new0 (MetaWaylandFifoSurface, 1);
|
||||
fifo->surface = surface;
|
||||
|
||||
fifo->destroy_handler_id =
|
||||
g_signal_connect (surface,
|
||||
"destroy",
|
||||
G_CALLBACK (on_surface_destroyed),
|
||||
fifo);
|
||||
|
||||
g_object_set_data (G_OBJECT (surface), "-meta-wayland-fifo", fifo);
|
||||
|
||||
wl_resource_set_implementation (fifo_resource,
|
||||
&meta_wayland_fifo_interface,
|
||||
fifo,
|
||||
fifo_destructor);
|
||||
}
|
||||
|
||||
static const struct wp_fifo_manager_v1_interface meta_wayland_fifo_manager_interface =
|
||||
{
|
||||
fifo_manager_destroy,
|
||||
fifo_manager_get_queue,
|
||||
};
|
||||
|
||||
static void
|
||||
bind_fifo (struct wl_client *client,
|
||||
void *data,
|
||||
uint32_t version,
|
||||
uint32_t id)
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
|
||||
resource = wl_resource_create (client,
|
||||
&wp_fifo_manager_v1_interface,
|
||||
version, id);
|
||||
|
||||
wl_resource_set_implementation (resource,
|
||||
&meta_wayland_fifo_manager_interface,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_fifo_init (MetaWaylandCompositor *compositor)
|
||||
{
|
||||
if (wl_global_create (compositor->wayland_display,
|
||||
&wp_fifo_manager_v1_interface,
|
||||
META_WP_FIFO_V1_VERSION,
|
||||
NULL,
|
||||
bind_fifo) == NULL)
|
||||
g_error ("Failed to register a global fifo object");
|
||||
}
|
25
src/wayland/meta-wayland-fifo.h
Normal file
25
src/wayland/meta-wayland-fifo.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Valve Corporation
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "wayland/meta-wayland-types.h"
|
||||
|
||||
void meta_wayland_fifo_init (MetaWaylandCompositor *compositor);
|
@ -118,6 +118,9 @@ struct _MetaWaylandCompositor
|
||||
|
||||
/* Transactions with time constraints. */
|
||||
GQueue *timed_transactions;
|
||||
|
||||
/* Surfaces with fifo barriers. */
|
||||
GList *barrier_surfaces;
|
||||
};
|
||||
|
||||
gboolean meta_wayland_compositor_is_egl_display_bound (MetaWaylandCompositor *compositor);
|
||||
|
@ -142,6 +142,9 @@ struct _MetaWaylandSurfaceState
|
||||
|
||||
gboolean has_target_time;
|
||||
int64_t target_time_us;
|
||||
|
||||
gboolean fifo_barrier;
|
||||
gboolean fifo_wait;
|
||||
};
|
||||
|
||||
struct _MetaWaylandDragDestFuncs
|
||||
@ -285,6 +288,8 @@ struct _MetaWaylandSurface
|
||||
|
||||
/* color-management */
|
||||
ClutterColorState *color_state;
|
||||
|
||||
gboolean fifo_barrier;
|
||||
};
|
||||
|
||||
void meta_wayland_shell_init (MetaWaylandCompositor *compositor);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "backends/meta-cursor-tracker-private.h"
|
||||
#include "clutter/clutter.h"
|
||||
#include "cogl/cogl.h"
|
||||
#include "fifo-v1-server-protocol.h"
|
||||
#include "compositor/meta-surface-actor-wayland.h"
|
||||
#include "compositor/meta-surface-actor.h"
|
||||
#include "compositor/meta-window-actor-private.h"
|
||||
@ -456,6 +457,9 @@ meta_wayland_surface_state_set_default (MetaWaylandSurfaceState *state)
|
||||
|
||||
state->has_new_color_state = FALSE;
|
||||
state->color_state = NULL;
|
||||
|
||||
state->fifo_wait = FALSE;
|
||||
state->fifo_barrier = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -629,6 +633,12 @@ meta_wayland_surface_state_merge_into (MetaWaylandSurfaceState *from,
|
||||
from->subsurface_placement_ops = NULL;
|
||||
}
|
||||
|
||||
if (from->fifo_wait)
|
||||
to->fifo_wait = TRUE;
|
||||
|
||||
if (from->fifo_barrier)
|
||||
to->fifo_barrier = TRUE;
|
||||
|
||||
/*
|
||||
* A new commit indicates a new content update, so any previous
|
||||
* content update did not go on screen and needs to be discarded.
|
||||
@ -802,6 +812,13 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface,
|
||||
state->buffer->type != META_WAYLAND_BUFFER_TYPE_SINGLE_PIXEL));
|
||||
}
|
||||
|
||||
if (state->fifo_barrier)
|
||||
{
|
||||
surface->fifo_barrier = TRUE;
|
||||
meta_wayland_compositor_add_barrier_surface (surface->compositor,
|
||||
surface);
|
||||
}
|
||||
|
||||
if (state->has_new_buffer_transform)
|
||||
surface->buffer_transform = state->buffer_transform;
|
||||
|
||||
@ -1056,7 +1073,10 @@ meta_wayland_surface_commit (MetaWaylandSurface *surface)
|
||||
}
|
||||
|
||||
if (meta_wayland_surface_is_synchronized (surface))
|
||||
transaction = meta_wayland_surface_ensure_transaction (surface);
|
||||
{
|
||||
pending->fifo_wait = FALSE;
|
||||
transaction = meta_wayland_surface_ensure_transaction (surface);
|
||||
}
|
||||
else
|
||||
transaction = meta_wayland_transaction_new (surface->compositor);
|
||||
|
||||
@ -1605,6 +1625,7 @@ meta_wayland_surface_dispose (GObject *object)
|
||||
meta_wayland_compositor_remove_frame_callback_surface (compositor, surface);
|
||||
meta_wayland_compositor_remove_presentation_feedback_surface (compositor,
|
||||
surface);
|
||||
meta_wayland_compositor_remove_barrier_surface (compositor, surface);
|
||||
|
||||
if (surface->outputs)
|
||||
{
|
||||
|
@ -248,6 +248,7 @@ has_dependencies (MetaWaylandTransaction *transaction)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
MetaWaylandSurface *surface;
|
||||
MetaWaylandTransactionEntry *entry;
|
||||
|
||||
if (transaction->target_presentation_time_us)
|
||||
return TRUE;
|
||||
@ -257,10 +258,24 @@ has_dependencies (MetaWaylandTransaction *transaction)
|
||||
return TRUE;
|
||||
|
||||
g_hash_table_iter_init (&iter, transaction->entries);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &surface, NULL))
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &surface,
|
||||
(gpointer *) &entry))
|
||||
{
|
||||
MetaSurfaceActor *actor;
|
||||
|
||||
if (surface->transaction.first_committed != transaction)
|
||||
return TRUE;
|
||||
|
||||
if (!entry || !entry->state)
|
||||
continue;
|
||||
|
||||
actor = meta_wayland_surface_get_actor (surface);
|
||||
if (!actor || meta_surface_actor_is_effectively_obscured (actor) ||
|
||||
!clutter_actor_is_mapped (CLUTTER_ACTOR (actor)))
|
||||
continue;
|
||||
|
||||
if (entry->state->fifo_wait && surface->fifo_barrier)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
@ -308,6 +323,30 @@ meta_wayland_transaction_unblock_timed (MetaWaylandTransaction *transaction,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_transaction_consider_surface (MetaWaylandSurface *surface)
|
||||
{
|
||||
MetaWaylandTransaction *transaction;
|
||||
|
||||
transaction = surface->transaction.first_committed;
|
||||
if (transaction)
|
||||
meta_wayland_transaction_maybe_apply (transaction);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_transaction_unblock_surface (MetaWaylandSurface *surface)
|
||||
{
|
||||
if (!surface->fifo_barrier)
|
||||
{
|
||||
g_warning ("Attempting to unblock a surface with no fifo_barrier");
|
||||
return;
|
||||
}
|
||||
|
||||
surface->fifo_barrier = FALSE;
|
||||
|
||||
meta_wayland_transaction_consider_surface (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_transaction_dma_buf_dispatch (MetaWaylandBuffer *buffer,
|
||||
gpointer user_data)
|
||||
|
@ -57,3 +57,7 @@ int64_t meta_wayland_transaction_get_target_presentation_time_us (const MetaWayl
|
||||
|
||||
gboolean meta_wayland_transaction_unblock_timed (MetaWaylandTransaction *transaction,
|
||||
int64_t target_time_us);
|
||||
|
||||
void meta_wayland_transaction_unblock_surface (MetaWaylandSurface *surface);
|
||||
|
||||
void meta_wayland_transaction_consider_surface (MetaWaylandSurface *surface);
|
||||
|
@ -64,3 +64,4 @@
|
||||
#define META_WP_SYSTEM_BELL_V1_VERSION 1
|
||||
#define META_XDG_TOPLEVEL_DRAG_VERSION 1
|
||||
#define META_WP_COMMIT_TIMING_V1_VERSION 1
|
||||
#define META_WP_FIFO_V1_VERSION 1
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "wayland/meta-wayland-buffer.h"
|
||||
#include "wayland/meta-wayland-color-management.h"
|
||||
#include "wayland/meta-wayland-commit-timing.h"
|
||||
#include "wayland/meta-wayland-fifo.h"
|
||||
#include "wayland/meta-wayland-data-device.h"
|
||||
#include "wayland/meta-wayland-dma-buf.h"
|
||||
#include "wayland/meta-wayland-egl-stream.h"
|
||||
@ -374,6 +375,36 @@ clear_time_constraints_for_stage_view_transactions (MetaWaylandCompositor *compo
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clear_barrier_for_stage_view_surfaces (MetaWaylandCompositor *compositor,
|
||||
ClutterStageView *stage_view)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
l = compositor->barrier_surfaces;
|
||||
while (l)
|
||||
{
|
||||
GList *l_cur = l;
|
||||
MetaWaylandSurface *surface = l->data;
|
||||
MetaSurfaceActor *actor;
|
||||
|
||||
l = l->next;
|
||||
|
||||
/* If the surface is not visible, the fifo condition should be
|
||||
* unblocked, even if it wasn't on this stage view */
|
||||
actor = meta_wayland_surface_get_actor (surface);
|
||||
if (actor && !meta_surface_actor_is_effectively_obscured (actor) &&
|
||||
clutter_actor_is_mapped (CLUTTER_ACTOR (actor)) &&
|
||||
!meta_surface_actor_wayland_is_view_primary (actor, stage_view))
|
||||
continue;
|
||||
|
||||
compositor->barrier_surfaces =
|
||||
g_list_delete_link (compositor->barrier_surfaces, l_cur);
|
||||
|
||||
meta_wayland_transaction_unblock_surface (surface);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_before_update (ClutterStage *stage,
|
||||
ClutterStageView *stage_view,
|
||||
@ -400,6 +431,8 @@ on_after_update (ClutterStage *stage,
|
||||
GSource *source;
|
||||
int64_t frame_deadline_us;
|
||||
|
||||
clear_barrier_for_stage_view_surfaces (compositor, stage_view);
|
||||
|
||||
if (!META_IS_BACKEND_NATIVE (backend))
|
||||
{
|
||||
emit_frame_callbacks_for_stage_view (compositor, stage_view);
|
||||
@ -430,6 +463,7 @@ on_after_update (ClutterStage *stage,
|
||||
|
||||
g_source_set_ready_time (source, frame_deadline_us);
|
||||
#else
|
||||
clear_barrier_for_stage_view_surfaces (compositor, stage_view);
|
||||
emit_frame_callbacks_for_stage_view (compositor, stage_view);
|
||||
#endif
|
||||
}
|
||||
@ -671,6 +705,25 @@ meta_wayland_compositor_remove_timed_transaction (MetaWaylandCompositor *compos
|
||||
g_queue_remove (compositor->timed_transactions, transaction);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_compositor_add_barrier_surface (MetaWaylandCompositor *compositor,
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
if (g_list_find (compositor->barrier_surfaces, surface))
|
||||
return;
|
||||
|
||||
compositor->barrier_surfaces =
|
||||
g_list_prepend (compositor->barrier_surfaces, surface);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_compositor_remove_barrier_surface (MetaWaylandCompositor *compositor,
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
compositor->barrier_surfaces =
|
||||
g_list_remove (compositor->barrier_surfaces, surface);
|
||||
}
|
||||
|
||||
GQueue *
|
||||
meta_wayland_compositor_get_committed_transactions (MetaWaylandCompositor *compositor)
|
||||
{
|
||||
@ -973,6 +1026,7 @@ meta_wayland_compositor_new (MetaContext *context)
|
||||
meta_wayland_drm_lease_manager_init (compositor);
|
||||
#endif
|
||||
meta_wayland_commit_timing_init (compositor);
|
||||
meta_wayland_fifo_init (compositor);
|
||||
|
||||
#ifdef HAVE_WAYLAND_EGLSTREAM
|
||||
{
|
||||
|
@ -68,6 +68,11 @@ void meta_wayland_compositor_add_timed_transaction (MetaWayla
|
||||
|
||||
void meta_wayland_compositor_remove_timed_transaction (MetaWaylandCompositor *compositor,
|
||||
MetaWaylandTransaction *transaction);
|
||||
void meta_wayland_compositor_add_barrier_surface (MetaWaylandCompositor *compositor,
|
||||
MetaWaylandSurface *surface);
|
||||
|
||||
void meta_wayland_compositor_remove_barrier_surface (MetaWaylandCompositor *compositor,
|
||||
MetaWaylandSurface *surface);
|
||||
|
||||
GQueue *meta_wayland_compositor_get_committed_transactions (MetaWaylandCompositor *compositor);
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
#include "wayland/meta-wayland-surface-private.h"
|
||||
#include "wayland/meta-wayland-toplevel-drag.h"
|
||||
#include "wayland/meta-wayland-transaction.h"
|
||||
#include "wayland/meta-wayland-window-configuration.h"
|
||||
#include "wayland/meta-wayland-xdg-shell.h"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user