pepper: View damage processing
authorTaekyun Kim <tkq.kim@samsung.com>
Thu, 11 Jun 2015 02:19:30 +0000 (11:19 +0900)
committerTaekyun Kim <tkq.kim@samsung.com>
Tue, 7 Jul 2015 06:56:50 +0000 (15:56 +0900)
Damage processing algorithm.

1. inflict damage for current visible area of a view when geometry or z-order
   change. Mark those views as "need_damage" so that damages for updated
   visible regions are getting inflicted.

2. Build a list of views sorted in z-order.

3. Do following things while traversing the view list from front to back

    a. update view geometry
    b. calculate visible region of the view : visible = bounding - opaque
    c. inflict damage for visible region of the view if marked as "need_damage"
    d. inflict damage for surface damage set by the client
    e. accumulate view's opaque region on the global opaque region

Now we have total damage region in compositor->damage_region.

Change-Id: I06c7098bb7edc954172177ee36442800d2b3ce26

pepper/src/compositor.c
pepper/src/pepper-internal.h
pepper/src/pepper.h
pepper/src/surface.c
pepper/src/view.c

index db53ad2..f314093 100644 (file)
@@ -102,6 +102,9 @@ pepper_compositor_create(const char *socket_name)
     }
 
     wl_list_init(&compositor->layers);
+    wl_list_init(&compositor->view_list);
+    pixman_region32_init(&compositor->damage_region);
+
     return compositor;
 
 error:
@@ -125,3 +128,9 @@ pepper_compositor_get_display(pepper_compositor_t *compositor)
 {
     return compositor->display;
 }
+
+void
+pepper_compositor_add_damage(pepper_compositor_t *compositor, pixman_region32_t *region)
+{
+    pixman_region32_union(&compositor->damage_region, &compositor->damage_region, region);
+}
index 57f38f9..9f87d74 100644 (file)
@@ -26,6 +26,9 @@ struct pepper_compositor
     struct wl_list      root_view_list;
 
     struct wl_list      event_hook_chain;
+
+    struct wl_list      view_list;
+    pixman_region32_t   damage_region;
 };
 
 struct pepper_output
@@ -245,6 +248,10 @@ struct pepper_view
     /* Geometry. */
     float                   x, y, w, h;
     pepper_matrix_t         transform;
+    pepper_matrix_t         matrix_to_parent;
+    pepper_matrix_t         matrix_to_global;
+    pixman_region32_t       bounding_region;
+    pepper_bool_t           geometry_dirty;
 
     /* Visibility. */
     pepper_bool_t           visibility;
@@ -261,8 +268,12 @@ struct pepper_view
 
     /* Clip. */
     pepper_bool_t           clip_to_parent;
-    pepper_bool_t           clip_children;
     pixman_region32_t       clip_region;
+
+    pixman_region32_t       opaque_region;
+    pixman_region32_t       visible_region;
+    struct wl_list          view_list_link;
+    pepper_bool_t           need_damage;
 };
 
 struct pepper_layer
@@ -272,7 +283,6 @@ struct pepper_layer
     struct wl_list          views;
 };
 
-
 /* Event hook */
 struct pepper_event_hook
 {
@@ -291,4 +301,10 @@ pepper_compositor_event_handler(pepper_seat_t           *seat,
                                 pepper_input_event_t    *event,
                                 void                    *data);
 
+void
+pepper_compositor_add_damage(pepper_compositor_t *compositor, pixman_region32_t *region);
+
+void
+pepper_surface_flush_damage(pepper_surface_t *surface);
+
 #endif /* PEPPER_INTERNAL_H */
index 50f46ff..1f5b1f7 100644 (file)
@@ -120,6 +120,18 @@ pepper_matrix_equal(const pepper_matrix_t *a, const pepper_matrix_t *b)
            a->m[14] == b->m[14] && a->m[15] && b->m[15];
 }
 
+static inline void
+pepper_matrix_multiply(pepper_matrix_t *dst, const pepper_matrix_t *a, const pepper_matrix_t *b)
+{
+    /* TODO: */
+}
+
+static inline void
+pepper_matrix_copy(pepper_matrix_t *dst, const pepper_matrix_t *src)
+{
+    memcpy(dst, src, sizeof(pepper_matrix_t));
+}
+
 /* TODO: Other matrix utility functions. */
 
 struct pepper_output_geometry
@@ -412,12 +424,6 @@ pepper_view_set_clip_to_parent(pepper_view_t *view, pepper_bool_t clip);
 PEPPER_API pepper_bool_t
 pepper_view_get_clip_to_parent(pepper_view_t *view);
 
-PEPPER_API void
-pepper_view_set_clip_children(pepper_view_t *view, pepper_bool_t clip);
-
-PEPPER_API pepper_bool_t
-pepper_view_get_clip_children(pepper_view_t *view);
-
 PEPPER_API pepper_bool_t
 pepper_view_set_clip_region(pepper_view_t *view, const pixman_region32_t *region);
 
index 72f945f..38e479b 100644 (file)
@@ -472,3 +472,9 @@ pepper_surface_get_input_region(pepper_surface_t *surface)
 {
     return &surface->input_region;
 }
+
+void
+pepper_surface_flush_damage(pepper_surface_t *surface)
+{
+    /* TODO: */
+}
index de1ed2c..9e52403 100644 (file)
@@ -9,6 +9,36 @@ handle_surface_destroy(struct wl_listener *listener, void *data)
     pepper_view_destroy(view);
 }
 
+static void
+damage_region_transform(pixman_region32_t *region, pepper_matrix_t *matrix)
+{
+    /* TODO: */
+}
+
+static void
+view_damage_below_consume(pepper_view_t *view)
+{
+    pepper_compositor_add_damage(view->compositor, &view->visible_region);
+    pixman_region32_init(&view->visible_region);
+}
+
+static void
+view_geometry_dirty(pepper_view_t *view)
+{
+    pepper_view_t *child;
+
+    if (view->geometry_dirty)
+        return;
+
+    view->geometry_dirty = PEPPER_TRUE;
+
+    view_damage_below_consume(view);
+    view->need_damage = PEPPER_TRUE;
+
+    wl_list_for_each(child, &view->child_list, parent_link)
+        view_geometry_dirty(child);
+}
+
 PEPPER_API pepper_view_t *
 pepper_compositor_add_view(pepper_compositor_t *compositor,
                            pepper_view_t *parent, pepper_view_t *pos, pepper_surface_t *surface)
@@ -51,6 +81,7 @@ pepper_compositor_add_view(pepper_compositor_t *compositor,
     }
 
     pixman_region32_init(&view->clip_region);
+    pixman_region32_init(&view->visible_region);
 
     if (pos)
         wl_list_insert(pos->parent_link.next, &view->parent_link);
@@ -64,6 +95,7 @@ pepper_compositor_add_view(pepper_compositor_t *compositor,
     else
         view->container_list = &compositor->root_view_list;
 
+    view_geometry_dirty(view);
     return view;
 }
 
@@ -85,11 +117,28 @@ pepper_compositor_get_bottom_root_view(pepper_compositor_t *compositor)
     return pepper_container_of(compositor->root_view_list.next, pepper_view_t, parent_link);
 }
 
+static void
+pepper_view_unmap(pepper_view_t *view)
+{
+    pepper_view_t *child;
+
+    if (!view->visibility)
+        return;
+
+    wl_list_for_each(child, &view->child_list, parent_link)
+        pepper_view_unmap(child);
+
+    view->visibility = PEPPER_FALSE;
+    view_damage_below_consume(view);
+}
+
 PEPPER_API void
 pepper_view_destroy(pepper_view_t *view)
 {
     pepper_view_t *child, *next;
 
+    pepper_view_unmap(view);
+
     /* Destroy all child views. */
     wl_list_for_each_safe(child, next, &view->child_list, parent_link)
         pepper_view_destroy(child);
@@ -143,6 +192,9 @@ pepper_view_stack_above(pepper_view_t *view, pepper_view_t *below)
     wl_list_remove(&view->parent_link);
     wl_list_insert(below->parent_link.next, &view->parent_link);
 
+    view_damage_below_consume(view);
+    view->need_damage = PEPPER_TRUE;
+
     return PEPPER_TRUE;
 }
 
@@ -158,21 +210,36 @@ pepper_view_stack_below(pepper_view_t *view, pepper_view_t *above)
     wl_list_remove(&view->parent_link);
     wl_list_insert(above->parent_link.prev, &view->parent_link);
 
+    view_damage_below_consume(view);
+    view->need_damage = PEPPER_TRUE;
+
     return PEPPER_TRUE;
 }
 
 PEPPER_API void
 pepper_view_stack_top(pepper_view_t *view)
 {
+    if (view->container_list->prev == &view->parent_link)
+        return;
+
     wl_list_remove(&view->parent_link);
     wl_list_insert(view->container_list->prev, &view->parent_link);
+
+    view_damage_below_consume(view);
+    view->need_damage = PEPPER_TRUE;
 }
 
 PEPPER_API void
 pepper_view_stack_bottom(pepper_view_t *view)
 {
+    if (view->container_list->next == &view->parent_link)
+        return;
+
     wl_list_remove(&view->parent_link);
     wl_list_insert(view->container_list, &view->parent_link);
+
+    view_damage_below_consume(view);
+    view->need_damage = PEPPER_TRUE;
 }
 
 PEPPER_API pepper_view_t *
@@ -223,6 +290,8 @@ pepper_view_resize(pepper_view_t *view, float w, float h)
 
     view->w = w;
     view->h = h;
+
+    view_geometry_dirty(view);
 }
 
 PEPPER_API void
@@ -240,6 +309,8 @@ pepper_view_set_position(pepper_view_t *view, float x, float y)
 {
     view->x = x;
     view->y = y;
+
+    view_geometry_dirty(view);
 }
 
 PEPPER_API void
@@ -256,6 +327,7 @@ PEPPER_API void
 pepper_view_set_transform(pepper_view_t *view, const pepper_matrix_t *matrix)
 {
     memcpy(&view->transform, matrix, sizeof(pepper_matrix_t));
+    view_geometry_dirty(view);
 }
 
 PEPPER_API const pepper_matrix_t *
@@ -267,7 +339,11 @@ pepper_view_get_transform(pepper_view_t *view)
 PEPPER_API void
 pepper_view_set_visibility(pepper_view_t *view, pepper_bool_t visibility)
 {
+    if (view->visibility == visibility)
+        return;
+
     view->visibility = visibility;
+    view_damage_below_consume(view);
 }
 
 PEPPER_API pepper_bool_t
@@ -285,7 +361,11 @@ pepper_view_set_alpha(pepper_view_t *view, float alpha)
     if (alpha > 1.0f)
         alpha = 1.0f;
 
+    if (view->alpha == alpha)
+        return;
+
     view->alpha = alpha;
+    view_damage_below_consume(view);
 }
 
 PEPPER_API float
@@ -297,10 +377,16 @@ pepper_view_get_alpha(pepper_view_t *view)
 PEPPER_API void
 pepper_view_set_viewport(pepper_view_t *view, int x, int y, int w, int h)
 {
+    if (view->viewport.x == x && view->viewport.y == y &&
+        view->viewport.w == w && view->viewport.h == h)
+        return;
+
     view->viewport.x = x;
     view->viewport.y = y;
     view->viewport.w = w;
     view->viewport.h = h;
+
+    view_damage_below_consume(view);
 }
 
 PEPPER_API void
@@ -322,7 +408,11 @@ pepper_view_get_viewport(pepper_view_t *view, int *x, int *y, int *w, int *h)
 PEPPER_API void
 pepper_view_set_clip_to_parent(pepper_view_t *view, pepper_bool_t clip)
 {
+    if (view->clip_to_parent == clip)
+        return;
+
     view->clip_to_parent = clip;
+    view_damage_below_consume(view);
 }
 
 PEPPER_API pepper_bool_t
@@ -331,24 +421,13 @@ pepper_view_get_clip_to_parent(pepper_view_t *view)
     return view->clip_to_parent;
 }
 
-PEPPER_API void
-pepper_view_set_clip_children(pepper_view_t *view, pepper_bool_t clip)
-{
-    view->clip_children = clip;
-}
-
-PEPPER_API pepper_bool_t
-pepper_view_get_clip_children(pepper_view_t *view)
-{
-    return view->clip_children;
-}
-
 PEPPER_API pepper_bool_t
 pepper_view_set_clip_region(pepper_view_t *view, const pixman_region32_t *region)
 {
     if (!pixman_region32_copy(&view->clip_region, (pixman_region32_t *)region))
         return PEPPER_FALSE;
 
+    view_damage_below_consume(view);
     return PEPPER_TRUE;
 }
 
@@ -357,3 +436,124 @@ pepper_view_get_clip_region(pepper_view_t *view)
 {
     return &view->clip_region;
 }
+
+static void
+view_update_bounding_region(pepper_view_t *view)
+{
+    /* TODO: */
+}
+
+void
+view_update_geometry(pepper_view_t *view)
+{
+    if (view->parent)
+        view_update_geometry(view->parent);
+
+    if (view->geometry_dirty)
+    {
+        view->matrix_to_parent.m[ 0] = view->transform.m[ 0] + view->transform.m[12] * view->x;
+        view->matrix_to_parent.m[ 1] = view->transform.m[ 1] + view->transform.m[13] * view->x;
+        view->matrix_to_parent.m[ 2] = view->transform.m[ 2] + view->transform.m[14] * view->x;
+        view->matrix_to_parent.m[ 3] = view->transform.m[ 3] + view->transform.m[15] * view->x;
+
+        view->matrix_to_parent.m[ 4] = view->transform.m[ 4] + view->transform.m[12] * view->y;
+        view->matrix_to_parent.m[ 5] = view->transform.m[ 5] + view->transform.m[13] * view->y;
+        view->matrix_to_parent.m[ 6] = view->transform.m[ 6] + view->transform.m[14] * view->y;
+        view->matrix_to_parent.m[ 7] = view->transform.m[ 7] + view->transform.m[15] * view->y;
+
+        view->matrix_to_parent.m[ 8] = view->transform.m[ 8];
+        view->matrix_to_parent.m[ 9] = view->transform.m[ 9];
+        view->matrix_to_parent.m[10] = view->transform.m[10];
+        view->matrix_to_parent.m[11] = view->transform.m[11];
+
+        view->matrix_to_parent.m[12] = view->transform.m[12];
+        view->matrix_to_parent.m[13] = view->transform.m[13];
+        view->matrix_to_parent.m[14] = view->transform.m[14];
+        view->matrix_to_parent.m[15] = view->transform.m[15];
+
+        if (view->parent)
+        {
+            pepper_matrix_multiply(&view->matrix_to_global,
+                                   &view->parent->matrix_to_global, &view->matrix_to_parent);
+        }
+        else
+        {
+            pepper_matrix_copy(&view->matrix_to_global, &view->matrix_to_parent);
+        }
+
+        view_update_bounding_region(view);
+        view->geometry_dirty = PEPPER_FALSE;
+    }
+}
+
+static void
+view_list_add(pepper_view_t *view)
+{
+    pepper_view_t *child;
+
+    wl_list_insert(&view->compositor->view_list, &view->view_list_link);
+
+    wl_list_for_each(child, &view->child_list, parent_link)
+        view_list_add(child);
+}
+
+void
+pepper_compositor_update_view_list(pepper_compositor_t *compositor)
+{
+    pepper_view_t      *view;
+    pixman_region32_t   visible;
+    pixman_region32_t   opaque;
+    pixman_region32_t   surface_damage;
+
+    pixman_region32_init(&visible);
+    pixman_region32_init(&opaque);
+    pixman_region32_init(&surface_damage);
+
+    /* Make compositor's view list empty. */
+    wl_list_init(&compositor->view_list);
+
+    /* Build z-ordered view list by traversing the view tree in depth-first order. */
+    wl_list_for_each(view, &compositor->root_view_list, parent_link)
+        view_list_add(view);
+
+    /* Update views from front to back. */
+    wl_list_for_each_reverse(view, &compositor->view_list, view_list_link)
+    {
+        view_update_geometry(view);
+
+        /* Update visible region. */
+        pixman_region32_subtract(&view->visible_region, &view->bounding_region, &opaque);
+
+        /* Inflict damage caused by geometry and z-order change. */
+        if (view->need_damage)
+        {
+            pepper_compositor_add_damage(view->compositor, &view->visible_region);
+            view->need_damage = PEPPER_FALSE;
+        }
+
+        /* Inflict surface damage. */
+        if (pixman_region32_not_empty(&view->surface->damage_region))
+        {
+            pepper_surface_flush_damage(view->surface);
+
+            /* Intersect surface damage region with viewport rectangle. */
+            pixman_region32_intersect_rect(&surface_damage, &view->surface->damage_region,
+                                           view->viewport.x, view->viewport.y,
+                                           view->viewport.w, view->viewport.h);
+
+            /* Translate surface damage to compensate viewport offset. */
+            pixman_region32_translate(&surface_damage, -view->viewport.x, -view->viewport.y);
+
+            /* Transform surface damage into global coordinate space. */
+            damage_region_transform(&surface_damage, &view->matrix_to_global);
+
+            /* Subtract area covered by opaque views. */
+            pixman_region32_subtract(&surface_damage, &surface_damage, &opaque);
+
+            pepper_compositor_add_damage(view->compositor, &surface_damage);
+        }
+
+        /* Accumulate opaque region. */
+        pixman_region32_union(&opaque, &opaque, &view->opaque_region);
+    }
+}