aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2019-06-14 10:05:50 +0200
committerGerd Hoffmann <kraxel@redhat.com>2019-06-14 10:05:50 +0200
commitac3a01bfe9520e61f44e7f9893145d82b53522ae (patch)
tree821b1f519438e1f486dfae5045070e7d7983e1c5
parente7580760b355347220993ae485d3e8962e14e77e (diff)
downloaddrminfo-ac3a01bfe9520e61f44e7f9893145d82b53522ae.tar.gz
add drm lease support to drmtest
-rw-r--r--drm-lease-x11.c245
-rw-r--r--drm-lease.c21
-rw-r--r--drm-lease.h2
-rw-r--r--drminfo.spec2
-rw-r--r--drmtest.c28
-rw-r--r--drmtools.c13
-rw-r--r--drmtools.h3
-rw-r--r--egltest.c2
-rw-r--r--meson.build12
-rw-r--r--virtiotest.c2
10 files changed, 310 insertions, 20 deletions
diff --git a/drm-lease-x11.c b/drm-lease-x11.c
new file mode 100644
index 0000000..e0a9c3e
--- /dev/null
+++ b/drm-lease-x11.c
@@ -0,0 +1,245 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "drm-lease.h"
+
+#ifdef HAVE_XRANDR
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+#include <X11/X.h>
+#include <xcb/randr.h>
+
+typedef struct xserver_t {
+ xcb_connection_t *conn;
+ xcb_window_t root;
+
+ const xcb_query_extension_reply_t *ext_r;
+
+ xcb_randr_output_t randr_output;
+ xcb_randr_crtc_t randr_crtc;
+ xcb_randr_lease_t randr_lease;
+ xcb_randr_mode_info_t randr_mode;
+ xcb_randr_get_screen_resources_reply_t *gsr_r;
+} xserver_t;
+
+static const char *core_err[] = {
+ [Success] = "Success",
+ [BadRequest] = "BadRequest",
+ [BadValue] = "BadValue",
+ [BadWindow] = "BadWindow",
+ [BadPixmap] = "BadPixmap",
+ [BadAtom] = "BadAtom",
+ [BadCursor] = "BadCursor",
+ [BadFont] = "BadFont",
+ [BadMatch] = "BadMatch",
+ [BadDrawable] = "BadDrawable",
+ [BadAccess] = "BadAccess",
+ [BadAlloc] = "BadAlloc",
+ [BadColor] = "BadColor",
+ [BadGC] = "BadGC",
+ [BadIDChoice] = "BadIDChoice",
+ [BadName] = "BadName",
+ [BadLength] = "BadLength",
+ [BadImplementation] = "BadImplementation",
+};
+
+static const char *xrandr_err[] = {
+ [XCB_RANDR_BAD_OUTPUT] = "BadOutput",
+ [XCB_RANDR_BAD_CRTC] = "BadCRTC",
+ [XCB_RANDR_BAD_MODE] = "BadMode",
+ [XCB_RANDR_BAD_PROVIDER] = "BadProvider",
+};
+
+static void xserver_print_error(xserver_t *x,
+ xcb_generic_error_t *error)
+{
+ const char *name;
+
+ if (error->error_code >= x->ext_r->first_error &&
+ error->error_code < x->ext_r->first_error + ARRAY_SIZE(xrandr_err)) {
+ name = xrandr_err[error->error_code - x->ext_r->first_error];
+ } else if (error->error_code < ARRAY_SIZE(core_err)) {
+ name = core_err[error->error_code];
+ } else {
+ name = "unknown";
+ }
+ fprintf(stderr, "%s (code %d, op %d:%d)\n", name, error->error_code,
+ error->major_code, error->minor_code);
+}
+
+static xcb_randr_output_t xserver_find_output(xserver_t *x,
+ const char *output_name)
+{
+ xcb_randr_get_output_info_cookie_t goi_c;
+ xcb_randr_get_output_info_reply_t *goi_r;
+ xcb_randr_output_t output = XCB_NONE;
+ xcb_randr_output_t *ro;
+ char *name;
+ int o, len;
+
+ ro = xcb_randr_get_screen_resources_outputs(x->gsr_r);
+ for (o = 0; o < x->gsr_r->num_outputs; o++) {
+ goi_c = xcb_randr_get_output_info(x->conn, ro[o], x->gsr_r->config_timestamp);
+ goi_r = xcb_randr_get_output_info_reply(x->conn, goi_c, NULL);
+ name = (char*)xcb_randr_get_output_info_name(goi_r);
+ len = xcb_randr_get_output_info_name_length(goi_r);
+ if (output_name == NULL || strncmp(name, output_name, len) == 0) {
+ output = ro[o];
+ }
+ free(goi_r);
+ }
+ return output;
+}
+
+static xcb_randr_crtc_t xserver_find_crtc(xserver_t *x, xcb_randr_output_t output)
+{
+ xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(x->gsr_r);
+ xcb_randr_get_crtc_info_cookie_t gci_c;
+ xcb_randr_get_crtc_info_reply_t *gci_r;
+ int c;
+
+ for (c = 0; c < x->gsr_r->num_crtcs; c++) {
+ gci_c = xcb_randr_get_crtc_info(x->conn, rc[c], x->gsr_r->config_timestamp);
+ gci_r = xcb_randr_get_crtc_info_reply(x->conn, gci_c, NULL);
+ if (gci_r->mode) {
+ int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r);
+ xcb_randr_output_t *outputs = xcb_randr_get_crtc_info_outputs(gci_r);
+ if (num_outputs == 1 && outputs[0] == output) {
+ return rc[c];
+ }
+ } else {
+ int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r);
+ xcb_randr_output_t *possible = xcb_randr_get_crtc_info_possible(gci_r);
+ for (int p = 0; p < num_possible; p++) {
+ if (possible[p] == output) {
+ return rc[c];
+ }
+ }
+ }
+ free(gci_r);
+ }
+ return XCB_NONE;
+}
+
+static void xserver_lease_setup(xserver_t *x, const char *output_name)
+{
+ const xcb_setup_t *setup;
+ xcb_screen_iterator_t iter;
+ xcb_generic_error_t *error;
+ xcb_randr_query_version_cookie_t ver_c;
+ xcb_randr_query_version_reply_t *ver_r;
+ xcb_randr_get_screen_resources_cookie_t gsr_c;
+ xcb_randr_output_t output;
+ xcb_randr_crtc_t crtc;
+ int screen;
+
+ x->conn = xcb_connect(NULL, &screen);
+ if (!x->conn) {
+ fprintf(stderr, "drm-lease: can not connect to X server\n");
+ exit(1);
+ }
+
+ /* find root window */
+ setup = xcb_get_setup(x->conn);
+ for (iter = xcb_setup_roots_iterator(setup); iter.rem; xcb_screen_next(&iter)) {
+ if (screen == 0) {
+ x->root = iter.data->root;
+ break;
+ }
+ screen--;
+ }
+
+ /* check for xrandr extension */
+ x->ext_r = xcb_get_extension_data(x->conn, &xcb_randr_id);
+ if (!x->ext_r->present) {
+ fprintf(stderr, "drm-lease: xrandr extension not present\n");
+ exit(1);
+ }
+
+ ver_c = xcb_randr_query_version(x->conn,
+ XCB_RANDR_MAJOR_VERSION,
+ XCB_RANDR_MINOR_VERSION);
+ ver_r = xcb_randr_query_version_reply(x->conn, ver_c, &error);
+ if (!ver_r) {
+ fprintf(stderr, "drm-lease: xrandr version query error\n");
+ exit(1);
+ }
+ fprintf(stderr, "drm-lease: xrandr: client v%d.%x, server v%d.%x\n",
+ XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION,
+ ver_r->major_version, ver_r->minor_version);
+ free(ver_r);
+
+ /* Get RandR resources */
+ gsr_c = xcb_randr_get_screen_resources(x->conn, x->root);
+ x->gsr_r = xcb_randr_get_screen_resources_reply(x->conn, gsr_c, &error);
+ if (!x->gsr_r) {
+ fprintf(stderr, "drm-lease: xrandr: can not get screen resources\n");
+ exit(1);
+ }
+
+ output = xserver_find_output(x, output_name);
+ if (output == XCB_NONE) {
+ fprintf(stderr, "drm-lease: xrandr: no output found\n");
+ exit(1);
+ }
+ fprintf(stderr, "drm-lease: xrandr: using output 0x%x\n", output);
+
+ crtc = xserver_find_crtc(x, output);
+ if (crtc == XCB_NONE) {
+ fprintf(stderr, "drm-lease: xrandr: crtc not found\n");
+ exit(1);
+ }
+ fprintf(stderr, "drm-lease: xrandr: using crtc 0x%x\n", crtc);
+
+ /* Generate RandR lease id */
+ x->randr_lease = xcb_generate_id(x->conn);
+ x->randr_output = output;
+ x->randr_crtc = crtc;
+}
+
+static int xserver_make_lease(xserver_t *x)
+{
+ xcb_randr_create_lease_cookie_t cl_c;
+ xcb_randr_create_lease_reply_t *cl_r;
+ xcb_generic_error_t *error;
+ int *rcl_f;
+ int fd = -1;
+
+ cl_c = xcb_randr_create_lease(x->conn, x->root,
+ x->randr_lease,
+ 1, 1,
+ &x->randr_crtc,
+ &x->randr_output);
+ cl_r = xcb_randr_create_lease_reply(x->conn, cl_c, &error);
+ if (!cl_r) {
+ fprintf(stderr, "drm-lease: xrandr: create lease failed: ");
+ xserver_print_error(x, error);
+ exit(1);
+ }
+
+ if (cl_r->nfd > 0) {
+ rcl_f = xcb_randr_create_lease_reply_fds(x->conn, cl_r);
+ fd = rcl_f[0];
+ }
+ free (cl_r);
+
+ if (fd < 0) {
+ fprintf(stderr, "drm-lease: xrandr: lease returned invalid fd\n");
+ exit(1);
+ }
+
+ return fd;
+}
+
+int drm_lease_xserver(const char *output)
+{
+ xserver_t *x = malloc(sizeof(xserver_t));
+
+ xserver_lease_setup(x, output);
+ return xserver_make_lease(x);
+}
+
+#endif /* HAVE_XRANDR */
diff --git a/drm-lease.c b/drm-lease.c
new file mode 100644
index 0000000..881bba2
--- /dev/null
+++ b/drm-lease.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "drm-lease.h"
+
+int drm_lease(const char *output)
+{
+ if (getenv("DISPLAY") != NULL) {
+#ifdef HAVE_XRANDR
+ return drm_lease_xserver(output);
+#else
+ fprintf(stderr, "drm-lease: compiled without xrandr support.\n");
+ exit(1);
+#endif
+ }
+
+ fprintf(stderr, "drm-lease: don't know where to lease from.\n");
+ exit(1);
+}
diff --git a/drm-lease.h b/drm-lease.h
new file mode 100644
index 0000000..e28bc2d
--- /dev/null
+++ b/drm-lease.h
@@ -0,0 +1,2 @@
+int drm_lease(const char *output);
+int drm_lease_xserver(const char *output);
diff --git a/drminfo.spec b/drminfo.spec
index b17a8e8..0d2a826 100644
--- a/drminfo.spec
+++ b/drminfo.spec
@@ -18,6 +18,8 @@ BuildRequires: pkgconfig(cairo)
BuildRequires: pkgconfig(pixman-1)
BuildRequires: pkgconfig(gtk+-3.0)
BuildRequires: pkgconfig(libsystemd)
+BuildRequires: pkgconfig(xcb)
+BuildRequires: pkgconfig(xcb-randr)
%description
drminfo - print drm device props
diff --git a/drmtest.c b/drmtest.c
index a8ab9a3..6c5b20b 100644
--- a/drmtest.c
+++ b/drmtest.c
@@ -24,6 +24,7 @@
#include "ttytools.h"
#include "logind.h"
#include "drmtools.h"
+#include "drm-lease.h"
#include "render.h"
#include "image.h"
@@ -183,15 +184,16 @@ static void usage(FILE *fp)
"usage: drmtest [ options ]\n"
"\n"
"options:\n"
- " -h print this\n"
- " -p pixman mode\n"
- " -a autotest mode (don't print hardware info)\n"
- " -c <nr> pick card\n"
- " -o <name> pick output\n"
- " -s <secs> set sleep time (default: 60)\n"
- " -i <file> load and display image <file>\n"
- " -f <fmt> pick framebuffer format\n"
- " -m <mode> pick video mode format\n"
+ " -h print this\n"
+ " -p pixman mode\n"
+ " -a autotest mode (don't print hardware info)\n"
+ " -c <nr> pick card\n"
+ " -o <name> pick output\n"
+ " -s <secs> set sleep time (default: 60)\n"
+ " -i <file> load and display image <file>\n"
+ " -f <fmt> pick framebuffer format\n"
+ " -m <mode> pick video mode format\n"
+ " -L <output> get a drm lease for output\n"
"\n");
}
@@ -199,6 +201,7 @@ int main(int argc, char **argv)
{
int card = 0;
int secs = 60;
+ int lease_fd = -1;
char *output = NULL;
char *format = NULL;
char *modename = NULL;
@@ -208,7 +211,7 @@ int main(int argc, char **argv)
int c,i;
for (;;) {
- c = getopt(argc, argv, "hpac:s:o:i:f:m:");
+ c = getopt(argc, argv, "hpaL:c:s:o:i:f:m:");
if (c == -1)
break;
switch (c) {
@@ -236,6 +239,9 @@ int main(int argc, char **argv)
case 'm':
modename = optarg;
break;
+ case 'L':
+ lease_fd = drm_lease(optarg);
+ break;
case 'h':
usage(stdout);
exit(0);
@@ -268,7 +274,7 @@ int main(int argc, char **argv)
}
logind_init();
- drm_init_dev(card, output, modename, false);
+ drm_init_dev(card, output, modename, false, lease_fd);
if (!fmt) {
/* find first supported in list */
diff --git a/drmtools.c b/drmtools.c
index 865a022..7c029f6 100644
--- a/drmtools.c
+++ b/drmtools.c
@@ -715,7 +715,8 @@ drmVersion *version = NULL;
static drmModeCrtc *scrtc = NULL;
void drm_init_dev(int devnr, const char *output,
- const char *modename, bool need_dumb)
+ const char *modename, bool need_dumb,
+ int lease_fd)
{
drmModeRes *res;
char dev[64];
@@ -724,9 +725,13 @@ void drm_init_dev(int devnr, const char *output,
int i, rc;
uint64_t has_dumb;
- /* open device */
- snprintf(dev, sizeof(dev), DRM_DEV_NAME, DRM_DIR_NAME, devnr);
- drm_fd = device_open(dev);
+ if (lease_fd >= 0) {
+ drm_fd = lease_fd;
+ } else {
+ /* open device */
+ snprintf(dev, sizeof(dev), DRM_DEV_NAME, DRM_DIR_NAME, devnr);
+ drm_fd = device_open(dev);
+ }
version = drmGetVersion(drm_fd);
if (need_dumb) {
diff --git a/drmtools.h b/drmtools.h
index 0fbcdb7..1ea9cb9 100644
--- a/drmtools.h
+++ b/drmtools.h
@@ -42,7 +42,8 @@ extern drmModeEncoder *drm_enc;
extern drmVersion *version;
void drm_init_dev(int devnr, const char *output,
- const char *modename, bool need_dumb);
+ const char *modename, bool need_dumb,
+ int lease_fd);
void drm_fini_dev(void);
void drm_show_fb(void);
diff --git a/egltest.c b/egltest.c
index adce4ce..08c43f4 100644
--- a/egltest.c
+++ b/egltest.c
@@ -124,7 +124,7 @@ int main(int argc, char **argv)
}
logind_init();
- drm_init_dev(card, output, modename, false);
+ drm_init_dev(card, output, modename, false, -1);
drm_setup_egl();
if (printinfo)
diff --git a/meson.build b/meson.build
index ff44250..e1d62e0 100644
--- a/meson.build
+++ b/meson.build
@@ -11,6 +11,8 @@ epoxy_dep = dependency('epoxy')
cairo_dep = dependency('cairo')
pixman_dep = dependency('pixman-1')
gtk3_dep = dependency('gtk+-3.0')
+xcb_dep = dependency('xcb', required : false)
+randr_dep = dependency('xcb-randr', required : false, version : '>=1.13')
systemd_dep = dependency('libsystemd', required : false, version : '>=221')
# configuration
@@ -18,15 +20,20 @@ config = configuration_data()
if systemd_dep.found()
config.set('HAVE_SYSTEMD', true)
endif
+if randr_dep.found()
+ config.set('HAVE_XRANDR', true)
+endif
configure_file(output : 'config.h', configuration : config)
# libjpeg dep
jpeg_dep = declare_dependency(link_args : '-ljpeg')
drminfo_srcs = [ 'drminfo.c', 'drmtools.c', 'logind.c' ]
-drmtest_srcs = [ 'drmtest.c', 'drmtools.c', 'logind.c', 'ttytools.c', 'render.c', 'image.c' ]
+drmtest_srcs = [ 'drmtest.c', 'drmtools.c', 'drm-lease.c', 'drm-lease-x11.c',
+ 'logind.c', 'ttytools.c', 'render.c', 'image.c' ]
fbinfo_srcs = [ 'fbinfo.c', 'fbtools.c', 'logind.c' ]
-fbtest_srcs = [ 'fbtest.c', 'fbtools.c', 'logind.c' , 'ttytools.c', 'render.c', 'image.c' ]
+fbtest_srcs = [ 'fbtest.c', 'fbtools.c', 'logind.c',
+ 'ttytools.c', 'render.c', 'image.c' ]
prime_srcs = [ 'prime.c', 'logind.c' ]
viotest_srcs = [ 'virtiotest.c', 'drmtools.c', 'logind.c', 'ttytools.c', 'render.c' ]
egltest_srcs = [ 'egltest.c', 'drmtools.c', 'drmtools-egl.c', 'logind.c', 'ttytools.c' ]
@@ -34,6 +41,7 @@ gtktest_srcs = [ 'gtktest.c', 'render.c', 'image.c' ]
drminfo_deps = [ libdrm_dep, cairo_dep, pixman_dep, systemd_dep ]
drmtest_deps = [ libdrm_dep, gbm_dep, epoxy_dep,
+ xcb_dep, randr_dep,
cairo_dep, pixman_dep, jpeg_dep, systemd_dep ]
fbinfo_deps = [ cairo_dep, systemd_dep ]
fbtest_deps = [ cairo_dep, pixman_dep, jpeg_dep, systemd_dep ]
diff --git a/virtiotest.c b/virtiotest.c
index e108232..8acce4c 100644
--- a/virtiotest.c
+++ b/virtiotest.c
@@ -292,7 +292,7 @@ int main(int argc, char **argv)
assert(fmt != NULL);
logind_init();
- drm_init_dev(card, output, modename, false);
+ drm_init_dev(card, output, modename, false, -1);
if (printinfo)
virtio_print_caps();