[systemd-devel] [RFC 10/12] gfx: add graphics test
David Herrmann
dh.herrmann at gmail.com
Wed Nov 27 10:48:45 PST 2013
The test-gfx helper simply renders a solid-color on all active pipelines.
Useful to debug monitor-hotplugging and GPU selection.
---
.gitignore | 1 +
Makefile.am | 9 ++
src/libsystemd-gfx/test-gfx.c | 302 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 312 insertions(+)
create mode 100644 src/libsystemd-gfx/test-gfx.c
diff --git a/.gitignore b/.gitignore
index f4921f5..a61f68d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -115,6 +115,7 @@
/test-env-replace
/test-event
/test-fileio
+/test-gfx
/test-hashmap
/test-hostname
/test-id128
diff --git a/Makefile.am b/Makefile.am
index e8822b2..aa17876 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3878,6 +3878,14 @@ libsystemd_gfx_la_LIBADD = \
libudev-internal.la \
src/libsystemd-gfx/unifont.bin.lo
+test_gfx_SOURCES = \
+ src/libsystemd-gfx/test-gfx.c
+
+test_gfx_LDADD = \
+ libsystemd-bus-internal.la \
+ libsystemd-shared.la \
+ libsystemd-gfx.la
+
test_kbd_SOURCES = \
src/libsystemd-gfx/test-kbd.c
@@ -3892,6 +3900,7 @@ test_kbd_LDADD = \
libsystemd-gfx.la
tests += \
+ test-gfx \
test-kbd
src/libsystemd-gfx/unifont.bin: make-unifont.py src/libsystemd-gfx/unifont.hex
diff --git a/src/libsystemd-gfx/test-gfx.c b/src/libsystemd-gfx/test-gfx.c
new file mode 100644
index 0000000..36157b6
--- /dev/null
+++ b/src/libsystemd-gfx/test-gfx.c
@@ -0,0 +1,302 @@
+/*-*- 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/>.
+***/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "build.h"
+#include "def.h"
+#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "sd-bus.h"
+#include "sd-daemon.h"
+#include "sd-event.h"
+#include "sd-gfx.h"
+#include "util.h"
+
+typedef struct Test Test;
+
+struct Test {
+ sd_event *event;
+ sd_event_source *sigs[_NSIG];
+ sd_gfx_monitor *mon;
+};
+
+static bool arg_all;
+static const char *arg_gpus;
+static const char *arg_keymap;
+
+static void test_pipe_draw(sd_gfx_pipe *pipe) {
+ sd_gfx_plane *primary;
+ sd_gfx_fb *fb;
+
+ primary = sd_gfx_pipe_get_primary_plane(pipe);
+ if (!primary) {
+ log_error("no primary plane on pipe");
+ return;
+ }
+
+ fb = sd_gfx_plane_get_front(primary);
+ if (!fb) {
+ log_error("no front-fb on primary plane");
+ return;
+ }
+
+ sd_gfx_fb_fill(fb,
+ 0xffaabb00,
+ 0,
+ 0,
+ sd_gfx_fb_get_width(fb),
+ sd_gfx_fb_get_height(fb));
+}
+
+static void test_card_fn(sd_gfx_card *card, void *fn_data, sd_gfx_card_event *ev) {
+ switch (ev->type) {
+ case SD_GFX_CARD_PIPE_WAKE_UP:
+ test_pipe_draw(ev->pipe);
+ break;
+ }
+}
+
+static void test_add(Test *t, sd_gfx_card *card) {
+ sd_gfx_card_set_event_fn(card, test_card_fn);
+}
+
+static void test_remove(Test *t, sd_gfx_card *card) {
+ sd_gfx_card_set_event_fn(card, NULL);
+}
+
+static void test_event_fn(sd_gfx_monitor *mon, void *fn_data, sd_gfx_monitor_event *ev) {
+ struct Test *t = fn_data;
+
+ switch (ev->type) {
+ case SD_GFX_MONITOR_CREATE:
+ if (ev->devtype == SD_GFX_DEV_CARD)
+ test_add(t, ev->card);
+ else
+ log_notice("unknown device of type %d", ev->devtype);
+ break;
+ case SD_GFX_MONITOR_DESTROY:
+ if (ev->devtype == SD_GFX_DEV_CARD)
+ test_remove(t, ev->card);
+ break;
+ default:
+ log_warning("unhandled monitor event: %d", ev->type);
+ break;
+ }
+}
+
+static int test_signal_fn(sd_event_source *s, const struct signalfd_siginfo *ssi, void *data) {
+ Test *t = data;
+
+ log_notice("catched signal %d, exiting..", (int)ssi->ssi_signo);
+ sd_event_request_quit(t->event);
+
+ return 0;
+}
+
+static int test_new(Test **out) {
+ static const int sigs[] = {
+ SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGPIPE, 0
+ };
+ unsigned int flags;
+ sigset_t mask;
+ Test *t;
+ int r, i;
+
+ t = calloc(1, sizeof(*t));
+ if (!t)
+ return log_oom();
+
+ r = sd_event_default(&t->event);
+ if (r < 0) {
+ log_error("cannot get default event-loop: %d", r);
+ goto err_t;
+ }
+
+ sigemptyset(&mask);
+ for (i = 0; sigs[i]; ++i) {
+ sigaddset(&mask, sigs[i]);
+ r = sd_event_add_signal(t->event,
+ sigs[i],
+ test_signal_fn,
+ t,
+ &t->sigs[i]);
+ if (r < 0) {
+ log_error("cannot block signal %d: %d",
+ sigs[i], r);
+ goto err_sigs;
+ }
+ }
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ flags = SD_GFX_MONITOR_DEFAULT;
+ if (arg_all)
+ flags |= SD_GFX_MONITOR_IGNORE_SEATS;
+
+ r = sd_gfx_monitor_new(&t->mon,
+ SD_GFX_DEV_CARD,
+ flags,
+ t->event);
+ if (r < 0)
+ goto err_sigs;
+
+ sd_gfx_monitor_set_fn_data(t->mon, t);
+ sd_gfx_monitor_set_event_fn(t->mon, test_event_fn);
+ sd_gfx_monitor_parse_cmdline(t->mon);
+ if (arg_gpus)
+ sd_gfx_monitor_set_gpus(t->mon, arg_gpus);
+ if (arg_keymap)
+ sd_gfx_monitor_set_keymap(t->mon, arg_keymap);
+
+ *out = t;
+ return 0;
+
+err_sigs:
+ for (i = 0; t->sigs[i]; ++i)
+ sd_event_source_unref(t->sigs[i]);
+ sd_event_unref(t->event);
+err_t:
+ free(t);
+ return r;
+}
+
+static void test_free(Test *t) {
+ int i;
+
+ if (!t)
+ return;
+
+ sd_gfx_monitor_free(t->mon);
+ for (i = 0; t->sigs[i]; ++i)
+ sd_event_source_unref(t->sigs[i]);
+ sd_event_unref(t->event);
+ free(t);
+}
+
+static int test_run(Test *t) {
+ return sd_event_loop(t->event);
+}
+
+static int help(void) {
+ printf("%s [OPTIONS...] ...\n\n"
+ "sd-gfx graphics test.\n\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " --all Use all devices\n"
+ " --gpus=MATCH List of GPUs to use\n"
+ " --keymap=LMVO XKB keymap to use\n"
+ , program_invocation_short_name);
+
+ return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+ enum {
+ ARG_VERSION = 0x100,
+ ARG_ALL,
+ ARG_GPUS,
+ ARG_KEYMAP,
+ };
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "all", no_argument, NULL, ARG_ALL },
+ { "gpus", required_argument, NULL, ARG_GPUS },
+ { "keymap", required_argument, NULL, ARG_KEYMAP },
+ {}
+ };
+ int c;
+
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+ switch(c) {
+ case 'h':
+ return help();
+ case ARG_VERSION:
+ puts(PACKAGE_STRING);
+ puts(SYSTEMD_FEATURES);
+ return 0;
+ case ARG_ALL:
+ arg_all = true;
+ break;
+ case ARG_GPUS:
+ arg_gpus = optarg;
+ break;
+ case ARG_KEYMAP:
+ arg_keymap = optarg;
+ break;
+ case '?':
+ return -EINVAL;
+ default:
+ assert_not_reached("Unhandled option");
+ }
+ }
+
+ if (optind < argc) {
+ log_error("This program does not take arguments.");
+ return -EINVAL;
+ }
+
+ return 1;
+}
+
+int main(int argc, char *argv[]) {
+ Test *t = NULL;
+ int r;
+
+ log_set_target(LOG_TARGET_AUTO);
+ log_parse_environment();
+ log_open();
+
+ umask(0022);
+ setlocale(LC_ALL, "");
+
+ r = parse_argv(argc, argv);
+ if (r < 0)
+ return EXIT_FAILURE;
+ if (r == 0)
+ return EXIT_SUCCESS;
+
+ r = test_new(&t);
+ if (r < 0)
+ goto finish;
+
+ r = test_run(t);
+
+finish:
+ if (t)
+ test_free(t);
+
+ log_debug("exiting..");
+ return abs(r);
+}
--
1.8.4.2
More information about the systemd-devel
mailing list