~sircmpwn/kmscube

7f065bcb2106e44cacdb01f2648365840e67f5bb — Keith Packard 2 years ago 8f5d22b
Add xcb code to get a lease from the X server for our output.

Signed-off-by: Keith Packard <keithp@keithp.com>
8 files changed, 179 insertions(+), 38 deletions(-)

M Makefile.am
M configure.ac
M cube-tex.c
M drm-atomic.c
M drm-common.c
M drm-common.h
M drm-legacy.c
M kmscube.c
M Makefile.am => Makefile.am +2 -0
@@ 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) \

M configure.ac => configure.ac +1 -0
@@ 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

M cube-tex.c => cube-tex.c +2 -1
@@ 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);

M drm-atomic.c => drm-atomic.c +2 -2
@@ 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;


M drm-common.c => drm-common.c +30 -10
@@ 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;

M drm-common.h => drm-common.h +4 -4
@@ 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 */

M drm-legacy.c => drm-legacy.c +2 -2
@@ 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;


M kmscube.c => kmscube.c +136 -19
@@ 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);
}