#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; drmModePropertySetPtr 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 = drmModePropertySetAlloc(); if (!pset) { printf("Failed to allocate property set"); return -1; } ret = drmModePropertySetAdd(pset, crtc->crtc->crtc_id, crtc->mode_pid, create_blob.blob_id) || drmModePropertySetAdd(pset, crtc->crtc->crtc_id, crtc->active_pid, 1) || drmModePropertySetAdd(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); drmModePropertySetFree(pset); return ret; } ret = drmModePropertySetCommit(dev->fd, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL, pset); drmModePropertySetFree(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, drmModePropertySetPtr 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 = drmModePropertySetAdd(pset, plane->plane->plane_id, plane->crtc_pid, crtc->crtc->crtc_id) || drmModePropertySetAdd(pset, plane->plane->plane_id, plane->fb_pid, plane->bo->fb_id) || drmModePropertySetAdd(pset, plane->plane->plane_id, plane->crtc_x_pid, x) || drmModePropertySetAdd(pset, plane->plane->plane_id, plane->crtc_y_pid, y) || drmModePropertySetAdd(pset, plane->plane->plane_id, plane->crtc_w_pid, w) || drmModePropertySetAdd(pset, plane->plane->plane_id, plane->crtc_h_pid, h) || drmModePropertySetAdd(pset, plane->plane->plane_id, plane->src_x_pid, 0) || drmModePropertySetAdd(pset, plane->plane->plane_id, plane->src_y_pid, 0) || drmModePropertySetAdd(pset, plane->plane->plane_id, plane->src_w_pid, w << 16) || drmModePropertySetAdd(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; }