From: Jaehoon Jeong Date: Fri, 20 Nov 2015 08:52:38 +0000 (+0900) Subject: pepper: Implement subsurface X-Git-Tag: submit/tizen/20151221.025226~25 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F05%2F52905%2F1;p=platform%2Fcore%2Fuifw%2Fpepper.git pepper: Implement subsurface - Update surface.commit for subsurface - Add link to its own subsurface_list Change-Id: I9fe3d1b1c9386f700d848f16b6d4c15b60b75533 --- diff --git a/src/lib/pepper/pepper-internal.h b/src/lib/pepper/pepper-internal.h index 2aa830a..d9e3d91 100644 --- a/src/lib/pepper/pepper-internal.h +++ b/src/lib/pepper/pepper-internal.h @@ -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); diff --git a/src/lib/pepper/subcompositor.c b/src/lib/pepper/subcompositor.c index c101119..4249cdf 100644 --- a/src/lib/pepper/subcompositor.c +++ b/src/lib/pepper/subcompositor.c @@ -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) { diff --git a/src/lib/pepper/subsurface.c b/src/lib/pepper/subsurface.c index 7a03870..29c3c83 100644 --- a/src/lib/pepper/subsurface.c +++ b/src/lib/pepper/subsurface.c @@ -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; +} diff --git a/src/lib/pepper/surface.c b/src/lib/pepper/surface.c index 3a96a09..201fc2e 100644 --- a/src/lib/pepper/surface.c +++ b/src/lib/pepper/surface.c @@ -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); }