367 lines
8.6 KiB
C
367 lines
8.6 KiB
C
#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);
|
|
}
|