[RFC][PATCH] libdrm: tests: Add planetest test from AOSP sources
Sean Paul
sean at poorly.run
Tue Apr 16 18:29:06 UTC 2019
On Tue, Apr 16, 2019 at 09:43:49AM -0700, John Stultz wrote:
> 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.
I'll start :)
IMO, we should just punt this into orbit. I just wrote it to do some very basic
testing when atomic was first being developed. I think modetest does all of
this and more, not to mention igt which does _much_ more. So unless someone
actually uses this, and has a compelling reason to upstream it I'd say revert it
from Android and we'll be in sync.
> Feedback and thoughts would be appreciated!
>
/snip
> +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;
Terrible names for these structs, geez!
Sean
> + 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 <stdio.h>
> +#include <stdlib.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +
> +#include <xf86drm.h>
> +#include <xf86drmMode.h>
> +#include <drm_fourcc.h>
> +
> +#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 <stdint.h>
> +
> +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 <stdio.h>
> +#include <stdlib.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <getopt.h>
> +
> +#include <drm.h>
> +#include <drm_fourcc.h>
> +#include <errno.h>
> +#include <xf86drm.h>
> +#include <xf86drmMode.h>
> +
> +#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 <stdint.h>
> +#include <xf86drmMode.h>
> +
> +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 <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <xf86drm.h>
> +#include <xf86drmMode.h>
> +#include <drm_fourcc.h>
> +
> +#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 <stdio.h>
> +#include <stdlib.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/select.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <signal.h>
> +#include <time.h>
> +#include <errno.h>
> +
> +#include <xf86drm.h>
> +
> +#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;
> +}
> --
> 2.7.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Sean Paul, Software Engineer, Google / Chromium OS
More information about the dri-devel
mailing list