| #include <stdio.h> |
| #include <stdlib.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <sys/types.h> |
| #include <dirent.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" |
| |
| #ifdef USE_ATOMIC_API |
| 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; |
| } |
| #endif |
| |
| 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) { |
| *format = plane->plane->formats[i]; |
| return 0; |
| } |
| } |
| printf("No suitable formats found!\n"); |
| return -ENOENT; |
| } |
| |
| static struct sp_dev *create_sp_dev_from_name(char *name) |
| { |
| struct sp_dev *dev; |
| int ret, fd, i, j; |
| drmModeRes *r = NULL; |
| drmModePlaneRes *pr = NULL; |
| char devPath[PATH_MAX]; |
| |
| strcpy(devPath, "/dev/dri/"); |
| strcat(devPath, name); |
| fd = open(devPath, 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; |
| |
| #ifdef SET_CLIENT_CAP_UNIVERSAL_PLANES |
| ret = drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); |
| if (ret) { |
| printf("failed to set client cap\n"); |
| goto err; |
| } |
| #endif |
| |
| r = drmModeGetResources(dev->fd); |
| if (!r) { |
| printf("%s failed to get r\n", devPath); |
| goto err; |
| } |
| |
| if (!r->count_crtcs || |
| !r->count_encoders || |
| !r->count_connectors) { |
| printf("%s no display resources\n", devPath); |
| goto err; |
| } |
| |
| dev->num_connectors = r->count_connectors; |
| dev->connectors = calloc(dev->num_connectors, sizeof(*dev->connectors)); |
| if (!dev->connectors) { |
| printf("failed to allocate connectors\n"); |
| goto err; |
| } |
| for (i = 0; i < dev->num_connectors; i++) { |
| dev->connectors[i] = drmModeGetConnector(dev->fd, |
| r->connectors[i]); |
| if (!dev->connectors[i]) { |
| printf("failed to get connector %d\n", i); |
| 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++) { |
| 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].scanout = NULL; |
| dev->crtcs[i].pipe = i; |
| dev->crtcs[i].num_planes = 0; |
| } |
| |
| 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; |
| } |
| #ifdef USE_ATOMIC_API |
| 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; |
| } |
| #endif |
| 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; |
| } |
| |
| struct sp_dev *create_sp_dev(void) |
| { |
| struct dirent de, *pde; |
| struct sp_dev *dev = NULL; |
| DIR *dir = opendir("/dev/dri"); |
| int res; |
| |
| if (!dir) |
| return NULL; |
| |
| while ((res = readdir_r(dir, &de, &pde)) == 0) { |
| if (!pde) |
| break; |
| if (de.d_type != DT_CHR) |
| continue; |
| dev = create_sp_dev_from_name(de.d_name); |
| if (dev) |
| break; |
| } |
| closedir(dir); |
| return dev; |
| } |
| |
| 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); |
| if (dev->crtcs[i].scanout) |
| free_sp_bo(dev->crtcs[i].scanout); |
| } |
| 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]) |
| drmModeFreeConnector(dev->connectors[i]); |
| } |
| free(dev->connectors); |
| } |
| |
| close(dev->fd); |
| free(dev); |
| } |