diff options
author | Keith Packard <keithp@keithp.com> | 2017-04-28 22:37:52 -0700 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2017-04-28 22:37:52 -0700 |
commit | 7f065bcb2106e44cacdb01f2648365840e67f5bb (patch) | |
tree | c358a76cd300f7229eb3657ec5fe32ae719895eb | |
parent | 8f5d22b111b4492a3aa388034f4e864d433fc003 (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.am | 2 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | cube-tex.c | 3 | ||||
-rw-r--r-- | drm-atomic.c | 4 | ||||
-rw-r--r-- | drm-common.c | 40 | ||||
-rw-r--r-- | drm-common.h | 8 | ||||
-rw-r--r-- | drm-legacy.c | 4 | ||||
-rw-r--r-- | kmscube.c | 155 |
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 @@ -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; @@ -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); } |