From 4033ceb27379757a38828aa73cb25a8b4ca179f5 Mon Sep 17 00:00:00 2001 From: Taekyun Kim Date: Tue, 7 Apr 2015 14:58:13 +0900 Subject: [PATCH] Initial renderer implementation Renderer base class and initial version of GL renderer implementation. Change-Id: I452144074a5526c1d2dde4b4bb70de40f184efa3 --- configure.ac | 16 +++ src/Makefile.am | 13 ++- src/gl-renderer.c | 279 +++++++++++++++++++++++++++++++++++++++++++++++ src/pepper-gl-renderer.h | 18 +++ src/pepper.h | 62 ++++++++++- src/renderer.c | 21 ++++ 6 files changed, 404 insertions(+), 5 deletions(-) create mode 100644 src/gl-renderer.c create mode 100644 src/pepper-gl-renderer.h create mode 100644 src/renderer.c diff --git a/configure.ac b/configure.ac index b1fddf8..51e0936 100644 --- a/configure.ac +++ b/configure.ac @@ -26,6 +26,18 @@ LIB_PEPPER_MODULES="wayland-server >= 1.6.00 pixman-1 >= 0.25.2" # Check pepper modules PKG_CHECK_MODULES(LIB_PEPPER, [$LIB_PEPPER_MODULES]) +# gl renderer +AC_ARG_ENABLE(gl-renderer, + AC_HELP_STRING([--enable-gl-renderer], [enable OpenGL renderer]), + [enable_gl_renderer=$enableval], [enable_gl_renderer=yes]) + +AM_CONDITIONAL(ENABLE_GL_RENDERER, test $enable_gl_renderer = yes) + +if test $enable_gl_renderer = yes; then + AC_DEFINE(ENABLE_GL_RENDERER, 1, [Enable OpenGL renderer]) + PKG_CHECK_MODULES(GL_RENDERER, [egl glesv2]) +fi + # wayland backend AC_ARG_ENABLE(wayland-backend, AC_HELP_STRING([--enable-wayland-backend], [enable wayland backend]), @@ -36,6 +48,10 @@ 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]) + + if test $enable_wayland_backend = yes; then + PKG_CHECK_MODULES(WAYLAND_BACKEND, [wayland-egl]) + fi fi # drm backend diff --git a/src/Makefile.am b/src/Makefile.am index 0c979dd..775de0d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,18 @@ libpepper_la_SOURCES = pepper.h \ shell.c \ surface.c \ region.c \ - buffer.c + buffer.c \ + renderer.c + +# gl renderer +if ENABLE_GL_RENDERER +include_HEADERS += pepper-gl-renderer.h + +libpepper_la_CFLAGS += $(GL_RENDERER_CFLAGS) +libpepper_la_LIBADD += $(GL_RENDERER_LIBS) + +libpepper_la_SOURCES += gl-renderer.c +endif # wayland backend if ENABLE_WAYLAND_BACKEND diff --git a/src/gl-renderer.c b/src/gl-renderer.c new file mode 100644 index 0000000..c71167f --- /dev/null +++ b/src/gl-renderer.c @@ -0,0 +1,279 @@ +#include "pepper.h" +#include "common.h" +#include +#include +#include +#include + +typedef struct gl_renderer gl_renderer_t; + +struct gl_renderer +{ + pepper_renderer_t base; + + EGLDisplay display; + EGLSurface surface; + EGLContext context; + EGLConfig config; +}; + +static pepper_bool_t +gl_renderer_use(gl_renderer_t *renderer) +{ + if (!eglMakeCurrent(renderer->display, renderer->surface, renderer->surface, renderer->context)) + return PEPPER_FALSE; + + return PEPPER_TRUE; +} + +static void +gl_renderer_destroy(pepper_renderer_t *r) +{ + gl_renderer_t *renderer = (gl_renderer_t *)r; + + if (renderer->context != EGL_NO_CONTEXT) + eglDestroyContext(renderer->display, renderer->context); + + if (renderer->surface != EGL_NO_SURFACE) + eglDestroySurface(renderer->display, renderer->surface); + + if (renderer->display != EGL_NO_DISPLAY) + eglTerminate(renderer->display); + + pepper_free(renderer); +} + +static pepper_bool_t +gl_renderer_read_pixels(pepper_renderer_t *r, int x, int y, int w, int h, + void *pixels, pepper_format_t format) +{ + gl_renderer_t *renderer = (gl_renderer_t *)r; + GLenum gl_format; + GLenum gl_type; + + if (!gl_renderer_use(renderer)) + return PEPPER_FALSE; + + switch (format) + { + case PEPPER_FORMAT_ARGB8888: + gl_format = GL_BGRA_EXT; + gl_type = GL_UNSIGNED_BYTE; + break; + case PEPPER_FORMAT_ABGR8888: + gl_format = GL_RGBA; + gl_type = GL_UNSIGNED_BYTE; + break; + default: + return PEPPER_FALSE; + } + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(x, y, w, h, gl_format, gl_type, pixels); + 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_t *renderer = (gl_renderer_t *)r; + + if (!gl_renderer_use(renderer)) + return; + + glClearColor(1.0, 1.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + eglSwapBuffers(renderer->display, renderer->surface); +} + +static pepper_bool_t +init_egl(gl_renderer_t *renderer, void *dpy, void *win, + pepper_format_t format, const uint32_t *native_visual_id) +{ + EGLDisplay display = EGL_NO_DISPLAY; + EGLSurface surface = EGL_NO_SURFACE; + EGLContext context = EGL_NO_CONTEXT; + EGLConfig config = NULL; + EGLint config_size = 0; + EGLint num_configs = 0; + EGLint major, minor; + EGLConfig *configs = NULL; + int i; + + EGLint context_attribs[] = + { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + EGLint config_attribs[] = + { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 0, + EGL_GREEN_SIZE, 0, + EGL_BLUE_SIZE, 0, + EGL_ALPHA_SIZE, 0, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE + }; + + config_attribs[3] = PEPPER_FORMAT_R(format); + config_attribs[5] = PEPPER_FORMAT_G(format); + config_attribs[7] = PEPPER_FORMAT_B(format); + config_attribs[9] = PEPPER_FORMAT_A(format); + + if ((display = eglGetDisplay((EGLNativeDisplayType)dpy)) == EGL_NO_DISPLAY) + { + PEPPER_ERROR("eglGetDisplay(%p) failed.\n", display); + goto error; + } + + if (!eglInitialize(display, &major, &minor)) + { + PEPPER_ERROR("eglInitialize() failed.\n"); + goto error; + } + + if (!eglBindAPI(EGL_OPENGL_ES_API)) + { + PEPPER_ERROR("eglBindAPI() failed.\n"); + return PEPPER_FALSE; + } + + if (!eglChooseConfig(display, config_attribs, NULL, 0, &config_size)) + { + PEPPER_ERROR("eglChooseConfig() failed.\n"); + goto error; + } + + if (config_size < 1) + { + PEPPER_ERROR("eglChooseConfig() returned no config.\n"); + goto error; + } + + if ((configs = (EGLConfig *)pepper_calloc(config_size, sizeof(EGLConfig))) == NULL) + goto error; + + if (num_configs < 1) + goto error; + + eglChooseConfig(display, config_attribs, configs, config_size, &num_configs); + PEPPER_ASSERT(config_size == num_configs); /* Paranoid check. */ + + for (i = 0; i < num_configs; i++) + { + EGLint attrib; + + if (native_visual_id) + { + /* Native visual id have privilege. */ + if (eglGetConfigAttrib(display, configs[i], EGL_NATIVE_VISUAL_ID, &attrib)) + { + if ((void *)attrib == (void *)(*native_visual_id)) + { + config = configs[i]; + break; + } + } + + continue; + } + + if (eglGetConfigAttrib(display, configs[i], EGL_BUFFER_SIZE, &attrib)) + { + if (attrib == PEPPER_FORMAT_BPP(format)) + { + config = configs[i]; + break; + } + } + } + + pepper_free(configs); + configs = NULL; + + if (!config) + { + PEPPER_ERROR("No matched config.\n"); + goto error; + } + + surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)win, NULL); + if (surface == EGL_NO_SURFACE) + { + PEPPER_ERROR("eglCreateWindowSurface() failed.\n"); + goto error; + } + + context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attribs); + if (context == EGL_NO_CONTEXT) + { + PEPPER_ERROR("eglCreateContext() failed.\n"); + goto error; + } + + if (!eglMakeCurrent(display, surface, surface, context)) + { + PEPPER_ERROR("eglMakeCurrent() failed.\n"); + goto error; + } + + renderer->display = display; + renderer->surface = surface; + renderer->context = context; + renderer->config = config; + + return PEPPER_TRUE; + +error: + if (context) + eglDestroyContext(display, context); + + if (surface) + eglDestroySurface(display, surface); + + if (display) + eglTerminate(display); + + if (configs) + pepper_free(configs); + + return PEPPER_FALSE; +} + +PEPPER_API pepper_renderer_t * +pepper_gl_renderer_create(void *display, void *window, + pepper_format_t format, const uint32_t *native_visual_id) +{ + gl_renderer_t *renderer; + + renderer = (gl_renderer_t *)pepper_calloc(1, sizeof(gl_renderer_t)); + if (!renderer) + return NULL; + + pepper_renderer_init(&renderer->base); + + if (!init_egl(renderer, display, window, format, native_visual_id)) + goto error; + + 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; + +error: + if (renderer) + gl_renderer_destroy(&renderer->base); + + return NULL; +} diff --git a/src/pepper-gl-renderer.h b/src/pepper-gl-renderer.h new file mode 100644 index 0000000..783fb50 --- /dev/null +++ b/src/pepper-gl-renderer.h @@ -0,0 +1,18 @@ +#ifndef PEPPER_GL_RENDERER_H +#define PEPPER_GL_RENDERER_H + +#include "pepper.h" + +#ifdef __cplusplus +extern "C" { +#endif + +PEPPER_API pepper_renderer_t * +pepper_gl_renderer_create(void *display, void *window, + pepper_format_t format, const uint32_t *native_visual_id); + +#ifdef __cplusplus +} +#endif + +#endif /* PEPPER_GL_RENDERER_H */ diff --git a/src/pepper.h b/src/pepper.h index a93e619..376f214 100644 --- a/src/pepper.h +++ b/src/pepper.h @@ -33,12 +33,46 @@ typedef struct pepper_touch pepper_touch_t; typedef struct pepper_input_event pepper_input_event_t; +typedef struct pepper_renderer pepper_renderer_t; + +#define PEPPER_FORMAT(type, bpp, a, r, g, b) \ + ((((type) & 0xff) << 24) | \ + (( (bpp) & 0xff) << 16) | \ + (( (a) & 0x0f) << 12) | \ + (( (r) & 0x0f) << 8) | \ + (( (g) & 0x0f) << 4) | \ + (( (b) & 0x0f) << 0)) + +#define PEPPER_FORMAT_TYPE(format) (((format) & 0xff000000) >> 24) +#define PEPPER_FORMAT_BPP(format) (((format) & 0x00ff0000) >> 16) +#define PEPPER_FORMAT_A(format) (((format) & 0x0000f000) >> 12) +#define PEPPER_FORMAT_R(format) (((format) & 0x00000f00) >> 8) +#define PEPPER_FORMAT_G(format) (((format) & 0x000000f0) >> 4) +#define PEPPER_FORMAT_B(format) (((format) & 0x0000000f) >> 0) + typedef enum { - PEPPER_RENDER_METHOD_NONE, - PEPPER_RENDER_METHOD_PIXMAN, - PEPPER_RENDER_METHOD_NATIVE, -} pepper_render_method_t; + PEPPER_FORMAT_TYPE_UNKNOWN, + PEPPER_FORMAT_TYPE_ARGB, + PEPPER_FORMAT_TYPE_ABGR, +} pepper_format_type_t; + +typedef enum +{ + PEPPER_FORMAT_UNKNOWN = PEPPER_FORMAT(PEPPER_FORMAT_TYPE_UNKNOWN, 0, 0, 0, 0, 0), + + PEPPER_FORMAT_ARGB8888 = PEPPER_FORMAT(PEPPER_FORMAT_TYPE_ARGB, 32, 8, 8, 8, 8), + PEPPER_FORMAT_XRGB8888 = PEPPER_FORMAT(PEPPER_FORMAT_TYPE_ARGB, 32, 0, 8, 8, 8), + PEPPER_FORMAT_RGB888 = PEPPER_FORMAT(PEPPER_FORMAT_TYPE_ARGB, 24, 0, 8, 8, 8), + PEPPER_FORMAT_RGB565 = PEPPER_FORMAT(PEPPER_FORMAT_TYPE_ARGB, 16, 0, 5, 6, 5), + + PEPPER_FORMAT_ABGR8888 = PEPPER_FORMAT(PEPPER_FORMAT_TYPE_ABGR, 32, 8, 8, 8, 8), + PEPPER_FORMAT_XBGR8888 = PEPPER_FORMAT(PEPPER_FORMAT_TYPE_ABGR, 32, 0, 8, 8, 8), + PEPPER_FORMAT_BGR888 = PEPPER_FORMAT(PEPPER_FORMAT_TYPE_ABGR, 24, 0, 8, 8, 8), + PEPPER_FORMAT_BGR565 = PEPPER_FORMAT(PEPPER_FORMAT_TYPE_ABGR, 16, 0, 5, 6, 5), + + PEPPER_FORMAT_ALPHA = PEPPER_FORMAT(PEPPER_FORMAT_TYPE_ARGB, 8, 8, 0, 0, 0), +} pepper_format_t; struct pepper_output_geometry { @@ -73,6 +107,8 @@ struct pepper_output_interface 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 (*schedule_repaint)(void *output, void *data /* TODO: view list or scene graph data. */); }; /* Compositor functions. */ @@ -170,6 +206,24 @@ struct pepper_input_event PEPPER_API pepper_bool_t pepper_seat_handle_event(pepper_seat_t *seat, pepper_input_event_t *event); +/* Renderer. */ +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, + 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: */); +}; + +PEPPER_API void +pepper_renderer_init(pepper_renderer_t *renderer); + +PEPPER_API void +pepper_renderer_destroy(pepper_renderer_t *renderer); + #ifdef __cplusplus } #endif diff --git a/src/renderer.c b/src/renderer.c new file mode 100644 index 0000000..7f84015 --- /dev/null +++ b/src/renderer.c @@ -0,0 +1,21 @@ +#include "pepper.h" +#include + +PEPPER_API void +pepper_renderer_init(pepper_renderer_t *renderer) +{ + memset(renderer, 0x00, sizeof(pepper_renderer_t)); +} + +static void +pepper_renderer_fini(pepper_renderer_t *renderer) +{ + memset(renderer, 0x00, sizeof(pepper_renderer_t)); +} + +PEPPER_API void +pepper_renderer_destroy(pepper_renderer_t *renderer) +{ + pepper_renderer_fini(renderer); + renderer->destroy(renderer); +} -- 2.7.4