You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
367 lines
8.6 KiB
367 lines
8.6 KiB
#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); |
|
}
|
|
|