The test-gl helper shows how sd_gfx_card can be used to get a full OpenGL context on the device. It is not added to the build-tools as it requires mesa and might break on Khronos header-updates (yes, they break API *and* ABI compatibility often!). --- .gitignore | 1 + Makefile.am | 18 +++ configure.ac | 3 + src/libsystemd-gfx/test-gl.c | 342 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 364 insertions(+) create mode 100644 src/libsystemd-gfx/test-gl.c
diff --git a/.gitignore b/.gitignore index a61f68d..c856412 100644 --- a/.gitignore +++ b/.gitignore @@ -116,6 +116,7 @@ /test-event /test-fileio /test-gfx +/test-gl /test-hashmap /test-hostname /test-id128 diff --git a/Makefile.am b/Makefile.am index aa17876..1e8aeed 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3886,6 +3886,19 @@ test_gfx_LDADD = \ libsystemd-shared.la \ libsystemd-gfx.la +test_gl_SOURCES = \ + src/libsystemd-gfx/test-gl.c + +test_gl_CFLAGS = \ + $(AM_CFLAGS) \ + $(GFX_GL_CFLAGS) + +test_gl_LDADD = \ + $(GFX_GL_LIBS) \ + libsystemd-bus-internal.la \ + libsystemd-shared.la \ + libsystemd-gfx.la + test_kbd_SOURCES = \ src/libsystemd-gfx/test-kbd.c @@ -3903,6 +3916,11 @@ tests += \ test-gfx \ test-kbd +if HAVE_GFX_GL +# Uncomment this to enable test-gl builds +#tests += test-gl +endif + src/libsystemd-gfx/unifont.bin: make-unifont.py src/libsystemd-gfx/unifont.hex $(AM_V_GEN)cat $(top_srcdir)/src/libsystemd-gfx/unifont.hex | $(PYTHON) $< >$@ diff --git a/configure.ac b/configure.ac index b76a86d..bf3fce3 100644 --- a/configure.ac +++ b/configure.ac @@ -299,8 +299,11 @@ if test "x$enable_gfx" != "xno"; then if test "x$have_gfx" = xno -a "x$enable_gfx" = xyes; then AC_MSG_ERROR([*** sd-gfx support requested, but libraries not found]) fi + PKG_CHECK_MODULES(GFX_GL, [ libdrm >= 2.4.47 gbm >= 9.2.3 egl glesv2 ], + [AC_DEFINE(HAVE_GFX_GL, 1, [Define if sd-gfx GL examples are built]) have_gfx_gl=yes], have_gfx_gl=no) fi AM_CONDITIONAL(HAVE_GFX, [test "$have_gfx" = "yes"]) +AM_CONDITIONAL(HAVE_GFX_GL, [test "$have_gfx_gl" = "yes"]) # ------------------------------------------------------------------------------ have_blkid=no diff --git a/src/libsystemd-gfx/test-gl.c b/src/libsystemd-gfx/test-gl.c new file mode 100644 index 0000000..733b451 --- /dev/null +++ b/src/libsystemd-gfx/test-gl.c @@ -0,0 +1,342 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 David Herrmann <dh.herrm...@gmail.com> + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#define EGL_EGLEXT_PROTOTYPES +#define GL_GLEXT_PROTOTYPES + +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <drm.h> +#include <drm_fourcc.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <gbm.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include "def.h" +#include "log.h" +#include "macro.h" +#include "missing.h" +#include "sd-event.h" +#include "sd-gfx.h" +#include "util.h" + +struct plane { + struct gbm_surface *gbm; + EGLSurface egl; + + struct gbm_surface *t_gbm; + EGLSurface t_egl; +}; + +static int gl_fd; +static struct gbm_device *gl_device; +static EGLDisplay gl_display; +static EGLConfig gl_config; +static EGLContext gl_context; + +static void err(const char *format, ...) { + va_list args; + + fprintf(stderr, "ERROR: "); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + + _exit(1); +} + +static void fb_unlink(sd_gfx_fb *fb, void *fn_data) { + struct gbm_bo *bo = fn_data; + + gbm_bo_set_user_data(bo, NULL, NULL); +} + +static void fb_unpin(sd_gfx_fb *fb, void *fn_data) { + struct gbm_bo *bo = fn_data; + sd_gfx_plane *plane = sd_gfx_fb_get_plane(fb); + struct plane *p = sd_gfx_plane_get_fn_data(plane); + + gbm_surface_release_buffer(p->gbm, bo); +} + +static void fb_destroy(struct gbm_bo *bo, void *data) { + sd_gfx_fb *fb = data; + + if (!fb) + return; + + err("fb_destroy()"); +} + +static sd_gfx_fb *bo_to_fb(sd_gfx_plane *plane, struct gbm_bo *bo) { + sd_gfx_fb *fb; + int r; + + fb = gbm_bo_get_user_data(bo); + if (fb) + return fb; + + r = sd_gfx_fb_new_rgb(&fb, + plane, + DRM_FORMAT_XRGB8888, + gbm_bo_get_handle(bo).u32, + gbm_bo_get_width(bo), + gbm_bo_get_height(bo), + gbm_bo_get_stride(bo), + 0, 0, 0); + if (r < 0) + return NULL; + + sd_gfx_fb_set_fn_data(fb, bo); + sd_gfx_fb_set_fns(fb, fb_unlink, fb_unpin); + gbm_bo_set_user_data(bo, fb, fb_destroy); + + return fb; +} + +static int plane_prepare(sd_gfx_plane *plane, void *fn_data, unsigned int width, unsigned int height, sd_gfx_fb **fb) { + struct plane *p = fn_data; + struct gbm_bo *bo; + + p->t_gbm = gbm_surface_create(gl_device, width, height, GBM_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + if (!p->t_gbm) + return -ENOMEM; + + p->t_egl = eglCreateWindowSurface(gl_display, gl_config, + (EGLNativeWindowType)p->t_gbm, NULL); + if (p->t_egl == EGL_NO_SURFACE) + goto err_gbm; + + if (!eglMakeCurrent(gl_display, p->t_egl, p->t_egl, gl_context)) + goto err_egl; + + glClearColor(0.5, 0.4, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + if (!eglSwapBuffers(gl_display, p->t_egl)) + goto err_ctx; + + bo = gbm_surface_lock_front_buffer(p->t_gbm); + if (!bo) + goto err_ctx; + + *fb = bo_to_fb(plane, bo); + if (!*fb) + goto err_unlock; + + return 0; + +err_unlock: + gbm_surface_release_buffer(p->t_gbm, bo); +err_ctx: + eglMakeCurrent(gl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +err_egl: + eglDestroySurface(gl_display, p->t_egl); +err_gbm: + gbm_surface_destroy(p->t_gbm); + return -EINVAL; +} + +static void plane_cancel(sd_gfx_plane *plane, void *fn_data, sd_gfx_fb *fb) { + struct plane *p = fn_data; + struct gbm_bo *bo = sd_gfx_fb_get_fn_data(fb); + + gbm_surface_release_buffer(p->t_gbm, bo); + + gbm_bo_set_user_data(bo, NULL, NULL); + sd_gfx_fb_set_fn_data(fb, NULL); + sd_gfx_fb_set_fns(fb, NULL, NULL); + + eglMakeCurrent(gl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(gl_display, p->t_egl); + gbm_surface_destroy(p->t_gbm); + + p->t_egl = NULL; + p->t_gbm = NULL; +} + +static void plane_finish(sd_gfx_plane *plane, void *fn_data, sd_gfx_fb *fb) { + struct plane *p = fn_data; + + if (p->gbm) { + eglDestroySurface(gl_display, p->egl); + gbm_surface_destroy(p->gbm); + } + + p->egl = p->t_egl; + p->gbm = p->t_gbm; + p->t_egl = NULL; + p->t_gbm = NULL; +} + +static int plane_create(sd_gfx_plane *plane) { + struct plane *p; + + p = calloc(1, sizeof(*p)); + if (!p) + return -ENOMEM; + + sd_gfx_plane_set_fn_data(plane, p); + sd_gfx_plane_set_fns(plane, plane_prepare, plane_cancel, plane_finish); + + return 0; +} + +static void plane_destroy(sd_gfx_plane *plane) { + struct plane *p = sd_gfx_plane_get_fn_data(plane); + + if (!p) + return; + + sd_gfx_plane_set_fn_data(plane, NULL); + sd_gfx_plane_set_fns(plane, NULL, NULL, NULL); + free(p); +} + +static void pipe_create(sd_gfx_pipe *pipe) { + sd_gfx_plane *plane = sd_gfx_pipe_get_primary_plane(pipe); + int r; + + r = plane_create(plane); + if (r < 0) + err("plane_create(): %d", r); +} + +static void pipe_destroy(sd_gfx_pipe *pipe) { + sd_gfx_plane *plane = sd_gfx_pipe_get_primary_plane(pipe); + + plane_destroy(plane); +} + +static void card_event_fn(sd_gfx_card *card, void *data, sd_gfx_card_event *ev) { + switch (ev->type) { + case SD_GFX_CARD_PIPE_CREATE: + log_debug("pipe %u create", sd_gfx_pipe_get_id(ev->pipe)); + pipe_create(ev->pipe); + break; + case SD_GFX_CARD_PIPE_DESTROY: + log_debug("pipe %u destroy", sd_gfx_pipe_get_id(ev->pipe)); + pipe_destroy(ev->pipe); + break; + } +} + +static void init_egl(void) { + static const EGLint conf_att[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 1, + EGL_GREEN_SIZE, 1, + EGL_BLUE_SIZE, 1, + EGL_ALPHA_SIZE, 0, + EGL_NONE, + }; + static const EGLint ctx_att[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + EGLint major, minor, n; + EGLenum api; + + gl_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC | O_NONBLOCK); + if (gl_fd < 0) + err("open(): %m"); + + gl_device = gbm_create_device(gl_fd); + if (!gl_device) + err("gbm_create_device(): %m"); + + gl_display = eglGetDisplay((EGLNativeDisplayType)gl_device); + if (gl_display == EGL_NO_DISPLAY) + err("eglGetDisplay(): %m"); + + if (!eglInitialize(gl_display, &major, &minor)) + err("eglInitialize(): %m"); + + log_debug("EGL Init %d.%d", major, minor); + log_debug("EGL Version %s", eglQueryString(gl_display, EGL_VERSION)); + log_debug("EGL Vendor %s", eglQueryString(gl_display, EGL_VENDOR)); + log_debug("EGL Extensions %s", eglQueryString(gl_display, EGL_EXTENSIONS)); + + api = EGL_OPENGL_ES_API; + if (!eglBindAPI(api)) + err("eglBindAPI(): %m"); + + if (!eglChooseConfig(gl_display, conf_att, &gl_config, 1, &n) || n != 1) + err("eglChooseConfig(%d): %m", (int)n); + + gl_context = eglCreateContext(gl_display, gl_config, EGL_NO_CONTEXT, ctx_att); + if (gl_context == EGL_NO_CONTEXT) + err("eglCreateContext(): %m"); +} + +static void destroy_egl(void) { + eglMakeCurrent(gl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(gl_display, gl_context); + eglTerminate(gl_display); + gbm_device_destroy(gl_device); + close(gl_fd); +} + +int main(int argc, char **argv) { + sd_event *event; + sd_gfx_card *card; + int r; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + r = sd_event_new(&event); + if (r < 0) + err("event_new(): %d", r); + + init_egl(); + + r = sd_gfx_card_new(&card, "/dev/dri/card0", gl_fd, event); + if (r < 0) + err("card_new(): %d", r); + sd_gfx_card_set_event_fn(card, card_event_fn); + + r = sd_gfx_card_wake_up(card); + if (r < 0) + err("card_wake_up(): %d", r); + + log_info("wait 2s.."); + sleep(2); + + sd_gfx_card_restore(card); + sd_gfx_card_free(card); + + destroy_egl(); + sd_event_unref(event); + + return 0; +} -- 1.8.4.2 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel