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

Jesse Barnes jbarnes at virtuousgeek.org
Mon Apr 25 15:12:20 PDT 2011


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.

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



More information about the dri-devel mailing list