[systemd-devel] [RFC 11/12] gfx: add unbuilt GL test

David Herrmann dh.herrmann at gmail.com
Wed Nov 27 10:48:46 PST 2013


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.herrmann at 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



More information about the systemd-devel mailing list