static int connector_find_plane(int fd, unsigned int *plane_id) { drmModePlaneRes *plane_resources; drmModePlane *ovr; int i; plane_resources = drmModeGetPlaneResources(fd); if (!plane_resources) { fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", strerror(errno)); return -1; } for (i = 0; i < plane_resources->count_planes; i++) { plane_id[i] = 0; ovr = drmModeGetPlane(fd, plane_resources->planes[i]); if (!ovr) { fprintf(stderr, "drmModeGetPlane failed: %s\n", strerror(errno)); continue; } if (ovr->possible_crtcs & (1 << 0)) plane_id[i] = ovr->plane_id; drmModeFreePlane(ovr); } return 0; }
static void dump_planes(int gfx_fd, drmModeRes *resources) { drmModePlaneRes *plane_resources; drmModePlane *ovr; int i; plane_resources = drmModeGetPlaneResources(gfx_fd); if (!plane_resources) { printf("drmModeGetPlaneResources failed: %s\n", strerror(errno)); return; } printf("Planes:\n"); printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\n"); for (i = 0; i < plane_resources->count_planes; i++) { ovr = drmModeGetPlane(gfx_fd, plane_resources->planes[i]); if (!ovr) { printf("drmModeGetPlane failed: %s\n", strerror(errno)); continue; } printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%d\n", ovr->plane_id, ovr->crtc_id, ovr->fb_id, ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y, ovr->gamma_size); drmModeFreePlane(ovr); } printf("\n"); return; }
static int kms_plane_probe(struct kms_plane *plane) { struct kms_device *device = plane->device; drmModeObjectPropertiesPtr props; drmModePlane *p; unsigned int i; p = drmModeGetPlane(device->fd, plane->id); if (!p) return -ENODEV; /* TODO: allow dynamic assignment to CRTCs */ if (p->crtc_id == 0) { for (i = 0; i < device->num_crtcs; i++) { if (p->possible_crtcs & (1 << i)) { p->crtc_id = device->crtcs[i]->id; break; } } } for (i = 0; i < device->num_crtcs; i++) { if (device->crtcs[i]->id == p->crtc_id) { plane->crtc = device->crtcs[i]; break; } } plane->formats = calloc(p->count_formats, sizeof(uint32_t)); if (!plane->formats) return -ENOMEM; for (i = 0; i < p->count_formats; i++) plane->formats[i] = p->formats[i]; plane->num_formats = p->count_formats; drmModeFreePlane(p); props = drmModeObjectGetProperties(device->fd, plane->id, DRM_MODE_OBJECT_PLANE); if (!props) return -ENODEV; for (i = 0; i < props->count_props; i++) { drmModePropertyPtr prop; prop = drmModeGetProperty(device->fd, props->props[i]); if (prop) { if (strcmp(prop->name, "type") == 0) plane->type = props->prop_values[i]; drmModeFreeProperty(prop); } } drmModeFreeObjectProperties(props); return 0; }
static drmModePlane * find_plane_for_crtc (int fd, drmModeRes * res, drmModePlaneRes * pres, int crtc_id) { drmModePlane *plane; int i, pipe; plane = NULL; pipe = -1; for (i = 0; i < res->count_crtcs; i++) { if (crtc_id == res->crtcs[i]) { pipe = i; break; } } if (pipe == -1) return NULL; for (i = 0; i < pres->count_planes; i++) { plane = drmModeGetPlane (fd, pres->planes[i]); if (plane->possible_crtcs & (1 << pipe)) return plane; drmModeFreePlane (plane); } return NULL; }
static uint32_t plane_get_igt_format(struct kms_atomic_plane_state *plane) { drmModePlanePtr plane_kms; const uint32_t *igt_formats; uint32_t ret = 0; int num_igt_formats; int i; plane_kms = drmModeGetPlane(plane->state->desc->fd, plane->obj); igt_assert(plane_kms); igt_get_all_cairo_formats(&igt_formats, &num_igt_formats); for (i = 0; i < num_igt_formats; i++) { int j; for (j = 0; j < plane_kms->count_formats; j++) { if (plane_kms->formats[j] == igt_formats[i]) { ret = plane_kms->formats[j]; break; } } } drmModeFreePlane(plane_kms); return ret; }
static void plane_check_current_state(struct kms_atomic_plane_state *plane, enum kms_atomic_check_relax relax) { drmModePlanePtr legacy; struct kms_atomic_plane_state plane_kernel; legacy = drmModeGetPlane(plane->state->desc->fd, plane->obj); igt_assert(legacy); igt_assert_eq_u32(legacy->crtc_id, plane->crtc_id); if (!(relax & PLANE_RELAX_FB)) igt_assert_eq_u32(legacy->fb_id, plane->fb_id); memcpy(&plane_kernel, plane, sizeof(plane_kernel)); plane_get_current_state(&plane_kernel); /* Legacy cursor ioctls create their own, unknowable, internal * framebuffer which we can't reason about. */ if (relax & PLANE_RELAX_FB) plane_kernel.fb_id = plane->fb_id; do_or_die(memcmp(&plane_kernel, plane, sizeof(plane_kernel))); drmModeFreePlane(legacy); }
static void init_crtc_rotations (MetaMonitorManager *manager, MetaCRTC *crtc, unsigned int idx) { MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); drmModeObjectPropertiesPtr props; drmModePlaneRes *planes; drmModePlane *drm_plane; MetaCRTCKms *crtc_kms; unsigned int i; crtc_kms = crtc->driver_private; planes = drmModeGetPlaneResources(manager_kms->fd); if (planes == NULL) return; for (i = 0; i < planes->count_planes; i++) { drmModePropertyPtr prop; drm_plane = drmModeGetPlane (manager_kms->fd, planes->planes[i]); if (!drm_plane) continue; if ((drm_plane->possible_crtcs & (1 << idx))) { props = drmModeObjectGetProperties (manager_kms->fd, drm_plane->plane_id, DRM_MODE_OBJECT_PLANE); if (props && is_primary_plane (manager, props)) { int rotation_idx; crtc_kms->primary_plane_id = drm_plane->plane_id; rotation_idx = find_property_index (manager, props, "rotation", &prop); if (rotation_idx >= 0) { crtc_kms->rotation_prop_id = props->props[rotation_idx]; parse_transforms (manager, prop, crtc); drmModeFreeProperty (prop); } } if (props) drmModeFreeObjectProperties (props); } drmModeFreePlane (drm_plane); } drmModeFreePlaneResources (planes); }
static int find_plane(int drmfd, struct setup *s) { drmModePlaneResPtr planes; drmModePlanePtr plane; unsigned int i; unsigned int j; int ret = 0; planes = drmModeGetPlaneResources(drmfd); if (WARN_ON(!planes, "drmModeGetPlaneResources failed: %s\n", ERRSTR)) return -1; for (i = 0; i < planes->count_planes; ++i) { plane = drmModeGetPlane(drmfd, planes->planes[i]); if (WARN_ON(!planes, "drmModeGetPlane failed: %s\n", ERRSTR)) break; if (!(plane->possible_crtcs & (1 << s->crtIdx))) { drmModeFreePlane(plane); continue; } for (j = 0; j < plane->count_formats; ++j) { if (plane->formats[j] == s->out_fourcc) break; } if (j == plane->count_formats) { drmModeFreePlane(plane); continue; } s->planeId = plane->plane_id; drmModeFreePlane(plane); break; } if (i == planes->count_planes) ret = -1; drmModeFreePlaneResources(planes); return ret; }
void CDRMUtils::DestroyDrm() { RestoreOriginalMode(); drmDropMaster(m_fd); close(m_fd); m_fd = -1; drmModeFreeResources(m_drm_resources); m_drm_resources = nullptr; drmModeFreeConnector(m_connector->connector); drmModeFreeObjectProperties(m_connector->props); delete [] m_connector->props_info; delete m_connector; m_connector = nullptr; drmModeFreeEncoder(m_encoder->encoder); delete m_encoder; m_encoder = nullptr; drmModeFreeCrtc(m_crtc->crtc); drmModeFreeObjectProperties(m_crtc->props); delete [] m_crtc->props_info; delete m_crtc; m_crtc = nullptr; drmModeFreePlane(m_primary_plane->plane); drmModeFreeObjectProperties(m_primary_plane->props); delete [] m_primary_plane->props_info; delete m_primary_plane; m_primary_plane = nullptr; drmModeFreePlane(m_overlay_plane->plane); drmModeFreeObjectProperties(m_overlay_plane->props); delete [] m_overlay_plane->props_info; delete m_overlay_plane; m_overlay_plane = nullptr; }
/* Pick a plane.. something that at a minimum can be connected to * the chosen crtc, but prefer primary plane. * * Seems like there is some room for a drmModeObjectGetNamedProperty() * type helper in libdrm.. */ static int get_plane_id(void) { drmModePlaneResPtr plane_resources; uint32_t i, j; int ret = -EINVAL; int found_primary = 0; plane_resources = drmModeGetPlaneResources(drm.fd); if (!plane_resources) { printf("drmModeGetPlaneResources failed: %s\n", strerror(errno)); return -1; } for (i = 0; (i < plane_resources->count_planes) && !found_primary; i++) { uint32_t id = plane_resources->planes[i]; drmModePlanePtr plane = drmModeGetPlane(drm.fd, id); if (!plane) { printf("drmModeGetPlane(%u) failed: %s\n", id, strerror(errno)); continue; } if (plane->possible_crtcs & (1 << drm.crtc_index)) { drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm.fd, id, DRM_MODE_OBJECT_PLANE); /* primary or not, this plane is good enough to use: */ ret = id; for (j = 0; j < props->count_props; j++) { drmModePropertyPtr p = drmModeGetProperty(drm.fd, props->props[j]); if ((strcmp(p->name, "type") == 0) && (props->prop_values[j] == DRM_PLANE_TYPE_PRIMARY)) { /* found our primary plane, lets use that: */ found_primary = 1; } drmModeFreeProperty(p); } drmModeFreeObjectProperties(props); } drmModeFreePlane(plane); } drmModeFreePlaneResources(plane_resources); return ret; }
int drm_get_overlay_plane(int drm_fd, int crtc_pipe, uint32_t format, uint32_t *plane_id) { drmModePlaneRes *res; drmModePlane *p; uint32_t id = 0; int i, j; if (drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) { ErrorMsg("Failed to set universal planes CAP\n"); goto err; } res = drmModeGetPlaneResources(drm_fd); if (!res) goto err; for (i = 0; i < res->count_planes && !id; i++) { p = drmModeGetPlane(drm_fd, res->planes[i]); if (!p) continue; if (!p->crtc_id && (p->possible_crtcs & (1 << crtc_pipe))) { if (drm_plane_type(drm_fd, p->plane_id) == DRM_PLANE_TYPE_OVERLAY) { for (j = 0; j < p->count_formats; j++) { if (p->formats[j] == format) { id = p->plane_id; break; } } } } drmModeFreePlane(p); } drmModeFreePlaneResources(res); if (!id) goto err; *plane_id = id; return 0; err: ErrorMsg("Failed to get overlay plane\n"); return -EFAULT; }
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); }
static int connector_find_plane(int gfx_fd, struct connector *c, unsigned int **sprite_plane_id) { drmModePlaneRes *plane_resources; drmModePlane *ovr; int i, sprite_plane_count = 0; plane_resources = drmModeGetPlaneResources(gfx_fd); if (!plane_resources) { printf("drmModeGetPlaneResources failed: %s\n", strerror(errno)); return 0; } /* Allocating buffer to hold sprite plane ids of the * current connector. */ *sprite_plane_id = (unsigned int *) malloc(plane_resources->count_planes * sizeof(unsigned int)); for (i = 0; i < plane_resources->count_planes; i++) { ovr = drmModeGetPlane(gfx_fd, plane_resources->planes[i]); if (!ovr) { printf("drmModeGetPlane failed: %s\n", strerror(errno)); continue; } /* Add the available sprite id to the buffer sprite_plane_id. */ if (ovr->possible_crtcs & (1 << c->pipe)) { (*sprite_plane_id)[sprite_plane_count++] = ovr->plane_id; } drmModeFreePlane(ovr); } return sprite_plane_count; }
bool CDRMUtils::GetPlanes() { drmModePlaneResPtr plane_resources; uint32_t primary_plane_id = 0; uint32_t overlay_plane_id = 0; uint32_t fourcc = 0; plane_resources = drmModeGetPlaneResources(m_fd); if (!plane_resources) { CLog::Log(LOGERROR, "CDRMUtils::%s - drmModeGetPlaneResources failed: %s", __FUNCTION__, strerror(errno)); return false; } for (uint32_t i = 0; i < plane_resources->count_planes; i++) { uint32_t id = plane_resources->planes[i]; drmModePlanePtr plane = drmModeGetPlane(m_fd, id); if (!plane) { CLog::Log(LOGERROR, "CDRMUtils::%s - drmModeGetPlane(%u) failed: %s", __FUNCTION__, id, strerror(errno)); continue; } if (plane->possible_crtcs & (1 << m_crtc_index)) { drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(m_fd, id, DRM_MODE_OBJECT_PLANE); for (uint32_t j = 0; j < props->count_props; j++) { drmModePropertyPtr p = drmModeGetProperty(m_fd, props->props[j]); if ((strcmp(p->name, "type") == 0) && (props->prop_values[j] == DRM_PLANE_TYPE_PRIMARY) && (primary_plane_id == 0)) { CLog::Log(LOGDEBUG, "CDRMUtils::%s - found primary plane: %u", __FUNCTION__, id); primary_plane_id = id; } else if ((strcmp(p->name, "type") == 0) && (props->prop_values[j] == DRM_PLANE_TYPE_OVERLAY) && (overlay_plane_id == 0)) { CLog::Log(LOGDEBUG, "CDRMUtils::%s - found overlay plane: %u", __FUNCTION__, id); overlay_plane_id = id; } drmModeFreeProperty(p); } drmModeFreeObjectProperties(props); } drmModeFreePlane(plane); } drmModeFreePlaneResources(plane_resources); // primary plane m_primary_plane->plane = drmModeGetPlane(m_fd, primary_plane_id); if (!m_primary_plane->plane) { CLog::Log(LOGERROR, "CDRMUtils::%s - could not get primary plane %u: %s", __FUNCTION__, primary_plane_id, strerror(errno)); return false; } if (!GetProperties(m_fd, primary_plane_id, DRM_MODE_OBJECT_PLANE, m_primary_plane)) { CLog::Log(LOGERROR, "CDRMUtils::%s - could not get primary plane %u properties: %s", __FUNCTION__, primary_plane_id, strerror(errno)); return false; } for (uint32_t i = 0; i < m_primary_plane->plane->count_formats; i++) { /* we want an alpha layer so break if we find one */ if (m_primary_plane->plane->formats[i] == DRM_FORMAT_XRGB8888) { fourcc = DRM_FORMAT_XRGB8888; m_primary_plane->format = fourcc; } else if (m_primary_plane->plane->formats[i] == DRM_FORMAT_ARGB8888) { fourcc = DRM_FORMAT_ARGB8888; m_primary_plane->format = fourcc; break; } } if (fourcc == 0) { CLog::Log(LOGERROR, "CDRMUtils::%s - could not find a suitable primary plane format", __FUNCTION__); return false; } CLog::Log(LOGDEBUG, "CDRMUtils::%s - primary plane format: %c%c%c%c", __FUNCTION__, fourcc, fourcc >> 8, fourcc >> 16, fourcc >> 24); if (overlay_plane_id != 0) { // overlay plane m_overlay_plane->plane = drmModeGetPlane(m_fd, overlay_plane_id); if (!m_overlay_plane->plane) { CLog::Log(LOGERROR, "CDRMUtils::%s - could not get overlay plane %u: %s", __FUNCTION__, overlay_plane_id, strerror(errno)); return false; } if (!GetProperties(m_fd, overlay_plane_id, DRM_MODE_OBJECT_PLANE, m_overlay_plane)) { CLog::Log(LOGERROR, "CDRMUtils::%s - could not get overlay plane %u properties: %s", __FUNCTION__, overlay_plane_id, strerror(errno)); return false; } fourcc = 0; for (uint32_t i = 0; i < m_overlay_plane->plane->count_formats; i++) { /* we want an alpha layer so break if we find one */ if (m_overlay_plane->plane->formats[i] == DRM_FORMAT_XRGB8888) { fourcc = DRM_FORMAT_XRGB8888; m_overlay_plane->format = fourcc; } else if(m_overlay_plane->plane->formats[i] == DRM_FORMAT_ARGB8888) { fourcc = DRM_FORMAT_ARGB8888; m_overlay_plane->format = fourcc; break; } } if (fourcc == 0) { CLog::Log(LOGERROR, "CDRMUtils::%s - could not find a suitable overlay plane format", __FUNCTION__); return false; } CLog::Log(LOGDEBUG, "CDRMUtils::%s - overlay plane format: %c%c%c%c", __FUNCTION__, fourcc, fourcc >> 8, fourcc >> 16, fourcc >> 24); }
int main(int argc, char *argv[]) { uint64_t has_dumb; int ret, fd, opt, i; void *map; struct drm_mode_destroy_dumb dreq; struct drm_mode_create_dumb creq; struct drm_mode_map_dumb mreq; drmModePlaneRes *resources; drmModePlane *plane = NULL; uint32_t handle, stride, size; uint32_t plane_id, crtc_id; uint32_t width, height; uint32_t posx, posy; uint32_t fb; /* parse command line */ while ((opt = getopt(argc, argv, "x:y:w:v:c:p:h")) != -1) { switch (opt) { case 'x': posx = atoi(optarg); break; case 'y': posy = atoi(optarg); break; case 'w': width = atoi(optarg); break; case 'v': height = atoi(optarg); break; case 'p': plane_id = atoi(optarg); break; case 'c': crtc_id = atoi(optarg); break; case 'h': default: printf("usage: -h] -c <connector> -e <encoder> -m <mode>\n"); printf("\t-h: this help message\n"); printf("\t-c <crtc> crtc id, default is 0\n"); printf("\t-p <plane> plane id, default is 0\n"); printf("\t-x <posx> plane top left corner xpos, default is 0'\n"); printf("\t-y <posy> plane top left corner ypos, default is 0'\n"); printf("\t-w <width> plane width, default is 0'\n"); printf("\t-v <height> plane height, default is 0'\n"); exit(0); } } /* open drm device */ fd = open(device_name, O_RDWR | O_CLOEXEC); if (fd < 0) { perror("cannot open drm device"); exit(-1); } drmSetMaster(fd); /* check dumb buffer support */ if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0) { perror("DRM_CAP_DUMB_BUFFER ioctl"); ret = -EFAULT; goto err_close; } if (!has_dumb) { fprintf(stderr, "driver does not support dumb buffers\n"); ret = -EFAULT; goto err_close; } /* get plane */ resources = drmModeGetPlaneResources(fd); if (!resources || resources->count_planes == 0) { fprintf(stderr, "drmModeGetPlaneResources failed\n"); ret = -ENODEV; goto err_close; } for (i = 0; i < resources->count_planes; i++) { drmModePlane *p = drmModeGetPlane(fd, resources->planes[i]); if (!p) continue; if (p->plane_id == plane_id) { plane = p; break; } drmModeFreePlane(plane); } if (!plane) { fprintf(stderr, "couldn't find specified plane\n"); ret = -ENODEV; goto err_close; } /* create dumb buffer object */ memset(&creq, 0, sizeof(creq)); creq.height = height; creq.width = width; creq.bpp = 32; ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); if (ret) { fprintf(stderr, "failed drmIoctl(DRM_IOCTL_MODE_CREATE_DUMB)\n"); goto err_close; } handle = creq.handle; stride = creq.pitch; size = creq.size; /* create framebuffer for dumb buffer object */ ret = drmModeAddFB(fd, width, height, 24, 32, stride, handle, &fb); if (ret) { fprintf(stderr, "cannot add drm framebuffer for dumb buffer object\n"); goto err_destroy_dumb; } /* map dumb buffer object */ memset(&mreq, 0, sizeof(mreq)); mreq.handle = handle; ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); if (ret) { fprintf(stderr, "failed drmIoctl(DRM_IOCTL_MODE_MAP_DUMB)\n"); goto err_destroy_fb; } map = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset); if (map == MAP_FAILED) { fprintf(stderr, "cannot mmap dumb buffer\n"); goto err_destroy_fb; } /* setup new plane */ ret = drmModeSetPlane(fd, plane_id, crtc_id, fb, 0, posx, posy, width, height, 0, 0, width << 16, height << 16); if (ret) { fprintf(stderr, "cannot set plane\n"); goto err_unmap; } /* draw on the screen */ draw_test_image((uint32_t *) map, width, height); getchar(); draw_fancy_image((uint32_t *) map, width, height); getchar(); drmModeSetPlane(fd, plane_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); err_unmap: if (map) munmap(map, size); err_destroy_fb: drmModeRmFB(fd, fb); err_destroy_dumb: memset(&dreq, 0, sizeof(dreq)); dreq.handle = handle; ret = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); if (ret) { fprintf(stderr, "cannot destroy dumb buffer\n"); } err_close: close(fd); return ret; }
/* This configures our only overlay plane to render the given surface. */ static void drm_plane_setup(struct drm_surface *surface) { int i,j; char fmt_name[5]; /* Get plane resources */ drmModePlane *plane; drmModePlaneRes *plane_resources; plane_resources = drmModeGetPlaneResources(drm.fd); if (!plane_resources) { RARCH_ERR ("DRM: No scaling planes available!\n"); } RARCH_LOG ("DRM: Number of planes on FD %d is %d\n", drm.fd, plane_resources->count_planes); /* dump_planes(drm.fd); */ /* Look for a plane/overlay we can use with the configured CRTC * Find a plane which can be connected to our CRTC. Find the * CRTC index first, then iterate over available planes. * Yes, strangely we need the in-use CRTC index to mask possible_crtc * during the planes iteration... */ unsigned int crtc_index = 0; for (i = 0; i < (unsigned int)drm.resources->count_crtcs; i++) { if (drm.crtc_id == drm.resources->crtcs[i]) { crtc_index = i; RARCH_LOG ("DRM: CRTC index found %d with ID %d\n", crtc_index, drm.crtc_id); break; } } /* Programmer!! Save your sanity!! Primary planes have to * cover the entire CRTC, and if you don't do that, you * will get dmesg error "Plane must cover entire CRTC". * * Look at linux/source/drivers/gpu/drm/drm_plane_helper.c comments for more info. * Also, primary planes can't be scaled: we need overlays for that. */ for (i = 0; i < plane_resources->count_planes; i++) { plane = drmModeGetPlane(drm.fd, plane_resources->planes[i]); if (!(plane->possible_crtcs & (1 << crtc_index))){ RARCH_LOG ("DRM: plane with ID %d can't be used with current CRTC\n", plane->plane_id); continue; } /* We are only interested in overlay planes. No overlay, no fun. * (no scaling, must cover crtc..etc) so we skip primary planes */ if (drm_plane_type(plane) != DRM_PLANE_TYPE_OVERLAY) { RARCH_LOG ("DRM: plane with ID %d is not an overlay. May be primary or cursor. Not usable.\n", plane->plane_id); continue; } if (!format_support(plane, surface->pixformat)) { RARCH_LOG ("DRM: plane with ID %d does not support framebuffer format\n", plane->plane_id); continue; } drm.plane_id = plane->plane_id; drmModeFreePlane(plane); } if (!drm.plane_id) { RARCH_LOG ("DRM: couldn't find an usable overlay plane for current CRTC and framebuffer pixel formal.\n"); deinit_drm(); exit (0); } else { RARCH_LOG ("DRM: using plane/overlay ID %d\n", drm.plane_id); } /* We are going to be changing the framebuffer ID property of the chosen overlay every time * we do a pageflip, so we get the property ID here to have it handy on the PageFlip function. */ drm.plane_fb_prop_id = get_plane_prop_id(drm.plane_id, "FB_ID"); if (!drm.plane_fb_prop_id) { RARCH_LOG("DRM: Can't get the FB property ID for plane(%u)\n", drm.plane_id); } /* Note src coords (last 4 args) are in Q16 format * crtc_w and crtc_h are the final size with applied scale/ratio. * crtc_x and crtc_y are the position of the plane * pw and ph are the input size: the size of the area we read from the fb. */ uint32_t plane_flags = 0; uint32_t plane_w = drm.current_mode->vdisplay * surface->aspect;; uint32_t plane_h = drm.current_mode->vdisplay; /* If we obtain a scaled image width that is bigger than the physical screen width, * then we keep the physical screen width as our maximun width. */ if (plane_w > drm.current_mode->hdisplay) plane_w = drm.current_mode->hdisplay; uint32_t plane_x = (drm.current_mode->hdisplay - plane_w) / 2; uint32_t plane_y = (drm.current_mode->vdisplay - plane_h) / 2; uint32_t src_w = surface->src_width; uint32_t src_h = surface->src_height; uint32_t src_x = 0; uint32_t src_y = 0; /* We have to set a buffer for the plane, whatever buffer we want, * but we must set a buffer so the plane starts reading from it now. */ if (drmModeSetPlane(drm.fd, drm.plane_id, drm.crtc_id, surface->pages[surface->flip_page].buf.fb_id, plane_flags, plane_x, plane_y, plane_w, plane_h, src_x<<16, src_y<<16, src_w<<16, src_h<<16)) { RARCH_ERR("DRM: failed to enable plane: %s\n", strerror(errno)); } RARCH_LOG("DRM: src_w %d, src_h %d, plane_w %d, plane_h %d\n", src_w, src_h, plane_w, plane_h); /* Report what plane (of overlay type) we're using. */ drm_format_name(surface->pixformat, fmt_name); RARCH_LOG("DRM: Using plane with ID %d on CRTC ID %d format %s\n", drm.plane_id, drm.crtc_id, fmt_name); }
static gboolean gst_kms_sink_start (GstBaseSink * bsink) { GstKMSSink *self; drmModeRes *res; drmModeConnector *conn; drmModeCrtc *crtc; drmModePlaneRes *pres; drmModePlane *plane; gboolean universal_planes; gboolean ret; self = GST_KMS_SINK (bsink); universal_planes = FALSE; ret = FALSE; res = NULL; conn = NULL; crtc = NULL; pres = NULL; plane = NULL; if (self->devname) self->fd = drmOpen (self->devname, NULL); else self->fd = kms_open (&self->devname); if (self->fd < 0) goto open_failed; log_drm_version (self); if (!get_drm_caps (self)) goto bail; res = drmModeGetResources (self->fd); if (!res) goto resources_failed; if (self->conn_id == -1) conn = find_main_monitor (self->fd, res); else conn = drmModeGetConnector (self->fd, self->conn_id); if (!conn) goto connector_failed; crtc = find_crtc_for_connector (self->fd, res, conn, &self->pipe); if (!crtc) goto crtc_failed; retry_find_plane: if (universal_planes && drmSetClientCap (self->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) goto set_cap_failed; pres = drmModeGetPlaneResources (self->fd); if (!pres) goto plane_resources_failed; if (self->plane_id == -1) plane = find_plane_for_crtc (self->fd, res, pres, crtc->crtc_id); else plane = drmModeGetPlane (self->fd, self->plane_id); if (!plane) goto plane_failed; /* let's get the available color formats in plane */ if (!ensure_allowed_caps (self, plane, res)) goto bail; self->conn_id = conn->connector_id; self->crtc_id = crtc->crtc_id; self->plane_id = plane->plane_id; GST_INFO_OBJECT (self, "connector id = %d / crtc id = %d / plane id = %d", self->conn_id, self->crtc_id, self->plane_id); self->hdisplay = crtc->mode.hdisplay; self->vdisplay = crtc->mode.vdisplay; self->buffer_id = crtc->buffer_id; self->mm_width = conn->mmWidth; self->mm_height = conn->mmHeight; GST_INFO_OBJECT (self, "display size: pixels = %dx%d / millimeters = %dx%d", self->hdisplay, self->vdisplay, self->mm_width, self->mm_height); self->pollfd.fd = self->fd; gst_poll_add_fd (self->poll, &self->pollfd); gst_poll_fd_ctl_read (self->poll, &self->pollfd, TRUE); ret = TRUE; bail: if (plane) drmModeFreePlane (plane); if (pres) drmModeFreePlaneResources (pres); if (crtc) drmModeFreeCrtc (crtc); if (conn) drmModeFreeConnector (conn); if (res) drmModeFreeResources (res); if (!ret && self->fd >= 0) { drmClose (self->fd); self->fd = -1; } return ret; /* ERRORS */ open_failed: { GST_ERROR_OBJECT (self, "Could not open DRM module %s: %s", GST_STR_NULL (self->devname), strerror (errno)); return FALSE; } resources_failed: { GST_ERROR_OBJECT (self, "drmModeGetResources failed: %s (%d)", strerror (errno), errno); goto bail; } connector_failed: { GST_ERROR_OBJECT (self, "Could not find a valid monitor connector"); goto bail; } crtc_failed: { GST_ERROR_OBJECT (self, "Could not find a crtc for connector"); goto bail; } set_cap_failed: { GST_ERROR_OBJECT (self, "Could not set universal planes capability bit"); goto bail; } plane_resources_failed: { GST_ERROR_OBJECT (self, "drmModeGetPlaneResources failed: %s (%d)", strerror (errno), errno); goto bail; } plane_failed: { if (universal_planes) { GST_ERROR_OBJECT (self, "Could not find a plane for crtc"); goto bail; } else { universal_planes = TRUE; goto retry_find_plane; } } }
int gralloc_kms_planes_init(struct gralloc_drm_t *drm) { drmModeResPtr resources; drmModePlaneResPtr planes; int i, order; /* What else than the ordering in the main resources would reliably tell us what the possible_crtcs field for the planes mean? Way to save overhead! */ resources = drmModeGetResources(drm->fd); if (!resources) { LOGE("Failed to get KMS resources\n"); return -EINVAL; } for (order = 0; order < resources->count_crtcs; order++) if (resources->crtcs[order] == drm->crtc_id) break; if (order == resources->count_crtcs) { LOGE("Failed to find crtc %d in KMS resources\n", drm->crtc_id); drmModeFreeResources(resources); return -EINVAL; } drmModeFreeResources(resources); planes = drmModeGetPlaneResources(drm->fd); if (!planes) { LOGE("Failed to get KMS Plane resources\n"); return -EINVAL; } for (i = 0; i < (int) planes->count_planes; i++) { drmModePlanePtr plane = drmModeGetPlane(drm->fd, planes->planes[i]); if (!plane) { LOGE("Failed to get Plane %d: %s\n", planes->planes[i], strerror(errno)); return errno; } if (plane->possible_crtcs & (1 << order)) { int ret = gralloc_kms_plane_add(drm, plane); if (ret) { drmModeFreePlane(plane); drmModeFreePlaneResources(planes); return ret; } } drmModeFreePlane(plane); } drmModeFreePlaneResources(planes); LOGI("%s: %d planes\n", __func__, drm->plane_count); for (i = 0; i < drm->plane_count; i++) { char buffer[1024]; int j; for (j = 0; j < drm->planes[i]->format_count; j++) sprintf(buffer + 6 * j, " %c%c%c%c,", drm->planes[i]->formats[j] & 0xFF, (drm->planes[i]->formats[j] >> 8) & 0xFF, (drm->planes[i]->formats[j] >> 16) & 0xFF, (drm->planes[i]->formats[j] >> 24) & 0xFF); LOGI("\t%d: %s", drm->planes[i]->id, buffer); } return 0; }
int DrmResources::Init() { char path[PROPERTY_VALUE_MAX]; property_get("hwc.drm.device", path, "/dev/dri/card0"); /* TODO: Use drmOpenControl here instead */ fd_ = open(path, O_RDWR); if (fd_ < 0) { ALOGE("Failed to open dri- %s", strerror(-errno)); return -ENODEV; } int ret = drmSetClientCap(fd_, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); if (ret) { ALOGE("Failed to set universal plane cap %d", ret); return ret; } ret = drmSetClientCap(fd_, DRM_CLIENT_CAP_ATOMIC, 1); if (ret) { ALOGE("Failed to set atomic cap %d", ret); return ret; } drmModeResPtr res = drmModeGetResources(fd_); if (!res) { ALOGE("Failed to get DrmResources resources"); return -ENODEV; } bool found_primary = false; int display_num = 1; for (int i = 0; !ret && i < res->count_crtcs; ++i) { drmModeCrtcPtr c = drmModeGetCrtc(fd_, res->crtcs[i]); if (!c) { ALOGE("Failed to get crtc %d", res->crtcs[i]); ret = -ENODEV; break; } DrmCrtc *crtc = new DrmCrtc(this, c, i); drmModeFreeCrtc(c); if (!crtc) { ALOGE("Failed to allocate crtc %d", res->crtcs[i]); ret = -ENOMEM; break; } ret = crtc->Init(); if (ret) { ALOGE("Failed to initialize crtc %d", res->crtcs[i]); delete crtc; break; } crtcs_.push_back(crtc); } for (int i = 0; !ret && i < res->count_encoders; ++i) { drmModeEncoderPtr e = drmModeGetEncoder(fd_, res->encoders[i]); if (!e) { ALOGE("Failed to get encoder %d", res->encoders[i]); ret = -ENODEV; break; } std::vector<DrmCrtc *> possible_crtcs; DrmCrtc *current_crtc = NULL; for (std::vector<DrmCrtc *>::const_iterator iter = crtcs_.begin(); iter != crtcs_.end(); ++iter) { if ((1 << (*iter)->pipe()) & e->possible_crtcs) possible_crtcs.push_back(*iter); if ((*iter)->id() == e->crtc_id) current_crtc = (*iter); } DrmEncoder *enc = new DrmEncoder(e, current_crtc, possible_crtcs); drmModeFreeEncoder(e); if (!enc) { ALOGE("Failed to allocate enc %d", res->encoders[i]); ret = -ENOMEM; break; } encoders_.push_back(enc); } for (int i = 0; !ret && i < res->count_connectors; ++i) { drmModeConnectorPtr c = drmModeGetConnector(fd_, res->connectors[i]); if (!c) { ALOGE("Failed to get connector %d", res->connectors[i]); ret = -ENODEV; break; } std::vector<DrmEncoder *> possible_encoders; DrmEncoder *current_encoder = NULL; for (int j = 0; j < c->count_encoders; ++j) { for (std::vector<DrmEncoder *>::const_iterator iter = encoders_.begin(); iter != encoders_.end(); ++iter) { if ((*iter)->id() == c->encoders[j]) possible_encoders.push_back((*iter)); if ((*iter)->id() == c->encoder_id) current_encoder = *iter; } } DrmConnector *conn = new DrmConnector(this, c, current_encoder, possible_encoders); drmModeFreeConnector(c); if (!conn) { ALOGE("Failed to allocate conn %d", res->connectors[i]); ret = -ENOMEM; break; } ret = conn->Init(); if (ret) { ALOGE("Init connector %d failed", res->connectors[i]); delete conn; break; } connectors_.push_back(conn); if (conn->built_in() && !found_primary) { conn->set_display(0); found_primary = true; } else { conn->set_display(display_num); ++display_num; } } if (res) drmModeFreeResources(res); // Catch-all for the above loops if (ret) return ret; drmModePlaneResPtr plane_res = drmModeGetPlaneResources(fd_); if (!plane_res) { ALOGE("Failed to get plane resources"); return -ENOENT; } for (uint32_t i = 0; i < plane_res->count_planes; ++i) { drmModePlanePtr p = drmModeGetPlane(fd_, plane_res->planes[i]); if (!p) { ALOGE("Failed to get plane %d", plane_res->planes[i]); ret = -ENODEV; break; } DrmPlane *plane = new DrmPlane(this, p); drmModeFreePlane(p); if (!plane) { ALOGE("Allocate plane %d failed", plane_res->planes[i]); ret = -ENOMEM; break; } ret = plane->Init(); if (ret) { ALOGE("Init plane %d failed", plane_res->planes[i]); delete plane; break; } planes_.push_back(plane); } drmModeFreePlaneResources(plane_res); if (ret) return ret; return compositor_.Init(); }
struct drm_atomic_context *drm_atomic_create_context(struct mp_log *log, int fd, int crtc_id, int connector_id, int osd_plane_id, int video_plane_id) { drmModePlaneRes *plane_res = NULL; drmModeRes *res = NULL; struct drm_object *plane = NULL; struct drm_atomic_context *ctx; int crtc_index = -1; int layercount = -1; int primary_id = 0; int overlay_id = 0; uint64_t value; res = drmModeGetResources(fd); if (!res) { mp_err(log, "Cannot retrieve DRM resources: %s\n", mp_strerror(errno)); goto fail; } plane_res = drmModeGetPlaneResources(fd); if (!plane_res) { mp_err(log, "Cannot retrieve plane ressources: %s\n", mp_strerror(errno)); goto fail; } ctx = talloc_zero(NULL, struct drm_atomic_context); if (!ctx) { mp_err(log, "Out of memory\n"); goto fail; } ctx->fd = fd; ctx->crtc = drm_object_create(log, ctx->fd, crtc_id, DRM_MODE_OBJECT_CRTC); if (!ctx->crtc) { mp_err(log, "Failed to create CRTC object\n"); goto fail; } for (int i = 0; i < res->count_crtcs; i++) { if (res->crtcs[i] == crtc_id) { crtc_index = i; break; } } for (int i = 0; i < res->count_connectors; i++) { drmModeConnector *connector = drmModeGetConnector(fd, res->connectors[i]); if (connector) { if (connector->connector_id == connector_id) ctx->connector = drm_object_create(log, ctx->fd, connector->connector_id, DRM_MODE_OBJECT_CONNECTOR); drmModeFreeConnector(connector); if (ctx->connector) break; } } for (unsigned int j = 0; j < plane_res->count_planes; j++) { drmModePlane *drmplane = drmModeGetPlane(ctx->fd, plane_res->planes[j]); const uint32_t possible_crtcs = drmplane->possible_crtcs; const uint32_t plane_id = drmplane->plane_id; drmModeFreePlane(drmplane); drmplane = NULL; if (possible_crtcs & (1 << crtc_index)) { plane = drm_object_create(log, ctx->fd, plane_id, DRM_MODE_OBJECT_PLANE); if (!plane) { mp_err(log, "Failed to create Plane object from plane ID %d\n", plane_id); goto fail; } if (drm_object_get_property(plane, "TYPE", &value) == -EINVAL) { mp_err(log, "Unable to retrieve type property from plane %d\n", j); goto fail; } if (value != DRM_PLANE_TYPE_CURSOR) { // Skip cursor planes layercount++; if ((!primary_id) && (value == DRM_PLANE_TYPE_PRIMARY)) primary_id = plane_id; if ((!overlay_id) && (value == DRM_PLANE_TYPE_OVERLAY)) overlay_id = plane_id; if (layercount == osd_plane_id) { ctx->osd_plane = plane; continue; } if (layercount == video_plane_id) { ctx->video_plane = plane; continue; } } drm_object_free(plane); plane = NULL; } } // default OSD plane to primary if unspecified if (!ctx->osd_plane) { if (primary_id) { mp_verbose(log, "Using default plane %d for OSD\n", primary_id); ctx->osd_plane = drm_object_create(log, ctx->fd, primary_id, DRM_MODE_OBJECT_PLANE); } else { mp_err(log, "Failed to find OSD plane with id=%d\n", osd_plane_id); goto fail; } } else { mp_verbose(log, "Found OSD plane with ID %d\n", ctx->osd_plane->id); } // default video plane to overlay if unspecified if (!ctx->video_plane) { if (overlay_id) { mp_verbose(log, "Using default plane %d for video\n", overlay_id); ctx->video_plane = drm_object_create(log, ctx->fd, overlay_id, DRM_MODE_OBJECT_PLANE); } else { mp_verbose(log, "Failed to find video plane with id=%d. drmprime-drm hwdec interop will not work\n", video_plane_id); } } else { mp_verbose(log, "Found video plane with ID %d\n", ctx->video_plane->id); } drmModeFreePlaneResources(plane_res); drmModeFreeResources(res); return ctx; fail: if (res) drmModeFreeResources(res); if (plane_res) drmModeFreePlaneResources(plane_res); if (plane) drm_object_free(plane); return NULL; }