From f71672d2a54fdbcc430b966abcbb6123a5f2aa41 Mon Sep 17 00:00:00 2001 From: Taekyun Kim Date: Wed, 8 Apr 2015 13:50:05 +0900 Subject: [PATCH] renderer: initial pixman renderer & wayland backend rendering functions Change-Id: I6b906148d73405da3adc1cda5cedbb3968641507 --- Makefile.am | 2 +- configure.ac | 15 +++- shared/Makefile.am | 3 + shared/pepper-os-compat.c | 94 ++++++++++++++++++++++ shared/pepper-os-compat.h | 33 ++++++++ src/Makefile.am | 9 ++- src/common.h | 6 +- src/gl-renderer.c | 2 +- src/modules/wayland/pepper-wayland.h | 2 +- src/modules/wayland/wayland-internal.h | 34 ++++++++ src/modules/wayland/wayland-output.c | 85 +++++++++++++++++++- src/pepper-pixman-renderer.h | 17 ++++ src/pixman-renderer.c | 137 +++++++++++++++++++++++++++++++++ 13 files changed, 423 insertions(+), 16 deletions(-) create mode 100644 shared/Makefile.am create mode 100644 shared/pepper-os-compat.c create mode 100644 shared/pepper-os-compat.h create mode 100644 src/pepper-pixman-renderer.h create mode 100644 src/pixman-renderer.c diff --git a/Makefile.am b/Makefile.am index af437a6..57300c2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1 +1 @@ -SUBDIRS = src +SUBDIRS = shared src diff --git a/configure.ac b/configure.ac index 51e0936..362cd0b 100644 --- a/configure.ac +++ b/configure.ac @@ -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 index 0000000..1eb15e3 --- /dev/null +++ b/shared/Makefile.am @@ -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 index 0000000..a965bdc --- /dev/null +++ b/shared/pepper-os-compat.c @@ -0,0 +1,94 @@ +#include "pepper-os-compat.h" +#include +#include +#include +#include + +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 index 0000000..0084a9f --- /dev/null +++ b/shared/pepper-os-compat.h @@ -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 + +int +pepper_create_anonymous_file(off_t size); + +#endif /* PEPPER_OS_COMPAT_H */ diff --git a/src/Makefile.am b/src/Makefile.am index 775de0d..90778fe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/common.h b/src/common.h index 0c5a620..fe6c4f9 100644 --- a/src/common.h +++ b/src/common.h @@ -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 diff --git a/src/gl-renderer.c b/src/gl-renderer.c index 9391caf..b44f3a2 100644 --- a/src/gl-renderer.c +++ b/src/gl-renderer.c @@ -1,4 +1,4 @@ -#include "pepper.h" +#include "pepper-gl-renderer.h" #include "common.h" #include #include diff --git a/src/modules/wayland/pepper-wayland.h b/src/modules/wayland/pepper-wayland.h index a56d925..b782b16 100644 --- a/src/modules/wayland/pepper-wayland.h +++ b/src/modules/wayland/pepper-wayland.h @@ -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 } diff --git a/src/modules/wayland/wayland-internal.h b/src/modules/wayland/wayland-internal.h index c6f52a2..bf83ef3 100644 --- a/src/modules/wayland/wayland-internal.h +++ b/src/modules/wayland/wayland-internal.h @@ -1,9 +1,18 @@ +#include #include "pepper-wayland.h" #include #include +#include + +#if ENABLE_WAYLAND_BACKEND_EGL +#include +#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 diff --git a/src/modules/wayland/wayland-output.c b/src/modules/wayland/wayland-output.c index 915e032..75c9af7 100644 --- a/src/modules/wayland/wayland-output.c +++ b/src/modules/wayland/wayland-output.c @@ -1,7 +1,15 @@ #include "wayland-internal.h" +#include +#include +#include -static const char *maker_name = "wayland"; -static const char *model_name = "wayland"; +#if ENABLE_WAYLAND_BACKEND_EGL && ENABLE_GL_RENDERER +#include +#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 index 0000000..4669060 --- /dev/null +++ b/src/pepper-pixman-renderer.h @@ -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 index 0000000..aa73f4a --- /dev/null +++ b/src/pixman-renderer.c @@ -0,0 +1,137 @@ +#include "pepper-pixman-renderer.h" +#include "common.h" +#include + +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; +} -- 2.7.4