#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); }