renderer: initial pixman renderer & wayland backend rendering functions
authorTaekyun Kim <tkq.kim@samsung.com>
Wed, 8 Apr 2015 04:50:05 +0000 (13:50 +0900)
committerTaekyun Kim <tkq.kim@samsung.com>
Fri, 19 Jun 2015 09:06:40 +0000 (18:06 +0900)
Change-Id: I6b906148d73405da3adc1cda5cedbb3968641507

13 files changed:
Makefile.am
configure.ac
shared/Makefile.am [new file with mode: 0644]
shared/pepper-os-compat.c [new file with mode: 0644]
shared/pepper-os-compat.h [new file with mode: 0644]
src/Makefile.am
src/common.h
src/gl-renderer.c
src/modules/wayland/pepper-wayland.h
src/modules/wayland/wayland-internal.h
src/modules/wayland/wayland-output.c
src/pepper-pixman-renderer.h [new file with mode: 0644]
src/pixman-renderer.c [new file with mode: 0644]

index af437a6..57300c2 100644 (file)
@@ -1 +1 @@
-SUBDIRS = src
+SUBDIRS = shared src
index 51e0936..362cd0b 100644 (file)
@@ -48,10 +48,18 @@ AM_CONDITIONAL(ENABLE_WAYLAND_BACKEND, test $enable_wayland_backend = yes)
 if test $enable_wayland_backend = yes; then
     AC_DEFINE(ENABLE_WAYLAND_BACKEND, 1, [Enable wayland backend])
     PKG_CHECK_MODULES(WAYLAND_BACKEND, [wayland-client >= 1.6.00])
+fi
+
+AC_ARG_ENABLE(wayland-backend-egl,
+              AC_HELP_STRING([--enable-wayland-backend-egl], [enable wayland backend EGL support]),
+              [enable_wayland_backend_egl=$enableval -a test $enable_wayland_backend=yes],
+              [enable_wayland_backend_egl=yes])
+
+AM_CONDITIONAL(ENABLE_WAYLAND_BACKEND_EGL, test $enable_wayland_backend_egl = yes)
 
-    if test $enable_wayland_backend = yes; then
-        PKG_CHECK_MODULES(WAYLAND_BACKEND, [wayland-egl])
-    fi
+if test $enable_wayland_backend_egl = yes; then
+    AC_DEFINE(ENABLE_WAYLAND_BACKEND_EGL, 1, [Enable wayland backend EGL support])
+    PKG_CHECK_MODULES(WAYLAND_BACKEND, [wayland-egl])
 fi
 
 # drm backend
@@ -94,6 +102,7 @@ fi
 # Output files
 AC_CONFIG_FILES([
 Makefile
+shared/Makefile
 src/Makefile
 ])
 
diff --git a/shared/Makefile.am b/shared/Makefile.am
new file mode 100644 (file)
index 0000000..1eb15e3
--- /dev/null
@@ -0,0 +1,3 @@
+noinst_LTLIBRARIES = libshared.la
+libshared_la_SOURCES =  pepper-os-compat.h  \
+                       pepper-os-compat.c
diff --git a/shared/pepper-os-compat.c b/shared/pepper-os-compat.c
new file mode 100644 (file)
index 0000000..a965bdc
--- /dev/null
@@ -0,0 +1,94 @@
+#include "pepper-os-compat.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+static int
+set_cloexec_or_close(int fd)
+{
+    long flags;
+
+    if (fd == -1)
+        return -1;
+
+    flags = fcntl(fd, F_GETFD);
+    if (flags == -1)
+        goto err;
+
+    if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+        goto err;
+
+    return fd;
+
+err:
+    close(fd);
+    return -1;
+}
+
+static int
+create_tmpfile_cloexec(char *tmpname)
+{
+    int fd;
+
+#ifdef HAVE_MKOSTEMP
+    fd = mkostemp(tmpname, O_CLOEXEC);
+    if (fd >= 0)
+        unlink(tmpname);
+#else
+    fd = mkstemp(tmpname);
+    if (fd >= 0) {
+        fd = set_cloexec_or_close(fd);
+        unlink(tmpname);
+    }
+#endif
+
+    return fd;
+}
+
+int
+pepper_create_anonymous_file(off_t size)
+{
+    static const char template[] = "/pepper-shared-XXXXXX";
+    const char *path;
+    char *name;
+    int fd;
+    int ret;
+
+    path = getenv("XDG_RUNTIME_DIR");
+    if (!path) {
+        errno = ENOENT;
+        return -1;
+    }
+
+    name = malloc(strlen(path) + sizeof(template));
+    if (!name)
+        return -1;
+
+    strcpy(name, path);
+    strcat(name, template);
+
+    fd = create_tmpfile_cloexec(name);
+
+    free(name);
+
+    if (fd < 0)
+        return -1;
+
+#ifdef HAVE_POSIX_FALLOCATE
+    ret = posix_fallocate(fd, 0, size);
+    if (ret != 0) {
+        close(fd);
+        errno = ret;
+        return -1;
+    }
+#else
+    ret = ftruncate(fd, size);
+    if (ret < 0) {
+        close(fd);
+        return -1;
+    }
+#endif
+
+    return fd;
+}
diff --git a/shared/pepper-os-compat.h b/shared/pepper-os-compat.h
new file mode 100644 (file)
index 0000000..0084a9f
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/* This source code was taken from weston's os-compatability.h. */
+
+#ifndef PEPPER_OS_COMPAT_H
+#define PEPPER_OS_COMPAT_H
+
+#include <stdio.h>
+
+int
+pepper_create_anonymous_file(off_t size);
+
+#endif /* PEPPER_OS_COMPAT_H */
index 775de0d..90778fe 100644 (file)
@@ -5,7 +5,7 @@ noinst_LTLIBRARIES =
 
 # pepper library
 lib_LTLIBRARIES += libpepper.la
-include_HEADERS += pepper.h
+include_HEADERS += pepper.h pepper-pixman-renderer.h
 
 libpepper_la_CFLAGS = $(LIB_PEPPER_CFLAGS) -Wall
 libpepper_la_LIBADD = $(LIB_PEPPER_LIBS)
@@ -22,7 +22,8 @@ libpepper_la_SOURCES = pepper.h                 \
                        surface.c                \
                        region.c                 \
                        buffer.c                 \
-                       renderer.c
+                       renderer.c               \
+                       pixman-renderer.c
 
 # gl renderer
 if ENABLE_GL_RENDERER
@@ -38,8 +39,8 @@ endif
 if ENABLE_WAYLAND_BACKEND
 include_HEADERS += modules/wayland/pepper-wayland.h
 
-libpepper_la_CFLAGS += $(WAYLAND_BACKEND_CFLAGS)
-libpepper_la_LIBADD += $(WAYLAND_BACKEND_LIBS)
+libpepper_la_CFLAGS += $(WAYLAND_BACKEND_CFLAGS) -I$(top_srcdir)/shared/
+libpepper_la_LIBADD += $(WAYLAND_BACKEND_LIBS) $(top_builddir)/shared/libshared.la
 
 libpepper_la_SOURCES += modules/wayland/wayland-internal.h  \
                         modules/wayland/wayland-common.c    \
index 0c5a620..fe6c4f9 100644 (file)
@@ -11,9 +11,9 @@
 
 /* TODO: Change logging destination. */
 
-#define PEPPER_ERROR(fmt, ...)                     \
-    do {                                           \
-       printf(fmt, ##__VA_ARGS__);                 \
+#define PEPPER_ERROR(fmt, ...)                                          \
+    do {                                                                \
+        printf("%s:%s: "fmt, __FILE__, __FUNCTION__, ##__VA_ARGS__);   \
     } while (0)
 
 #define PEPPER_TRACE   PEPPER_ERROR
index 9391caf..b44f3a2 100644 (file)
@@ -1,4 +1,4 @@
-#include "pepper.h"
+#include "pepper-gl-renderer.h"
 #include "common.h"
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
index a56d925..b782b16 100644 (file)
@@ -16,7 +16,7 @@ PEPPER_API void
 pepper_wayland_destroy(pepper_wayland_t *conn);
 
 PEPPER_API pepper_output_t *
-pepper_wayland_output_create(pepper_wayland_t *conn, int32_t w, int32_t h);
+pepper_wayland_output_create(pepper_wayland_t *conn, int32_t w, int32_t h, const char *renderer);
 
 #ifdef __cplusplus
 }
index c6f52a2..bf83ef3 100644 (file)
@@ -1,9 +1,18 @@
+#include <config.h>
 #include "pepper-wayland.h"
 #include <wayland-client.h>
 #include <common.h>
+#include <pixman.h>
+
+#if ENABLE_WAYLAND_BACKEND_EGL
+#include <wayland-egl.h>
+#endif
+
+#define NUM_SHM_BUFFERS 2
 
 typedef struct wayland_output       wayland_output_t;
 typedef struct wayland_seat         wayland_seat_t;
+typedef struct wayland_shm_buffer   wayland_shm_buffer_t;
 
 struct pepper_wayland
 {
@@ -24,6 +33,18 @@ struct pepper_wayland
 
 };
 
+struct wayland_shm_buffer
+{
+    struct wl_buffer   *buffer;
+    void               *pixels;
+    int                 size;
+    pixman_image_t     *image;
+    pixman_region32_t   damage;
+    void               *data;
+
+    struct wl_list      link;
+};
+
 struct wayland_output
 {
     pepper_wayland_t           *conn;
@@ -38,6 +59,19 @@ struct wayland_output
 
     struct wl_surface          *surface;
     struct wl_shell_surface    *shell_surface;
+
+    pepper_renderer_t          *renderer;
+
+    struct {
+        /* list containing free wl_shm_buffers. */
+        struct wl_list          free_buffers;
+    } shm;
+
+#if ENABLE_WAYLAND_BACKEND_EGL
+    struct {
+        struct wl_egl_window   *window;
+    } egl;
+#endif
 };
 
 struct wayland_seat
index 915e032..75c9af7 100644 (file)
@@ -1,7 +1,15 @@
 #include "wayland-internal.h"
+#include <pepper-os-compat.h>
+#include <string.h>
+#include <pepper-pixman-renderer.h>
 
-static const char *maker_name = "wayland";
-static const char *model_name = "wayland";
+#if ENABLE_WAYLAND_BACKEND_EGL && ENABLE_GL_RENDERER
+#include <pepper-gl-renderer.h>
+#endif
+
+static const char *maker_name       = "wayland";
+static const char *model_name       = "wayland";
+static const char *default_renderer = "pixman";
 
 static void
 shell_surface_ping(void *data, struct wl_shell_surface *shell_surface, uint32_t serial)
@@ -133,6 +141,12 @@ wayland_output_set_mode(void *o, const pepper_output_mode_t *mode)
     return PEPPER_TRUE;
 }
 
+static void
+wayland_output_schedule_repaint(void *o, void *data)
+{
+    /* TODO: */
+}
+
 static const pepper_output_interface_t wayland_output_interface =
 {
     wayland_output_destroy,
@@ -146,6 +160,8 @@ static const pepper_output_interface_t wayland_output_interface =
     wayland_output_get_mode_count,
     wayland_output_get_mode,
     wayland_output_set_mode,
+
+    wayland_output_schedule_repaint,
 };
 
 static void
@@ -155,8 +171,61 @@ handle_connection_destroy(struct wl_listener *listener, void *data)
     wayland_output_destroy(output);
 }
 
+static pepper_bool_t
+init_gl_renderer(wayland_output_t *output)
+{
+#if ENABLE_WAYLAND_BACKEND_EGL
+    output->egl.window = wl_egl_window_create(output->surface, output->w, output->h);
+
+    if (!output->egl.window)
+        return PEPPER_FALSE;
+
+    output->renderer = pepper_gl_renderer_create(output->conn->display,
+                                                 output->egl.window,
+                                                 PEPPER_FORMAT_ARGB8888,
+                                                 NULL);
+
+    if (output->renderer)
+        return PEPPER_TRUE;
+
+    /* Clean up. */
+    wl_egl_window_destroy(output->egl.window);
+    output->egl.window = NULL;
+#endif
+
+    return PEPPER_FALSE;
+}
+
+static pepper_bool_t
+init_pixman_renderer(wayland_output_t *output)
+{
+    wl_list_init(&output->shm.free_buffers);
+
+    output->renderer = pepper_pixman_renderer_create();
+
+    if (output->renderer)
+        return PEPPER_TRUE;
+
+    return PEPPER_FALSE;
+}
+
+static pepper_bool_t
+init_renderer(wayland_output_t *output, const char *name)
+{
+    if (strcmp(name, "gl") == 0)
+    {
+        return init_gl_renderer(output);
+    }
+    else if (strcmp(name, "pixman") == 0)
+    {
+        return init_pixman_renderer(output);
+    }
+
+    return PEPPER_FALSE;
+}
+
 PEPPER_API pepper_output_t *
-pepper_wayland_output_create(pepper_wayland_t *conn, int32_t w, int32_t h)
+pepper_wayland_output_create(pepper_wayland_t *conn, int32_t w, int32_t h, const char *renderer)
 {
     pepper_output_t    *base;
     wayland_output_t   *output;
@@ -189,5 +258,15 @@ pepper_wayland_output_create(pepper_wayland_t *conn, int32_t w, int32_t h)
     output->conn_destroy_listener.notify = handle_connection_destroy;
     wl_signal_add(&conn->destroy_signal, &output->conn_destroy_listener);
 
+    /* Create renderer. */
+    if (!renderer)
+        renderer = default_renderer;
+
+    if (!init_renderer(output, renderer))
+    {
+        wayland_output_destroy(output);
+        return NULL;
+    }
+
     return base;
 }
diff --git a/src/pepper-pixman-renderer.h b/src/pepper-pixman-renderer.h
new file mode 100644 (file)
index 0000000..4669060
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef PEPPER_PIXMAN_RENDERER_H
+#define PEPPER_PIXMAN_RENDERER_H
+
+#include "pepper.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+PEPPER_API pepper_renderer_t *
+pepper_pixman_renderer_create();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEPPER_PIXMAN_RENDERER_H */
diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
new file mode 100644 (file)
index 0000000..aa73f4a
--- /dev/null
@@ -0,0 +1,137 @@
+#include "pepper-pixman-renderer.h"
+#include "common.h"
+#include <pixman.h>
+
+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
+get_pixman_format(pepper_format_t format)
+{
+    switch (format)
+    {
+    case PEPPER_FORMAT_ARGB8888:
+        return PIXMAN_a8r8g8b8;
+    case PEPPER_FORMAT_XRGB8888:
+        return PIXMAN_x8r8g8b8;
+    case PEPPER_FORMAT_RGB888:
+        return PIXMAN_r8g8b8;
+    case PEPPER_FORMAT_RGB565:
+        return PIXMAN_r5g6b5;
+    case PEPPER_FORMAT_ABGR8888:
+        return PIXMAN_a8b8g8r8;
+    case PEPPER_FORMAT_XBGR8888:
+        return PIXMAN_x8b8g8r8;
+    case PEPPER_FORMAT_BGR888:
+        return PIXMAN_b8g8r8;
+    case PEPPER_FORMAT_BGR565:
+        return PIXMAN_b5g6r5;
+    case PEPPER_FORMAT_ALPHA:
+        return PIXMAN_a8;
+    default:
+        break;
+    }
+
+    return (pixman_format_code_t)0;
+}
+
+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,
+                            void *pixels, pepper_format_t format)
+{
+    pixman_renderer_t      *renderer = (pixman_renderer_t *)r;
+    pixman_image_t         *dst;
+    pixman_format_code_t    pixman_format;
+    int                     stride;
+
+    if (!renderer->target)
+        return PEPPER_FALSE;
+
+    pixman_format = get_pixman_format(format);
+
+    if (!pixman_format)
+    {
+        PEPPER_ERROR("Invalid format.\n");
+        return PEPPER_FALSE;
+    }
+
+    stride = (PEPPER_FORMAT_BPP(format) / 8) * w;
+    dst = pixman_image_create_bits(pixman_format, w, h, pixels, stride);
+
+    if (!dst)
+    {
+        PEPPER_ERROR("Failed to create pixman image.\n");
+        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;
+
+    return PEPPER_TRUE;
+}
+
+static void
+pixman_renderer_draw(pepper_renderer_t *r, void *data)
+{
+    pixman_renderer_t *renderer = (pixman_renderer_t *)r;
+
+    if (renderer->target)
+    {
+        /* TODO: */
+        pixman_image_t *image = renderer->target;
+        pixman_fill(pixman_image_get_data(image),
+                    pixman_image_get_stride(image),
+                    PIXMAN_FORMAT_BPP(pixman_image_get_format(image)),
+                    0, 0,
+                    pixman_image_get_width(image),
+                    pixman_image_get_height(image),
+                    0xffffffff);
+    }
+}
+
+PEPPER_API pepper_renderer_t *
+pepper_pixman_renderer_create()
+{
+    pixman_renderer_t    *renderer;
+
+    renderer = pepper_calloc(1, sizeof(pixman_renderer_t));
+    if (!renderer)
+        return NULL;
+
+    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;
+}