MetaWaylandSurface: Keep an extra buffer use count for role-less surfaces

Whether a surface needs to keep the committed wl_buffer un-released
depends on what role the surface gets assigned to. For example a cursor
role may need an unreleased shm buffer in order to create a hw cursor from
it.

In order to support this, keep a separate reference and use count to
the buffer on behalf of the in the future assigned role, and release
those references after the surface was assigned a role. A role that
needs its own references and use counts, must in its assign function
make sure to add those.

https://bugzilla.gnome.org/show_bug.cgi?id=762828
This commit is contained in:
Jonas Ådahl 2016-03-16 14:55:51 +08:00
parent 10a0114856
commit f44238a72f
2 changed files with 66 additions and 7 deletions

View File

@ -140,6 +140,10 @@ G_DEFINE_TYPE (MetaWaylandSurfaceRoleDND,
static void static void
meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *surface_role); meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *surface_role);
static void
meta_wayland_surface_role_pre_commit (MetaWaylandSurfaceRole *surface_role,
MetaWaylandPendingState *pending);
static void static void
meta_wayland_surface_role_commit (MetaWaylandSurfaceRole *surface_role, meta_wayland_surface_role_commit (MetaWaylandSurfaceRole *surface_role,
MetaWaylandPendingState *pending); MetaWaylandPendingState *pending);
@ -163,6 +167,13 @@ meta_wayland_surface_assign_role (MetaWaylandSurface *surface,
meta_wayland_surface_role_assigned (surface->role); meta_wayland_surface_role_assigned (surface->role);
/* Release the use count held on behalf of the just assigned role. */
if (surface->unassigned.buffer)
{
meta_wayland_surface_unref_buffer_use_count (surface);
g_clear_object (&surface->unassigned.buffer);
}
return TRUE; return TRUE;
} }
else if (G_OBJECT_TYPE (surface->role) != role_type) else if (G_OBJECT_TYPE (surface->role) != role_type)
@ -663,6 +674,19 @@ apply_pending_state (MetaWaylandSurface *surface,
MetaSurfaceActorWayland *surface_actor_wayland = MetaSurfaceActorWayland *surface_actor_wayland =
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor); META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
if (surface->role)
{
meta_wayland_surface_role_pre_commit (surface->role, pending);
}
else
{
if (pending->newly_attached && surface->unassigned.buffer)
{
meta_wayland_surface_unref_buffer_use_count (surface);
g_clear_object (&surface->unassigned.buffer);
}
}
if (pending->newly_attached) if (pending->newly_attached)
{ {
gboolean switched_buffer; gboolean switched_buffer;
@ -708,13 +732,6 @@ apply_pending_state (MetaWaylandSurface *surface,
if (!cairo_region_is_empty (pending->damage)) if (!cairo_region_is_empty (pending->damage))
surface_process_damage (surface, pending->damage); surface_process_damage (surface, pending->damage);
/* If we have a buffer that we are not using, decrease the use count so it may
* be released if no-one else has a use-reference to it.
*/
if (pending->newly_attached &&
!surface->buffer_held && surface->buffer_ref.buffer)
meta_wayland_surface_unref_buffer_use_count (surface);
surface->offset_x += pending->dx; surface->offset_x += pending->dx;
surface->offset_y += pending->dy; surface->offset_y += pending->dy;
@ -752,8 +769,26 @@ apply_pending_state (MetaWaylandSurface *surface,
wl_list_insert_list (&surface->pending_frame_callback_list, wl_list_insert_list (&surface->pending_frame_callback_list,
&pending->frame_callback_list); &pending->frame_callback_list);
wl_list_init (&pending->frame_callback_list); wl_list_init (&pending->frame_callback_list);
if (pending->newly_attached)
{
/* The need to keep the wl_buffer from being released depends on what
* 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.
*/
g_set_object (&surface->unassigned.buffer, surface->buffer_ref.buffer);
if (surface->unassigned.buffer)
meta_wayland_surface_ref_buffer_use_count (surface);
}
} }
/* If we have a buffer that we are not using, decrease the use count so it may
* be released if no-one else has a use-reference to it.
*/
if (pending->newly_attached &&
!surface->buffer_held && surface->buffer_ref.buffer)
meta_wayland_surface_unref_buffer_use_count (surface);
g_signal_emit (pending, g_signal_emit (pending,
pending_state_signals[PENDING_STATE_SIGNAL_APPLIED], pending_state_signals[PENDING_STATE_SIGNAL_APPLIED],
0); 0);
@ -1147,6 +1182,12 @@ wl_surface_destructor (struct wl_resource *resource)
if (surface->window) if (surface->window)
destroy_window (surface); destroy_window (surface);
if (surface->unassigned.buffer)
{
meta_wayland_surface_unref_buffer_use_count (surface);
g_clear_object (&surface->unassigned.buffer);
}
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_object (&surface->buffer_ref.buffer); g_clear_object (&surface->buffer_ref.buffer);
@ -2653,6 +2694,17 @@ meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *surface_role)
META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role)->assigned (surface_role); META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role)->assigned (surface_role);
} }
static void
meta_wayland_surface_role_pre_commit (MetaWaylandSurfaceRole *surface_role,
MetaWaylandPendingState *pending)
{
MetaWaylandSurfaceRoleClass *klass;
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
if (klass->pre_commit)
klass->pre_commit (surface_role, pending);
}
static void static void
meta_wayland_surface_role_commit (MetaWaylandSurfaceRole *surface_role, meta_wayland_surface_role_commit (MetaWaylandSurfaceRole *surface_role,
MetaWaylandPendingState *pending) MetaWaylandPendingState *pending)

View File

@ -56,6 +56,8 @@ struct _MetaWaylandSurfaceRoleClass
GObjectClass parent_class; GObjectClass parent_class;
void (*assigned) (MetaWaylandSurfaceRole *surface_role); void (*assigned) (MetaWaylandSurfaceRole *surface_role);
void (*pre_commit) (MetaWaylandSurfaceRole *surface_role,
MetaWaylandPendingState *pending);
void (*commit) (MetaWaylandSurfaceRole *surface_role, void (*commit) (MetaWaylandSurfaceRole *surface_role,
MetaWaylandPendingState *pending); MetaWaylandPendingState *pending);
gboolean (*is_on_output) (MetaWaylandSurfaceRole *surface_role, gboolean (*is_on_output) (MetaWaylandSurfaceRole *surface_role,
@ -172,6 +174,11 @@ struct _MetaWaylandSurface
*/ */
struct wl_list pending_frame_callback_list; struct wl_list pending_frame_callback_list;
/* Intermediate state for when no role has been assigned. */
struct {
MetaWaylandBuffer *buffer;
} unassigned;
struct { struct {
const MetaWaylandDragDestFuncs *funcs; const MetaWaylandDragDestFuncs *funcs;
} dnd; } dnd;