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@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/dri-devel -- Sean Paul, Software Engineer, Google / Chromium OS _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel