[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