[RFC] drm: add overlays as first class KMS objects

Rob Clark robdclark at gmail.com
Thu Apr 28 10:03:32 PDT 2011


On Mon, Apr 25, 2011 at 5:12 PM, Jesse Barnes <jbarnes at virtuousgeek.org> wrote:
> Looking for comments on this.  Obviously if we're going to add a new type
> of KMS object, we'd better get the ioctl more or less right to begin with,
> which means having all the attributes we'd like to track, plus some
> padding, available from the outset.
>
> So I'd like comments on this; the whole approach may be broken for things
> like OMAP; if so I'd like to hear about it now.  Overall, overlays are
> treated a little like CRTCs, but without associated modes our encoder
> trees hanging off of them.  That is, they can be enabled with a specific
> fb attached at a specific location, but they don't have to worry about
> mode setting, per se (though they do need to have an associated CRTC to
> actually pump their pixels out, post-blend).
>
> Flipping could be done either with the existing ioctl by updating the fb
> base pointer, or through a new flip ioctl similar to what we have already,
> but taking an overlay object instead of a CRTC.

One thing I am wondering about is how to synchronize overlay position
w/ flipping in the primary gfx layer?  Assuming you actually are
flipping in primary layer you'd want a new set of overlay
position/size to take effect on the same vblank that the flip in the
gfx layer happens, because you are probably relying on some
transparent pixels (or colorkey, if anyone still uses that) to be
drawn in the UI layer.

BR,
-R


> Overlays are a bit like half-CRTCs.  They have a location and fb, but
> don't drive outputs directly.  Add support for handling them to the core
> KMS code.
>
> Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
> ---
>  drivers/gpu/drm/drm_crtc.c |  219 ++++++++++++++++++++++++++++++++++++++++++++
>  include/drm/drm.h          |    3 +
>  include/drm/drm_crtc.h     |   61 ++++++++++++
>  include/drm/drm_mode.h     |   39 ++++++++
>  4 files changed, 322 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 799e149..77ff9e0 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -533,6 +533,34 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
>  }
>  EXPORT_SYMBOL(drm_encoder_cleanup);
>
> +void drm_overlay_init(struct drm_device *dev, struct drm_overlay *overlay,
> +                     const struct drm_overlay_funcs *funcs)
> +{
> +       mutex_lock(&dev->mode_config.mutex);
> +
> +       overlay->dev = dev;
> +       drm_mode_object_get(dev, &overlay->base, DRM_MODE_OBJECT_OVERLAY);
> +       overlay->funcs = funcs;
> +
> +       list_add_tail(&overlay->head, &dev->mode_config.overlay_list);
> +       dev->mode_config.num_overlay++;
> +
> +       mutex_unlock(&dev->mode_config.mutex);
> +}
> +EXPORT_SYMBOL(drm_overlay_init);
> +
> +void drm_overlay_cleanup(struct drm_overlay *overlay)
> +{
> +       struct drm_device *dev = overlay->dev;
> +
> +       mutex_lock(&dev->mode_config.mutex);
> +       drm_mode_object_put(dev, &overlay->base);
> +       list_del(&overlay->head);
> +       dev->mode_config.num_overlay--;
> +       mutex_unlock(&dev->mode_config.mutex);
> +}
> +EXPORT_SYMBOL(drm_overlay_cleanup);
> +
>  /**
>  * drm_mode_create - create a new display mode
>  * @dev: DRM device
> @@ -864,6 +892,7 @@ void drm_mode_config_init(struct drm_device *dev)
>        INIT_LIST_HEAD(&dev->mode_config.encoder_list);
>        INIT_LIST_HEAD(&dev->mode_config.property_list);
>        INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
> +       INIT_LIST_HEAD(&dev->mode_config.overlay_list);
>        idr_init(&dev->mode_config.crtc_idr);
>
>        mutex_lock(&dev->mode_config.mutex);
> @@ -1467,6 +1496,196 @@ out:
>  }
>
>  /**
> + * drm_mode_getoverlay_res - get overlay info
> + * @dev: DRM device
> + * @data: ioctl data
> + * @file_priv: DRM file info
> + *
> + * Return an overlay count and set of IDs.
> + */
> +int drm_mode_getoverlay_res(struct drm_device *dev, void *data,
> +                           struct drm_file *file_priv)
> +{
> +       struct drm_mode_get_overlay_res *overlay_resp = data;
> +       struct drm_mode_config *config;
> +       struct drm_overlay *overlay;
> +       uint32_t __user *overlay_ptr;
> +       int copied = 0, ret = 0;
> +
> +       if (!drm_core_check_feature(dev, DRIVER_MODESET))
> +               return -EINVAL;
> +
> +       mutex_lock(&dev->mode_config.mutex);
> +       config = &dev->mode_config;
> +
> +       /*
> +        * This ioctl is called twice, once to determine how much space is
> +        * needed, and the 2nd time to fill it.
> +        */
> +       if (config->num_overlay &&
> +           (overlay_resp->count_overlays >= config->num_overlay)) {
> +               overlay_ptr = (uint32_t *)(unsigned long)overlay_resp->overlay_id_ptr;
> +
> +               list_for_each_entry(overlay, &config->overlay_list, head) {
> +                       if (put_user(overlay->base.id, overlay_ptr + copied)) {
> +                               ret = -EFAULT;
> +                               goto out;
> +                       }
> +                       copied++;
> +               }
> +       }
> +       overlay_resp->count_overlays = config->num_overlay;
> +
> +out:
> +       mutex_unlock(&dev->mode_config.mutex);
> +       return ret;
> +}
> +
> +/**
> + * drm_mode_getoverlay - get overlay info
> + * @dev: DRM device
> + * @data: ioctl data
> + * @file_priv: DRM file info
> + *
> + * Return overlay info, including formats supported, gamma size, any
> + * current fb, etc.
> + */
> +int drm_mode_getoverlay(struct drm_device *dev, void *data,
> +                       struct drm_file *file_priv)
> +{
> +       struct drm_mode_get_overlay *overlay_resp = data;
> +       struct drm_mode_object *obj;
> +       struct drm_overlay *overlay;
> +       uint32_t __user *format_ptr;
> +       int ret = 0;
> +
> +       if (!drm_core_check_feature(dev, DRIVER_MODESET))
> +               return -EINVAL;
> +
> +       mutex_lock(&dev->mode_config.mutex);
> +       obj = drm_mode_object_find(dev, overlay_resp->overlay_id,
> +                                  DRM_MODE_OBJECT_OVERLAY);
> +       if (!obj) {
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +       overlay = obj_to_overlay(obj);
> +
> +       if (overlay->crtc)
> +               overlay_resp->crtc_id = overlay->crtc->base.id;
> +       else
> +               overlay_resp->crtc_id = 0;
> +
> +       if (overlay->fb)
> +               overlay_resp->fb_id = overlay->fb->base.id;
> +       else
> +               overlay_resp->fb_id = 0;
> +
> +       overlay_resp->overlay_id = overlay->base.id;
> +       overlay_resp->possible_crtcs = overlay->possible_crtcs;
> +       overlay_resp->gamma_size = overlay->gamma_size;
> +       overlay_resp->crtc_x = overlay->crtc_x;
> +       overlay_resp->crtc_y = overlay->crtc_y;
> +       overlay_resp->x = overlay->x;
> +       overlay_resp->y = overlay->y;
> +
> +       /*
> +        * This ioctl is called twice, once to determine how much space is
> +        * needed, and the 2nd time to fill it.
> +        */
> +       if (overlay->format_count &&
> +           (overlay_resp->count_format_types >= overlay->format_count)) {
> +               format_ptr = (uint32_t *)(unsigned long)overlay_resp->format_type_ptr;
> +               if (copy_to_user(format_ptr,
> +                                overlay->format_types,
> +                                sizeof(uint32_t) * overlay->format_count)) {
> +                       ret = -EFAULT;
> +                       goto out;
> +               }
> +       }
> +       overlay_resp->count_format_types = overlay->format_count;
> +
> +out:
> +       mutex_unlock(&dev->mode_config.mutex);
> +       return ret;
> +}
> +
> +/**
> + * drm_mode_setoverlay - set up or tear down an overlay
> + * @dev: DRM device
> + * @data: ioctl data*
> + * @file_prive: DRM file info
> + *
> + * Set overlay info, including placement, fb, scaling, and other factors.
> + * Or pass a NULL fb to disable.
> + */
> +int drm_mode_setoverlay(struct drm_device *dev, void *data,
> +                       struct drm_file *file_priv)
> +{
> +       struct drm_mode_set_overlay *overlay_req = data;
> +       struct drm_mode_object *obj;
> +       struct drm_overlay *overlay;
> +       struct drm_crtc *crtc;
> +       struct drm_framebuffer *fb;
> +       int ret = 0;
> +
> +       if (!drm_core_check_feature(dev, DRIVER_MODESET))
> +               return -EINVAL;
> +
> +       mutex_lock(&dev->mode_config.mutex);
> +
> +       /*
> +        * First, find the overlay, crtc, and fb objects.  If not available,
> +        * we don't bother to call the driver.
> +        */
> +       obj = drm_mode_object_find(dev, overlay_req->overlay_id,
> +                                  DRM_MODE_OBJECT_OVERLAY);
> +       if (!obj) {
> +               DRM_DEBUG_KMS("Unknown overlay ID %d\n",
> +                             overlay_req->overlay_id);
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +       overlay = obj_to_overlay(obj);
> +
> +       /* No fb means shut it down */
> +       if (!overlay_req->fb_id) {
> +               overlay->funcs->disable_overlay(overlay);
> +               goto out;
> +       }
> +
> +       obj = drm_mode_object_find(dev, overlay_req->crtc_id,
> +                                  DRM_MODE_OBJECT_CRTC);
> +       if (!obj) {
> +               DRM_DEBUG_KMS("Unknown crtc ID %d\n",
> +                             overlay_req->crtc_id);
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +       crtc = obj_to_crtc(obj);
> +
> +       obj = drm_mode_object_find(dev, overlay_req->fb_id,
> +                                  DRM_MODE_OBJECT_FB);
> +       if (!obj) {
> +               DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
> +                             overlay_req->fb_id);
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +       fb = obj_to_fb(obj);
> +
> +       ret = overlay->funcs->update_overlay(overlay, crtc, fb,
> +                                            overlay_req->crtc_x,
> +                                            overlay_req->crtc_y,
> +                                            overlay_req->x, overlay_req->y);
> +
> +out:
> +       mutex_unlock(&dev->mode_config.mutex);
> +
> +       return ret;
> +}
> +
> +/**
>  * drm_mode_setcrtc - set CRTC configuration
>  * @inode: inode from the ioctl
>  * @filp: file * from the ioctl
> diff --git a/include/drm/drm.h b/include/drm/drm.h
> index 4be33b4..47909af 100644
> --- a/include/drm/drm.h
> +++ b/include/drm/drm.h
> @@ -714,6 +714,9 @@ struct drm_get_cap {
>  #define DRM_IOCTL_MODE_CREATE_DUMB DRM_IOWR(0xB2, struct drm_mode_create_dumb)
>  #define DRM_IOCTL_MODE_MAP_DUMB    DRM_IOWR(0xB3, struct drm_mode_map_dumb)
>  #define DRM_IOCTL_MODE_DESTROY_DUMB    DRM_IOWR(0xB4, struct drm_mode_destroy_dumb)
> +#define DRM_IOCTL_MODE_GETOVERLAYRESOURCES DRM_IOWR(0xB5, struct drm_mode_get_overlay_res)
> +#define DRM_IOCTL_MODE_GETOVERLAY      DRM_IOWR(0xB6, struct drm_mode_get_overlay)
> +#define DRM_IOCTL_MODE_SETOVERLAY      DRM_IOWR(0xB7, struct drm_mode_set_overlay)
>
>  /**
>  * Device specific ioctls should only be in their respective headers
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index b786a24..07a9025 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -44,6 +44,7 @@ struct drm_framebuffer;
>  #define DRM_MODE_OBJECT_PROPERTY 0xb0b0b0b0
>  #define DRM_MODE_OBJECT_FB 0xfbfbfbfb
>  #define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb
> +#define DRM_MODE_OBJECT_OVERLAY 0xeeeeeeee
>
>  struct drm_mode_object {
>        uint32_t id;
> @@ -276,6 +277,7 @@ struct drm_crtc;
>  struct drm_connector;
>  struct drm_encoder;
>  struct drm_pending_vblank_event;
> +struct drm_overlay;
>
>  /**
>  * drm_crtc_funcs - control CRTCs for a given device
> @@ -523,6 +525,57 @@ struct drm_connector {
>  };
>
>  /**
> + * drm_overlay_funcs - driver overlay control functions
> + * @update_overlay: update the overlay configuration
> + */
> +struct drm_overlay_funcs {
> +       int (*update_overlay)(struct drm_overlay *overlay,
> +                             struct drm_crtc *crtc, struct drm_framebuffer *fb,
> +                             int crtc_x, int crtc_y, int x, int y);
> +       void (*disable_overlay)(struct drm_overlay *overlay);
> +};
> +
> +/**
> + * drm_overlay - central DRM overlay control structure
> + * @dev: DRM device this overlay belongs to
> + * @kdev: kernel device
> + * @attr: kdev attributes
> + * @head: for list management
> + * @base: base mode object
> + * @crtc_x: x position of overlay (relative to pipe base)
> + * @crtc_y: y position of overlay
> + * @x: x offset into fb
> + * @y: y offset into fb
> + * @crtc: CRTC this overlay is feeding
> + */
> +struct drm_overlay {
> +       struct drm_device *dev;
> +       struct device kdev;
> +       struct device_attribute *attr;
> +       struct list_head head;
> +
> +       struct drm_mode_object base;
> +
> +       int crtc_x, crtc_y;
> +       int x, y;
> +       uint32_t possible_crtcs;
> +       uint32_t *format_types;
> +       uint32_t format_count;
> +
> +       struct drm_crtc *crtc;
> +       struct drm_framebuffer *fb;
> +
> +       /* CRTC gamma size for reporting to userspace */
> +       uint32_t gamma_size;
> +       uint16_t *gamma_store;
> +
> +       bool enabled;
> +
> +       const struct drm_overlay_funcs *funcs;
> +       void *helper_private;
> +};
> +
> +/**
>  * struct drm_mode_set
>  *
>  * Represents a single crtc the connectors that it drives with what mode
> @@ -576,6 +629,8 @@ struct drm_mode_config {
>        struct list_head connector_list;
>        int num_encoder;
>        struct list_head encoder_list;
> +       int num_overlay;
> +       struct list_head overlay_list;
>
>        int num_crtc;
>        struct list_head crtc_list;
> @@ -628,6 +683,7 @@ struct drm_mode_config {
>  #define obj_to_fb(x) container_of(x, struct drm_framebuffer, base)
>  #define obj_to_property(x) container_of(x, struct drm_property, base)
>  #define obj_to_blob(x) container_of(x, struct drm_property_blob, base)
> +#define obj_to_overlay(x) container_of(x, struct drm_overlay, base)
>
>
>  extern void drm_crtc_init(struct drm_device *dev,
> @@ -647,6 +703,11 @@ extern void drm_encoder_init(struct drm_device *dev,
>                             const struct drm_encoder_funcs *funcs,
>                             int encoder_type);
>
> +extern void drm_overlay_init(struct drm_device *dev,
> +                            struct drm_overlay *overlay,
> +                            const struct drm_overlay_funcs *funcs);
> +extern void drm_overlay_cleanup(struct drm_overlay *overlay);
> +
>  extern void drm_encoder_cleanup(struct drm_encoder *encoder);
>
>  extern char *drm_get_connector_name(struct drm_connector *connector);
> diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
> index ae6b7a3..349052a 100644
> --- a/include/drm/drm_mode.h
> +++ b/include/drm/drm_mode.h
> @@ -120,6 +120,45 @@ struct drm_mode_crtc {
>        struct drm_mode_modeinfo mode;
>  };
>
> +#define DRM_MODE_OVERLAY_FORMAT_YUV422         1 /* YUV 4:2:2 packed */
> +#define DRM_MODE_OVERLAY_FORMAT_RGBX101010     2 /* RGB 10bpc, ign. alpha */
> +#define DRM_MODE_OVERLAY_FORMAT_RGBX888                3 /* Standard x:8:8:8 RGB */
> +#define DRM_MODE_OVERLAY_FORMAT_RGBX161616     4 /* x:16:16:16 float RGB */
> +
> +/* Overlays blend with or override other bits on the CRTC */
> +struct drm_mode_set_overlay {
> +       __u32 overlay_id;
> +       __u32 crtc_id;
> +       __u32 fb_id; /* contains surface format type */
> +
> +       __u32 crtc_x, crtc_y;
> +       __u32 x, y;
> +
> +       /* FIXME: color key/mask, scaling, z-order, other? */
> +};
> +
> +struct drm_mode_get_overlay {
> +       __u64 format_type_ptr;
> +       __u32 overlay_id;
> +
> +       __u32 crtc_id;
> +       __u32 fb_id;
> +
> +       __u32 crtc_x, crtc_y;
> +       __u32 x, y;
> +
> +       __u32 possible_crtcs;
> +       __u32 gamma_size;
> +
> +       __u32 count_format_types;
> +};
> +
> +
> +struct drm_mode_get_overlay_res {
> +       __u64 overlay_id_ptr;
> +       __u32 count_overlays;
> +};
> +
>  #define DRM_MODE_ENCODER_NONE  0
>  #define DRM_MODE_ENCODER_DAC   1
>  #define DRM_MODE_ENCODER_TMDS  2
> --
> 1.7.4.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>


More information about the dri-devel mailing list