pepper: Implement subsurface 05/52905/1
authorJaehoon Jeong <jh01.j@samsung.com>
Fri, 20 Nov 2015 08:52:38 +0000 (17:52 +0900)
committerTaekyun Kim <tkq.kim@samsung.com>
Fri, 27 Nov 2015 10:27:46 +0000 (19:27 +0900)
    - Update surface.commit for subsurface
    - Add link to its own subsurface_list

Change-Id: I9fe3d1b1c9386f700d848f16b6d4c15b60b75533

src/lib/pepper/pepper-internal.h
src/lib/pepper/subcompositor.c
src/lib/pepper/subsurface.c
src/lib/pepper/surface.c

index 2aa830ae0eec7d774ff704f2293228ac4c00429e..d9e3d911a353e92819f137f1141f631d6ab7727d 100644 (file)
@@ -232,6 +232,9 @@ pepper_surface_destroy(pepper_surface_t *surface);
 void
 pepper_surface_commit(pepper_surface_t *surface);
 
+void
+pepper_surface_commit_state(pepper_surface_t *surface, pepper_surface_state_t *state);
+
 void
 pepper_surface_send_frame_callback_done(pepper_surface_t *surface, uint32_t time);
 
@@ -280,31 +283,42 @@ struct pepper_subsurface
     struct wl_resource      *resource;
 
     double                   x, y;
-    pepper_list_t            parent_link;
+    pepper_list_t            children_list;
+
+    pepper_list_t            parent_link;       /* link to parent's children_list */
+    pepper_list_t            self_link;         /* link to its own children_list */
 
     /* This state is applied when the parent surface's wl_surface state is applied,
      * regardless of the sub-surface's mode. */
     struct
     {
         double               x, y;
+        pepper_list_t        children_list;
+
         pepper_list_t        parent_link;
+        pepper_list_t        self_link;
     } pending;
 
-    pepper_bool_t            restacked;
+    pepper_bool_t            need_restack;
 
-    pepper_bool_t            synchronized;    /* commit behavior */
+    pepper_bool_t            sync;          /* requested commit behavior */
 
     /* In sync mode, wl_surface.commit will apply the pending state into cache.
      * And cached state will flush into surface's current when parent's wl_surface.commit called */
     pepper_surface_state_t   cache;
+    pepper_bool_t            cached;
 
     pepper_event_listener_t *parent_destroy_listener;
+    pepper_event_listener_t *parent_commit_listener;
 };
 
 pepper_subsurface_t *
 pepper_subsurface_create(pepper_surface_t *surface, pepper_surface_t *parent,
                          struct wl_client *client, struct wl_resource *resource, uint32_t id);
 
+pepper_bool_t
+pepper_subsurface_commit(pepper_subsurface_t *subsurface);
+
 void
 pepper_subsurface_destroy(pepper_subsurface_t *subsurface);
 
index c10111930b0e8938ed46aa9289c384a3fefd2dfc..4249cdfe109c1004f6d026236a2c0d0ab4fb7678 100644 (file)
@@ -41,10 +41,8 @@ subcompositor_get_subsurface(struct wl_client   *client,
                              struct wl_resource *surface_resource,
                              struct wl_resource *parent_resource)
 {
-    pepper_subcompositor_t  *subcompositor = wl_resource_get_user_data(resource);
     pepper_surface_t        *surface = wl_resource_get_user_data(surface_resource);
     pepper_surface_t        *parent  = wl_resource_get_user_data(parent_resource);
-    pepper_subsurface_t     *subsurface;
 
     if (surface->sub)
     {
index 7a03870cada4380240659f669fd04eb759500d7c..29c3c8395d88cc3da4e5c5ec8836dff4dbeffacb 100644 (file)
@@ -50,30 +50,35 @@ subsurface_set_position(struct wl_client    *client,
 static pepper_bool_t
 subsurface_is_sibling(pepper_subsurface_t *subsurface, pepper_surface_t *sib)
 {
-    pepper_subsurface_t *sibling = sib->sub;
-
-    if (sibling)
-    {
-        if (subsurface->parent == sibling->surface)
-            return PEPPER_TRUE;
-        else if(subsurface->parent == sibling->parent)
-            return PEPPER_TRUE;
-    }
+    if (subsurface->parent == sib)
+        return PEPPER_TRUE;
+    else if(sib->sub && sib->sub->parent == subsurface->parent)
+        return PEPPER_TRUE;
 
     return PEPPER_FALSE;
 }
 
 static void
-subsurface_stack_above(pepper_subsurface_t *subsurface, pepper_surface_t *sib)
+subsurface_stack_above(pepper_subsurface_t *subsurface, pepper_subsurface_t *sibling)
 {
-    pepper_subsurface_t *sibling = sib->sub;
+    pepper_subsurface_t *parent;
+    pepper_list_t       *pos;
 
-    /* TODO: sibling == parent */
+    if (subsurface->parent == sibling->surface)
+    {
+        parent = sibling;
+        pos = &parent->pending.self_link;
+    }
+    else
+    {
+        parent = subsurface->parent->sub;
+        pos = &sibling->pending.parent_link;
+    }
 
     pepper_list_remove(&subsurface->pending.parent_link);
-    pepper_list_insert(&sibling->pending.parent_link, &subsurface->pending.parent_link);
+    pepper_list_insert(pos, &subsurface->pending.parent_link);
 
-    subsurface->restacked = PEPPER_TRUE;
+    parent->need_restack = PEPPER_TRUE;
 }
 
 static void
@@ -107,20 +112,30 @@ subsurface_place_above(struct wl_client     *client,
         return ;
     }
 
-    subsurface_stack_above(sub, sibling);
+    subsurface_stack_above(sub, sibling->sub);
 }
 
 static void
-subsurface_stack_below(pepper_subsurface_t *subsurface, pepper_surface_t *sib)
+subsurface_stack_below(pepper_subsurface_t *subsurface, pepper_subsurface_t *sibling)
 {
-    pepper_subsurface_t *sibling = sib->sub;
+    pepper_subsurface_t *parent;
+    pepper_list_t       *pos;
 
-    /* TODO: sibling == parent */
+    if (subsurface->parent == sibling->surface)
+    {
+        parent = sibling;
+        pos = &parent->pending.self_link;
+    }
+    else
+    {
+        parent = subsurface->parent->sub;
+        pos = &sibling->pending.parent_link;
+    }
 
     pepper_list_remove(&subsurface->pending.parent_link);
-    pepper_list_insert(sibling->pending.parent_link.prev, &subsurface->pending.parent_link);
+    pepper_list_insert(pos->prev, &subsurface->pending.parent_link);
 
-    subsurface->restacked = PEPPER_TRUE;
+    parent->need_restack = PEPPER_TRUE;
 }
 
 static void
@@ -154,7 +169,7 @@ subsurface_place_below(struct wl_client     *client,
         return ;
     }
 
-    subsurface_stack_below(sub, sibling);
+    subsurface_stack_below(sub, sibling->sub);
 }
 
 static void
@@ -163,7 +178,179 @@ subsurface_set_sync(struct wl_client    *client,
 {
     pepper_subsurface_t *subsurface = wl_resource_get_user_data(resource);
 
-    subsurface->synchronized = 1;
+    subsurface->sync = PEPPER_TRUE;
+}
+
+/* Copy 'from' -> 'to' state and clear 'from' state */
+static void
+surface_state_move(pepper_surface_state_t *from, pepper_surface_state_t *to)
+{
+    if (from->newly_attached)
+    {
+        to->newly_attached = PEPPER_TRUE;
+        to->buffer         = from->buffer;
+
+        from->newly_attached = PEPPER_FALSE;
+        from->buffer         = NULL;
+    }
+
+    to->transform = from->transform;
+    to->scale     = from->scale;
+    to->x        += from->x;
+    to->y        += from->y;
+
+    /* FIXME: Need to create another one? */
+    to->buffer_destroy_listener = from->buffer_destroy_listener;
+
+    pixman_region32_copy(&to->damage_region, &from->damage_region);
+    pixman_region32_copy(&to->opaque_region, &from->opaque_region);
+    pixman_region32_copy(&to->input_region,  &from->input_region);
+
+    wl_list_insert_list(&to->frame_callback_list, &from->frame_callback_list);
+
+    /* Clear 'from' state */
+    from->x         = 0;
+    from->y         = 0;
+    from->scale     = 1;
+    from->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+    from->buffer_destroy_listener = NULL;
+
+    pixman_region32_clear(&from->damage_region);
+    pixman_region32_clear(&from->opaque_region);
+    pixman_region32_clear(&from->input_region);
+
+    wl_list_init(&from->frame_callback_list);
+}
+
+static void
+surface_commit_to_cache(pepper_subsurface_t *subsurface)
+{
+    /* Commit surface.pending to subsurface.cache */
+    surface_state_move(&subsurface->surface->pending, &subsurface->cache);
+    subsurface->cached = PEPPER_TRUE;
+}
+
+static void
+surface_commit_from_cache(pepper_subsurface_t *subsurface)
+{
+    /* check if dummy */
+    if (!subsurface->parent)
+        return ;
+
+    /* Commit subsurface.cache to surface.current directly */
+    pepper_surface_commit_state(subsurface->surface, &subsurface->cache);
+    subsurface->cached = PEPPER_FALSE;
+
+    /* Subsurface emit commit event in here */
+    pepper_object_emit_event(&subsurface->surface->base, PEPPER_EVENT_SURFACE_COMMIT, NULL);
+}
+
+static pepper_bool_t
+subsurface_get_sync(pepper_subsurface_t *subsurface)
+{
+    /* TODO: FIXME */
+    if (!subsurface)
+        return PEPPER_FALSE;
+
+    if (!subsurface->parent)
+        return PEPPER_FALSE;
+
+    if (subsurface->sync)
+        return PEPPER_TRUE;
+
+    if (subsurface->parent->sub)
+        return subsurface_get_sync(subsurface->parent->sub);
+
+    return PEPPER_FALSE;
+}
+
+#define EACH_LIST_FOR_EACH(pos1, head1, pos2, head2, member)                             \
+    for (pos1 = pepper_container_of((head1)->next, pos1, member), pos2 = pepper_container_of((head2)->next, pos2, member);              \
+         (&pos1->member != (head1)) && (&pos2->member != (head2));                                            \
+         pos1 = pepper_container_of(pos1->member.next, pos1, member), pos2 = pepper_container_of(pos2->member.next, pos2, member))
+static void
+subsurface_restack_view(pepper_subsurface_t *subsurface)
+{
+    pepper_subsurface_t *child1 = NULL, *child2;
+    pepper_list_t       *list;
+
+    pepper_list_for_each_list(list, &subsurface->children_list)
+    {
+        pepper_view_t *view1, *view2;
+
+        child2 = list->item;
+
+        if (!child1)
+        {
+            child1 = child2;
+            continue;
+        }
+
+        EACH_LIST_FOR_EACH(view1, &child1->surface->view_list,
+                           view2, &child2->surface->view_list,
+                           surface_link)
+        {
+            pepper_view_stack_above(view1, view2, PEPPER_TRUE);
+        }
+
+        child1 = child2;
+    }
+}
+#undef EACH_LIST_FOR_EACH
+
+static void
+subsurface_apply_order(pepper_subsurface_t *subsurface)
+{
+    pepper_list_t       *list;
+    pepper_subsurface_t *child;
+
+    if (!subsurface->need_restack)
+        return ;
+
+    pepper_list_for_each_list(list, &subsurface->pending.children_list)
+    {
+        child = list->item;
+        if (child)
+        {
+            /* */
+            if (child == subsurface)
+            {
+                pepper_list_remove(&child->self_link);
+                pepper_list_insert(&subsurface->children_list, &child->self_link);
+            }
+            else
+            {
+                pepper_list_remove(&child->parent_link);
+                pepper_list_insert(&subsurface->children_list, &child->parent_link);
+            }
+        }
+    }
+    subsurface_restack_view(subsurface);
+
+    subsurface->need_restack = PEPPER_FALSE;
+}
+
+static void
+subsurface_apply_position(pepper_subsurface_t *subsurface)
+{
+    pepper_view_t *view;
+
+    /* Check this subsurface is dummy */
+    if (!subsurface->parent)
+        return ;
+
+    subsurface->x = subsurface->pending.x;
+    subsurface->y = subsurface->pending.y;
+
+    pepper_list_for_each(view, &subsurface->surface->view_list, surface_link)
+        pepper_view_set_position(view, subsurface->x, subsurface->y);
+}
+
+static void
+subsurface_apply_pending_state(pepper_subsurface_t *subsurface)
+{
+    subsurface_apply_position(subsurface);
+    subsurface_apply_order(subsurface);
 }
 
 static void
@@ -172,12 +359,10 @@ subsurface_set_desync(struct wl_client      *client,
 {
     pepper_subsurface_t *subsurface = wl_resource_get_user_data(resource);
 
-    if (subsurface->synchronized )
-    {
-        /* TODO: subsurface_commit(subsurface);? */
-    }
+    if (subsurface->cached)
+        surface_commit_from_cache(subsurface);
 
-    subsurface->synchronized = 0;
+    subsurface->sync = PEPPER_FALSE;
 }
 
 static struct wl_subsurface_interface subsurface_implementation =
@@ -193,14 +378,17 @@ static struct wl_subsurface_interface subsurface_implementation =
 void
 pepper_subsurface_destroy(pepper_subsurface_t *subsurface)
 {
-    pepper_view_t   *view;
-
     pepper_surface_state_fini(&subsurface->cache);
-    pepper_list_remove(&subsurface->parent_link);
-    pepper_list_remove(&subsurface->pending.parent_link);
 
-    pepper_list_for_each(view, &subsurface->surface->view_list, surface_link)
-        pepper_view_destroy(view);
+    if (subsurface->parent)
+    {
+        pepper_list_remove(&subsurface->parent_link);
+        pepper_list_remove(&subsurface->pending.parent_link);
+        pepper_event_listener_remove(subsurface->parent_destroy_listener);
+        pepper_event_listener_remove(subsurface->parent_commit_listener);
+    }
+
+    /* TODO: handle view_list */
 
     free(subsurface);
 }
@@ -216,9 +404,36 @@ static void
 handle_parent_destroy(pepper_event_listener_t *listener,
                       pepper_object_t *object, uint32_t id, void *info, void *data)
 {
-    /* TODO */
+    pepper_subsurface_t *subsurface = data;
+
+    /* TODO: handle view_list */
+
+    pepper_list_remove(&subsurface->parent_link);
+    pepper_list_remove(&subsurface->pending.parent_link);
+
+    pepper_event_listener_remove(subsurface->parent_destroy_listener);
+
+    subsurface->parent = NULL;
+}
+
+static void
+subsurface_parent_commit(pepper_subsurface_t *subsurface)
+{
+    /* Apply subsurface's pending state, and propagate to children */
+    subsurface_apply_pending_state(subsurface);
+
+    if (subsurface->cached)
+        surface_commit_from_cache(subsurface);
 }
 
+static void
+handle_parent_commit(pepper_event_listener_t *listener,
+                     pepper_object_t *object, uint32_t id, void *info, void *data)
+{
+    pepper_subsurface_t *subsurface = data;
+
+    subsurface_parent_commit(subsurface);
+}
 static pepper_bool_t
 pepper_subsurface_create_views(pepper_subsurface_t *subsurface)
 {
@@ -232,13 +447,36 @@ pepper_subsurface_create_views(pepper_subsurface_t *subsurface)
 
         pepper_view_set_surface(subview, subsurface->surface);
         pepper_view_set_parent(subview, parent_view);
+        pepper_view_stack_above(subview, parent_view, PEPPER_TRUE);
         pepper_view_set_transform_inherit(subview, PEPPER_TRUE);
+
+        /* FIXME: map later, when ? */
         pepper_view_map(subview);
     }
 
     return PEPPER_TRUE;
 }
 
+static pepper_subsurface_t *
+pepper_dummy_subsurface_create_for_parent(pepper_surface_t *parent)
+{
+    pepper_subsurface_t *subsurface;
+
+    subsurface = calloc(1, sizeof(pepper_subsurface_t));
+    PEPPER_CHECK(subsurface, return NULL, "calloc() failed.\n");
+
+    subsurface->surface = parent;
+
+    /* Insert itself to own children_list. Parent can be placed below/above of own children */
+    pepper_list_init(&subsurface->children_list);
+    pepper_list_insert(&subsurface->children_list, &subsurface->self_link);
+
+    pepper_list_init(&subsurface->pending.children_list);
+    pepper_list_insert(&subsurface->pending.children_list, &subsurface->pending.self_link);
+
+    return subsurface;
+}
+
 pepper_subsurface_t *
 pepper_subsurface_create(pepper_surface_t   *surface,
                          pepper_surface_t   *parent,
@@ -272,19 +510,43 @@ pepper_subsurface_create(pepper_surface_t   *surface,
 
     subsurface->surface      = surface;
     subsurface->parent       = parent;
-    subsurface->synchronized = PEPPER_TRUE;
+
+    /* A sub-surface is initially in the synchronized mode. */
+    subsurface->sync         = PEPPER_TRUE;
 
     subsurface->x            = subsurface->y         = 0.f;
     subsurface->pending.x    = subsurface->pending.y = 0.f;
 
+    subsurface->parent_link.item         = subsurface;
+    subsurface->self_link.item           = subsurface;
+    subsurface->pending.parent_link.item = subsurface;
+    subsurface->pending.self_link.item   = subsurface;
+
+    subsurface->parent_destroy_listener =
+        pepper_object_add_event_listener(&parent->base, PEPPER_EVENT_OBJECT_DESTROY, 0,
+                                         handle_parent_destroy, subsurface);
+
+    subsurface->parent_commit_listener =
+        pepper_object_add_event_listener(&parent->base, PEPPER_EVENT_SURFACE_COMMIT, 0,
+                                         handle_parent_commit, subsurface);
+
     pepper_surface_state_init(&subsurface->cache);
 
-    pepper_object_add_event_listener(&parent->base, PEPPER_EVENT_OBJECT_DESTROY, 0,
-                                     handle_parent_destroy, subsurface);
+    if (!parent->sub)
+        parent->sub = pepper_dummy_subsurface_create_for_parent(parent);
+    PEPPER_CHECK(parent->sub, goto error, "pepper_dummy_subsurface_create_for_parent() failed\n");
+
+    /* children_list is z-order sorted, youngest child is top-most */
+    pepper_list_init(&subsurface->children_list);
+    pepper_list_init(&subsurface->pending.children_list);
+
+    /* link to myself */
+    pepper_list_insert(&subsurface->children_list, &subsurface->self_link);
+    pepper_list_insert(&subsurface->pending.children_list, &subsurface->pending.self_link);
 
-    /* subsurface_list is z-order sorted, youngest child is top-most */
-    pepper_list_insert(&parent->subsurface_list, &subsurface->parent_link);
-    pepper_list_insert(&parent->subsurface_pending_list, &subsurface->pending.parent_link);
+    /* link to parent */
+    pepper_list_insert(&parent->sub->children_list, &subsurface->parent_link);
+    pepper_list_insert(&parent->sub->pending.children_list, &subsurface->pending.parent_link);
 
     /* create views that corresponding to parent's views */
     ret = pepper_subsurface_create_views(subsurface);
@@ -300,3 +562,17 @@ error:
 
     return NULL;
 }
+
+pepper_bool_t
+pepper_subsurface_commit(pepper_subsurface_t *subsurface)
+{
+    if (subsurface_get_sync(subsurface))
+    {
+        surface_commit_to_cache(subsurface);
+
+        /* consume this commit */
+        return PEPPER_TRUE;
+    }
+
+    return PEPPER_FALSE;
+}
index 3a96a09d3fe9ad6098425a4543e366667f52fdbf..201fc2ec379b3ccaaa4bf1d22112956df1b26b88 100644 (file)
@@ -243,6 +243,12 @@ static void
 surface_commit(struct wl_client *client, struct wl_resource *resource)
 {
     pepper_surface_t *surface = wl_resource_get_user_data(resource);
+
+    /* If this surface is subsurface and subsurface is in synchronized mode,
+     * pending surface_state should be commit to cache, not current */
+    if (pepper_subsurface_commit(surface->sub))
+        return ;
+
     pepper_surface_commit(surface);
 }
 
@@ -324,8 +330,6 @@ pepper_surface_create(pepper_compositor_t *compositor,
 
     wl_list_init(&surface->frame_callback_list);
     pepper_list_init(&surface->view_list);
-    pepper_list_init(&surface->subsurface_list);
-    pepper_list_init(&surface->subsurface_pending_list);
     pepper_object_emit_event(&compositor->base, PEPPER_EVENT_COMPOSITOR_SURFACE_ADD, surface);
 
     return surface;
@@ -395,12 +399,12 @@ attach_surface_to_outputs(pepper_surface_t *surface)
 }
 
 void
-pepper_surface_commit(pepper_surface_t *surface)
+pepper_surface_commit_state(pepper_surface_t *surface, pepper_surface_state_t *state)
 {
     pepper_view_t *view;
 
     /* surface.attach(). */
-    if (surface->pending.newly_attached)
+    if (state->newly_attached)
     {
         if (surface->buffer.buffer)
         {
@@ -410,46 +414,46 @@ pepper_surface_commit(pepper_surface_t *surface)
                 pepper_buffer_unreference(surface->buffer.buffer);
         }
 
-        if (surface->pending.buffer)
+        if (state->buffer)
         {
-            pepper_event_listener_remove(surface->pending.buffer_destroy_listener);
-            pepper_buffer_reference(surface->pending.buffer);
+            pepper_event_listener_remove(state->buffer_destroy_listener);
+            pepper_buffer_reference(state->buffer);
             surface->buffer.has_ref  = PEPPER_TRUE;
 
             surface->buffer.destroy_listener =
-                pepper_object_add_event_listener(&surface->pending.buffer->base,
+                pepper_object_add_event_listener(&state->buffer->base,
                                                  PEPPER_EVENT_OBJECT_DESTROY, 0,
                                                  surface_handle_buffer_destroy, surface);
         }
 
-        surface->buffer.buffer   = surface->pending.buffer;
-        surface->buffer.x       += surface->pending.x;
-        surface->buffer.y       += surface->pending.y;
+        surface->buffer.buffer   = state->buffer;
+        surface->buffer.x       += state->x;
+        surface->buffer.y       += state->y;
 
-        surface->pending.newly_attached = PEPPER_FALSE;
-        surface->pending.buffer = NULL;
+        state->newly_attached = PEPPER_FALSE;
+        state->buffer = NULL;
 
         /* Attach to all outputs. */
         attach_surface_to_outputs(surface);
     }
 
     /* surface.set_buffer_transform(), surface.set_buffer_scale(). */
-    surface->buffer.transform  = surface->pending.transform;
-    surface->buffer.scale      = surface->pending.scale;
+    surface->buffer.transform  = state->transform;
+    surface->buffer.scale      = state->scale;
 
     surface_update_size(surface);
 
     /* surface.frame(). */
-    wl_list_insert_list(&surface->frame_callback_list, &surface->pending.frame_callback_list);
-    wl_list_init(&surface->pending.frame_callback_list);
+    wl_list_insert_list(&surface->frame_callback_list, &state->frame_callback_list);
+    wl_list_init(&state->frame_callback_list);
 
     /* surface.damage(). */
-    pixman_region32_copy(&surface->damage_region, &surface->pending.damage_region);
-    pixman_region32_clear(&surface->pending.damage_region);
+    pixman_region32_copy(&surface->damage_region, &state->damage_region);
+    pixman_region32_clear(&state->damage_region);
 
     /* surface.set_opaque_region(), surface.set_input_region(). */
-    pixman_region32_copy(&surface->opaque_region, &surface->pending.opaque_region);
-    pixman_region32_copy(&surface->input_region, &surface->pending.input_region);
+    pixman_region32_copy(&surface->opaque_region, &state->opaque_region);
+    pixman_region32_copy(&surface->input_region, &state->input_region);
 
     pepper_list_for_each(view, &surface->view_list, surface_link)
     {
@@ -457,6 +461,12 @@ pepper_surface_commit(pepper_surface_t *surface)
         pepper_view_resize(view, surface->w, surface->h);
         pepper_view_mark_dirty(view, PEPPER_VIEW_CONTENT_DIRTY);
     }
+}
+
+void
+pepper_surface_commit(pepper_surface_t *surface)
+{
+    pepper_surface_commit_state(surface, &surface->pending);
 
     pepper_object_emit_event(&surface->base, PEPPER_EVENT_SURFACE_COMMIT, NULL);
 }