[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