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. https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
This commit is contained in:
parent
3d47c7edc1
commit
47002bf0cd
@ -156,7 +156,7 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor
|
|||||||
surface_actor = priv->actor;
|
surface_actor = priv->actor;
|
||||||
stex = meta_surface_actor_get_texture (surface_actor);
|
stex = meta_surface_actor_get_texture (surface_actor);
|
||||||
|
|
||||||
buffer = surface->buffer_ref.buffer;
|
buffer = surface->buffer_ref->buffer;
|
||||||
if (buffer)
|
if (buffer)
|
||||||
{
|
{
|
||||||
CoglSnippet *snippet;
|
CoglSnippet *snippet;
|
||||||
|
@ -986,7 +986,7 @@ meta_wayland_zxdg_popup_v6_apply_state (MetaWaylandSurfaceRole *surface_role,
|
|||||||
if (!pending->newly_attached)
|
if (!pending->newly_attached)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!surface->buffer_ref.buffer)
|
if (!surface->buffer_ref->buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (pending->has_acked_configure_serial)
|
if (pending->has_acked_configure_serial)
|
||||||
@ -1348,7 +1348,7 @@ meta_wayland_zxdg_surface_v6_apply_state (MetaWaylandSurfaceRole *surface_role,
|
|||||||
if (!priv->resource)
|
if (!priv->resource)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (surface->buffer_ref.buffer == NULL && priv->first_buffer_attached)
|
if (!surface->buffer_ref->buffer && priv->first_buffer_attached)
|
||||||
{
|
{
|
||||||
/* XDG surfaces can't commit NULL buffers */
|
/* XDG surfaces can't commit NULL buffers */
|
||||||
wl_resource_post_error (surface->resource,
|
wl_resource_post_error (surface->resource,
|
||||||
@ -1357,7 +1357,7 @@ meta_wayland_zxdg_surface_v6_apply_state (MetaWaylandSurfaceRole *surface_role,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (surface->buffer_ref.buffer && !priv->configure_sent)
|
if (surface->buffer_ref->buffer && !priv->configure_sent)
|
||||||
{
|
{
|
||||||
wl_resource_post_error (surface->resource,
|
wl_resource_post_error (surface->resource,
|
||||||
ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER,
|
ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER,
|
||||||
@ -1368,7 +1368,7 @@ meta_wayland_zxdg_surface_v6_apply_state (MetaWaylandSurfaceRole *surface_role,
|
|||||||
if (!window)
|
if (!window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (surface->buffer_ref.buffer)
|
if (surface->buffer_ref->buffer)
|
||||||
priv->first_buffer_attached = TRUE;
|
priv->first_buffer_attached = TRUE;
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
@ -1413,7 +1413,7 @@ meta_wayland_zxdg_surface_v6_assigned (MetaWaylandSurfaceRole *surface_role)
|
|||||||
priv->configure_sent = FALSE;
|
priv->configure_sent = FALSE;
|
||||||
priv->first_buffer_attached = FALSE;
|
priv->first_buffer_attached = FALSE;
|
||||||
|
|
||||||
if (surface->buffer_ref.buffer)
|
if (surface->buffer_ref->buffer)
|
||||||
{
|
{
|
||||||
wl_resource_post_error (xdg_shell_resource,
|
wl_resource_post_error (xdg_shell_resource,
|
||||||
ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
|
ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
|
||||||
@ -1957,7 +1957,7 @@ zxdg_shell_v6_get_xdg_surface (struct wl_client *client,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (surface->buffer_ref.buffer)
|
if (surface->buffer_ref->buffer)
|
||||||
{
|
{
|
||||||
wl_resource_post_error (resource,
|
wl_resource_post_error (resource,
|
||||||
ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
|
ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
|
||||||
|
@ -245,7 +245,7 @@ meta_wayland_shell_surface_surface_pre_apply_state (MetaWaylandSurfaceRole *sur
|
|||||||
meta_wayland_surface_role_get_surface (surface_role);
|
meta_wayland_surface_role_get_surface (surface_role);
|
||||||
|
|
||||||
if (pending->newly_attached &&
|
if (pending->newly_attached &&
|
||||||
!surface->buffer_ref.buffer &&
|
!surface->buffer_ref->buffer &&
|
||||||
priv->window)
|
priv->window)
|
||||||
meta_window_queue (priv->window, META_QUEUE_CALC_SHOWING);
|
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);
|
META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_shell_surface_parent_class);
|
||||||
surface_role_class->apply_state (surface_role, pending);
|
surface_role_class->apply_state (surface_role, pending);
|
||||||
|
|
||||||
buffer = surface->buffer_ref.buffer;
|
buffer = surface->buffer_ref->buffer;
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ sync_actor_subsurface_state (MetaWaylandSurface *surface)
|
|||||||
clutter_actor_set_position (actor, x, y);
|
clutter_actor_set_position (actor, x, y);
|
||||||
clutter_actor_set_reactive (actor, TRUE);
|
clutter_actor_set_reactive (actor, TRUE);
|
||||||
|
|
||||||
if (surface->buffer_ref.buffer)
|
if (surface->buffer_ref->buffer)
|
||||||
clutter_actor_show (actor);
|
clutter_actor_show (actor);
|
||||||
else
|
else
|
||||||
clutter_actor_hide (actor);
|
clutter_actor_hide (actor);
|
||||||
|
@ -120,6 +120,22 @@ meta_wayland_surface_role_is_on_logical_monitor (MetaWaylandSurfaceRole *surface
|
|||||||
static MetaWaylandSurface *
|
static MetaWaylandSurface *
|
||||||
meta_wayland_surface_role_get_toplevel (MetaWaylandSurfaceRole *surface_role);
|
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
|
static void
|
||||||
role_assignment_valist_to_properties (GType role_type,
|
role_assignment_valist_to_properties (GType role_type,
|
||||||
const char *first_property_name,
|
const char *first_property_name,
|
||||||
@ -364,30 +380,30 @@ meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface
|
|||||||
MetaWaylandBuffer *
|
MetaWaylandBuffer *
|
||||||
meta_wayland_surface_get_buffer (MetaWaylandSurface *surface)
|
meta_wayland_surface_get_buffer (MetaWaylandSurface *surface)
|
||||||
{
|
{
|
||||||
return surface->buffer_ref.buffer;
|
return surface->buffer_ref->buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_wayland_surface_ref_buffer_use_count (MetaWaylandSurface *surface)
|
meta_wayland_surface_ref_buffer_use_count (MetaWaylandSurface *surface)
|
||||||
{
|
{
|
||||||
g_return_if_fail (surface->buffer_ref.buffer);
|
g_return_if_fail (surface->buffer_ref->buffer);
|
||||||
g_warn_if_fail (surface->buffer_ref.buffer->resource);
|
g_warn_if_fail (surface->buffer_ref->buffer->resource);
|
||||||
|
|
||||||
surface->buffer_ref.use_count++;
|
surface->buffer_ref->use_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_wayland_surface_unref_buffer_use_count (MetaWaylandSurface *surface)
|
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);
|
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);
|
wl_buffer_send_release (buffer->resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,7 +650,7 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface,
|
|||||||
if (surface->buffer_held)
|
if (surface->buffer_held)
|
||||||
meta_wayland_surface_unref_buffer_use_count (surface);
|
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)
|
if (state->buffer)
|
||||||
meta_wayland_surface_ref_buffer_use_count (surface);
|
meta_wayland_surface_ref_buffer_use_count (surface);
|
||||||
@ -739,7 +755,8 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface,
|
|||||||
* role the surface is given. That means we need to also keep a use
|
* 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.
|
* 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)
|
if (surface->unassigned.buffer)
|
||||||
meta_wayland_surface_ref_buffer_use_count (surface);
|
meta_wayland_surface_ref_buffer_use_count (surface);
|
||||||
}
|
}
|
||||||
@ -750,7 +767,7 @@ cleanup:
|
|||||||
* be released if no-one else has a use-reference to it.
|
* be released if no-one else has a use-reference to it.
|
||||||
*/
|
*/
|
||||||
if (state->newly_attached &&
|
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);
|
meta_wayland_surface_unref_buffer_use_count (surface);
|
||||||
|
|
||||||
g_signal_emit (state,
|
g_signal_emit (state,
|
||||||
@ -1278,7 +1295,8 @@ wl_surface_destructor (struct wl_resource *resource)
|
|||||||
if (surface->buffer_held)
|
if (surface->buffer_held)
|
||||||
meta_wayland_surface_unref_buffer_use_count (surface);
|
meta_wayland_surface_unref_buffer_use_count (surface);
|
||||||
g_clear_pointer (&surface->texture, cogl_object_unref);
|
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->cached_state);
|
||||||
g_clear_object (&surface->pending_state);
|
g_clear_object (&surface->pending_state);
|
||||||
@ -1544,6 +1562,9 @@ static void
|
|||||||
meta_wayland_surface_init (MetaWaylandSurface *surface)
|
meta_wayland_surface_init (MetaWaylandSurface *surface)
|
||||||
{
|
{
|
||||||
surface->pending_state = g_object_new (META_TYPE_WAYLAND_SURFACE_STATE, NULL);
|
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_branch_node = g_node_new (surface);
|
||||||
surface->subsurface_leaf_node =
|
surface->subsurface_leaf_node =
|
||||||
g_node_prepend_data (surface->subsurface_branch_node, surface);
|
g_node_prepend_data (surface->subsurface_branch_node, surface);
|
||||||
@ -1813,7 +1834,7 @@ meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface)
|
|||||||
cairo_region_t *region;
|
cairo_region_t *region;
|
||||||
cairo_rectangle_int_t buffer_rect;
|
cairo_rectangle_int_t buffer_rect;
|
||||||
|
|
||||||
if (!surface->buffer_ref.buffer)
|
if (!surface->buffer_ref->buffer)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
buffer_rect = (cairo_rectangle_int_t) {
|
buffer_rect = (cairo_rectangle_int_t) {
|
||||||
|
@ -136,6 +136,12 @@ struct _MetaWaylandDragDestFuncs
|
|||||||
MetaWaylandSurface *surface);
|
MetaWaylandSurface *surface);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct _MetaWaylandBufferRef
|
||||||
|
{
|
||||||
|
MetaWaylandBuffer *buffer;
|
||||||
|
unsigned int use_count;
|
||||||
|
} MetaWaylandBufferRef;
|
||||||
|
|
||||||
struct _MetaWaylandSurface
|
struct _MetaWaylandSurface
|
||||||
{
|
{
|
||||||
GObject parent;
|
GObject parent;
|
||||||
@ -156,10 +162,7 @@ struct _MetaWaylandSurface
|
|||||||
CoglTexture *texture;
|
CoglTexture *texture;
|
||||||
|
|
||||||
/* Buffer reference state. */
|
/* Buffer reference state. */
|
||||||
struct {
|
MetaWaylandBufferRef *buffer_ref;
|
||||||
MetaWaylandBuffer *buffer;
|
|
||||||
unsigned int use_count;
|
|
||||||
} buffer_ref;
|
|
||||||
|
|
||||||
/* Buffer renderer state. */
|
/* Buffer renderer state. */
|
||||||
gboolean buffer_held;
|
gboolean buffer_held;
|
||||||
|
@ -598,11 +598,11 @@ wl_shell_surface_role_apply_state (MetaWaylandSurfaceRole *surface_role,
|
|||||||
/* For wl_shell, it's equivalent to an unmap. Semantics
|
/* For wl_shell, it's equivalent to an unmap. Semantics
|
||||||
* are poorly defined, so we can choose some that are
|
* are poorly defined, so we can choose some that are
|
||||||
* convenient for us. */
|
* convenient for us. */
|
||||||
if (surface->buffer_ref.buffer && !window)
|
if (surface->buffer_ref->buffer && !window)
|
||||||
{
|
{
|
||||||
create_wl_shell_surface_window (surface);
|
create_wl_shell_surface_window (surface);
|
||||||
}
|
}
|
||||||
else if (!surface->buffer_ref.buffer && window)
|
else if (!surface->buffer_ref->buffer && window)
|
||||||
{
|
{
|
||||||
if (wl_shell_surface->popup)
|
if (wl_shell_surface->popup)
|
||||||
meta_wayland_popup_dismiss (wl_shell_surface->popup);
|
meta_wayland_popup_dismiss (wl_shell_surface->popup);
|
||||||
|
@ -754,7 +754,7 @@ meta_wayland_xdg_toplevel_apply_state (MetaWaylandSurfaceRole *surface_role,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!surface->buffer_ref.buffer && xdg_surface_priv->first_buffer_attached)
|
if (!surface->buffer_ref->buffer && xdg_surface_priv->first_buffer_attached)
|
||||||
{
|
{
|
||||||
MetaWaylandActorSurface *actor_surface =
|
MetaWaylandActorSurface *actor_surface =
|
||||||
META_WAYLAND_ACTOR_SURFACE (xdg_toplevel);
|
META_WAYLAND_ACTOR_SURFACE (xdg_toplevel);
|
||||||
@ -1100,7 +1100,7 @@ meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role,
|
|||||||
if (xdg_popup->setup.parent_surface)
|
if (xdg_popup->setup.parent_surface)
|
||||||
finish_popup_setup (xdg_popup);
|
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_xdg_surface_reset (xdg_surface);
|
||||||
meta_wayland_surface_cache_pending_frame_callbacks (surface, pending);
|
meta_wayland_surface_cache_pending_frame_callbacks (surface, pending);
|
||||||
@ -1111,7 +1111,7 @@ meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role,
|
|||||||
META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_popup_parent_class);
|
META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_popup_parent_class);
|
||||||
surface_role_class->apply_state (surface_role, pending);
|
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,
|
wl_resource_post_error (xdg_popup->resource,
|
||||||
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
|
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
|
||||||
@ -1127,7 +1127,7 @@ meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role,
|
|||||||
if (!pending->newly_attached)
|
if (!pending->newly_attached)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!surface->buffer_ref.buffer)
|
if (!surface->buffer_ref->buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (pending->has_acked_configure_serial)
|
if (pending->has_acked_configure_serial)
|
||||||
@ -1524,7 +1524,7 @@ meta_wayland_xdg_surface_apply_state (MetaWaylandSurfaceRole *surface_role,
|
|||||||
if (!window)
|
if (!window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (surface->buffer_ref.buffer)
|
if (surface->buffer_ref->buffer)
|
||||||
priv->first_buffer_attached = TRUE;
|
priv->first_buffer_attached = TRUE;
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
@ -1568,7 +1568,7 @@ meta_wayland_xdg_surface_assigned (MetaWaylandSurfaceRole *surface_role)
|
|||||||
priv->configure_sent = FALSE;
|
priv->configure_sent = FALSE;
|
||||||
priv->first_buffer_attached = FALSE;
|
priv->first_buffer_attached = FALSE;
|
||||||
|
|
||||||
if (surface->buffer_ref.buffer)
|
if (surface->buffer_ref->buffer)
|
||||||
{
|
{
|
||||||
wl_resource_post_error (xdg_wm_base_resource,
|
wl_resource_post_error (xdg_wm_base_resource,
|
||||||
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
|
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
|
||||||
@ -2254,7 +2254,7 @@ xdg_wm_base_get_xdg_surface (struct wl_client *client,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (surface->buffer_ref.buffer)
|
if (surface->buffer_ref->buffer)
|
||||||
{
|
{
|
||||||
wl_resource_post_error (resource,
|
wl_resource_post_error (resource,
|
||||||
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
|
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
|
||||||
|
@ -182,7 +182,7 @@ meta_xwayland_surface_pre_apply_state (MetaWaylandSurfaceRole *surface_role,
|
|||||||
MetaXwaylandSurface *xwayland_surface = META_XWAYLAND_SURFACE (surface_role);
|
MetaXwaylandSurface *xwayland_surface = META_XWAYLAND_SURFACE (surface_role);
|
||||||
|
|
||||||
if (pending->newly_attached &&
|
if (pending->newly_attached &&
|
||||||
surface->buffer_ref.buffer &&
|
surface->buffer_ref->buffer &&
|
||||||
xwayland_surface->window)
|
xwayland_surface->window)
|
||||||
meta_window_queue (xwayland_surface->window, META_QUEUE_CALC_SHOWING);
|
meta_window_queue (xwayland_surface->window, META_QUEUE_CALC_SHOWING);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user