pepper: pepper_plane_t and per-plane damage processing
authorTaekyun Kim <tkq.kim@samsung.com>
Wed, 15 Jul 2015 08:09:16 +0000 (17:09 +0900)
committerGerrit Code Review <root@ap3>
Thu, 16 Jul 2015 05:27:59 +0000 (14:27 +0900)
Plane is a logical rendering surface maintaing its own damage region. A plane
belongs to an output and a view can be on a plane per output at a time.

<< Overall Data Relationship >>
* Compositor
    - output list
    - view list in sorted z-order

* Output
    - plane list

* Plane
    - plane entry list
    - damage region
    - clip region (obscured by other planes)

* View
    - Geometry (position, size, transform)
    - plane entries

<< Output Repaint Scheduling >>
* surface.commit() causes all outputs to be scheduled to do repaint.
* Repaint is scheduled on an output when one of its plane gets damaged.

<< Output Repaint Process >>
* Update geometry of all views in the compositor.
* Build a list of views that overlap with the output rectangle.
* Ask output backend to assign a plane of each view in the list.
* Build a list of plane entries for the views assigned to each plane.
* Accumulate damage for each plane.
* Call backend.repaint()

<< Damage Processing >>
* Geometry & Z-order change
    - Inflict damage instantly with current visible region of the view on each
      plane where the view belongs to.

    - Mark it as damaged. Damage accumulation function should add visible region
      of damaged views to the planes.

* Plane move
    - Inflict damage instantly on previous plane and mark it as damaged.

* Surface damage
    - Added while accumulating plane damage.

Change-Id: I7c4bd95f439f0cf0356bcbf2f060b09800ea4528

23 files changed:
drm/src/drm-internal.h
drm/src/drm-output.c
fbdev/src/fbdev-internal.h
fbdev/src/fbdev-output.c
pepper/src/Makefile.am
pepper/src/compositor.c
pepper/src/output.c
pepper/src/pepper-internal.h
pepper/src/pepper-output-backend.h [new file with mode: 0644]
pepper/src/pepper.h
pepper/src/plane.c [new file with mode: 0644]
pepper/src/surface.c
pepper/src/view.c
render/src/gl-renderer.c
render/src/pepper-render-internal.h
render/src/pepper-render.h
render/src/pixman-renderer.c
render/src/renderer.c
wayland/src/wayland-internal.h
wayland/src/wayland-output.c
x11/src/x11-common.c
x11/src/x11-internal.h
x11/src/x11-output.c

index 44a7dd7..1a656ee 100644 (file)
@@ -85,6 +85,8 @@ struct drm_output
     pepper_bool_t               vblank_pending;
     pepper_bool_t               page_flip_pending;
 
+    pepper_object_t            *primary_plane;
+
     /* TODO */
 };
 
index c4ea267..b3b6ada 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "drm-internal.h"
 
+#include <pepper-output-backend.h>
 #include <pepper-pixman-renderer.h>
 #include <pepper-gl-renderer.h>
 
@@ -249,36 +250,68 @@ update_back_buffer(drm_output_t *output)
 }
 
 static void
-drm_output_repaint(void *o, const pepper_list_t *view_list, const pixman_region32_t *damage)
+drm_output_assign_planes(void *o, const pepper_list_t *view_list)
+{
+    drm_output_t   *output = (drm_output_t *)o;
+    pepper_list_t  *l;
+
+    PEPPER_LIST_FOR_EACH(view_list, l)
+    {
+        pepper_object_t *view = l->item;
+        pepper_view_assign_plane(view, output->base, output->primary_plane);
+    }
+}
+
+static void
+drm_output_repaint(void *o, const pepper_list_t *plane_list)
 {
     int             ret;
     drm_output_t   *output = (drm_output_t *)o;
+    pepper_list_t  *l;
 
-    pepper_renderer_set_target(output->renderer, output->render_target);
-    pepper_renderer_repaint_output(output->renderer, output->base, view_list, damage);
+    PEPPER_LIST_FOR_EACH(plane_list, l)
+    {
+        pepper_object_t *plane = l->item;
 
-    update_back_buffer(output);
+        if (plane == output->primary_plane)
+        {
+            pixman_region32_t   *damage = pepper_plane_get_damage_region(plane);
+            const pepper_list_t *render_list = pepper_plane_get_render_list(plane);
 
-    if (!output->back_fb)
-        return;
+            pepper_renderer_set_target(output->renderer, output->render_target);
+            pepper_renderer_repaint_output(output->renderer, output->base, render_list, damage);
 
-    if (!output->front_fb)
-    {
-        ret = drmModeSetCrtc(output->drm->drm_fd, output->crtc_id, output->back_fb->id,
-                             0, 0, &output->conn_id, 1, output->current_mode);
-    }
+            /* NULL means that whole damage region is updated.
+             * If only visible damage region is updated, pass that region to this function
+             * so that pepper core correctly manage remaining damage region. */
+            pepper_plane_subtract_damage_region(plane, NULL);
 
-    ret = drmModePageFlip(output->drm->drm_fd, output->crtc_id, output->back_fb->id,
-                          DRM_MODE_PAGE_FLIP_EVENT, output);
-    if (ret < 0)
-    {
-        PEPPER_ERROR("Failed to queue pageflip in %s\n", __FUNCTION__);
-        return;
-    }
+            update_back_buffer(output);
 
-    output->page_flip_pending = PEPPER_TRUE;
+            if (!output->back_fb)
+                return;
 
-    /* TODO: set planes */
+            if (!output->front_fb)
+            {
+                ret = drmModeSetCrtc(output->drm->drm_fd, output->crtc_id, output->back_fb->id,
+                                     0, 0, &output->conn_id, 1, output->current_mode);
+            }
+
+            ret = drmModePageFlip(output->drm->drm_fd, output->crtc_id, output->back_fb->id,
+                                  DRM_MODE_PAGE_FLIP_EVENT, output);
+            if (ret < 0)
+            {
+                PEPPER_ERROR("Failed to queue pageflip in %s\n", __FUNCTION__);
+                return;
+            }
+
+            output->page_flip_pending = PEPPER_TRUE;
+        }
+
+        /* TODO: Cursor plane. */
+
+        /* TODO: drmModeSetPlane(). */
+    }
 }
 
 static void
@@ -308,6 +341,7 @@ struct pepper_output_backend drm_output_backend =
     drm_output_get_mode,
     drm_output_set_mode,
 
+    drm_output_assign_planes,
     drm_output_repaint,
     drm_output_attach_surface,
     drm_output_add_frame_listener,
@@ -782,6 +816,7 @@ add_outputs(pepper_drm_t *drm, struct udev_device *device)
             continue;
         }
 
+        output->primary_plane = pepper_output_add_plane(output->base, NULL);
         drmModeFreeConnector(conn);
     }
 
@@ -895,6 +930,8 @@ update_outputs(pepper_drm_t *drm, struct udev_device *device)
                 drmModeFreeConnector(conn);
                 continue;
             }
+
+            output->primary_plane = pepper_output_add_plane(output->base, NULL);
         }
 
         drmModeFreeConnector(conn);
index f49a33b..0569e0a 100644 (file)
@@ -54,6 +54,7 @@ struct fbdev_output
     struct wl_signal            mode_change_signal;
     struct wl_signal            frame_signal;
 
+    pepper_object_t            *primary_plane;
     /* TODO */
 };
 
index cd88fcf..3c4e668 100644 (file)
@@ -11,6 +11,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include <pepper-output-backend.h>
 #include <pepper-pixman-renderer.h>
 #include <pepper-gl-renderer.h>
 
@@ -166,16 +167,44 @@ fbdev_output_set_mode(void *o, const pepper_output_mode_t *mode)
 }
 
 static void
-fbdev_output_repaint(void *o, const pepper_list_t *view_list, const pixman_region32_t *damage)
+fbdev_output_assign_planes(void *o, const pepper_list_t *view_list)
 {
     fbdev_output_t *output = (fbdev_output_t *)o;
-    pepper_renderer_repaint_output(output->renderer, output->base, view_list, damage);
+    pepper_list_t  *l;
 
-    /* FIXME: composite with damage? */
-    if (output->use_shadow)
-        pixman_image_composite32(PIXMAN_OP_SRC, output->shadow_image, NULL,
-                                 output->frame_buffer_image, 0, 0, 0, 0, 0, 0,
-                                 output->w, output->h);
+    PEPPER_LIST_FOR_EACH(view_list, l)
+    {
+        pepper_object_t *view = l->item;
+        pepper_view_assign_plane(view, output->base, output->primary_plane);
+    }
+}
+
+static void
+fbdev_output_repaint(void *o, const pepper_list_t *plane_list)
+{
+    fbdev_output_t *output = (fbdev_output_t *)o;
+    pepper_list_t  *l;
+
+    PEPPER_LIST_FOR_EACH(plane_list, l)
+    {
+        pepper_object_t *plane = l->item;
+
+        if (plane == output->primary_plane)
+        {
+            const pepper_list_t *render_list = pepper_plane_get_render_list(plane);
+            pixman_region32_t   *damage = pepper_plane_get_damage_region(plane);
+
+            pepper_renderer_repaint_output(output->renderer, output->base, render_list, damage);
+
+            /* FIXME: composite with damage? */
+            if (output->use_shadow)
+                pixman_image_composite32(PIXMAN_OP_SRC, output->shadow_image, NULL,
+                                         output->frame_buffer_image, 0, 0, 0, 0, 0, 0,
+                                         output->w, output->h);
+        }
+
+        /* TODO: No overlays on fbdev??? */
+    }
 }
 
 static void
@@ -205,6 +234,7 @@ struct pepper_output_backend fbdev_output_backend =
     fbdev_output_get_mode,
     fbdev_output_set_mode,
 
+    fbdev_output_assign_planes,
     fbdev_output_repaint,
     fbdev_output_attach_surface,
     fbdev_output_add_frame_listener,
@@ -346,7 +376,9 @@ pepper_fbdev_output_create(pepper_fbdev_t *fbdev, const char *renderer)
         goto error;
     }
 
+    output->primary_plane = pepper_output_add_plane(output->base, NULL);
     wl_list_insert(&fbdev->output_list, &output->link);
+
     return PEPPER_TRUE;
 
 error:
index 32f3cd4..2f9c06d 100644 (file)
@@ -1,5 +1,5 @@
 lib_LTLIBRARIES = libpepper.la
-include_HEADERS = pepper.h pepper-utils.h
+include_HEADERS = pepper.h pepper-utils.h pepper-output-backend.h
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = pepper.pc
@@ -20,6 +20,7 @@ libpepper_la_SOURCES = pepper.h                 \
                        buffer.c                 \
                        data-device.c            \
                        view.c                   \
+                       plane.c                  \
                        utils-file.c             \
                        utils-map.c              \
                        utils-log.c              \
index 30d0fe7..925b59b 100644 (file)
@@ -75,10 +75,8 @@ pepper_compositor_create(const char *socket_name)
                      compositor_bind);
     wl_list_init(&compositor->surfaces);
     wl_list_init(&compositor->seat_list);
-    wl_list_init(&compositor->output_list);
+    pepper_list_init(&compositor->output_list);
     wl_list_init(&compositor->event_hook_chain);
-
-    pepper_list_init(&compositor->root_view_list);
     pepper_list_init(&compositor->view_list);
 
     /* Install default input event handler */
@@ -132,36 +130,3 @@ pepper_compositor_get_display(pepper_object_t *cmp)
     CHECK_MAGIC_AND_NON_NULL(cmp, PEPPER_COMPOSITOR);
     return compositor->display;
 }
-
-void
-pepper_compositor_add_damage(pepper_compositor_t *compositor, const pixman_region32_t *region)
-{
-    pepper_output_t    *output;
-
-    CHECK_MAGIC_AND_NON_NULL(&compositor->base, PEPPER_COMPOSITOR);
-
-    wl_list_for_each(output, &compositor->output_list, link)
-        pepper_output_add_damage(&output->base, region, output->geometry.x, output->geometry.y);
-}
-
-void
-pepper_compositor_add_damage_rect(pepper_compositor_t *compositor,
-                                  int x, int y, unsigned int w, unsigned int h)
-{
-    pixman_region32_t region;
-
-    pixman_region32_init_rect(&region, x, y, w, h);
-    pepper_compositor_add_damage(compositor, &region);
-    pixman_region32_fini(&region);
-}
-
-void
-pepper_compositor_schedule_repaint(pepper_compositor_t *compositor)
-{
-    pepper_output_t    *output;
-
-    CHECK_MAGIC_AND_NON_NULL(&compositor->base, PEPPER_COMPOSITOR);
-
-    wl_list_for_each(output, &compositor->output_list, link)
-        pepper_output_schedule_repaint(output);
-}
index 400e4ac..4792822 100644 (file)
@@ -125,6 +125,67 @@ handle_mode_change(struct wl_listener *listener, void *data)
 }
 
 static void
+output_accumulate_damage(pepper_output_t *output)
+{
+    pepper_list_t      *l;
+    pixman_region32_t   clip;
+    pixman_region32_t   plane_clip;
+
+    pixman_region32_init(&clip);
+
+    PEPPER_LIST_FOR_EACH_REVERSE(&output->plane_list, l)
+    {
+        pepper_plane_t *plane = l->item;
+
+        pepper_plane_accumulate_damage(plane, &plane_clip);
+        pixman_region32_copy(&plane->clip_region, &clip);
+        pixman_region32_union(&clip, &clip, &plane_clip);
+    }
+
+    pixman_region32_fini(&clip);
+}
+
+static void
+output_repaint(pepper_output_t *output)
+{
+    pepper_list_t          *l;
+
+    PEPPER_LIST_FOR_EACH(&output->compositor->view_list, l)
+        pepper_view_update_geometry((pepper_view_t *)l->item);
+
+    pepper_list_init(&output->view_list);
+
+    /* Build a list of views in sorted z-order that are visible on the given output. */
+    PEPPER_LIST_FOR_EACH(&output->compositor->view_list, l)
+    {
+        pepper_view_t *view = l->item;
+
+        if (!view->visibility || !(view->output_overlap & (1 << output->id)))
+        {
+            /* Detach from the previously assigned plane. */
+            pepper_view_assign_plane(&view->base, &output->base, NULL);
+            continue;
+        }
+
+        pepper_list_insert(&output->view_list, &view->link);
+        view->link.item = view;
+    }
+
+    output->backend->assign_planes(output->data, &output->view_list);
+
+    PEPPER_LIST_FOR_EACH(&output->plane_list, l)
+        pepper_plane_update((pepper_plane_t *)l->item, &output->view_list);
+
+    output_accumulate_damage(output);
+    output->backend->repaint(output->data, &output->plane_list);
+
+    output->frame.pending = PEPPER_TRUE;
+    output->frame.scheduled = PEPPER_FALSE;
+
+    /* TODO: Send frame done to the callback objects of this output. */
+}
+
+static void
 handle_output_frame(struct wl_listener *listener, void *data)
 {
     pepper_output_t *output = pepper_container_of(listener, pepper_output_t, frame.frame_listener);
@@ -133,7 +194,7 @@ handle_output_frame(struct wl_listener *listener, void *data)
 
     /* TODO: Better repaint scheduling by putting a delay before repaint. */
     if (output->frame.scheduled)
-        pepper_output_repaint(output);
+        output_repaint(output);
 }
 
 static void
@@ -144,7 +205,7 @@ idle_repaint(void *data)
     if (!output->frame.pending)
     {
         /* We can repaint a frame immediately if it is not in pending state. */
-        pepper_output_repaint(output);
+        output_repaint(output);
     }
 }
 
@@ -162,21 +223,16 @@ pepper_output_schedule_repaint(pepper_output_t *output)
     output->frame.scheduled = PEPPER_TRUE;
 }
 
-void
-pepper_output_repaint(pepper_output_t *output)
+PEPPER_API void
+pepper_output_add_damage_region(pepper_object_t *out, pixman_region32_t *region)
 {
-    PEPPER_ASSERT(!output->frame.pending);
-
-    pepper_compositor_update_views(output->compositor);
-
-    output->backend->repaint(output->data, &output->compositor->view_list, &output->damage_region);
-    output->frame.pending = PEPPER_TRUE;
-    output->frame.scheduled = PEPPER_FALSE;
+    pepper_list_t   *l;
+    pepper_output_t *output = (pepper_output_t *)out;
 
-    /* TODO: Send frame done to the callback objects of this output. */
+    CHECK_MAGIC_AND_NON_NULL(out, PEPPER_OUTPUT);
 
-    /* Output has been repainted, so damage region is totally consumed. */
-    pixman_region32_clear(&output->damage_region);
+    PEPPER_LIST_FOR_EACH(&output->plane_list, l)
+        pepper_plane_add_damage_region((pepper_plane_t *)l->item, region);
 }
 
 PEPPER_API pepper_object_t *
@@ -239,7 +295,8 @@ pepper_compositor_add_output(pepper_object_t *cmp,
     output->geometry.w = output->current_mode->w;
     output->geometry.h = output->current_mode->h;
 
-    wl_list_insert(&compositor->output_list, &output->link);
+    pepper_list_insert(&compositor->output_list, &output->link);
+    output->link.item = output;
 
     /* Install listeners. */
     output->data_destroy_listener.notify = handle_output_data_destroy;
@@ -251,7 +308,7 @@ pepper_compositor_add_output(pepper_object_t *cmp,
     output->frame.frame_listener.notify = handle_output_frame;
     backend->add_frame_listener(data, &output->frame.frame_listener);
 
-    pepper_output_add_damage_whole(&output->base);
+    pepper_list_init(&output->plane_list);
     return &output->base;
 }
 
@@ -271,7 +328,7 @@ pepper_output_destroy(pepper_object_t *out)
     pepper_object_fini(&output->base);
 
     output->compositor->output_id_allocator &= ~(1 << output->id);
-    wl_list_remove(&output->link);
+    pepper_list_remove(&output->link, NULL);
 
     if (output->backend && output->data)
         output->backend->destroy(output->data);
@@ -297,7 +354,7 @@ pepper_output_move(pepper_object_t *out, int32_t x, int32_t y)
         output->geometry.x = x;
         output->geometry.y = y;
 
-        pepper_output_add_damage_whole(out);
+        /* TODO: pepper_output_add_damage_whole(out); */
         output_send_geometry(output);
     }
 }
@@ -349,60 +406,9 @@ pepper_output_set_mode(pepper_object_t *out, const pepper_output_mode_t *mode)
 
     if (output->backend->set_mode(output->data, mode))
     {
-        pepper_output_add_damage_whole(out);
+        /* TODO: pepper_output_add_damage_whole(out); */
         return PEPPER_TRUE;
     }
 
     return PEPPER_FALSE;
 }
-
-PEPPER_API void
-pepper_output_add_damage(pepper_object_t *out,
-                         const pixman_region32_t *region, int x, int y)
-{
-    pepper_output_t    *output = (pepper_output_t *)out;
-    pixman_region32_t   damage;
-
-    CHECK_MAGIC_AND_NON_NULL(out, PEPPER_OUTPUT);
-
-    pixman_region32_init(&damage);
-    pixman_region32_copy(&damage, (pixman_region32_t *)region);
-    pixman_region32_translate(&damage, x, y);
-    pixman_region32_intersect_rect(&damage, &damage, 0, 0, output->geometry.w, output->geometry.h);
-
-    if (pixman_region32_not_empty(&damage))
-    {
-        pixman_region32_union(&output->damage_region, &output->damage_region, &damage);
-        pepper_output_schedule_repaint(output);
-    }
-
-    pixman_region32_fini(&damage);
-}
-
-PEPPER_API void
-pepper_output_add_damage_rect(pepper_object_t *out, int x, int y, unsigned int w, unsigned int h)
-{
-    pepper_output_t    *output = (pepper_output_t *)out;
-    pixman_region32_t   damage;
-
-    CHECK_MAGIC_AND_NON_NULL(out, PEPPER_OUTPUT);
-
-    pixman_region32_init_rect(&damage, x, y, w, h);
-    pixman_region32_intersect_rect(&damage, &damage, 0, 0, output->geometry.w, output->geometry.h);
-
-    if (pixman_region32_not_empty(&damage))
-        pixman_region32_union(&output->damage_region, &output->damage_region, &damage);
-
-    pixman_region32_fini(&damage);
-    pepper_output_schedule_repaint(output);
-}
-
-PEPPER_API void
-pepper_output_add_damage_whole(pepper_object_t *out)
-{
-    pepper_output_t *output = (pepper_output_t *)out;
-
-    CHECK_MAGIC_AND_NON_NULL(out, PEPPER_OUTPUT);
-    pixman_region32_init_rect(&output->damage_region, 0, 0, output->geometry.w, output->geometry.h);
-    pepper_output_schedule_repaint(output);
-}
index 1f94f52..9304ad0 100644 (file)
@@ -5,6 +5,7 @@
 #include "pepper.h"
 #include <wayland-util.h>
 #include <pixman.h>
+#include <pepper-output-backend.h>
 
 typedef struct pepper_compositor    pepper_compositor_t;
 typedef struct pepper_output        pepper_output_t;
@@ -15,6 +16,7 @@ typedef struct pepper_seat          pepper_seat_t;
 typedef struct pepper_pointer       pepper_pointer_t;
 typedef struct pepper_keyboard      pepper_keyboard_t;
 typedef struct pepper_touch         pepper_touch_t;
+typedef struct pepper_plane         pepper_plane_t;
 
 #define CHECK_NON_NULL(ptr)                                                     \
     do {                                                                        \
@@ -43,10 +45,11 @@ typedef struct pepper_touch         pepper_touch_t;
             CHECK_MAGIC(obj, val);                                              \
     } while (0)
 
-#define PEPPER_MAX_OUTPUT_ID    32
+#define PEPPER_MAX_OUTPUT_COUNT 32
 
 typedef struct pepper_region        pepper_region_t;
 typedef struct pepper_surface_state pepper_surface_state_t;
+typedef struct pepper_plane_entry   pepper_plane_entry_t;
 typedef struct pepper_data_source   pepper_data_source_t;
 typedef struct pepper_data_device   pepper_data_device_t;
 typedef struct pepper_data_offer    pepper_data_offer_t;
@@ -62,6 +65,7 @@ enum pepper_magic
     PEPPER_POINTER      = 0x00000007,
     PEPPER_KEYBOARD     = 0x00000008,
     PEPPER_TOUCH        = 0x00000009,
+    PEPPER_PLANE        = 0x0000000a,
 };
 
 struct pepper_object
@@ -90,10 +94,9 @@ struct pepper_compositor
     struct wl_list      surfaces;
     struct wl_list      regions;
     struct wl_list      seat_list;
-    struct wl_list      output_list;
+    pepper_list_t       output_list;
     uint32_t            output_id_allocator;
     struct wl_list      event_hook_chain;
-    pepper_list_t       root_view_list;
     pepper_list_t       view_list;
 };
 
@@ -105,7 +108,7 @@ struct pepper_output
 
     struct wl_global           *global;
     struct wl_list              resources;
-    struct wl_list              link;
+    pepper_list_t               link;
 
     pepper_output_geometry_t    geometry;
     int32_t                     scale;
@@ -129,16 +132,13 @@ struct pepper_output
         struct wl_listener      frame_listener;
     } frame;
 
-    /* Region damaged but not repainted. */
-    pixman_region32_t           damage_region;
+    pepper_list_t               plane_list;
+    pepper_list_t               view_list;
 };
 
 void
 pepper_output_schedule_repaint(pepper_output_t *output);
 
-void
-pepper_output_repaint(pepper_output_t *output);
-
 struct pepper_buffer
 {
     pepper_object_t         base;
@@ -200,7 +200,7 @@ struct pepper_surface
 
     char                   *role;
     pepper_map_t           *user_data_map;
-    struct wl_list          view_list;
+    pepper_list_t           view_list;
 };
 
 pepper_surface_t *
@@ -306,25 +306,37 @@ struct pepper_data_device
 pepper_bool_t
 pepper_data_device_manager_init(struct wl_display *display);
 
+struct pepper_plane_entry
+{
+    pepper_render_item_t    base;
+
+    pepper_plane_t         *plane;
+    struct wl_listener      plane_destroy_listener;
+    pepper_bool_t           need_damage;
+
+    pepper_list_t           link;
+};
+
 struct pepper_view
 {
     pepper_object_t         base;
     pepper_compositor_t    *compositor;
+    pepper_list_t           compositor_link;
 
-    /* Hierarchy & Z-order. */
+    /* Hierarchy. */
     pepper_view_t          *parent;
-    pepper_list_t           children_list;
     pepper_list_t           parent_link;
-    pepper_list_t           z_link;
+    pepper_list_t           children_list;
 
     /* Geometry. */
+    pepper_bool_t           geometry_dirty;
     double                  x, y;
     int                     w, h;
     pepper_mat4_t           transform;
-    pepper_mat4_t           matrix_to_parent;
-    pepper_mat4_t           matrix_to_global;
+    pepper_mat4_t           global_transform;
+
     pixman_region32_t       bounding_region;
-    pepper_bool_t           geometry_dirty;
+    pixman_region32_t       opaque_region;
 
     /* Visibility. */
     pepper_bool_t           visibility;
@@ -332,17 +344,64 @@ struct pepper_view
 
     /* Content. */
     pepper_surface_t       *surface;
-    struct wl_list          surface_link;
+    pepper_list_t           surface_link;
     struct wl_listener      surface_destroy_listener;
 
-    pixman_region32_t       opaque_region;
-    pixman_region32_t       visible_region;
+    /* Output info. */
+    uint32_t                output_overlap;
+    pepper_plane_entry_t    plane_entries[PEPPER_MAX_OUTPUT_COUNT];
 
-    pepper_view_state_t     state;
+    /* Temporary resource. */
+    pepper_list_t           link;
 };
 
 void
-pepper_compositor_update_views(pepper_compositor_t *compositor);
+pepper_view_assign_plane(pepper_object_t *view, pepper_object_t *output, pepper_object_t *plane);
+
+void
+pepper_view_damage_below(pepper_view_t *view);
+
+void
+pepper_view_update_geometry(pepper_view_t *view);
+
+struct pepper_plane
+{
+    pepper_object_t     base;
+    pepper_output_t    *output;
+
+    pepper_list_t       entry_list;
+    pixman_region32_t   damage_region;
+    pixman_region32_t   clip_region;
+
+    pepper_list_t       link;
+};
+
+pepper_object_t *
+pepper_plane_create(pepper_object_t *output, pepper_object_t *above_plane);
+
+void
+pepper_plane_destroy(pepper_object_t *plane);
+
+pixman_region32_t *
+pepper_plane_get_damage_region(pepper_object_t *plane);
+
+pixman_region32_t *
+pepper_plane_get_clip_region(pepper_object_t *plane);
+
+const pepper_list_t *
+pepper_plane_get_render_node_list(pepper_object_t *plane);
+
+void
+pepper_plane_subtract_damage_region(pepper_object_t *plane, pixman_region32_t *region);
+
+void
+pepper_plane_add_damage_region(pepper_plane_t *plane, pixman_region32_t *region);
+
+void
+pepper_plane_accumulate_damage(pepper_plane_t *plane, pixman_region32_t *clip);
+
+void
+pepper_plane_update(pepper_plane_t *plane, const pepper_list_t *view_list);
 
 /* Event hook */
 struct pepper_event_hook
@@ -363,13 +422,6 @@ pepper_compositor_event_handler(pepper_object_t         *seat,
                                 void                    *data);
 
 void
-pepper_compositor_add_damage(pepper_compositor_t *compositor, const pixman_region32_t *region);
-
-void
-pepper_compositor_add_damage_rect(pepper_compositor_t *compositor,
-                                  int x, int y, unsigned int w, unsigned int h);
-
-void
 pepper_surface_flush_damage(pepper_surface_t *surface);
 
 #endif /* PEPPER_INTERNAL_H */
diff --git a/pepper/src/pepper-output-backend.h b/pepper/src/pepper-output-backend.h
new file mode 100644 (file)
index 0000000..6e7784b
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef PEPPER_OUTPUT_BACKEND_H
+#define PEPPER_OUTPUT_BACKEND_H
+
+#include <pepper.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pepper_output_backend    pepper_output_backend_t;
+typedef struct pepper_render_item       pepper_render_item_t;
+
+struct pepper_output_backend
+{
+    void            (*destroy)(void *output);
+
+    void            (*add_destroy_listener)(void *output, struct wl_listener *listener);
+    void            (*add_mode_change_listener)(void *output, struct wl_listener *listener);
+
+    int32_t         (*get_subpixel_order)(void *output);
+    const char *    (*get_maker_name)(void *output);
+    const char *    (*get_model_name)(void *output);
+
+    int             (*get_mode_count)(void *output);
+    void            (*get_mode)(void *output, int index, pepper_output_mode_t *mode);
+    pepper_bool_t   (*set_mode)(void *output, const pepper_output_mode_t *mode);
+
+    void            (*assign_planes)(void *output, const pepper_list_t *view_list);
+    void            (*repaint)(void *output, const pepper_list_t *plane_list);
+    void            (*attach_surface)(void *output, pepper_object_t *surface, int *w, int *h);
+
+    void            (*add_frame_listener)(void *output, struct wl_listener *listener);
+};
+
+PEPPER_API pepper_object_t *
+pepper_compositor_add_output(pepper_object_t *compositor,
+                             const pepper_output_backend_t *backend, void *data);
+
+struct pepper_render_item
+{
+    pepper_object_t    *view;
+    pepper_mat4_t       transform;
+    pixman_region32_t   visible_region;
+};
+
+PEPPER_API pepper_object_t *
+pepper_output_add_plane(pepper_object_t *output, pepper_object_t *above_plane);
+
+PEPPER_API void
+pepper_plane_destroy(pepper_object_t *plane);
+
+PEPPER_API pixman_region32_t *
+pepper_plane_get_damage_region(pepper_object_t *plane);
+
+PEPPER_API pixman_region32_t *
+pepper_plane_get_clip_region(pepper_object_t *plane);
+
+PEPPER_API const pepper_list_t *
+pepper_plane_get_render_list(pepper_object_t *plane);
+
+PEPPER_API void
+pepper_plane_subtract_damage_region(pepper_object_t *plane, pixman_region32_t *damage);
+
+PEPPER_API void
+pepper_view_assign_plane(pepper_object_t *view, pepper_object_t *output, pepper_object_t *plane);
+
+PEPPER_API void
+pepper_output_add_damage_region(pepper_object_t *output, pixman_region32_t *region);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEPPER_OUTPUT_BACKEND_H */
index 27ff4ec..1896885 100644 (file)
@@ -11,27 +11,12 @@ extern "C" {
 #endif
 
 typedef struct pepper_object            pepper_object_t;
-
 typedef struct pepper_output_geometry   pepper_output_geometry_t;
 typedef struct pepper_output_mode       pepper_output_mode_t;
-typedef struct pepper_output_backend    pepper_output_backend_t;
-
 typedef struct pepper_seat_backend      pepper_seat_backend_t;
-
 typedef struct pepper_input_event       pepper_input_event_t;
 typedef struct pepper_event_hook        pepper_event_hook_t;
 
-typedef struct pepper_view_state        pepper_view_state_t;
-
-struct pepper_view_state
-{
-    pepper_object_t            *view;
-    const pepper_mat4_t        *transform;
-    const pixman_region32_t    *bounding;
-    const pixman_region32_t    *opaque;
-    const pixman_region32_t    *visible;
-};
-
 struct pepper_output_geometry
 {
     int32_t     x;
@@ -51,28 +36,6 @@ struct pepper_output_mode
     int32_t     refresh;
 };
 
-struct pepper_output_backend
-{
-    void            (*destroy)(void *output);
-
-    void            (*add_destroy_listener)(void *output, struct wl_listener *listener);
-    void            (*add_mode_change_listener)(void *output, struct wl_listener *listener);
-
-    int32_t         (*get_subpixel_order)(void *output);
-    const char *    (*get_maker_name)(void *output);
-    const char *    (*get_model_name)(void *output);
-
-    int             (*get_mode_count)(void *output);
-    void            (*get_mode)(void *output, int index, pepper_output_mode_t *mode);
-    pepper_bool_t   (*set_mode)(void *output, const pepper_output_mode_t *mode);
-
-    void            (*repaint)(void *output,
-                               const pepper_list_t *view_list, const pixman_region32_t *damage);
-    void            (*attach_surface)(void *output, pepper_object_t *surface, int *w, int *h);
-
-    void            (*add_frame_listener)(void *output, struct wl_listener *listener);
-};
-
 /* Generic object functions. */
 PEPPER_API void
 pepper_object_set_user_data(pepper_object_t *object, const void *key, void *data,
@@ -95,11 +58,6 @@ PEPPER_API struct wl_display *
 pepper_compositor_get_display(pepper_object_t *compositor);
 
 PEPPER_API pepper_object_t *
-pepper_compositor_add_output(pepper_object_t *compositor,
-                             const pepper_output_backend_t *backend,
-                             void *data);
-
-PEPPER_API pepper_object_t *
 pepper_compositor_add_seat(pepper_object_t *compositor,
                            const pepper_seat_backend_t *backend,
                            void *data);
@@ -128,16 +86,6 @@ pepper_output_get_mode(pepper_object_t *output, int index);
 PEPPER_API pepper_bool_t
 pepper_output_set_mode(pepper_object_t *output, const pepper_output_mode_t *mode);
 
-PEPPER_API void
-pepper_output_add_damage(pepper_object_t *output,
-                         const pixman_region32_t *region, int x, int y);
-
-PEPPER_API void
-pepper_output_add_damage_rect(pepper_object_t *output, int x, int y, unsigned int w, unsigned int h);
-
-PEPPER_API void
-pepper_output_add_damage_whole(pepper_object_t *output);
-
 /* Input. */
 struct pepper_seat_backend
 {
diff --git a/pepper/src/plane.c b/pepper/src/plane.c
new file mode 100644 (file)
index 0000000..dc25460
--- /dev/null
@@ -0,0 +1,164 @@
+#include "pepper-internal.h"
+
+void
+pepper_plane_update(pepper_plane_t *plane, const pepper_list_t *view_list)
+{
+    pepper_list_t  *l;
+    double          output_x = plane->output->geometry.x;
+    double          output_y = plane->output->geometry.y;
+
+    pepper_list_init(&plane->entry_list);
+
+    PEPPER_LIST_FOR_EACH(view_list, l)
+    {
+        pepper_view_t          *view  = l->item;
+        pepper_plane_entry_t   *entry = &view->plane_entries[plane->output->id];
+
+        if (entry->plane == plane)
+        {
+            pepper_list_insert(&plane->entry_list, &entry->link);
+
+            /* Calculate view transform on output local coordinate space. */
+            pepper_mat4_init_translate(&entry->base.transform, -output_x, -output_y, 0.0);
+            pepper_mat4_multiply(&entry->base.transform,
+                                 &entry->base.transform, &view->global_transform);
+        }
+    }
+}
+
+void
+pepper_plane_accumulate_damage(pepper_plane_t *plane, pixman_region32_t *clip)
+{
+    pepper_list_t  *l;
+    int             x = plane->output->geometry.x;
+    int             y = plane->output->geometry.y;
+    int             w = plane->output->geometry.w;
+    int             h = plane->output->geometry.h;
+
+    pixman_region32_init(clip);
+
+    PEPPER_LIST_FOR_EACH_REVERSE(&plane->entry_list, l)
+    {
+        pepper_plane_entry_t   *entry = l->item;
+        pepper_view_t          *view = (pepper_view_t *)entry->base.view;
+
+        pixman_region32_subtract(&entry->base.visible_region, &view->bounding_region, clip);
+        pixman_region32_translate(&entry->base.visible_region, -x, -y);
+        pixman_region32_intersect_rect(&entry->base.visible_region,
+                                       &entry->base.visible_region, 0, 0, w, h);
+
+        pixman_region32_union(clip, clip, &view->opaque_region);
+
+        if (entry->need_damage)
+        {
+            pepper_view_damage_below(view);
+            entry->need_damage = PEPPER_FALSE;
+        }
+    }
+
+    pixman_region32_translate(clip, -x, -y);
+    pixman_region32_intersect_rect(clip, clip, 0, 0, w, h);
+}
+
+PEPPER_API pepper_object_t *
+pepper_output_add_plane(pepper_object_t *out, pepper_object_t *above_plane)
+{
+    pepper_plane_t  *plane;
+    pepper_output_t *output = (pepper_output_t *)out;
+    pepper_plane_t  *above = (pepper_plane_t *)above_plane;
+
+    CHECK_MAGIC_AND_NON_NULL(out, PEPPER_OUTPUT);
+    CHECK_MAGIC_IF_NON_NULL(above_plane, PEPPER_PLANE);
+
+    if (above && above->output != output)
+        return NULL;
+
+    plane = (pepper_plane_t *)pepper_object_alloc(sizeof(pepper_plane_t), PEPPER_PLANE);
+    if (!plane)
+        return NULL;
+
+    plane->output = output;
+    plane->link.item = plane;
+
+    if (above)
+        pepper_list_insert(above->link.prev, &plane->link);
+    else
+        pepper_list_insert(output->plane_list.prev, &plane->link);
+
+    pepper_list_init(&plane->entry_list);
+    pixman_region32_init(&plane->damage_region);
+    pixman_region32_init(&plane->clip_region);
+
+    return &plane->base;
+}
+
+void
+pepper_plane_destroy(pepper_object_t *pln)
+{
+    pepper_plane_t *plane = (pepper_plane_t *)pln;
+    pepper_list_t  *l;
+
+    CHECK_MAGIC_AND_NON_NULL(pln, PEPPER_PLANE);
+
+    pepper_object_fini(pln);
+
+    PEPPER_LIST_FOR_EACH(&plane->entry_list, l)
+    {
+        pepper_plane_entry_t *entry = l->item;
+        pepper_view_assign_plane(entry->base.view, &plane->output->base, NULL);
+    }
+
+    pepper_list_remove(&plane->link, NULL);
+    pixman_region32_fini(&plane->damage_region);
+    pixman_region32_fini(&plane->clip_region);
+
+    pepper_free(plane);
+}
+
+void
+pepper_plane_add_damage_region(pepper_plane_t *plane, pixman_region32_t *damage)
+{
+    if (!damage)
+    {
+        pixman_region32_union_rect(&plane->damage_region, &plane->damage_region,
+                                   0, 0, plane->output->geometry.w, plane->output->geometry.h);
+        pepper_output_schedule_repaint(plane->output);
+    }
+    else if (pixman_region32_not_empty(damage))
+    {
+        pixman_region32_union(&plane->damage_region, &plane->damage_region, damage);
+        pepper_output_schedule_repaint(plane->output);
+    }
+}
+
+PEPPER_API pixman_region32_t *
+pepper_plane_get_damage_region(pepper_object_t *pln)
+{
+    pepper_plane_t *plane = (pepper_plane_t *)pln;
+    CHECK_MAGIC_AND_NON_NULL(pln, PEPPER_PLANE);
+    return &plane->damage_region;
+}
+
+pixman_region32_t *
+pepper_plane_get_clip_region(pepper_object_t *pln)
+{
+    pepper_plane_t *plane = (pepper_plane_t *)pln;
+    CHECK_MAGIC_AND_NON_NULL(pln, PEPPER_PLANE);
+    return &plane->clip_region;
+}
+
+const pepper_list_t *
+pepper_plane_get_render_list(pepper_object_t *pln)
+{
+    pepper_plane_t *plane = (pepper_plane_t *)pln;
+    CHECK_MAGIC_AND_NON_NULL(pln, PEPPER_PLANE);
+    return &plane->entry_list;
+}
+
+void
+pepper_plane_subtract_damage_region(pepper_object_t *pln, pixman_region32_t *damage)
+{
+    pepper_plane_t *plane = (pepper_plane_t *)pln;
+    CHECK_MAGIC_AND_NON_NULL(pln, PEPPER_PLANE);
+    pixman_region32_subtract(&plane->damage_region, &plane->damage_region, damage);
+}
index 72f9554..cfd45f8 100644 (file)
@@ -259,7 +259,7 @@ pepper_surface_create(pepper_compositor_t *compositor,
     pixman_region32_init(&surface->input_region);
 
     wl_list_init(&surface->frame_callbacks);
-    wl_list_init(&surface->view_list);
+    pepper_list_init(&surface->view_list);
 
     return surface;
 }
index da652b5..80feee5 100644 (file)
@@ -2,6 +2,15 @@
 #include <string.h>
 
 static void
+view_mark_plane_entries_damaged(pepper_view_t *view)
+{
+    int i;
+
+    for (i = 0; i < PEPPER_MAX_OUTPUT_COUNT; i++)
+        view->plane_entries[i].need_damage = PEPPER_TRUE;
+}
+
+static void
 view_handle_surface_destroy(struct wl_listener *listener, void *data)
 {
     pepper_view_t *view = pepper_container_of(listener, pepper_view_t, surface_destroy_listener);
@@ -18,7 +27,7 @@ view_geometry_dirty(pepper_view_t *view)
         return;
 
     view->geometry_dirty = PEPPER_TRUE;
-    pepper_compositor_add_damage(view->compositor, &view->visible_region);
+    pepper_view_damage_below(view);
 
     PEPPER_LIST_FOR_EACH(&view->children_list, l)
         view_geometry_dirty((pepper_view_t *)l->item);
@@ -121,134 +130,201 @@ transform_region_bounding(pixman_region32_t *region, const pepper_mat4_t *matrix
 }
 
 static void
-view_update_geometry(pepper_view_t *view)
+view_update_output_overlap(pepper_view_t *view)
 {
-    if (view->parent)
-        view_update_geometry(view->parent);
+    pepper_list_t *l;
 
-    if (view->geometry_dirty)
+    view->output_overlap = 0;
+
+    PEPPER_LIST_FOR_EACH(&view->compositor->output_list, l)
     {
-        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_mat4_multiply(&view->matrix_to_global,
-                                   &view->parent->matrix_to_global, &view->matrix_to_parent);
-        }
-        else
+        pepper_output_t *output = l->item;
+        pixman_box32_t   box =
         {
-            pepper_mat4_copy(&view->matrix_to_global, &view->matrix_to_parent);
-        }
+            output->geometry.x,
+            output->geometry.y,
+            output->geometry.x + output->geometry.w,
+            output->geometry.y + output->geometry.h
+        };
+
+        if (pixman_region32_contains_rectangle(&view->bounding_region, &box) != PIXMAN_REGION_OUT)
+            view->output_overlap |= (1 << output->id);
+    }
+}
+
+static pepper_list_t *
+view_insert(pepper_view_t *view, pepper_list_t *pos, pepper_bool_t subtree)
+{
+    if (pos->next != &view->compositor_link)
+    {
+        pepper_list_remove(&view->compositor_link, NULL);
+        pepper_list_insert(pos, &view->compositor_link);
 
-        if (view->surface)
+        if (view->visibility)
         {
-            view->w = view->surface->w;
-            view->h = view->surface->h;
+            pepper_view_damage_below(view);
+            view_mark_plane_entries_damaged(view);
         }
+    }
+
+    pos = &view->compositor_link;
 
-        /* Bounding region. */
-        pixman_region32_init_rect(&view->bounding_region, 0, 0, view->w, view->h);
-        transform_region_bounding(&view->bounding_region, &view->matrix_to_global);
+    if (subtree)
+    {
+        pepper_list_t *l;
 
-        /* Opaque region. */
-        pixman_region32_init(&view->opaque_region);
+        PEPPER_LIST_FOR_EACH(&view->children_list, l)
+            pos = view_insert((pepper_view_t *)l->item, pos, subtree);
+    }
 
-        if (view->surface && pepper_mat4_is_translation(&view->matrix_to_global))
-        {
-            pixman_region32_copy(&view->opaque_region, &view->surface->opaque_region);
-            pixman_region32_translate(&view->opaque_region,
-                                      view->matrix_to_global.m[3], view->matrix_to_global.m[7]);
-        }
+    return pos;
+}
+static void
+view_handle_plane_destroy(struct wl_listener *listener, void *data);
+
+static void
+plane_entry_set_plane(pepper_plane_entry_t *entry, pepper_plane_t *plane)
+{
+    if (entry->plane == plane)
+        return;
+
+    if (entry->plane)
+    {
+        pepper_view_damage_below((pepper_view_t *)entry->base.view);
+        entry->plane = NULL;
+        wl_list_remove(&entry->plane_destroy_listener.link);
+        pixman_region32_fini(&entry->base.visible_region);
+    }
 
-        view->geometry_dirty = PEPPER_FALSE;
+    entry->plane = plane;
+
+    if (entry->plane)
+    {
+        entry->plane_destroy_listener.notify = view_handle_plane_destroy;
+        pepper_object_add_destroy_listener(&plane->base, &entry->plane_destroy_listener);
+        pixman_region32_init(&entry->base.visible_region);
+        entry->need_damage = PEPPER_TRUE;
     }
 }
 
+static void
+view_handle_plane_destroy(struct wl_listener *listener, void *data)
+{
+    pepper_plane_entry_t *entry =
+        pepper_container_of(listener, pepper_plane_entry_t, plane_destroy_listener);
+
+    PEPPER_ASSERT(entry->plane != NULL);
+    plane_entry_set_plane(entry, NULL);
+}
+
 void
-pepper_compositor_update_views(pepper_compositor_t *compositor)
+pepper_view_assign_plane(pepper_object_t *v, pepper_object_t *out, pepper_object_t *pln)
 {
-    pepper_list_t      *l;
-    pixman_region32_t   visible;
-    pixman_region32_t   opaque;
-    pixman_region32_t   surface_damage;
-    pixman_region32_t   damage;
+    pepper_view_t          *view = (pepper_view_t *)v;
+    pepper_output_t        *output = (pepper_output_t *)out;
+    pepper_plane_t         *plane = (pepper_plane_t *)pln;
 
-    pixman_region32_init(&visible);
-    pixman_region32_init(&opaque);
-    pixman_region32_init(&surface_damage);
-    pixman_region32_init(&damage);
+    CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
+    CHECK_MAGIC_AND_NON_NULL(out, PEPPER_OUTPUT);
+    CHECK_MAGIC_IF_NON_NULL(pln, PEPPER_PLANE);
 
-    /* Update views from front to back. */
-    PEPPER_LIST_FOR_EACH_REVERSE(&compositor->view_list, l)
+    if (plane && plane->output != output)
     {
-        pepper_view_t *view = (pepper_view_t *)(((pepper_view_state_t *)l->item)->view);
+        PEPPER_ERROR("Output mismatch.\n");
+        return;
+    }
 
-        view_update_geometry(view);
+    plane_entry_set_plane(&view->plane_entries[output->id], plane);
+}
 
-        /* Calculate updated visible region. */
-        pixman_region32_subtract(&visible, &view->bounding_region, &opaque);
-        pixman_region32_subtract(&damage, &visible, &view->visible_region);
+void
+pepper_view_damage_below(pepper_view_t *view)
+{
+    int i;
 
-        /* Inflict damage for the visible region change. */
-        pepper_compositor_add_damage(view->compositor, &damage);
+    for (i = 0; i < PEPPER_MAX_OUTPUT_COUNT; i++)
+    {
+        pepper_plane_entry_t *entry = &view->plane_entries[i];
 
-        /* Update visible region of the view. */
-        pixman_region32_copy(&view->visible_region, &visible);
+        if (entry->plane)
+            pepper_plane_add_damage_region(entry->plane, &entry->base.visible_region);
+    }
+}
 
-        /* Inflict surface damage. */
-        if (pixman_region32_not_empty(&view->surface->damage_region))
-        {
-            pepper_surface_flush_damage(view->surface);
+void
+pepper_view_update_geometry(pepper_view_t *view)
+{
+    if (!view->geometry_dirty)
+        return;
 
-            pixman_region32_copy(&surface_damage, &view->surface->damage_region);
+    pepper_mat4_init_translate(&view->global_transform, view->x, view->y, 0.0);
+    pepper_mat4_multiply(&view->global_transform, &view->transform, &view->global_transform);
 
-            /* Transform surface damage into global coordinate space. */
-            transform_region_bounding(&surface_damage, &view->matrix_to_global);
+    if (view->parent)
+    {
+        pepper_view_update_geometry(view->parent);
+        pepper_mat4_multiply(&view->global_transform,
+                             &view->parent->global_transform, &view->global_transform);
+    }
 
-            /* Clip surface damage with view's bounding region. */
-            pixman_region32_intersect(&surface_damage, &surface_damage, &view->bounding_region);
+    if (view->surface)
+    {
+        view->w = view->surface->w;
+        view->h = view->surface->h;
+    }
 
-            /* Subtract area covered by opaque views. */
-            pixman_region32_subtract(&surface_damage, &surface_damage, &opaque);
+    /* Bounding region. */
+    pixman_region32_init_rect(&view->bounding_region, 0, 0, view->w, view->h);
+    transform_region_bounding(&view->bounding_region, &view->global_transform);
 
-            pepper_compositor_add_damage(view->compositor, &surface_damage);
-        }
+    /* Opaque region. */
+    pixman_region32_init(&view->opaque_region);
 
-        /* Accumulate opaque region. */
-        pixman_region32_union(&opaque, &opaque, &view->opaque_region);
+    if (view->surface && pepper_mat4_is_translation(&view->global_transform))
+    {
+        pixman_region32_copy(&view->opaque_region, &view->surface->opaque_region);
+        pixman_region32_translate(&view->opaque_region,
+                                  view->global_transform.m[3], view->global_transform.m[7]);
     }
 
-    pixman_region32_fini(&visible);
-    pixman_region32_fini(&opaque);
-    pixman_region32_fini(&surface_damage);
-    pixman_region32_fini(&damage);
+    view->geometry_dirty = PEPPER_FALSE;
+    view_update_output_overlap(view);
+    view_mark_plane_entries_damaged(view);
+}
+
+static void
+view_init(pepper_view_t *view, pepper_compositor_t *compositor)
+{
+    int i;
+
+    view->compositor = compositor;
+    view->compositor_link.item = view;
+    pepper_list_insert(compositor->view_list.prev, &view->compositor_link);
+
+    view->parent_link.item = view;
+    pepper_list_init(&view->children_list);
+
+    pepper_mat4_init_identity(&view->transform);
+    pepper_mat4_init_identity(&view->global_transform);
+    pixman_region32_init(&view->bounding_region);
+    pixman_region32_init(&view->opaque_region);
+
+    for (i = 0; i < PEPPER_MAX_OUTPUT_COUNT; i++)
+    {
+        view->plane_entries[i].base.view = &view->base;
+        view->plane_entries[i].link.item = &view->plane_entries[i];
+    }
 }
+
 PEPPER_API pepper_object_t *
 pepper_compositor_add_surface_view(pepper_object_t *comp, pepper_object_t *sfc)
 {
     pepper_view_t       *view;
     pepper_compositor_t *compositor = (pepper_compositor_t *)comp;
+    pepper_surface_t    *surface = (pepper_surface_t *)sfc;
 
     CHECK_MAGIC_AND_NON_NULL(comp, PEPPER_COMPOSITOR);
-    CHECK_MAGIC_IF_NON_NULL(sfc, PEPPER_SURFACE);
+    CHECK_MAGIC_AND_NON_NULL(sfc, PEPPER_SURFACE);
 
     view = (pepper_view_t *)pepper_object_alloc(sizeof(pepper_view_t), PEPPER_VIEW);
     if (!view)
@@ -257,50 +333,21 @@ pepper_compositor_add_surface_view(pepper_object_t *comp, pepper_object_t *sfc)
         return NULL;
     }
 
-    view->compositor = compositor;
+    view_init(view, compositor);
 
     view->x = 0.0;
     view->y = 0.0;
+    view->w = surface->w;
+    view->h = surface->h;
 
-    view->w = 0;
-    view->h = 0;
-
-    pepper_mat4_init_identity(&view->transform);
-    pepper_mat4_init_identity(&view->matrix_to_parent);
-    pepper_mat4_init_identity(&view->matrix_to_global);
-
-    view->parent_link.item = (void *)view;
-
-    pepper_list_init(&view->children_list);
-    pepper_list_insert(compositor->root_view_list.prev, &view->parent_link);
-    pepper_list_insert(compositor->view_list.prev, &view->z_link);
-
-    if (sfc)
-    {
-        pepper_surface_t *surface = (pepper_surface_t *)sfc;
-
-        view->surface = surface;
-        wl_list_insert(&surface->view_list, &view->surface_link);
-
-        view->surface_destroy_listener.notify = view_handle_surface_destroy;
-        pepper_object_add_destroy_listener(&surface->base, &view->surface_destroy_listener);
-
-        view->w = surface->w;
-        view->h = surface->h;
-    }
-
-    pixman_region32_init_rect(&view->bounding_region, 0, 0, view->w, view->h);
-    pixman_region32_init(&view->opaque_region);
-    pixman_region32_init(&view->visible_region);
+    view->geometry_dirty = PEPPER_TRUE;
 
-    view->state.view        = &view->base;
-    view->state.transform   = &view->matrix_to_global;
-    view->state.bounding    = &view->bounding_region;
-    view->state.opaque      = &view->opaque_region;
-    view->state.visible     = &view->visible_region;
-    view->z_link.item = &view->state;
+    view->surface = surface;
+    view->surface_link.item = view;
+    pepper_list_insert(&surface->view_list, &view->surface_link);
+    view->surface_destroy_listener.notify = view_handle_surface_destroy;
+    pepper_object_add_destroy_listener(&surface->base, &view->surface_destroy_listener);
 
-    view->geometry_dirty = PEPPER_TRUE;
     return &view->base;
 }
 
@@ -309,6 +356,7 @@ pepper_view_destroy(pepper_object_t *v)
 {
     pepper_view_t  *view = (pepper_view_t *)v;
     pepper_list_t  *l, *next;
+    int             i;
 
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
 
@@ -318,22 +366,26 @@ pepper_view_destroy(pepper_object_t *v)
     pepper_object_fini(&view->base);
     view_unmap(view);
 
+    for (i = 0; i < PEPPER_MAX_OUTPUT_COUNT; i++)
+        plane_entry_set_plane(&view->plane_entries[i], NULL);
+
     PEPPER_LIST_FOR_EACH_SAFE(&view->children_list, l, next)
         pepper_view_destroy((pepper_object_t *)(l->item));
 
     PEPPER_ASSERT(pepper_list_empty(&view->children_list));
 
-    pepper_list_remove(&view->parent_link, NULL);
-    pepper_list_remove(&view->z_link, NULL);
+    if (view->parent)
+        pepper_list_remove(&view->parent_link, NULL);
+
+    pepper_list_remove(&view->compositor_link, NULL);
 
     if (view->surface)
     {
-        wl_list_remove(&view->surface_link);
+        pepper_list_remove(&view->surface_link, NULL);
         wl_list_remove(&view->surface_destroy_listener.link);
     }
 
     pixman_region32_fini(&view->opaque_region);
-    pixman_region32_fini(&view->visible_region);
     pixman_region32_fini(&view->bounding_region);
 
     pepper_free(view);
@@ -375,8 +427,6 @@ pepper_view_set_parent(pepper_object_t *v, pepper_object_t *p)
 
     if (view->parent)
         pepper_list_insert(view->parent->children_list.prev, &view->parent_link);
-    else
-        pepper_list_insert(view->compositor->root_view_list.prev, &view->parent_link);
 
     view_geometry_dirty(view);
 }
@@ -389,31 +439,6 @@ pepper_view_get_parent(pepper_object_t *v)
     return &view->parent->base;
 }
 
-static pepper_list_t *
-view_insert(pepper_view_t *view, pepper_list_t *pos, pepper_bool_t subtree)
-{
-    if (pos->next != &view->z_link)
-    {
-        pepper_list_remove(&view->z_link, NULL);
-        pepper_list_insert(pos, &view->z_link);
-
-        if (view->visibility)
-            pepper_compositor_add_damage(view->compositor, &view->visible_region);
-    }
-
-    pos = &view->z_link;
-
-    if (subtree)
-    {
-        pepper_list_t *l;
-
-        PEPPER_LIST_FOR_EACH(&view->children_list, l)
-            pos = view_insert((pepper_view_t *)l->item, pos, subtree);
-    }
-
-    return pos;
-}
-
 PEPPER_API pepper_bool_t
 pepper_view_stack_above(pepper_object_t *v, pepper_object_t *b, pepper_bool_t subtree)
 {
@@ -423,7 +448,7 @@ pepper_view_stack_above(pepper_object_t *v, pepper_object_t *b, pepper_bool_t su
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
     CHECK_MAGIC_AND_NON_NULL(b, PEPPER_VIEW);
 
-    view_insert(view, &below->z_link, subtree);
+    view_insert(view, &below->compositor_link, subtree);
     return PEPPER_TRUE;
 }
 
@@ -436,7 +461,7 @@ pepper_view_stack_below(pepper_object_t *v, pepper_object_t *a, pepper_bool_t su
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
     CHECK_MAGIC_AND_NON_NULL(a, PEPPER_VIEW);
 
-    view_insert(view, above->z_link.prev, subtree);
+    view_insert(view, above->compositor_link.prev, subtree);
     return PEPPER_TRUE;
 }
 
@@ -461,7 +486,7 @@ pepper_view_get_above(pepper_object_t *v)
 {
     pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-    return view->z_link.next->item;
+    return view->compositor_link.next->item;
 }
 
 PEPPER_API pepper_object_t *
@@ -469,7 +494,7 @@ pepper_view_get_below(pepper_object_t *v)
 {
     pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-    return view->z_link.prev->item;
+    return view->compositor_link.prev->item;
 }
 
 PEPPER_API const pepper_list_t *
index 873d50a..bc47a00 100644 (file)
@@ -488,7 +488,7 @@ gl_renderer_read_pixels(pepper_renderer_t *renderer,
 
 static void
 gl_renderer_repaint_output(pepper_renderer_t *renderer, pepper_object_t *out,
-                           const pepper_list_t *list, const pixman_region32_t *damage)
+                           const pepper_list_t *list, pixman_region32_t *damage)
 {
     gl_renderer_t  *gr = (gl_renderer_t *)renderer;
 
index b7cea1c..1ce8160 100644 (file)
@@ -33,8 +33,8 @@ struct pepper_renderer
 
     void            (*repaint_output)(pepper_renderer_t *renderer,
                                       pepper_object_t *output,
-                                      const pepper_list_t *view_list,
-                                      const pixman_region32_t *damage);
+                                      const pepper_list_t *render_list,
+                                      pixman_region32_t *damage);
 };
 
 #endif /* PEPPER_RENDER_INTERNAL_H */
index 8640784..ceaf1e3 100644 (file)
@@ -31,7 +31,7 @@ pepper_renderer_flush_surface_damage(pepper_renderer_t *renderer, pepper_object_
 
 PEPPER_API void
 pepper_renderer_repaint_output(pepper_renderer_t *renderer, pepper_object_t *output,
-                               const pepper_list_t *view_list, const pixman_region32_t *damage);
+                               const pepper_list_t *view_list, pixman_region32_t *damage);
 
 PEPPER_API pepper_bool_t
 pepper_renderer_read_pixels(pepper_renderer_t *renderer, int x, int y, int w, int h,
index e1f1b07..662ddba 100644 (file)
@@ -1,5 +1,6 @@
 #include "pepper-pixman-renderer.h"
 #include "pepper-render-internal.h"
+#include <pepper-output-backend.h>
 
 typedef struct pixman_renderer      pixman_renderer_t;
 typedef struct pixman_surface_state pixman_surface_state_t;
@@ -228,44 +229,26 @@ pixman_renderer_read_pixels(pepper_renderer_t *renderer,
 }
 
 static void
-repaint_view(pepper_renderer_t *renderer, pepper_object_t *output, pepper_view_state_t *view_state,
-             const pixman_region32_t *global_damage) /* global coordinate */
+repaint_view(pepper_renderer_t *renderer, pepper_render_item_t *node, pixman_region32_t *damage)
 {
     pixman_render_target_t  *target = (pixman_render_target_t*)renderer->target;
     pixman_region32_t        repaint;
-    pepper_object_t         *view;
-    pepper_object_t         *view_surf;
-    pixman_surface_state_t  *ps;
-
-    view = view_state->view;
-    PEPPER_ASSERT(view);
-
-    view_surf = pepper_view_get_surface(view);
-    if (!view_surf)
-        return;
-
-    ps = get_surface_state(renderer, view_surf);
-    if (!ps || !ps->image)
-        return;
+    pixman_surface_state_t  *ps = get_surface_state(renderer, pepper_view_get_surface(node->view));
 
     pixman_region32_init(&repaint);
-    pixman_region32_intersect(&repaint, (pixman_region32_t*) view_state->visible,
-                              (pixman_region32_t*) global_damage);
+    pixman_region32_intersect(&repaint, &node->visible_region, damage);
 
     if (pixman_region32_not_empty(&repaint))
     {
-        int                         x, y, w, h;
-        const pepper_mat4_t        *transform = view_state->transform;
+        int x, y, w, h;
 
-        /* set clip on destination */
         pixman_image_set_clip_region32(target->image, &repaint);
 
         /* TODO: consider transform such as rotation */
-        x = transform->m[3];
-        y = transform->m[7];
-        pepper_view_get_size(view, &w, &h);
+        x = node->transform.m[3];
+        y = node->transform.m[7];
+        pepper_view_get_size(node->view, &w, &h);
 
-        /* composite */
         pixman_image_composite32(PIXMAN_OP_SRC, ps->image, NULL, target->image,
                                  0, 0, /* src_x, src_y */
                                  0, 0, /* mask_x, mask_y */
@@ -278,31 +261,15 @@ repaint_view(pepper_renderer_t *renderer, pepper_object_t *output, pepper_view_s
 
 static void
 pixman_renderer_repaint_output(pepper_renderer_t *renderer, pepper_object_t *output,
-                               const pepper_list_t *view_list,
-                               const pixman_region32_t *output_damage)
+                               const pepper_list_t *render_list,
+                               pixman_region32_t *damage)
 {
-    pixman_render_target_t      *target = (pixman_render_target_t *)renderer->target;
-
-    if (target && pixman_region32_not_empty((pixman_region32_t*) output_damage))
+    if (pixman_region32_not_empty(damage))
     {
-        const pepper_output_geometry_t  *geometry;
-        pixman_region32_t                global_damage;
-        pepper_list_t                   *cur_list;
-        pepper_view_state_t             *view_state;
-
-        /* translate damage to global coordinate */
-        geometry = pepper_output_get_geometry(output);
-        pixman_region32_init(&global_damage);
-        pixman_region32_copy(&global_damage, (pixman_region32_t*) output_damage);
-        pixman_region32_translate(&global_damage, geometry->x, geometry->y);
-
-        PEPPER_LIST_FOR_EACH_REVERSE(view_list, cur_list)
-        {
-            view_state = cur_list->item;
-            repaint_view(renderer, output, view_state, (const pixman_region32_t *) &global_damage);
-        }
-
-        pixman_region32_fini(&global_damage);
+        pepper_list_t *l;
+
+        PEPPER_LIST_FOR_EACH_REVERSE(render_list, l)
+            repaint_view(renderer, (pepper_render_item_t *)l->item, damage);
     }
 }
 
index 7a0ad43..04876c9 100644 (file)
@@ -43,7 +43,7 @@ pepper_renderer_flush_surface_damage(pepper_renderer_t *renderer, pepper_object_
 
 PEPPER_API void
 pepper_renderer_repaint_output(pepper_renderer_t *renderer, pepper_object_t *output,
-                               const pepper_list_t *view_list, const pixman_region32_t *damage)
+                               const pepper_list_t *view_list, pixman_region32_t *damage)
 {
     renderer->repaint_output(renderer, output, view_list, damage);
 }
index 6372522..cf465e4 100644 (file)
@@ -101,6 +101,8 @@ struct wayland_output
         struct wl_egl_window   *window;
     } egl;
 #endif
+
+    pepper_object_t            *primary_plane;
 };
 
 struct wayland_seat
index 346c386..f634dcf 100644 (file)
@@ -1,6 +1,7 @@
 #include "wayland-internal.h"
 #include <string.h>
 #include <stdlib.h>
+#include <pepper-output-backend.h>
 #include <pepper-pixman-renderer.h>
 
 #if ENABLE_WAYLAND_BACKEND_EGL && ENABLE_GL_RENDERER
@@ -164,23 +165,49 @@ static const struct wl_callback_listener frame_listener =
 };
 
 static void
-wayland_output_repaint(void *o, const pepper_list_t *view_list, const pixman_region32_t *damage)
+wayland_output_assign_planes(void *o, const pepper_list_t *view_list)
+{
+    wayland_output_t   *output = (wayland_output_t *)o;
+    pepper_list_t      *l;
+
+    PEPPER_LIST_FOR_EACH(view_list, l)
+    {
+        pepper_object_t *view = l->item;
+        pepper_view_assign_plane(view, output->base, output->primary_plane);
+    }
+}
+
+static void
+wayland_output_repaint(void *o, const pepper_list_t *plane_list)
 {
     wayland_output_t   *output = o;
     struct wl_callback *callback;
 
-    if (output->render_pre)
-        output->render_pre(output);
+    pepper_list_t  *l;
 
-    pepper_renderer_repaint_output(output->renderer, output->base, view_list, damage);
+    PEPPER_LIST_FOR_EACH(plane_list, l)
+    {
+        pepper_object_t *plane = l->item;
+
+        if (plane == output->primary_plane)
+        {
+            const pepper_list_t *render_list = pepper_plane_get_render_list(plane);
+            pixman_region32_t   *damage = pepper_plane_get_damage_region(plane);
+
+            if (output->render_pre)
+                output->render_pre(output);
 
-    if (output->render_post)
-        output->render_post(output);
+            pepper_renderer_repaint_output(output->renderer, output->base, render_list, damage);
 
-    callback = wl_surface_frame(output->surface);
-    wl_callback_add_listener(callback, &frame_listener, output);
-    wl_surface_commit(output->surface);
-    wl_display_flush(output->conn->display);
+            if (output->render_post)
+                output->render_post(output);
+
+            callback = wl_surface_frame(output->surface);
+            wl_callback_add_listener(callback, &frame_listener, output);
+            wl_surface_commit(output->surface);
+            wl_display_flush(output->conn->display);
+        }
+    }
 }
 
 static void
@@ -210,6 +237,7 @@ static const pepper_output_backend_t wayland_output_backend =
     wayland_output_get_mode,
     wayland_output_set_mode,
 
+    wayland_output_assign_planes,
     wayland_output_repaint,
     wayland_output_attach_surface,
     wayland_output_add_frame_listener,
@@ -359,5 +387,6 @@ pepper_wayland_output_create(pepper_wayland_t *conn, int32_t w, int32_t h, const
         return NULL;
     }
 
+    output->primary_plane = pepper_output_add_plane(output->base, NULL);
     return output->base;
 }
index e7abf5a..020625b 100644 (file)
@@ -76,7 +76,7 @@ x11_handle_event(int fd, uint32_t mask, void *data)
                 if (output)
                 {
                     /* TODO: Damage only newly exposed area. */
-                    pepper_output_add_damage_whole(output->base);
+                    pepper_output_add_damage_region(output->base, NULL);
                 }
             }
             break;
index d6c35c0..be5376a 100644 (file)
@@ -42,8 +42,8 @@ struct x11_shm_image
 
 struct x11_output
 {
-    pepper_object_t         *base;
-    pepper_x11_connection_t *connection;
+    pepper_object_t            *base;
+    pepper_x11_connection_t    *connection;
 
     int32_t                  x, y;
     uint32_t                 w, h;
@@ -69,6 +69,8 @@ struct x11_output
     struct wl_listener       conn_destroy_listener;
 
     struct wl_list           link;
+
+    pepper_object_t         *primary_plane;
 };
 
 struct x11_seat
index 9b800f6..609274e 100644 (file)
@@ -1,5 +1,6 @@
 #include "x11-internal.h"
 
+#include <pepper-output-backend.h>
 #include "pepper-gl-renderer.h"
 #include "pepper-pixman-renderer.h"
 
@@ -444,45 +445,72 @@ x11_output_add_mode_change_listener(void *o, struct wl_listener *listener)
 }
 
 static void
-x11_output_repaint(void *o, const pepper_list_t *view_list, const pixman_region32_t *damage)
+x11_output_assign_planes(void *o, const pepper_list_t *view_list)
 {
-    x11_output_t *output = o;
+    x11_output_t   *output = (x11_output_t *)o;
+    pepper_list_t  *l;
 
-    pepper_renderer_set_target(output->renderer, output->target);
-    pepper_renderer_repaint_output(output->renderer, output->base, view_list, damage);
+    PEPPER_LIST_FOR_EACH(view_list, l)
+    {
+        pepper_object_t *view = l->item;
+        pepper_view_assign_plane(view, output->base, output->primary_plane);
+    }
+}
 
-    if (output->renderer == output->connection->pixman_renderer)
+static void
+x11_output_repaint(void *o, const pepper_list_t *plane_list)
+{
+    x11_output_t *output = o;
+    pepper_list_t  *l;
+
+    PEPPER_LIST_FOR_EACH(plane_list, l)
     {
-        xcb_void_cookie_t    cookie;
-        xcb_generic_error_t *err;
-
-        cookie = xcb_shm_put_image_checked(output->connection->xcb_connection,
-                                           output->window,
-                                           output->gc,
-                                           output->w * output->scale,   /* total_width  */
-                                           output->h * output->scale,   /* total_height */
-                                           0,   /* src_x */
-                                           0,   /* src_y */
-                                           output->shm.w,  /* src_w */
-                                           output->shm.h, /* src_h */
-                                           0,   /* dst_x */
-                                           0,   /* dst_y */
-                                           output->depth,   /* depth */
-                                           XCB_IMAGE_FORMAT_Z_PIXMAP,   /* format */
-                                           0,   /* send_event */
-                                           output->shm.segment, /* xcb shm segment */
-                                           0);  /* offset */
-
-        err = xcb_request_check(output->connection->xcb_connection, cookie);
-        if (err)
+        pepper_object_t *plane = l->item;
+
+        if (plane == output->primary_plane)
         {
-            PEPPER_ERROR("Failed to put shm image, err: %d\n", err->error_code);
-            free(err);
+            const pepper_list_t *render_list = pepper_plane_get_render_list(plane);
+            pixman_region32_t   *damage = pepper_plane_get_damage_region(plane);
+
+            pepper_renderer_set_target(output->renderer, output->target);
+            pepper_renderer_repaint_output(output->renderer, output->base, render_list, damage);
+
+            if (output->renderer == output->connection->pixman_renderer)
+            {
+                xcb_void_cookie_t    cookie;
+                xcb_generic_error_t *err;
+
+                cookie = xcb_shm_put_image_checked(output->connection->xcb_connection,
+                                                   output->window,
+                                                   output->gc,
+                                                   output->w * output->scale,   /* total_width  */
+                                                   output->h * output->scale,   /* total_height */
+                                                   0,   /* src_x */
+                                                   0,   /* src_y */
+                                                   output->shm.w,  /* src_w */
+                                                   output->shm.h, /* src_h */
+                                                   0,   /* dst_x */
+                                                   0,   /* dst_y */
+                                                   output->depth,   /* depth */
+                                                   XCB_IMAGE_FORMAT_Z_PIXMAP,   /* format */
+                                                   0,   /* send_event */
+                                                   output->shm.segment, /* xcb shm segment */
+                                                   0);  /* offset */
+
+                err = xcb_request_check(output->connection->xcb_connection, cookie);
+                if (err)
+                {
+                    PEPPER_ERROR("Failed to put shm image, err: %d\n", err->error_code);
+                    free(err);
+                }
+            }
+
+            /* XXX: frame_done callback called after 10ms, referenced from weston */
+            wl_event_source_timer_update(output->frame_done_timer, 10);
         }
-    }
 
-    /* XXX: frame_done callback called after 10ms, referenced from weston */
-    wl_event_source_timer_update(output->frame_done_timer, 10);
+        /* TODO: Cursor??? */
+    }
 }
 
 static void
@@ -513,6 +541,7 @@ static const pepper_output_backend_t x11_output_backend =
     x11_output_get_mode,
     x11_output_set_mode,
 
+    x11_output_assign_planes,
     x11_output_repaint,
     x11_output_attach_surface,
     x11_output_add_frame_listener,
@@ -647,8 +676,7 @@ pepper_x11_output_create(pepper_x11_connection_t *connection,
 
     /* Register output object */
     base = pepper_compositor_add_output(connection->compositor,
-                                        &x11_output_backend,
-                                        output);
+                                        &x11_output_backend, output);
     if (!base)
     {
         PEPPER_ERROR("pepper_compositor_add_output failed\n");
@@ -657,6 +685,7 @@ pepper_x11_output_create(pepper_x11_connection_t *connection,
     }
 
     output->base = base;
+    output->primary_plane = pepper_output_add_plane(output->base, NULL);
 
     /* X11 input seat create */
     if (!connection->use_xinput)