From patchwork Tue Apr 16 16:43:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 162349 Delivered-To: patches@linaro.org Received: by 2002:a02:c6d8:0:0:0:0:0 with SMTP id r24csp4437063jan; Tue, 16 Apr 2019 09:44:01 -0700 (PDT) X-Received: by 2002:a63:ef09:: with SMTP id u9mr77936449pgh.126.1555433041751; Tue, 16 Apr 2019 09:44:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1555433041; cv=none; d=google.com; s=arc-20160816; b=sqwyJSbRJMVz694V3I603GS0a21h7X9xl9lF9fxbgrwDmQel6TU5KDs0+KdMlG9fxF /S+UTNnJ+eAx6u7yXp+BDUYotrD3UUUz22ioWEGha6N/Kvr4RZ8gzTr3XRdW4hDlPAGP GeYnV1mzAF/GaKRIVnsva3oO8ou6vAZS3kkd6r0nJ7bSnIXQNlgrnhAk+1xxmVPMR+gC nXglZRi+/TFccr06t+97lJ+OPHDDduXAnOX2OKGPpPozNYi5E45FByqPC3VRiffwSb8r WAHgK/pcMVYoRBpv+TR4HlRgqIdo0vY1OGzhvOqPaGgWVzzf3XkGeF34d6hJq7uel9AV Go1Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=message-id:date:subject:cc:to:from:dkim-signature; bh=6/OgN7ov7PLKhsnSKLcS7bt3JZ9B1KybThg/ZaUleU8=; b=Q1UT4p9xEKT6Dkt3OOTRGB2jFrh3xVKLAL+J8OrO75BDHKP6L0O6Zjq0XO1DBTR9IR Dx+TNDXqYUtEr5wQeNvdh3eEeHu7u08MNqjqjjAO8eRwNn9rAxQPS9Mv/9uF4+IIAz5Z zVnj8esL989RQRl3xt82ZXUOo5uS7q5G4QSw2Xnf+O4Nb85P3JaWA5dHFoC+7l0ghp15 tAcb6bMQ7L/KmlXS/Jtu+TEizxb53GkbPUv11ldjzC1UukICahVKAJmyRUAj4OI9lHF3 /PAPT6PPLOjGWCaFbT4OdKByHRl8PiGIFQ8Ui1zGuHJBaNHTQEMobUbjED5qqjS82ToN 6/gA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b="FYUR/xOo"; spf=pass (google.com: domain of john.stultz@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=john.stultz@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id 92sor69345168plw.48.2019.04.16.09.44.01 for (Google Transport Security); Tue, 16 Apr 2019 09:44:01 -0700 (PDT) Received-SPF: pass (google.com: domain of john.stultz@linaro.org designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b="FYUR/xOo"; spf=pass (google.com: domain of john.stultz@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=john.stultz@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=6/OgN7ov7PLKhsnSKLcS7bt3JZ9B1KybThg/ZaUleU8=; b=FYUR/xOoOfgRK5qdBw+NWKj4BOeHXJoYaV0BHhwJPp6GzSkSMqSswlAGimu+ZOUAG3 z1pQiuDKnisuIwami7cPzR2YFor1Hh9HvBGTyySwBYAPQDhIKWZz5ib9By9VMvg4dXaF GaRWysES2azVVEFHZnmy4TA14D2Vuse8FjaKqGRRvKgBjNqzFDxHsLDGOp/c8ZBgrtnu hCaBRuyYDtRvFDrIXgoeNqJpXAvnfpbAP5yYIW0GOTCCFYndD5vuxAVUgkUgu18fLUz0 9KFrgZytfONB9BZyYof3cWJCJET3oBTd8Ev21EJvQgutOXj9TMeWeiVUJcqlcvtABPq0 xmOg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=6/OgN7ov7PLKhsnSKLcS7bt3JZ9B1KybThg/ZaUleU8=; b=fgZABK07HqCFy3Z62mYDn4WwvaLvMUdjiR1r73yNsLXF+XnCKOqgHKheEiNNnNvTKy suLAgMslrrV49fvqiBF4by5EIeOm4+UfBwjopwTYs+hMbNoz83paE2CoD95vo/p7SFIc M80WumjDLIqWDorL6n5+bx9mTv/AQaT2ct/8zBp2mCuTrM1xCVoUGgJ/VPI2BM/uYuWr BB23MWYM4sB4i9vlEGaq7zk0UEQzGm8IwOyjiCos6yJoTYVHbhkoat7Bg47FAbch/yrM LPAk2fjyZkRtVcjEUJXSe970XlpmH3OA4+SRrnaTUIm5fLPoyYmjZhHOlyjitsH/KVnk l7qQ== X-Gm-Message-State: APjAAAXsOxagm827SS6EUwXg/Maza9de3OZTMoe0MbR3xUQfbyYktN/u faQZADqaDcfsMfFhbXCIPANwOt0tNH7PRg== X-Google-Smtp-Source: APXvYqw2vfK1JQM9UFKngb4d1iFc664n0NCuNZhRQ/PG1r0yIQTb14PmnNWjYaN+RNfL4BOjDLN+GQ== X-Received: by 2002:a17:902:2862:: with SMTP id e89mr64540407plb.203.1555433040848; Tue, 16 Apr 2019 09:44:00 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:1c2:680:1319:4e72:b9ff:fe99:466a]) by smtp.gmail.com with ESMTPSA id s21sm37266200pfm.3.2019.04.16.09.43.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 16 Apr 2019 09:43:59 -0700 (PDT) From: John Stultz To: dri-devel Cc: John Stultz , Sean Paul , Benjamin Gaignard , Alex Deucher Subject: [RFC][PATCH] libdrm: tests: Add planetest test from AOSP sources Date: Tue, 16 Apr 2019 09:43:49 -0700 Message-Id: <1555433029-25490-1-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 2.7.4 In trying to further align the AOSP libdrm branch with upstream, I wanted to submit the added test planetest that they have been carrying for awhile. Mostly sending this out for initial reactions and to stir some discussion on if folks think upstreaming this would be useful. Feedback and thoughts would be appreciated! Originally-by: Sean Paul With fixes folded in by: Benjamin Gaignard Vincent Palatin Cc: Sean Paul Cc: Benjamin Gaignard Cc: Alex Deucher Signed-off-by: John Stultz --- tests/Makefile.am | 2 +- tests/planetest/Makefile.am | 30 ++++ tests/planetest/Makefile.sources | 13 ++ tests/planetest/atomictest.c | 151 ++++++++++++++++ tests/planetest/bo.c | 234 +++++++++++++++++++++++++ tests/planetest/bo.h | 34 ++++ tests/planetest/dev.c | 367 +++++++++++++++++++++++++++++++++++++++ tests/planetest/dev.h | 65 +++++++ tests/planetest/modeset.c | 232 +++++++++++++++++++++++++ tests/planetest/modeset.h | 19 ++ tests/planetest/planetest.c | 116 +++++++++++++ 11 files changed, 1262 insertions(+), 1 deletion(-) create mode 100644 tests/planetest/Makefile.am create mode 100644 tests/planetest/Makefile.sources create mode 100644 tests/planetest/atomictest.c create mode 100644 tests/planetest/bo.c create mode 100644 tests/planetest/bo.h create mode 100644 tests/planetest/dev.c create mode 100644 tests/planetest/dev.h create mode 100644 tests/planetest/modeset.c create mode 100644 tests/planetest/modeset.h create mode 100644 tests/planetest/planetest.c -- 2.7.4 diff --git a/tests/Makefile.am b/tests/Makefile.am index d274a3e..42d9854 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS = util kms modeprint proptest modetest vbltest if HAVE_LIBKMS -SUBDIRS += kmstest +SUBDIRS += kmstest planetest endif if HAVE_RADEON diff --git a/tests/planetest/Makefile.am b/tests/planetest/Makefile.am new file mode 100644 index 0000000..b82d05b --- /dev/null +++ b/tests/planetest/Makefile.am @@ -0,0 +1,30 @@ +include Makefile.sources + +AM_CFLAGS = $(filter-out -Wpointer-arith, $(WARN_CFLAGS)) + +AM_CFLAGS += \ + -I$(top_srcdir)/include/drm \ + -I$(top_srcdir)/libkms/ \ + -I$(top_srcdir) + +PLANETEST_COMMON_LDADD = \ + $(top_builddir)/libdrm.la \ + $(top_builddir)/libkms/libkms.la \ + -lpthread + +if HAVE_INSTALL_TESTS +bin_PROGRAMS = \ + atomictest \ + planetest +else +noinst_PROGRAMS = \ + atomictest \ + planetest +endif + +atomictest_CFLAGS=-DUSE_ATOMIC_API ${AM_CFLAGS} +atomictest_SOURCES=${PLANETEST_COMMON_FILES} ${ATOMICTEST_FILES} +planetest_SOURCES=${PLANETEST_COMMON_FILES} ${PLANETEST_FILES} + +atomictest_LDADD=${PLANETEST_COMMON_LDADD} +planetest_LDADD=${PLANETEST_COMMON_LDADD} diff --git a/tests/planetest/Makefile.sources b/tests/planetest/Makefile.sources new file mode 100644 index 0000000..3cbeb2b --- /dev/null +++ b/tests/planetest/Makefile.sources @@ -0,0 +1,13 @@ +PLANETEST_COMMON_FILES := \ + bo.c \ + bo.h \ + dev.c \ + dev.h \ + modeset.c \ + modeset.h + +ATOMICTEST_FILES := \ + atomictest.c + +PLANETEST_FILES := \ + planetest.c diff --git a/tests/planetest/atomictest.c b/tests/planetest/atomictest.c new file mode 100644 index 0000000..891d242 --- /dev/null +++ b/tests/planetest/atomictest.c @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dev.h" +#include "bo.h" +#include "modeset.h" + +static int terminate = 0; + +static void sigint_handler(int arg) +{ + terminate = 1; +} + +static void +page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec, + unsigned int tv_usec, void *user_data) +{ +} + +static void incrementor(int *inc, int *val, int increment, int lower, int upper) +{ + if(*inc > 0) + *inc = *val + increment >= upper ? -1 : 1; + else + *inc = *val - increment <= lower ? 1 : -1; + *val += *inc * increment; +} + +int main(int argc, char *argv[]) +{ + int ret, i, j, num_test_planes; + int x_inc = 1, x = 0, y_inc = 1, y = 0; + uint32_t plane_w = 128, plane_h = 128; + struct sp_dev *dev; + struct sp_plane **plane = NULL; + struct sp_crtc *test_crtc; + fd_set fds; + drmModeAtomicReqPtr pset; + drmEventContext event_context = { + .version = DRM_EVENT_CONTEXT_VERSION, + .page_flip_handler = page_flip_handler, + }; + int card = 0, crtc = 0; + + signal(SIGINT, sigint_handler); + + parse_arguments(argc, argv, &card, &crtc); + + dev = create_sp_dev(card); + if (!dev) { + printf("Failed to create sp_dev\n"); + return -1; + } + + if (crtc >= dev->num_crtcs) { + printf("Invalid crtc %d (num=%d)\n", crtc, dev->num_crtcs); + return -1; + } + + ret = initialize_screens(dev); + if (ret) { + printf("Failed to initialize screens\n"); + goto out; + } + test_crtc = &dev->crtcs[crtc]; + + plane = calloc(dev->num_planes, sizeof(*plane)); + if (!plane) { + printf("Failed to allocate plane array\n"); + goto out; + } + + /* Create our planes */ + num_test_planes = test_crtc->num_planes; + for (i = 0; i < num_test_planes; i++) { + plane[i] = get_sp_plane(dev, test_crtc); + if (!plane[i]) { + printf("no unused planes available\n"); + goto out; + } + + plane[i]->bo = create_sp_bo(dev, plane_w, plane_h, 16, plane[i]->format, 0); + if (!plane[i]->bo) { + printf("failed to create plane bo\n"); + goto out; + } + + fill_bo(plane[i]->bo, 0xFF, 0xFF, 0xFF, 0xFF); + } + + pset = drmModeAtomicAlloc(); + if (!pset) { + printf("Failed to allocate the property set\n"); + goto out; + } + + while (!terminate) { + FD_ZERO(&fds); + FD_SET(dev->fd, &fds); + + incrementor(&x_inc, &x, 5, 0, + test_crtc->crtc->mode.hdisplay - plane_w); + incrementor(&y_inc, &y, 5, 0, test_crtc->crtc->mode.vdisplay - + plane_h * num_test_planes); + + for (j = 0; j < num_test_planes; j++) { + ret = set_sp_plane_pset(dev, plane[j], pset, test_crtc, + x, y + j * plane_h); + if (ret) { + printf("failed to move plane %d\n", ret); + goto out; + } + } + + ret = drmModeAtomicCommit(dev->fd, pset, + DRM_MODE_PAGE_FLIP_EVENT, NULL); + if (ret) { + printf("failed to commit properties ret=%d\n", ret); + goto out; + } + + do { + ret = select(dev->fd + 1, &fds, NULL, NULL, NULL); + } while (ret == -1 && errno == EINTR); + + if (FD_ISSET(dev->fd, &fds)) + drmHandleEvent(dev->fd, &event_context); + } + + drmModeAtomicFree(pset); + + for (i = 0; i < num_test_planes; i++) + put_sp_plane(plane[i]); + +out: + destroy_sp_dev(dev); + free(plane); + return ret; +} diff --git a/tests/planetest/bo.c b/tests/planetest/bo.c new file mode 100644 index 0000000..d4b82c6 --- /dev/null +++ b/tests/planetest/bo.c @@ -0,0 +1,234 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "bo.h" +#include "dev.h" + +#define MAKE_YUV_601_Y(r, g, b) \ + ((( 66 * (r) + 129 * (g) + 25 * (b) + 128) >> 8) + 16) +#define MAKE_YUV_601_U(r, g, b) \ + (((-38 * (r) - 74 * (g) + 112 * (b) + 128) >> 8) + 128) +#define MAKE_YUV_601_V(r, g, b) \ + (((112 * (r) - 94 * (g) - 18 * (b) + 128) >> 8) + 128) + +static void draw_rect_yuv(struct sp_bo *bo, uint32_t x, uint32_t y, uint32_t width, + uint32_t height, uint8_t a, uint8_t r, uint8_t g, uint8_t b) +{ + uint32_t i, j, xmax = x + width, ymax = y + height; + + if (xmax > bo->width) + xmax = bo->width; + if (ymax > bo->height) + ymax = bo->height; + + for (i = y; i < ymax; i++) { + uint8_t *luma = bo->map_addr + i * bo->pitch; + + for (j = x; j < xmax; j++) + luma[j] = MAKE_YUV_601_Y(r, g, b); + } + + for (i = y; i < ymax / 2; i++) { + uint8_t *chroma = bo->map_addr + (i + height) * bo->pitch; + + for (j = x; j < xmax / 2; j++) { + chroma[j*2] = MAKE_YUV_601_U(r, g, b); + chroma[j*2 + 1] = MAKE_YUV_601_V(r, g, b); + } + } +} + +void fill_bo(struct sp_bo *bo, uint8_t a, uint8_t r, uint8_t g, uint8_t b) +{ + if (bo->format == DRM_FORMAT_NV12) + draw_rect_yuv(bo, 0, 0, bo->width, bo->height, a, r, g, b); + else + draw_rect(bo, 0, 0, bo->width, bo->height, a, r, g, b); +} + +void draw_rect(struct sp_bo *bo, uint32_t x, uint32_t y, uint32_t width, + uint32_t height, uint8_t a, uint8_t r, uint8_t g, uint8_t b) +{ + uint32_t i, j, xmax = x + width, ymax = y + height; + + if (xmax > bo->width) + xmax = bo->width; + if (ymax > bo->height) + ymax = bo->height; + + for (i = y; i < ymax; i++) { + uint8_t *row = bo->map_addr + i * bo->pitch; + + for (j = x; j < xmax; j++) { + uint8_t *pixel = row + j * 4; + + if (bo->format == DRM_FORMAT_ARGB8888 || + bo->format == DRM_FORMAT_XRGB8888) + { + pixel[0] = b; + pixel[1] = g; + pixel[2] = r; + pixel[3] = a; + } else if (bo->format == DRM_FORMAT_RGBA8888) { + pixel[0] = r; + pixel[1] = g; + pixel[2] = b; + pixel[3] = a; + } + } + } +} + +static int add_fb_sp_bo(struct sp_bo *bo, uint32_t format) +{ + int ret; + uint32_t handles[4], pitches[4], offsets[4]; + + handles[0] = bo->handle; + pitches[0] = bo->pitch; + offsets[0] = 0; + if (bo->format == DRM_FORMAT_NV12) { + handles[1] = bo->handle; + pitches[1] = pitches[0]; + offsets[1] = pitches[0] * bo->height; + } + + ret = drmModeAddFB2(bo->dev->fd, bo->width, bo->height, + format, handles, pitches, offsets, + &bo->fb_id, bo->flags); + if (ret) { + printf("failed to create fb ret=%d\n", ret); + return ret; + } + return 0; +} + +static int map_sp_bo(struct sp_bo *bo) +{ + int ret; + struct drm_mode_map_dumb md; + + if (bo->map_addr) + return 0; + + md.handle = bo->handle; + ret = drmIoctl(bo->dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &md); + if (ret) { + printf("failed to map sp_bo ret=%d\n", ret); + return ret; + } + + bo->map_addr = mmap(NULL, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, + bo->dev->fd, md.offset); + if (bo->map_addr == MAP_FAILED) { + printf("failed to map bo ret=%d\n", -errno); + return -errno; + } + return 0; +} + +static int format_to_bpp(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_NV12: + return 8; + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_RGBA8888: + default: + return 32; + } +} + +struct sp_bo *create_sp_bo(struct sp_dev *dev, uint32_t width, uint32_t height, + uint32_t depth, uint32_t format, uint32_t flags) +{ + int ret; + struct drm_mode_create_dumb cd; + struct sp_bo *bo; + + bo = calloc(1, sizeof(*bo)); + if (!bo) + return NULL; + + if (format == DRM_FORMAT_NV12) + cd.height = height * 3 / 2; + else + cd.height = height; + + cd.width = width; + cd.bpp = format_to_bpp(format); + cd.flags = flags; + + ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &cd); + if (ret) { + printf("failed to create sp_bo %d\n", ret); + goto err; + } + + bo->dev = dev; + bo->width = width; + bo->height = height; + bo->depth = depth; + bo->bpp = format_to_bpp(format); + bo->format = format; + bo->flags = flags; + + bo->handle = cd.handle; + bo->pitch = cd.pitch; + bo->size = cd.size; + + ret = add_fb_sp_bo(bo, format); + if (ret) { + printf("failed to add fb ret=%d\n", ret); + goto err; + } + + ret = map_sp_bo(bo); + if (ret) { + printf("failed to map bo ret=%d\n", ret); + goto err; + } + + return bo; + +err: + free_sp_bo(bo); + return NULL; +} + +void free_sp_bo(struct sp_bo *bo) +{ + int ret; + struct drm_mode_destroy_dumb dd; + + if (!bo) + return; + + if (bo->map_addr) + munmap(bo->map_addr, bo->size); + + if (bo->fb_id) { + ret = drmModeRmFB(bo->dev->fd, bo->fb_id); + if (ret) + printf("Failed to rmfb ret=%d!\n", ret); + } + + if (bo->handle) { + dd.handle = bo->handle; + ret = drmIoctl(bo->dev->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dd); + if (ret) + printf("Failed to destroy buffer ret=%d\n", ret); + } + + free(bo); +} diff --git a/tests/planetest/bo.h b/tests/planetest/bo.h new file mode 100644 index 0000000..7471e12 --- /dev/null +++ b/tests/planetest/bo.h @@ -0,0 +1,34 @@ +#ifndef __BO_H_INCLUDED__ +#define __BO_H_INCLUDED__ + +#include + +struct sp_dev; + +struct sp_bo { + struct sp_dev *dev; + + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t bpp; + uint32_t format; + uint32_t flags; + + uint32_t fb_id; + uint32_t handle; + void *map_addr; + uint32_t pitch; + uint32_t size; +}; + +struct sp_bo *create_sp_bo(struct sp_dev *dev, uint32_t width, uint32_t height, + uint32_t depth, uint32_t format, uint32_t flags); + +void fill_bo(struct sp_bo *bo, uint8_t a, uint8_t r, uint8_t g, uint8_t b); +void draw_rect(struct sp_bo *bo, uint32_t x, uint32_t y, uint32_t width, + uint32_t height, uint8_t a, uint8_t r, uint8_t g, uint8_t b); + +void free_sp_bo(struct sp_bo *bo); + +#endif /* __BO_H_INCLUDED__ */ diff --git a/tests/planetest/dev.c b/tests/planetest/dev.c new file mode 100644 index 0000000..bd0968c --- /dev/null +++ b/tests/planetest/dev.c @@ -0,0 +1,367 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "bo.h" +#include "dev.h" +#include "modeset.h" + +static void show_usage(char *name) +{ + printf("Usage: %s [OPTION]\n", name); + printf(" -c, --card Index of dri card (ie: /dev/dri/cardN)\n"); + printf(" -r, --crtc Index of crtc to use for test\n"); + printf("\n\n"); +} + +void parse_arguments(int argc, char *argv[], int *card, int *crtc) +{ + static struct option options[] = { + { "card", required_argument, NULL, 'c' }, + { "crtc", required_argument, NULL, 'r' }, + { "help", no_argument, NULL, 'h' }, + }; + int option_index = 0; + int c; + + *card = -1; + *crtc = -1; + do { + c = getopt_long(argc, argv, "c:r:h", options, &option_index); + switch (c) { + case 0: + case 'h': + show_usage(argv[0]); + exit(0); + case -1: + break; + case 'c': + if (optarg[0] < '0' || optarg[0] > '9') { + printf("Invalid card value '%s'!\n", optarg); + show_usage(argv[0]); + exit(-1); + } + *card = optarg[0] - '0'; + break; + case 'r': + if (optarg[0] < '0' || optarg[0] > '9') { + printf("Invalid crtc value '%s'!\n", optarg); + show_usage(argv[0]); + exit(-1); + } + *crtc = optarg[0] - '0'; + break; + } + } while (c != -1); + + if (*card < 0 || *crtc < 0) { + show_usage(argv[0]); + exit(-1); + } +} + +static uint32_t get_prop_id(struct sp_dev *dev, + drmModeObjectPropertiesPtr props, const char *name) +{ + drmModePropertyPtr p; + uint32_t i, prop_id = 0; /* Property ID should always be > 0 */ + + for (i = 0; !prop_id && i < props->count_props; i++) { + p = drmModeGetProperty(dev->fd, props->props[i]); + if (!strcmp(p->name, name)) + prop_id = p->prop_id; + drmModeFreeProperty(p); + } + if (!prop_id) + printf("Could not find %s property\n", name); + return prop_id; +} + +static int get_supported_format(struct sp_plane *plane, uint32_t *format) +{ + uint32_t i; + + for (i = 0; i < plane->plane->count_formats; i++) { + if (plane->plane->formats[i] == DRM_FORMAT_XRGB8888 || + plane->plane->formats[i] == DRM_FORMAT_ARGB8888 || + plane->plane->formats[i] == DRM_FORMAT_RGBA8888 || + plane->plane->formats[i] == DRM_FORMAT_NV12) { + *format = plane->plane->formats[i]; + return 0; + } + } + printf("No suitable formats found!\n"); + return -ENOENT; +} + +struct sp_dev *create_sp_dev(int card) +{ + struct sp_dev *dev; + int ret, fd, i, j; + drmModeRes *r = NULL; + drmModePlaneRes *pr = NULL; + char card_path[256]; + + snprintf(card_path, sizeof(card_path), "/dev/dri/card%d", card); + + fd = open(card_path, O_RDWR); + if (fd < 0) { + printf("failed to open card0\n"); + return NULL; + } + + dev = calloc(1, sizeof(*dev)); + if (!dev) { + printf("failed to allocate dev\n"); + return NULL; + } + + dev->fd = fd; + + ret = drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + if (ret) { + printf("failed to set client cap\n"); + goto err; + } + + ret = drmSetClientCap(dev->fd, DRM_CLIENT_CAP_ATOMIC, 1); + if (ret) { + printf("Failed to set atomic cap %d", ret); + goto err; + } + + r = drmModeGetResources(dev->fd); + if (!r) { + printf("failed to get r\n"); + goto err; + } + + dev->num_connectors = r->count_connectors; + dev->connectors = calloc(dev->num_connectors, + sizeof(struct sp_connector)); + if (!dev->connectors) { + printf("failed to allocate connectors\n"); + goto err; + } + for (i = 0; i < dev->num_connectors; i++) { + drmModeObjectPropertiesPtr props; + dev->connectors[i].conn = drmModeGetConnector(dev->fd, + r->connectors[i]); + if (!dev->connectors[i].conn) { + printf("failed to get connector %d\n", i); + goto err; + } + + props = drmModeObjectGetProperties(dev->fd, r->connectors[i], + DRM_MODE_OBJECT_CONNECTOR); + if (!props) { + printf("failed to get connector properties\n"); + goto err; + } + + dev->connectors[i].crtc_id_pid = get_prop_id(dev, props, + "CRTC_ID"); + drmModeFreeObjectProperties(props); + if (!dev->connectors[i].crtc_id_pid) + goto err; + } + + dev->num_encoders = r->count_encoders; + dev->encoders = calloc(dev->num_encoders, sizeof(*dev->encoders)); + if (!dev->encoders) { + printf("failed to allocate encoders\n"); + goto err; + } + for (i = 0; i < dev->num_encoders; i++) { + dev->encoders[i] = drmModeGetEncoder(dev->fd, r->encoders[i]); + if (!dev->encoders[i]) { + printf("failed to get encoder %d\n", i); + goto err; + } + } + + dev->num_crtcs = r->count_crtcs; + dev->crtcs = calloc(dev->num_crtcs, sizeof(struct sp_crtc)); + if (!dev->crtcs) { + printf("failed to allocate crtcs\n"); + goto err; + } + for (i = 0; i < dev->num_crtcs; i++) { + drmModeObjectPropertiesPtr props; + + dev->crtcs[i].crtc = drmModeGetCrtc(dev->fd, r->crtcs[i]); + if (!dev->crtcs[i].crtc) { + printf("failed to get crtc %d\n", i); + goto err; + } + dev->crtcs[i].pipe = i; + dev->crtcs[i].num_planes = 0; + + props = drmModeObjectGetProperties(dev->fd, r->crtcs[i], + DRM_MODE_OBJECT_CRTC); + if (!props) { + printf("failed to get crtc properties\n"); + goto err; + } + + dev->crtcs[i].mode_pid = get_prop_id(dev, props, "MODE_ID"); + dev->crtcs[i].active_pid = get_prop_id(dev, props, "ACTIVE"); + drmModeFreeObjectProperties(props); + if (!dev->crtcs[i].mode_pid || !dev->crtcs[i].active_pid) + goto err; + } + + pr = drmModeGetPlaneResources(dev->fd); + if (!pr) { + printf("failed to get plane resources\n"); + goto err; + } + dev->num_planes = pr->count_planes; + dev->planes = calloc(dev->num_planes, sizeof(struct sp_plane)); + for(i = 0; i < dev->num_planes; i++) { + drmModeObjectPropertiesPtr props; + struct sp_plane *plane = &dev->planes[i]; + + plane->dev = dev; + plane->plane = drmModeGetPlane(dev->fd, pr->planes[i]); + if (!plane->plane) { + printf("failed to get plane %d\n", i); + goto err; + } + plane->bo = NULL; + plane->in_use = 0; + + ret = get_supported_format(plane, &plane->format); + if (ret) { + printf("failed to get supported format: %d\n", ret); + goto err; + } + + for (j = 0; j < dev->num_crtcs; j++) { + if (plane->plane->possible_crtcs & (1 << j)) + dev->crtcs[j].num_planes++; + } + + props = drmModeObjectGetProperties(dev->fd, pr->planes[i], + DRM_MODE_OBJECT_PLANE); + if (!props) { + printf("failed to get plane properties\n"); + goto err; + } + plane->crtc_pid = get_prop_id(dev, props, "CRTC_ID"); + if (!plane->crtc_pid) { + drmModeFreeObjectProperties(props); + goto err; + } + plane->fb_pid = get_prop_id(dev, props, "FB_ID"); + if (!plane->fb_pid) { + drmModeFreeObjectProperties(props); + goto err; + } + plane->crtc_x_pid = get_prop_id(dev, props, "CRTC_X"); + if (!plane->crtc_x_pid) { + drmModeFreeObjectProperties(props); + goto err; + } + plane->crtc_y_pid = get_prop_id(dev, props, "CRTC_Y"); + if (!plane->crtc_y_pid) { + drmModeFreeObjectProperties(props); + goto err; + } + plane->crtc_w_pid = get_prop_id(dev, props, "CRTC_W"); + if (!plane->crtc_w_pid) { + drmModeFreeObjectProperties(props); + goto err; + } + plane->crtc_h_pid = get_prop_id(dev, props, "CRTC_H"); + if (!plane->crtc_h_pid) { + drmModeFreeObjectProperties(props); + goto err; + } + plane->src_x_pid = get_prop_id(dev, props, "SRC_X"); + if (!plane->src_x_pid) { + drmModeFreeObjectProperties(props); + goto err; + } + plane->src_y_pid = get_prop_id(dev, props, "SRC_Y"); + if (!plane->src_y_pid) { + drmModeFreeObjectProperties(props); + goto err; + } + plane->src_w_pid = get_prop_id(dev, props, "SRC_W"); + if (!plane->src_w_pid) { + drmModeFreeObjectProperties(props); + goto err; + } + plane->src_h_pid = get_prop_id(dev, props, "SRC_H"); + if (!plane->src_h_pid) { + drmModeFreeObjectProperties(props); + goto err; + } + drmModeFreeObjectProperties(props); + } + + if (pr) + drmModeFreePlaneResources(pr); + if (r) + drmModeFreeResources(r); + + return dev; +err: + if (pr) + drmModeFreePlaneResources(pr); + if (r) + drmModeFreeResources(r); + destroy_sp_dev(dev); + return NULL; +} + +void destroy_sp_dev(struct sp_dev *dev) +{ + int i; + + if (dev->planes) { + for (i = 0; i< dev->num_planes; i++) { + if (dev->planes[i].in_use) + put_sp_plane(&dev->planes[i]); + if (dev->planes[i].plane) + drmModeFreePlane(dev->planes[i].plane); + if (dev->planes[i].bo) + free_sp_bo(dev->planes[i].bo); + } + free(dev->planes); + } + if (dev->crtcs) { + for (i = 0; i< dev->num_crtcs; i++) { + if (dev->crtcs[i].crtc) + drmModeFreeCrtc(dev->crtcs[i].crtc); + } + free(dev->crtcs); + } + if (dev->encoders) { + for (i = 0; i< dev->num_encoders; i++) { + if (dev->encoders[i]) + drmModeFreeEncoder(dev->encoders[i]); + } + free(dev->encoders); + } + if (dev->connectors) { + for (i = 0; i< dev->num_connectors; i++) { + if (dev->connectors[i].conn) + drmModeFreeConnector(dev->connectors[i].conn); + } + free(dev->connectors); + } + + close(dev->fd); + free(dev); +} diff --git a/tests/planetest/dev.h b/tests/planetest/dev.h new file mode 100644 index 0000000..04dec79 --- /dev/null +++ b/tests/planetest/dev.h @@ -0,0 +1,65 @@ +#ifndef __DEV_H_INCLUDED__ +#define __DEV_H_INCLUDED__ + +#include +#include + +struct sp_bo; +struct sp_dev; + +struct sp_plane { + struct sp_dev *dev; + drmModePlanePtr plane; + struct sp_bo *bo; + int in_use; + uint32_t format; + + /* Property ID's */ + uint32_t crtc_pid; + uint32_t fb_pid; + uint32_t zpos_pid; + uint32_t crtc_x_pid; + uint32_t crtc_y_pid; + uint32_t crtc_w_pid; + uint32_t crtc_h_pid; + uint32_t src_x_pid; + uint32_t src_y_pid; + uint32_t src_w_pid; + uint32_t src_h_pid; +}; + +struct sp_connector { + drmModeConnectorPtr conn; + uint32_t crtc_id_pid; +}; + +struct sp_crtc { + drmModeCrtcPtr crtc; + int pipe; + int num_planes; + uint32_t mode_pid; + uint32_t active_pid; +}; + +struct sp_dev { + int fd; + + int num_connectors; + struct sp_connector *connectors; + + int num_encoders; + drmModeEncoderPtr *encoders; + + int num_crtcs; + struct sp_crtc *crtcs; + + int num_planes; + struct sp_plane *planes; +}; + +void parse_arguments(int argc, char *argv[], int *card, int *crtc); + +struct sp_dev *create_sp_dev(int card); +void destroy_sp_dev(struct sp_dev *dev); + +#endif /* __DEV_H_INCLUDED__ */ diff --git a/tests/planetest/modeset.c b/tests/planetest/modeset.c new file mode 100644 index 0000000..b8f6690 --- /dev/null +++ b/tests/planetest/modeset.c @@ -0,0 +1,232 @@ +#include +#include +#include + +#include +#include +#include + +#include "modeset.h" +#include "bo.h" +#include "dev.h" + +static int set_crtc_mode(struct sp_dev *dev, struct sp_crtc *crtc, + struct sp_connector *conn, drmModeModeInfoPtr mode) +{ + int ret; + struct drm_mode_create_blob create_blob; + drmModeAtomicReqPtr pset; + + memset(&create_blob, 0, sizeof(create_blob)); + create_blob.length = sizeof(struct drm_mode_modeinfo); + create_blob.data = (__u64)(uintptr_t)mode; + + ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob); + if (ret) { + printf("Failed to create mode property blob %d", ret); + return ret; + } + + pset = drmModeAtomicAlloc(); + if (!pset) { + printf("Failed to allocate property set"); + return -1; + } + + ret = drmModeAtomicAddProperty(pset, crtc->crtc->crtc_id, + crtc->mode_pid, create_blob.blob_id) || + drmModeAtomicAddProperty(pset, crtc->crtc->crtc_id, + crtc->active_pid, 1) || + drmModeAtomicAddProperty(pset, conn->conn->connector_id, + conn->crtc_id_pid, crtc->crtc->crtc_id); + if (ret) { + printf("Failed to add blob %d to pset", create_blob.blob_id); + drmModeAtomicFree(pset); + return ret; + } + + ret = drmModeAtomicCommit(dev->fd, pset, DRM_MODE_ATOMIC_ALLOW_MODESET, + NULL); + + drmModeAtomicFree(pset); + + if (ret) { + printf("Failed to commit pset ret=%d\n", ret); + return ret; + } + + memcpy(&crtc->crtc->mode, mode, sizeof(struct drm_mode_modeinfo)); + crtc->crtc->mode_valid = 1; + return 0; +} + +int initialize_screens(struct sp_dev *dev) +{ + int ret, i, j; + unsigned crtc_mask = 0; + + for (i = 0; i < dev->num_connectors; i++) { + struct sp_connector *c = &dev->connectors[i]; + drmModeModeInfoPtr m = NULL; + drmModeEncoderPtr e = NULL; + struct sp_crtc *cr = NULL; + + if (c->conn->connection != DRM_MODE_CONNECTED) + continue; + + if (!c->conn->count_modes) { + printf("connector has no modes, skipping\n"); + continue; + } + + /* Take the first unless there's a preferred mode */ + m = &c->conn->modes[0]; + for (j = 0; j < c->conn->count_modes; j++) { + drmModeModeInfoPtr tmp_m = &c->conn->modes[j]; + + if (!(tmp_m->type & DRM_MODE_TYPE_PREFERRED)) + continue; + + m = tmp_m; + break; + } + + if (!c->conn->count_encoders) { + printf("no possible encoders for connector\n"); + continue; + } + + for (j = 0; j < dev->num_encoders; j++) { + e = dev->encoders[j]; + if (e->encoder_id == c->conn->encoders[0]) + break; + } + if (j == dev->num_encoders) { + printf("could not find encoder for the connector\n"); + continue; + } + + for (j = 0; j < dev->num_crtcs; j++) { + if ((1 << j) & crtc_mask) + continue; + + cr = &dev->crtcs[j]; + + if ((1 << j) & e->possible_crtcs) + break; + } + if (j == dev->num_crtcs) { + printf("could not find crtc for the encoder\n"); + continue; + } + + ret = set_crtc_mode(dev, cr, c, m); + if (ret) { + printf("failed to set mode!\n"); + continue; + } + crtc_mask |= 1 << j; + } + return 0; +} + +struct sp_plane *get_sp_plane(struct sp_dev *dev, struct sp_crtc *crtc) +{ + int i; + + for(i = 0; i < dev->num_planes; i++) { + struct sp_plane *p = &dev->planes[i]; + + if (p->in_use) + continue; + + if (!(p->plane->possible_crtcs & (1 << crtc->pipe))) + continue; + + p->in_use = 1; + return p; + } + return NULL; +} + +void put_sp_plane(struct sp_plane *plane) +{ + drmModePlanePtr p; + + /* Get the latest plane information (most notably the crtc_id) */ + p = drmModeGetPlane(plane->dev->fd, plane->plane->plane_id); + if (p) + plane->plane = p; + + if (plane->bo) { + free_sp_bo(plane->bo); + plane->bo = NULL; + } + plane->in_use = 0; +} + +int set_sp_plane(struct sp_dev *dev, struct sp_plane *plane, + struct sp_crtc *crtc, int x, int y) +{ + int ret; + uint32_t w, h; + + w = plane->bo->width; + h = plane->bo->height; + + if ((w + x) > crtc->crtc->mode.hdisplay) + w = crtc->crtc->mode.hdisplay - x; + if ((h + y) > crtc->crtc->mode.vdisplay) + h = crtc->crtc->mode.vdisplay - y; + + ret = drmModeSetPlane(dev->fd, plane->plane->plane_id, + crtc->crtc->crtc_id, plane->bo->fb_id, 0, x, y, w, h, + 0, 0, w << 16, h << 16); + if (ret) { + printf("failed to set plane to crtc ret=%d\n", ret); + return ret; + } + + return ret; +} +int set_sp_plane_pset(struct sp_dev *dev, struct sp_plane *plane, + drmModeAtomicReqPtr pset, struct sp_crtc *crtc, int x, int y) +{ + int ret; + uint32_t w, h; + + w = plane->bo->width; + h = plane->bo->height; + + if ((w + x) > crtc->crtc->mode.hdisplay) + w = crtc->crtc->mode.hdisplay - x; + if ((h + y) > crtc->crtc->mode.vdisplay) + h = crtc->crtc->mode.vdisplay - y; + + ret = drmModeAtomicAddProperty(pset, plane->plane->plane_id, + plane->crtc_pid, crtc->crtc->crtc_id) + || drmModeAtomicAddProperty(pset, plane->plane->plane_id, + plane->fb_pid, plane->bo->fb_id) + || drmModeAtomicAddProperty(pset, plane->plane->plane_id, + plane->crtc_x_pid, x) + || drmModeAtomicAddProperty(pset, plane->plane->plane_id, + plane->crtc_y_pid, y) + || drmModeAtomicAddProperty(pset, plane->plane->plane_id, + plane->crtc_w_pid, w) + || drmModeAtomicAddProperty(pset, plane->plane->plane_id, + plane->crtc_h_pid, h) + || drmModeAtomicAddProperty(pset, plane->plane->plane_id, + plane->src_x_pid, 0) + || drmModeAtomicAddProperty(pset, plane->plane->plane_id, + plane->src_y_pid, 0) + || drmModeAtomicAddProperty(pset, plane->plane->plane_id, + plane->src_w_pid, w << 16) + || drmModeAtomicAddProperty(pset, plane->plane->plane_id, + plane->src_h_pid, h << 16); + if (ret) { + printf("failed to add properties to the set\n"); + return -1; + } + + return ret; +} diff --git a/tests/planetest/modeset.h b/tests/planetest/modeset.h new file mode 100644 index 0000000..5499959 --- /dev/null +++ b/tests/planetest/modeset.h @@ -0,0 +1,19 @@ +#ifndef __MODESET_H_INCLUDED__ +#define __MODESET_H_INCLUDED__ + +struct sp_dev; +struct sp_crtc; + +int initialize_screens(struct sp_dev *dev); + + +struct sp_plane *get_sp_plane(struct sp_dev *dev, struct sp_crtc *crtc); +void put_sp_plane(struct sp_plane *plane); + +int set_sp_plane(struct sp_dev *dev, struct sp_plane *plane, + struct sp_crtc *crtc, int x, int y); + +int set_sp_plane_pset(struct sp_dev *dev, struct sp_plane *plane, + drmModeAtomicReqPtr pset, struct sp_crtc *crtc, int x, int y); + +#endif /* __MODESET_H_INCLUDED__ */ diff --git a/tests/planetest/planetest.c b/tests/planetest/planetest.c new file mode 100644 index 0000000..5e187c9 --- /dev/null +++ b/tests/planetest/planetest.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dev.h" +#include "bo.h" +#include "modeset.h" + +static int terminate = 0; + +static void sigint_handler(int arg) +{ + terminate = 1; +} + +static void incrementor(int *inc, int *val, int increment, int lower, int upper) +{ + if(*inc > 0) + *inc = *val + increment >= upper ? -1 : 1; + else + *inc = *val - increment <= lower ? 1 : -1; + *val += *inc * increment; +} + +int main(int argc, char *argv[]) +{ + int ret, i, j, num_test_planes; + int x_inc = 1, x = 0, y_inc = 1, y = 0; + uint32_t plane_w = 128, plane_h = 128; + struct sp_dev *dev; + struct sp_plane **plane = NULL; + struct sp_crtc *test_crtc; + int card = 0, crtc = 0; + + signal(SIGINT, sigint_handler); + + parse_arguments(argc, argv, &card, &crtc); + + dev = create_sp_dev(card); + if (!dev) { + printf("Failed to create sp_dev\n"); + return -1; + } + + if (crtc >= dev->num_crtcs) { + printf("Invalid crtc %d (num=%d)\n", crtc, dev->num_crtcs); + return -1; + } + + ret = initialize_screens(dev); + if (ret) { + printf("Failed to initialize screens\n"); + goto out; + } + test_crtc = &dev->crtcs[crtc]; + + plane = calloc(dev->num_planes, sizeof(*plane)); + if (!plane) { + printf("Failed to allocate plane array\n"); + goto out; + } + + /* Create our planes */ + num_test_planes = test_crtc->num_planes; + for (i = 0; i < num_test_planes; i++) { + plane[i] = get_sp_plane(dev, test_crtc); + if (!plane[i]) { + printf("no unused planes available\n"); + goto out; + } + + plane[i]->bo = create_sp_bo(dev, plane_w, plane_h, 16, + plane[i]->format, 0); + if (!plane[i]->bo) { + printf("failed to create plane bo\n"); + goto out; + } + + fill_bo(plane[i]->bo, 0xFF, 0xFF, 0xFF, 0xFF); + } + + while (!terminate) { + incrementor(&x_inc, &x, 5, 0, + test_crtc->crtc->mode.hdisplay - plane_w); + incrementor(&y_inc, &y, 5, 0, test_crtc->crtc->mode.vdisplay - + plane_h * num_test_planes); + + for (j = 0; j < num_test_planes; j++) { + ret = set_sp_plane(dev, plane[j], test_crtc, + x, y + j * plane_h); + if (ret) { + printf("failed to set plane %d %d\n", j, ret); + goto out; + } + } + usleep(15 * 1000); + } + + for (i = 0; i < num_test_planes; i++) + put_sp_plane(plane[i]); + +out: + destroy_sp_dev(dev); + free(plane); + return ret; +}