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;
}
Beispiel #2
0
/* 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);
}