wayland: pixman rendering via wl_shm_buffer
authorTaekyun Kim <tkq.kim@samsung.com>
Wed, 15 Apr 2015 09:59:52 +0000 (18:59 +0900)
committerTaekyun Kim <tkq.kim@samsung.com>
Fri, 19 Jun 2015 09:06:40 +0000 (18:06 +0900)
Change-Id: If95a155db5942f3fa08b49b2c2d53bf8ad40c5bb

src/Makefile.am
src/gl-renderer.c
src/modules/wayland/wayland-common.c
src/modules/wayland/wayland-internal.h
src/modules/wayland/wayland-output.c
src/modules/wayland/wayland-shm-buffer.c [new file with mode: 0644]
src/output.c
src/pepper.h
src/pixman-renderer.c

index 90778fe..e246a9b 100644 (file)
@@ -45,7 +45,8 @@ libpepper_la_LIBADD += $(WAYLAND_BACKEND_LIBS) $(top_builddir)/shared/libshared.
 libpepper_la_SOURCES += modules/wayland/wayland-internal.h  \
                         modules/wayland/wayland-common.c    \
                         modules/wayland/wayland-output.c    \
-                        modules/wayland/wayland-input.c
+                        modules/wayland/wayland-input.c     \
+                        modules/wayland/wayland-shm-buffer.c
 endif
 
 # drm backend
index b44f3a2..84b2637 100644 (file)
@@ -44,7 +44,8 @@ gl_renderer_destroy(pepper_renderer_t *r)
 }
 
 static pepper_bool_t
-gl_renderer_read_pixels(pepper_renderer_t *r, int x, int y, int w, int h,
+gl_renderer_read_pixels(pepper_renderer_t *r, void *target,
+                        int x, int y, int w, int h,
                         void *pixels, pepper_format_t format)
 {
     gl_renderer_t  *renderer = (gl_renderer_t *)r;
@@ -73,15 +74,8 @@ gl_renderer_read_pixels(pepper_renderer_t *r, int x, int y, int w, int h,
     return PEPPER_TRUE;
 }
 
-static pepper_bool_t
-gl_renderer_set_render_target(pepper_renderer_t *r, void *target)
-{
-    /* Can't change gl renderer's render target. */
-    return PEPPER_FALSE;
-}
-
 static void
-gl_renderer_draw(pepper_renderer_t *r, void *data)
+gl_renderer_draw(pepper_renderer_t *r, void *target, void *data)
 {
     gl_renderer_t  *renderer = (gl_renderer_t *)r;
 
@@ -266,7 +260,6 @@ pepper_gl_renderer_create(void *display, void *window,
 
     renderer->base.destroy              =   gl_renderer_destroy;
     renderer->base.read_pixels          =   gl_renderer_read_pixels;
-    renderer->base.set_render_target    =   gl_renderer_set_render_target;
     renderer->base.draw                 =   gl_renderer_draw;
 
     return &renderer->base;
index 7cbe4b1..8bb61fd 100644 (file)
@@ -19,6 +19,10 @@ handle_global(void *data, struct wl_registry *registry,
     {
         conn->shell = wl_registry_bind(registry, name, &wl_shell_interface, 1);
     }
+    else if (strcmp(interface, "wl_shm") == 0)
+    {
+        conn->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
+    }
 }
 
 static void
@@ -78,6 +82,7 @@ pepper_wayland_connect(pepper_compositor_t *compositor, const char *socket_name)
     loop = wl_display_get_event_loop(compositor_display);
     conn->event_source = wl_event_loop_add_fd(loop, conn->fd, WL_EVENT_READABLE,
                                               handle_wayland_event, conn);
+    wl_event_source_check(conn->event_source);
 
     wl_list_init(&conn->seat_list);
     wl_signal_init(&conn->destroy_signal);
index eeaef9f..5f42e74 100644 (file)
@@ -31,18 +31,26 @@ struct pepper_wayland
 
     struct wl_signal        destroy_signal;
 
+    struct wl_shm          *shm;
+
 };
 
 struct wayland_shm_buffer
 {
+    wayland_output_t   *output;
+    struct wl_list      link;
+
     struct wl_buffer   *buffer;
+
     void               *pixels;
+    int                 stride;
     int                 size;
+    int                 w, h;
+
     pixman_image_t     *image;
     pixman_region32_t   damage;
-    void               *data;
 
-    struct wl_list      link;
+    void               *data;
 };
 
 struct wayland_output
@@ -63,9 +71,18 @@ struct wayland_output
 
     pepper_renderer_t          *renderer;
 
+    void    (*render_pre)(wayland_output_t *output);
+    void    (*render_post)(wayland_output_t *output);
+
     struct {
-        /* list containing free wl_shm_buffers. */
+        /* list containing free buffers. */
         struct wl_list          free_buffers;
+
+        /* list containing attached but not released (from the compositor) buffers. */
+        struct wl_list          attached_buffers;
+
+        /* current render target buffer. */
+        wayland_shm_buffer_t   *current_buffer;
     } shm;
 
 #if ENABLE_WAYLAND_BACKEND_EGL
@@ -101,3 +118,9 @@ struct wayland_seat
 void
 wayland_handle_global_seat(pepper_wayland_t *conn, struct wl_registry *registry,
                            uint32_t name, uint32_t version);
+
+wayland_shm_buffer_t *
+wayland_shm_buffer_create(wayland_output_t *output);
+
+void
+wayland_shm_buffer_destroy(wayland_shm_buffer_t *buffer);
index 0c17ef0..376d1de 100644 (file)
@@ -21,7 +21,8 @@ static void
 shell_surface_configure(void *data, struct wl_shell_surface *shell_surface, uint32_t edges,
                         int32_t w, int32_t h)
 {
-    wayland_output_t *output = data;
+    wayland_output_t       *output = data;
+    wayland_shm_buffer_t   *buffer, *next;
 
     PEPPER_IGNORE(shell_surface);
     PEPPER_IGNORE(edges);
@@ -29,6 +30,21 @@ shell_surface_configure(void *data, struct wl_shell_surface *shell_surface, uint
     output->w = w;
     output->h = h;
 
+    /* Destroy free buffers immediately. */
+    wl_list_for_each_safe(buffer, next, &output->shm.free_buffers, link)
+        wayland_shm_buffer_destroy(buffer);
+
+    /* Orphan attached buffers. They will be destroyed when the compositor releases them. */
+    wl_list_for_each_safe(buffer, next, &output->shm.attached_buffers, link)
+    {
+        buffer->output = NULL;
+        wl_list_remove(&buffer->link);
+    }
+
+    PEPPER_ASSERT(wl_list_empty(&output->shm.free_buffers));
+    PEPPER_ASSERT(wl_list_empty(&output->shm.attached_buffers));
+
+    /* We are ready to emit mode change signal. */
     wl_signal_emit(&output->mode_change_signal, NULL);
 }
 
@@ -142,12 +158,38 @@ wayland_output_set_mode(void *o, const pepper_output_mode_t *mode)
 }
 
 static void
+frame_done(void *data, struct wl_callback *callback, uint32_t time)
+{
+    wayland_output_t *output = data;
+
+    wl_callback_destroy(callback);
+    wl_signal_emit(&output->frame_signal, NULL);
+}
+
+static const struct wl_callback_listener frame_listener =
+{
+    frame_done,
+};
+
+static void
 wayland_output_repaint(void *o)
 {
-    wayland_output_t *output = o;
+    wayland_output_t   *output = o;
+    struct wl_callback *callback;
+
+    if (output->render_pre)
+        output->render_pre(output);
 
     /* TODO: Pass rendering data to the renderer. maybe view list? or scene graph data? */
-    output->renderer->draw(output->renderer, NULL);
+    output->renderer->draw(output->renderer, output->shm.current_buffer->image, NULL);
+
+    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
@@ -182,6 +224,32 @@ handle_connection_destroy(struct wl_listener *listener, void *data)
     wayland_output_destroy(output);
 }
 
+static void
+pixman_render_pre(wayland_output_t *output)
+{
+    wayland_shm_buffer_t *buffer = NULL;
+
+    if (wl_list_empty(&output->shm.free_buffers))
+    {
+        buffer = wayland_shm_buffer_create(output);
+    }
+    else
+    {
+        buffer = wl_container_of(output->shm.free_buffers.next, buffer, link);
+        wl_list_remove(&buffer->link);
+    }
+
+    wl_list_insert(output->shm.attached_buffers.prev, &buffer->link);
+    output->shm.current_buffer = buffer;
+}
+
+static void
+pixman_render_post(wayland_output_t *output)
+{
+    wl_surface_attach(output->surface, output->shm.current_buffer->buffer, 0, 0);
+    wl_surface_damage(output->surface, 0, 0, output->w, output->h);
+}
+
 static pepper_bool_t
 init_gl_renderer(wayland_output_t *output)
 {
@@ -211,11 +279,16 @@ static pepper_bool_t
 init_pixman_renderer(wayland_output_t *output)
 {
     wl_list_init(&output->shm.free_buffers);
+    wl_list_init(&output->shm.attached_buffers);
 
     output->renderer = pepper_pixman_renderer_create();
 
     if (output->renderer)
+    {
+        output->render_pre  = pixman_render_pre;
+        output->render_post = pixman_render_post;
         return PEPPER_TRUE;
+    }
 
     return PEPPER_FALSE;
 }
@@ -261,6 +334,7 @@ pepper_wayland_output_create(pepper_wayland_t *conn, int32_t w, int32_t h, const
     output->surface = wl_compositor_create_surface(conn->compositor);
     output->shell_surface = wl_shell_get_shell_surface(conn->shell, output->surface);
     wl_shell_surface_add_listener(output->shell_surface, &shell_surface_listener, output);
+    wl_shell_surface_set_toplevel(output->shell_surface);
 
     /* Add compositor base class output object for this output. */
     base = pepper_compositor_add_output(conn->pepper, &wayland_output_interface, output);
diff --git a/src/modules/wayland/wayland-shm-buffer.c b/src/modules/wayland/wayland-shm-buffer.c
new file mode 100644 (file)
index 0000000..7248298
--- /dev/null
@@ -0,0 +1,94 @@
+#include "wayland-internal.h"
+#include <pepper-os-compat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+static void
+buffer_release(void *data, struct wl_buffer *buf)
+{
+    wayland_shm_buffer_t *buffer = data;
+
+    if (buffer->output)
+    {
+        /* Move to free buffer list. */
+        wl_list_remove(&buffer->link);
+        wl_list_insert(buffer->output->shm.free_buffers.next, &buffer->link);
+    }
+    else
+    {
+        /* Orphaned buffer due to output resize or something. Destroy it. */
+        wayland_shm_buffer_destroy(buffer);
+    }
+}
+
+static const struct wl_buffer_listener buffer_listener =
+{
+    buffer_release,
+};
+
+wayland_shm_buffer_t *
+wayland_shm_buffer_create(wayland_output_t *output)
+{
+    wayland_shm_buffer_t   *buffer;
+    int                     fd;
+    struct wl_shm_pool     *pool;
+
+    buffer = pepper_calloc(1, sizeof(wayland_shm_buffer_t));
+    if (!buffer)
+        return NULL;
+
+    buffer->output = output;
+    wl_list_init(&buffer->link);
+
+    buffer->w = output->w;
+    buffer->h = output->h;
+    buffer->stride  = buffer->w * 4;
+    buffer->size    = buffer->stride * buffer->h;
+
+    fd = pepper_create_anonymous_file(buffer->size);
+
+    if (fd < 0)
+    {
+        PEPPER_ERROR("Failed to create anonymous file");
+        goto error;
+    }
+
+    buffer->pixels = mmap(NULL, buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    if (!buffer->pixels)
+    {
+        PEPPER_ERROR("mmap() failed for fd=%d\n", fd);
+        goto error;
+    }
+
+    pool = wl_shm_create_pool(output->conn->shm, fd, buffer->size);
+    buffer->buffer = wl_shm_pool_create_buffer(pool, 0, buffer->w, buffer->h,
+                                               buffer->stride, WL_SHM_FORMAT_ARGB8888);
+    wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
+    wl_shm_pool_destroy(pool);
+    close(fd);
+
+    buffer->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, buffer->w, buffer->h,
+                                             buffer->pixels, buffer->stride);
+    pixman_region32_init_rect(&buffer->damage, 0, 0, buffer->w, buffer->h);
+
+    return buffer;
+
+error:
+    if (fd >= 0)
+        close(fd);
+
+    if (buffer)
+        pepper_free(buffer);
+
+    return NULL;
+}
+
+void
+wayland_shm_buffer_destroy(wayland_shm_buffer_t *buffer)
+{
+    pixman_region32_fini(&buffer->damage);
+    pixman_image_unref(buffer->image);
+    wl_buffer_destroy(buffer->buffer);
+    munmap(buffer->pixels, buffer->size);
+    wl_list_remove(&buffer->link);
+}
index 3d6a45f..00c9c2b 100644 (file)
@@ -139,7 +139,6 @@ idle_repaint(void *data)
     {
         /* We can repaint a frame immediately if it is not in pending state. */
         pepper_output_repaint(output);
-        return;
     }
 }
 
@@ -222,6 +221,8 @@ pepper_compositor_add_output(pepper_compositor_t *compositor,
     output->frame.frame_listener.notify = handle_output_frame;
     interface->add_frame_listener(data, &output->frame.frame_listener);
 
+    pepper_output_schedule_repaint(output);
+
     return output;
 }
 
index eb607e5..3409df2 100644 (file)
@@ -212,11 +212,11 @@ struct pepper_renderer
 {
     void            (*destroy)(pepper_renderer_t *renderer);
 
-    pepper_bool_t   (*read_pixels)(pepper_renderer_t *renderer, int x, int y, int w, int h,
+    pepper_bool_t   (*read_pixels)(pepper_renderer_t *renderer, void *target,
+                                   int x, int y, int w, int h,
                                    void *pixels, pepper_format_t format);
 
-    pepper_bool_t   (*set_render_target)(pepper_renderer_t *renderer, void *target);
-    void            (*draw)(pepper_renderer_t *renderer, void *data /* TODO: */);
+    void            (*draw)(pepper_renderer_t *renderer, void *data, void *target);
 };
 
 PEPPER_API void
index aa73f4a..f48fcb2 100644 (file)
@@ -7,8 +7,6 @@ typedef struct pixman_renderer  pixman_renderer_t;
 struct pixman_renderer
 {
     pepper_renderer_t   base;
-
-    pixman_image_t     *target;
 };
 
 static PEPPER_INLINE pixman_format_code_t
@@ -45,23 +43,20 @@ static void
 pixman_renderer_destroy(pepper_renderer_t *r)
 {
     pixman_renderer_t *renderer = (pixman_renderer_t *)r;
-
-    if (renderer->target)
-        pixman_image_unref(renderer->target);
-
     pepper_free(renderer);
 }
 
 static pepper_bool_t
-pixman_renderer_read_pixels(pepper_renderer_t *r, int x, int y, int w, int h,
+pixman_renderer_read_pixels(pepper_renderer_t *r, void *target,
+                            int x, int y, int w, int h,
                             void *pixels, pepper_format_t format)
 {
-    pixman_renderer_t      *renderer = (pixman_renderer_t *)r;
+    pixman_image_t         *image = (pixman_image_t *)target;
     pixman_image_t         *dst;
     pixman_format_code_t    pixman_format;
     int                     stride;
 
-    if (!renderer->target)
+    if (!image)
         return PEPPER_FALSE;
 
     pixman_format = get_pixman_format(format);
@@ -81,36 +76,20 @@ pixman_renderer_read_pixels(pepper_renderer_t *r, int x, int y, int w, int h,
         return PEPPER_FALSE;
     }
 
-    pixman_image_composite(PIXMAN_OP_SRC, renderer->target, NULL, dst, x, y, 0, 0, 0, 0, w, h);
-    return PEPPER_TRUE;
-}
-
-static pepper_bool_t
-pixman_renderer_set_render_target(pepper_renderer_t *r, void *target)
-{
-    pixman_renderer_t   *renderer = (pixman_renderer_t *)r;
-    pixman_image_t      *image = target;
-
-    if (renderer->target)
-        pixman_image_unref(renderer->target);
-
-    pixman_image_ref(image);
-    renderer->target = image;
-
+    pixman_image_composite(PIXMAN_OP_SRC, image, NULL, dst, x, y, 0, 0, 0, 0, w, h);
     return PEPPER_TRUE;
 }
 
 static void
-pixman_renderer_draw(pepper_renderer_t *r, void *data)
+pixman_renderer_draw(pepper_renderer_t *r, void *target, void *data)
 {
-    pixman_renderer_t *renderer = (pixman_renderer_t *)r;
+    pixman_image_t     *image = (pixman_image_t *)target;
 
-    if (renderer->target)
+    if (image)
     {
         /* TODO: */
-        pixman_image_t *image = renderer->target;
         pixman_fill(pixman_image_get_data(image),
-                    pixman_image_get_stride(image),
+                    pixman_image_get_stride(image) / sizeof(uint32_t),
                     PIXMAN_FORMAT_BPP(pixman_image_get_format(image)),
                     0, 0,
                     pixman_image_get_width(image),
@@ -130,7 +109,6 @@ pepper_pixman_renderer_create()
 
     renderer->base.destroy              = pixman_renderer_destroy;
     renderer->base.read_pixels          = pixman_renderer_read_pixels;
-    renderer->base.set_render_target    = pixman_renderer_set_render_target;
     renderer->base.draw                 = pixman_renderer_draw;
 
     return &renderer->base;