summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2017-04-28 22:37:52 -0700
committerKeith Packard <keithp@keithp.com>2017-04-28 22:37:52 -0700
commit7f065bcb2106e44cacdb01f2648365840e67f5bb (patch)
treec358a76cd300f7229eb3657ec5fe32ae719895eb
parent8f5d22b111b4492a3aa388034f4e864d433fc003 (diff)
Add xcb code to get a lease from the X server for our output.drm-lease
Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac1
-rw-r--r--cube-tex.c3
-rw-r--r--drm-atomic.c4
-rw-r--r--drm-common.c40
-rw-r--r--drm-common.h8
-rw-r--r--drm-legacy.c4
-rw-r--r--kmscube.c155
8 files changed, 179 insertions, 38 deletions
diff --git a/Makefile.am b/Makefile.am
index 55b4d99..7997546 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -26,6 +26,7 @@ bin_PROGRAMS = kmscube
CFLAGS=-O0 -g
kmscube_LDADD = \
+ $(XCB_LIBS) \
$(DRM_LIBS) \
$(GBM_LIBS) \
$(EGL_LIBS) \
@@ -36,6 +37,7 @@ kmscube_LDADD = \
kmscube_CFLAGS = \
-O0 -g \
-Wall -Wextra \
+ $(XCB_CFLAGS) \
$(DRM_CFLAGS) \
$(GBM_CFLAGS) \
$(EGL_CFLAGS) \
diff --git a/configure.ac b/configure.ac
index 4df788c..4df1500 100644
--- a/configure.ac
+++ b/configure.ac
@@ -39,6 +39,7 @@ PKG_CHECK_MODULES(DRM, libdrm)
PKG_CHECK_MODULES(GBM, gbm)
PKG_CHECK_MODULES(EGL, egl)
PKG_CHECK_MODULES(GLES2, glesv2)
+PKG_CHECK_MODULES(XCB, xcb-randr xcb)
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
diff --git a/cube-tex.c b/cube-tex.c
index 556abfa..05f63c5 100644
--- a/cube-tex.c
+++ b/cube-tex.c
@@ -222,7 +222,8 @@ static int get_fd_rgba(struct gl *gl, uint32_t *pstride)
/* NOTE: do not actually use GBM_BO_USE_WRITE since that gets us a dumb buffer: */
bo = gbm_bo_create(gl->gbm->dev, texw, texh, GBM_FORMAT_ARGB8888, GBM_BO_USE_LINEAR);
- map = gbm_bo_map(bo, 0, 0, texw, texh, GBM_BO_TRANSFER_WRITE, &stride, &map_data);
+ map = gbm_bo_map(bo, 0, 0, texw, texh, GBM_BO_TRANSFER_WRITE,
+ &stride, &map_data);
for (uint32_t i = 0; i < texh; i++) {
memcpy(&map[stride * i], &src[texw * 4 * i], texw * 4);
diff --git a/drm-atomic.c b/drm-atomic.c
index 39bbb4c..e77bd9d 100644
--- a/drm-atomic.c
+++ b/drm-atomic.c
@@ -311,13 +311,13 @@ static int get_plane_id(struct drm *drm)
return ret;
}
-struct drm * init_drm_atomic(int fd)
+struct drm * init_drm_atomic(int fd, int nfd)
{
uint32_t plane_id;
int ret;
struct drm *drm = calloc(1, sizeof (struct drm));
- ret = init_drm(drm, fd);
+ ret = init_drm(drm, fd, nfd);
if (ret)
return NULL;
diff --git a/drm-common.c b/drm-common.c
index 0cd9776..fd2cdb3 100644
--- a/drm-common.c
+++ b/drm-common.c
@@ -91,7 +91,27 @@ static uint32_t find_crtc_for_encoder(const drmModeRes *resources,
return -1;
}
-static uint32_t find_crtc_for_connector(const struct drm *drm, const drmModeRes *resources,
+static int leased(int fd, int nfd, int id)
+{
+ if (fd != nfd && nfd != -1) {
+ drmModeObjectListPtr lease = drmModeGetLease(nfd);
+ int ret = 0;
+
+ if (lease) {
+ uint32_t u;
+ for (u = 0; u < lease->count; u++)
+ if (lease->objects[u] == (uint32_t) id) {
+ ret = 1;
+ break;
+ }
+ free(lease);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static uint32_t find_crtc_for_connector(int fd, int nfd, const struct drm *drm, const drmModeRes *resources,
const drmModeConnector *connector) {
int i;
@@ -99,7 +119,7 @@ static uint32_t find_crtc_for_connector(const struct drm *drm, const drmModeRes
const uint32_t encoder_id = connector->encoders[i];
drmModeEncoder *encoder = drmModeGetEncoder(drm->fd, encoder_id);
- if (encoder) {
+ if (encoder && !leased(fd, nfd, encoder->encoder_id)) {
const uint32_t crtc_id = find_crtc_for_encoder(resources, encoder);
drmModeFreeEncoder(encoder);
@@ -113,7 +133,7 @@ static uint32_t find_crtc_for_connector(const struct drm *drm, const drmModeRes
return -1;
}
-int find_drm(struct drm_resources *drm_resources, int fd)
+int find_drm(struct drm_resources *drm_resources, int fd, int nfd)
{
drmModeRes *resources;
drmModeConnector *connector = NULL;
@@ -129,7 +149,7 @@ int find_drm(struct drm_resources *drm_resources, int fd)
/* find a connected connector: */
for (i = 0; i < resources->count_connectors; i++) {
connector = drmModeGetConnector(fd, resources->connectors[i]);
- if (connector->connection == DRM_MODE_CONNECTED) {
+ if (connector->connection == DRM_MODE_CONNECTED && !leased(fd, nfd, connector->connector_id)) {
printf("connector id %u\n", connector->connector_id);
/* it's connected, let's use this! */
drm_resources->connector = connector->connector_id;
@@ -150,7 +170,7 @@ int find_drm(struct drm_resources *drm_resources, int fd)
/* find encoder: */
for (i = 0; i < resources->count_encoders; i++) {
encoder = drmModeGetEncoder(fd, resources->encoders[i]);
- if (encoder->encoder_id == connector->encoder_id)
+ if (encoder->encoder_id == connector->encoder_id && !leased(fd, nfd, encoder->encoder_id))
break;
drmModeFreeEncoder(encoder);
encoder = NULL;
@@ -165,7 +185,7 @@ int find_drm(struct drm_resources *drm_resources, int fd)
const uint32_t encoder_id = connector->encoders[i];
drmModeEncoder *encoder = drmModeGetEncoder(fd, encoder_id);
- if (encoder) {
+ if (encoder && !leased(fd, nfd, encoder->encoder_id)) {
crtc_id = find_crtc_for_encoder(resources, encoder);
if (crtc_id != 0)
@@ -187,7 +207,7 @@ int find_drm(struct drm_resources *drm_resources, int fd)
return 0;
}
-int init_drm(struct drm *drm, int fd)
+int init_drm(struct drm *drm, int fd, int nfd)
{
drmModeRes *resources;
drmModeConnector *connector = NULL;
@@ -205,7 +225,7 @@ int init_drm(struct drm *drm, int fd)
/* find a connected connector: */
for (i = 0; i < resources->count_connectors; i++) {
connector = drmModeGetConnector(drm->fd, resources->connectors[i]);
- if (connector->connection == DRM_MODE_CONNECTED) {
+ if (!leased(fd, nfd, connector->connector_id) && connector->connection == DRM_MODE_CONNECTED) {
printf("connector id %u\n", connector->connector_id);
/* it's connected, let's use this! */
break;
@@ -245,7 +265,7 @@ int init_drm(struct drm *drm, int fd)
/* find encoder: */
for (i = 0; i < resources->count_encoders; i++) {
encoder = drmModeGetEncoder(drm->fd, resources->encoders[i]);
- if (encoder->encoder_id == connector->encoder_id)
+ if (!leased(fd, nfd, encoder->encoder_id) && encoder->encoder_id == connector->encoder_id)
break;
drmModeFreeEncoder(encoder);
encoder = NULL;
@@ -254,7 +274,7 @@ int init_drm(struct drm *drm, int fd)
if (encoder) {
drm->crtc_id = encoder->crtc_id;
} else {
- uint32_t crtc_id = find_crtc_for_connector(drm, resources, connector);
+ uint32_t crtc_id = find_crtc_for_connector(fd, nfd, drm, resources, connector);
if (crtc_id == 0) {
printf("no crtc found!\n");
return -1;
diff --git a/drm-common.h b/drm-common.h
index 59e9945..7898ee3 100644
--- a/drm-common.h
+++ b/drm-common.h
@@ -73,9 +73,9 @@ struct drm_fb {
struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo);
-int init_drm(struct drm *drm, int fd);
-struct drm * init_drm_legacy(int fd);
-struct drm * init_drm_atomic(int fd);
+int init_drm(struct drm *drm, int fd, int nfd);
+struct drm * init_drm_legacy(int fd, int nfd);
+struct drm * init_drm_atomic(int fd, int nfd);
struct drm_resources {
uint32_t encoder;
@@ -83,6 +83,6 @@ struct drm_resources {
uint32_t crtc;
};
-int find_drm(struct drm_resources *drm_resources, int fd);
+int find_drm(struct drm_resources *drm_resources, int fd, int nfd);
#endif /* _DRM_COMMON_H */
diff --git a/drm-legacy.c b/drm-legacy.c
index 8c87d82..5d28f49 100644
--- a/drm-legacy.c
+++ b/drm-legacy.c
@@ -112,12 +112,12 @@ static int legacy_run(struct drm *drm, const struct gbm *gbm, struct egl *egl)
return 0;
}
-struct drm * init_drm_legacy(int fd)
+struct drm * init_drm_legacy(int fd, int nfd)
{
int ret;
struct drm *drm = calloc (1, sizeof (struct drm));
- ret = init_drm(drm, fd);
+ ret = init_drm(drm, fd, nfd);
if (ret)
return NULL;
diff --git a/kmscube.c b/kmscube.c
index fb4e2ef..99d9d84 100644
--- a/kmscube.c
+++ b/kmscube.c
@@ -30,6 +30,8 @@
#include <stdio.h>
#include <getopt.h>
#include <pthread.h>
+#include <xcb/xcb.h>
+#include <xcb/randr.h>
#include "common.h"
#include "drm-common.h"
@@ -37,7 +39,7 @@
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
-static const char shortopts[] = "ArD:M:";
+static const char shortopts[] = "ArD:M:l";
static enum mode mode = SMOOTH;
static int atomic = 0;
@@ -47,6 +49,7 @@ static const struct option longopts[] = {
{"device", required_argument, 0, 'D'},
{"mode", required_argument, 0, 'M'},
{"thread", no_argument, 0, 't'},
+ {"lease", no_argument, 0, 'l'},
{0, 0, 0, 0}
};
@@ -58,6 +61,7 @@ static void usage(const char *name)
" -A, --atomic use atomic modesetting and fencing\n"
" -D, --device=DEVICE use the given device\n"
" -t, --thread two threads and cubes on two monitors\n"
+ " -l, --lease lease output from the X server\n"
" -M, --mode=MODE specify mode, one of:\n"
" smooth - smooth shaded cube (default)\n"
" rgba - rgba textured cube\n"
@@ -90,16 +94,16 @@ static void dump_objects(char *head, drmModeObjectListPtr objects) {
printf("\n");
}
-int run(int fd) {
+int run(int fd, int nfd) {
struct egl *egl;
struct gbm *gbm;
struct drm *drm;
int ret;
if (atomic)
- drm = init_drm_atomic(fd);
+ drm = init_drm_atomic(fd, nfd);
else
- drm = init_drm_legacy(fd);
+ drm = init_drm_legacy(fd, nfd);
if (!drm) {
printf("failed to initialize %s DRM\n", atomic ? "atomic" : "legacy");
return -1;
@@ -137,7 +141,7 @@ static void *thread_run(void *arg)
printf("child on fd %d\n", fd);
printf("child running now...\n");
- run(fd);
+ run(fd, -1);
return 0;
}
@@ -145,8 +149,10 @@ int main(int argc, char *argv[])
{
const char *device = "/dev/dri/card0";
int do_thread = 0;
+ int do_lease = 0;
int opt;
int fd;
+ int nfd = -1;
while ((opt = getopt_long_only(argc, argv, shortopts, longopts, NULL)) != -1) {
switch (opt) {
@@ -174,29 +180,140 @@ int main(int argc, char *argv[])
case 't':
do_thread = 1;
break;
+ case 'l':
+ do_lease = 1;
+ break;
default:
usage(argv[0]);
return -1;
}
}
- fd = open(device, O_RDWR);
- if (fd < 0) {
- printf("could not open drm device\n");
- return -1;
+ if (do_lease) {
+ xcb_connection_t *connection;
+ int screen;
+
+ connection = xcb_connect(NULL, &screen);
+ if (!connection) {
+ printf("Connection to X server failed\n");
+ exit(1);
+ }
+ xcb_randr_query_version_cookie_t rqv_c = xcb_randr_query_version(connection,
+ XCB_RANDR_MAJOR_VERSION,
+ XCB_RANDR_MINOR_VERSION);
+ xcb_randr_query_version_reply_t *rqv_r = xcb_randr_query_version_reply(connection, rqv_c, NULL);
+
+ if (!rqv_r || rqv_r->minor_version < 6) {
+ printf("No new-enough RandR version\n");
+ exit(1);
+ }
+
+ xcb_screen_iterator_t s_i;
+
+ int i_s = 0;
+
+ for (s_i = xcb_setup_roots_iterator(xcb_get_setup(connection));
+ s_i.rem;
+ xcb_screen_next(&s_i), i_s++) {
+ printf ("index %d screen %d\n", s_i.index, screen);
+ if (i_s == screen)
+ break;
+ }
+
+ xcb_window_t root = s_i.data->root;
+
+ printf("root %x\n", root);
+
+ xcb_randr_get_screen_resources_cookie_t gsr_c = xcb_randr_get_screen_resources(connection, root);
+
+ xcb_randr_get_screen_resources_reply_t *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
+
+ if (!gsr_r) {
+ printf("get_screen_resources failed\n");
+ exit(1);
+ }
+
+ xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
+ int o, c;
+
+ xcb_randr_output_t output = 0;
+
+ /* Find a connected but idle output */
+ for (o = 0; output == 0 && o < gsr_r->num_outputs; o++) {
+ xcb_randr_get_output_info_cookie_t goi_c = xcb_randr_get_output_info(connection, ro[o], gsr_r->config_timestamp);
+
+ xcb_randr_get_output_info_reply_t *goi_r = xcb_randr_get_output_info_reply(connection, goi_c, NULL);
+
+ /* Find the first connected but unused output */
+ if (goi_r->connection == XCB_RANDR_CONNECTION_CONNECTED &&
+ goi_r->crtc == 0) {
+ output = ro[o];
+ }
+
+ free(goi_r);
+ }
+
+ xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
+
+ xcb_randr_crtc_t crtc = 0;
+
+ /* Find an idle crtc */
+ for (c = 0; crtc == 0 && c < gsr_r->num_crtcs; c++) {
+ xcb_randr_get_crtc_info_cookie_t gci_c = xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
+
+ xcb_randr_get_crtc_info_reply_t *gci_r = xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
+
+ /* Find the first connected but unused crtc */
+ if (gci_r->mode == 0)
+ crtc = rc[c];
+
+ free(gci_r);
+ }
+
+ free(gsr_r);
+
+ printf("output %x crtc %x\n", output, crtc);
+
+ xcb_randr_lease_t lease = xcb_generate_id(connection);
+
+ xcb_randr_create_lease_cookie_t rcl_c = xcb_randr_create_lease(connection,
+ root,
+ lease,
+ 1,
+ 1,
+ &crtc,
+ &output);
+ xcb_randr_create_lease_reply_t *rcl_r = xcb_randr_create_lease_reply(connection, rcl_c, NULL);
+
+ if (!rcl_r) {
+ printf("create_lease failed\n");
+ exit(1);
+ }
+
+ int *rcl_f = xcb_randr_create_lease_reply_fds(connection, rcl_r);
+
+ fd = rcl_f[0];
+
+ printf("fd %d\n", fd);
+
+ } else {
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ printf("could not open drm device\n");
+ return -1;
+ }
}
if (do_thread) {
struct drm_resources resources;
uint32_t objects[3];
int nobjects;
- int nfd;
uint32_t lessee;
pthread_t thread;
drmModeLesseeListPtr l_list;
drmModeObjectListPtr o_list;
- if (find_drm(&resources, fd) != 0) {
+ if (find_drm(&resources, fd, -1) != 0) {
printf("Could not get DRM resources for fork\n");
return -1;
}
@@ -211,36 +328,36 @@ int main(int argc, char *argv[])
if (resources.crtc)
objects[nobjects++] = resources.crtc;
- o_list = drmModeGetLease(fd, 0);
+ o_list = drmModeGetLease(fd);
dump_objects("owner before lease", o_list);
free(o_list);
- l_list = drmModeListLessees(fd, 0);
+ l_list = drmModeListLessees(fd);
dump_lessees("owner before lease", l_list);
free(l_list);
- nfd = drmModeCreateLease(fd, objects, nobjects, 0, 1, &lessee);
+ nfd = drmModeCreateLease(fd, objects, nobjects, 0, &lessee);
- o_list = drmModeGetLease(fd, 0);
+ o_list = drmModeGetLease(fd);
dump_objects("owner after lease", o_list);
free(o_list);
- l_list = drmModeListLessees(fd, 0);
+ l_list = drmModeListLessees(fd);
dump_lessees("owner after lease", l_list);
free(l_list);
- o_list = drmModeGetLease(nfd, lessee);
+ o_list = drmModeGetLease(nfd);
dump_objects("lessee after lease", o_list);
free(o_list);
- l_list = drmModeListLessees(nfd, lessee);
+ l_list = drmModeListLessees(nfd);
dump_lessees("lessee after lease", l_list);
@@ -259,5 +376,5 @@ int main(int argc, char *argv[])
printf("parent running now...\n");
}
- return run(fd);
+ return run(fd, nfd);
}