[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