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



commit f44238a72f2879a2a9b13a50fd42752bb84ff1b9
Author: Jonas Ådahl <jadahl gmail com>
Date:   Wed Mar 16 14:55:51 2016 +0800

    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

 src/wayland/meta-wayland-surface.c |   66 ++++++++++++++++++++++++++++++++----
 src/wayland/meta-wayland-surface.h |    7 ++++
 2 files changed, 66 insertions(+), 7 deletions(-)
---
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 7e1fb01..90ffd94 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -141,6 +141,10 @@ static void
 meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *surface_role);
 
 static void
+meta_wayland_surface_role_pre_commit (MetaWaylandSurfaceRole  *surface_role,
+                                      MetaWaylandPendingState *pending);
+
+static void
 meta_wayland_surface_role_commit (MetaWaylandSurfaceRole  *surface_role,
                                   MetaWaylandPendingState *pending);
 
@@ -163,6 +167,13 @@ meta_wayland_surface_assign_role (MetaWaylandSurface *surface,
 
       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;
     }
   else if (G_OBJECT_TYPE (surface->role) != role_type)
@@ -663,6 +674,19 @@ apply_pending_state (MetaWaylandSurface      *surface,
   MetaSurfaceActorWayland *surface_actor_wayland =
     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)
     {
       gboolean switched_buffer;
@@ -708,13 +732,6 @@ apply_pending_state (MetaWaylandSurface      *surface,
   if (!cairo_region_is_empty (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_y += pending->dy;
 
@@ -752,8 +769,26 @@ apply_pending_state (MetaWaylandSurface      *surface,
       wl_list_insert_list (&surface->pending_frame_callback_list,
                            &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,
                  pending_state_signals[PENDING_STATE_SIGNAL_APPLIED],
                  0);
@@ -1147,6 +1182,12 @@ wl_surface_destructor (struct wl_resource *resource)
   if (surface->window)
     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)
     meta_wayland_surface_unref_buffer_use_count (surface);
   g_clear_object (&surface->buffer_ref.buffer);
@@ -2654,6 +2695,17 @@ meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *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
 meta_wayland_surface_role_commit (MetaWaylandSurfaceRole  *surface_role,
                                   MetaWaylandPendingState *pending)
 {
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index e7523d8..c817ed7 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -56,6 +56,8 @@ struct _MetaWaylandSurfaceRoleClass
   GObjectClass parent_class;
 
   void (*assigned) (MetaWaylandSurfaceRole *surface_role);
+  void (*pre_commit) (MetaWaylandSurfaceRole  *surface_role,
+                      MetaWaylandPendingState *pending);
   void (*commit) (MetaWaylandSurfaceRole  *surface_role,
                   MetaWaylandPendingState *pending);
   gboolean (*is_on_output) (MetaWaylandSurfaceRole *surface_role,
@@ -172,6 +174,11 @@ struct _MetaWaylandSurface
    */
   struct wl_list pending_frame_callback_list;
 
+  /* Intermediate state for when no role has been assigned. */
+  struct {
+    MetaWaylandBuffer *buffer;
+  } unassigned;
+
   struct {
     const MetaWaylandDragDestFuncs *funcs;
   } dnd;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]