Planes 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.
v2: fix ABI of get_plane - move format_type_ptr to the end
Acked-by: Alan Cox alan@lxorguk.ukuu.org.uk Reviewed-by: Rob Clark rob.clark@linaro.org Reviewed-by: Daniel Vetter daniel.vetter@ffwll.ch Signed-off-by: Jesse Barnes jbarnes@virtuousgeek.org --- drivers/gpu/drm/drm_crtc.c | 257 +++++++++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/drm_drv.c | 3 + include/drm/drm.h | 3 + include/drm/drm_crtc.h | 75 +++++++++++++- include/drm/drm_mode.h | 33 ++++++ 5 files changed, 368 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index fe738f0..804ef12 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -321,6 +321,7 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) { struct drm_device *dev = fb->dev; struct drm_crtc *crtc; + struct drm_plane *plane; struct drm_mode_set set; int ret;
@@ -337,6 +338,15 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) } }
+ list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + if (plane->fb == fb) { + /* should turn off the crtc */ + ret = plane->funcs->disable_plane(plane); + if (ret) + DRM_ERROR("failed to disable plane with busy fb\n"); + } + } + drm_mode_object_put(dev, &fb->base); list_del(&fb->head); dev->mode_config.num_fb--; @@ -535,6 +545,50 @@ void drm_encoder_cleanup(struct drm_encoder *encoder) } EXPORT_SYMBOL(drm_encoder_cleanup);
+int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, + unsigned long possible_crtcs, + const struct drm_plane_funcs *funcs, + uint32_t *formats, uint32_t format_count) +{ + mutex_lock(&dev->mode_config.mutex); + + plane->dev = dev; + drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); + plane->funcs = funcs; + plane->format_types = kmalloc(sizeof(uint32_t) * format_count, + GFP_KERNEL); + if (!plane->format_types) { + DRM_DEBUG_KMS("out of memory when allocating plane\n"); + drm_mode_object_put(dev, &plane->base); + return -ENOMEM; + } + + memcpy(plane->format_types, formats, format_count); + plane->format_count = format_count; + plane->possible_crtcs = possible_crtcs; + + list_add_tail(&plane->head, &dev->mode_config.plane_list); + dev->mode_config.num_plane++; + + mutex_unlock(&dev->mode_config.mutex); + + return 0; +} +EXPORT_SYMBOL(drm_plane_init); + +void drm_plane_cleanup(struct drm_plane *plane) +{ + struct drm_device *dev = plane->dev; + + mutex_lock(&dev->mode_config.mutex); + kfree(plane->format_types); + drm_mode_object_put(dev, &plane->base); + list_del(&plane->head); + dev->mode_config.num_plane--; + mutex_unlock(&dev->mode_config.mutex); +} +EXPORT_SYMBOL(drm_plane_cleanup); + /** * drm_mode_create - create a new display mode * @dev: DRM device @@ -866,6 +920,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.plane_list); idr_init(&dev->mode_config.crtc_idr);
mutex_lock(&dev->mode_config.mutex); @@ -942,6 +997,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) struct drm_encoder *encoder, *enct; struct drm_framebuffer *fb, *fbt; struct drm_property *property, *pt; + struct drm_plane *plane, *plt;
list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, head) { @@ -966,6 +1022,10 @@ void drm_mode_config_cleanup(struct drm_device *dev) crtc->funcs->destroy(crtc); }
+ list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, + head) { + plane->funcs->destroy(plane); + } } EXPORT_SYMBOL(drm_mode_config_cleanup);
@@ -1466,6 +1526,197 @@ out: }
/** + * drm_mode_getplane_res - get plane info + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Return an plane count and set of IDs. + */ +int drm_mode_getplane_res(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_get_plane_res *plane_resp = data; + struct drm_mode_config *config; + struct drm_plane *plane; + uint32_t __user *plane_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_plane && + (plane_resp->count_planes >= config->num_plane)) { + plane_ptr = (uint32_t *)(unsigned long)plane_resp->plane_id_ptr; + + list_for_each_entry(plane, &config->plane_list, head) { + if (put_user(plane->base.id, plane_ptr + copied)) { + ret = -EFAULT; + goto out; + } + copied++; + } + } + plane_resp->count_planes = config->num_plane; + +out: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + +/** + * drm_mode_getplane - get plane info + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Return plane info, including formats supported, gamma size, any + * current fb, etc. + */ +int drm_mode_getplane(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_get_plane *plane_resp = data; + struct drm_mode_object *obj; + struct drm_plane *plane; + 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, plane_resp->plane_id, + DRM_MODE_OBJECT_PLANE); + if (!obj) { + ret = -ENOENT; + goto out; + } + plane = obj_to_plane(obj); + + if (plane->crtc) + plane_resp->crtc_id = plane->crtc->base.id; + else + plane_resp->crtc_id = 0; + + if (plane->fb) + plane_resp->fb_id = plane->fb->base.id; + else + plane_resp->fb_id = 0; + + plane_resp->plane_id = plane->base.id; + plane_resp->possible_crtcs = plane->possible_crtcs; + plane_resp->gamma_size = plane->gamma_size; + + /* + * This ioctl is called twice, once to determine how much space is + * needed, and the 2nd time to fill it. + */ + if (plane->format_count && + (plane_resp->count_format_types >= plane->format_count)) { + format_ptr = (uint32_t *)(unsigned long)plane_resp->format_type_ptr; + if (copy_to_user(format_ptr, + plane->format_types, + sizeof(uint32_t) * plane->format_count)) { + ret = -EFAULT; + goto out; + } + } + plane_resp->count_format_types = plane->format_count; + +out: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + +/** + * drm_mode_setplane - set up or tear down an plane + * @dev: DRM device + * @data: ioctl data* + * @file_prive: DRM file info + * + * Set plane info, including placement, fb, scaling, and other factors. + * Or pass a NULL fb to disable. + */ +int drm_mode_setplane(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_set_plane *plane_req = data; + struct drm_mode_object *obj; + struct drm_plane *plane; + 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 plane, crtc, and fb objects. If not available, + * we don't bother to call the driver. + */ + obj = drm_mode_object_find(dev, plane_req->plane_id, + DRM_MODE_OBJECT_PLANE); + if (!obj) { + DRM_DEBUG_KMS("Unknown plane ID %d\n", + plane_req->plane_id); + ret = -ENOENT; + goto out; + } + plane = obj_to_plane(obj); + + /* No fb means shut it down */ + if (!plane_req->fb_id) { + plane->funcs->disable_plane(plane); + goto out; + } + + obj = drm_mode_object_find(dev, plane_req->crtc_id, + DRM_MODE_OBJECT_CRTC); + if (!obj) { + DRM_DEBUG_KMS("Unknown crtc ID %d\n", + plane_req->crtc_id); + ret = -ENOENT; + goto out; + } + crtc = obj_to_crtc(obj); + + obj = drm_mode_object_find(dev, plane_req->fb_id, + DRM_MODE_OBJECT_FB); + if (!obj) { + DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", + plane_req->fb_id); + ret = -ENOENT; + goto out; + } + fb = obj_to_fb(obj); + + ret = plane->funcs->update_plane(plane, crtc, fb, + plane_req->crtc_x, plane_req->crtc_y, + plane_req->crtc_w, plane_req->crtc_h, + plane_req->src_x, plane_req->src_y, + plane_req->src_w, plane_req->src_h); + if (!ret) { + plane->crtc = crtc; + plane->fb = fb; + } + +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 @@ -1688,11 +1939,13 @@ int drm_mode_addfb(struct drm_device *dev, return -EINVAL;
if ((config->min_width > r->width) || (r->width > config->max_width)) { - DRM_ERROR("mode new framebuffer width not within limits\n"); + DRM_ERROR("bad framebuffer width %d, should be >= %d && <= %d\n", + r->width, config->min_width, config->max_width); return -EINVAL; } if ((config->min_height > r->height) || (r->height > config->max_height)) { - DRM_ERROR("mode new framebuffer height not within limits\n"); + DRM_ERROR("bad framebuffer height %d, should be >= %d && <= %d\n", + r->height, config->min_height, config->max_height); return -EINVAL; }
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 7a87e08..d782bd1 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -135,8 +135,11 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED), diff --git a/include/drm/drm.h b/include/drm/drm.h index 4be33b4..2897967 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_GETPLANERESOURCES DRM_IOWR(0xB5, struct drm_mode_get_plane_res) +#define DRM_IOCTL_MODE_GETPLANE DRM_IOWR(0xB6, struct drm_mode_get_plane) +#define DRM_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct drm_mode_set_plane)
/** * 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 8020798..e20867e 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_PLANE 0xeeeeeeee
struct drm_mode_object { uint32_t id; @@ -278,6 +279,7 @@ struct drm_crtc; struct drm_connector; struct drm_encoder; struct drm_pending_vblank_event; +struct drm_plane;
/** * drm_crtc_funcs - control CRTCs for a given device @@ -536,6 +538,62 @@ struct drm_connector { };
/** + * drm_plane_funcs - driver plane control functions + * @update_plane: update the plane configuration + * @disable_plane: shut down the plane + * @destroy: clean up plane resources + */ +struct drm_plane_funcs { + int (*update_plane)(struct drm_plane *plane, + struct drm_crtc *crtc, struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h); + int (*disable_plane)(struct drm_plane *plane); + void (*destroy)(struct drm_plane *plane); +}; + +/** + * drm_plane - central DRM plane control structure + * @dev: DRM device this plane belongs to + * @head: for list management + * @base: base mode object + * @possible_crtcs: pipes this plane can be bound to + * @format_types: array of formats supported by this plane + * @format_count: number of formats supported + * @crtc: currently bound CRTC + * @fb: currently bound fb + * @gamma_size: size of gamma table + * @gamma_store: gamma correction table + * @enabled: enabled flag + * @funcs: helper functions + * @helper_private: storage for drver layer + */ +struct drm_plane { + struct drm_device *dev; + struct list_head head; + + struct drm_mode_object base; + + 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_plane_funcs *funcs; + void *helper_private; +}; + +/** * struct drm_mode_set * * Represents a single crtc the connectors that it drives with what mode @@ -589,6 +647,8 @@ struct drm_mode_config { struct list_head connector_list; int num_encoder; struct list_head encoder_list; + int num_plane; + struct list_head plane_list;
int num_crtc; struct list_head crtc_list; @@ -641,6 +701,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_plane(x) container_of(x, struct drm_plane, base)
extern void drm_crtc_init(struct drm_device *dev, @@ -660,6 +721,13 @@ extern void drm_encoder_init(struct drm_device *dev, const struct drm_encoder_funcs *funcs, int encoder_type);
+extern int drm_plane_init(struct drm_device *dev, + struct drm_plane *plane, + unsigned long possible_crtcs, + const struct drm_plane_funcs *funcs, + uint32_t *formats, uint32_t format_count); +extern void drm_plane_cleanup(struct drm_plane *plane); + extern void drm_encoder_cleanup(struct drm_encoder *encoder);
extern char *drm_get_connector_name(struct drm_connector *connector); @@ -753,13 +821,18 @@ extern struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, /* IOCTLs */ extern int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); - +extern int drm_mode_getplane_res(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int drm_mode_getcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_getconnector(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_getplane(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int drm_mode_setplane(struct drm_device *dev, + void *data, struct drm_file *file_priv); extern int drm_mode_cursor_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_addfb(struct drm_device *dev, diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index c4961ea..1e4747c 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -120,6 +120,39 @@ struct drm_mode_crtc { struct drm_mode_modeinfo mode; };
+/* Planes blend with or override other bits on the CRTC */ +struct drm_mode_set_plane { + __u32 plane_id; + __u32 crtc_id; + __u32 fb_id; /* fb object contains surface format type */ + + /* Signed dest location allows it to be partially off screen */ + __s32 crtc_x, crtc_y; + __u32 crtc_w, crtc_h; + + /* Source values are 16.16 fixed point */ + __u32 src_x, src_y; + __u32 src_h, src_w; +}; + +struct drm_mode_get_plane { + __u32 plane_id; + + __u32 crtc_id; + __u32 fb_id; + + __u32 possible_crtcs; + __u32 gamma_size; + + __u32 count_format_types; + __u64 format_type_ptr; +}; + +struct drm_mode_get_plane_res { + __u64 plane_id_ptr; + __u32 count_planes; +}; + #define DRM_MODE_ENCODER_NONE 0 #define DRM_MODE_ENCODER_DAC 1 #define DRM_MODE_ENCODER_TMDS 2
To properly support the various plane formats supported by different hardware, the kernel must know the pixel format of a framebuffer object. So add a new ioctl taking a format argument corresponding to a fourcc name from the new drm_fourcc.h header file. Implement the fb creation hooks in terms of the new mode_fb_cmd2 using helpers where the old bpp/depth values are needed.
v2: create DRM specific fourcc header file for sharing with libdrm etc v3: fix rebase failure and use DRM fourcc codes in intel_display.c and update commit message v4: make fb_cmd2 handle field into an array for multi-object formats pull in Ville's fix for the memcpy in drm_plane_init apply Ville's cleanup to zero out fb_cmd2 arg in drm_mode_addfb
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com Acked-by: Alan Cox alan@lxorguk.ukuu.org.uk Reviewed-by: Rob Clark rob.clark@linaro.org Signed-off-by: Jesse Barnes jbarnes@virtuousgeek.org --- drivers/gpu/drm/drm_crtc.c | 111 +++++++++++++++++++++++++++-- drivers/gpu/drm/drm_crtc_helper.c | 51 ++++++++++++- drivers/gpu/drm/drm_drv.c | 1 + drivers/gpu/drm/i915/intel_display.c | 39 ++++++----- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_fb.c | 11 ++-- drivers/gpu/drm/nouveau/nouveau_display.c | 6 +- drivers/gpu/drm/nouveau/nouveau_fb.h | 2 +- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 13 ++-- drivers/gpu/drm/radeon/radeon_display.c | 8 +- drivers/gpu/drm/radeon/radeon_fb.c | 18 +++-- drivers/gpu/drm/radeon/radeon_mode.h | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 22 ++++-- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 1 + drivers/staging/gma500/framebuffer.c | 2 +- include/drm/drm.h | 1 + include/drm/drm_crtc.h | 9 ++- include/drm/drm_crtc_helper.h | 4 +- include/drm/drm_fourcc.h | 63 ++++++++++++++++ include/drm/drm_mode.h | 24 ++++++ 20 files changed, 324 insertions(+), 66 deletions(-) create mode 100644 include/drm/drm_fourcc.h
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 804ef12..30a70a4 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -35,6 +35,7 @@ #include "drmP.h" #include "drm_crtc.h" #include "drm_edid.h" +#include "drm_fourcc.h"
struct drm_prop_enum_list { int type; @@ -563,7 +564,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, return -ENOMEM; }
- memcpy(plane->format_types, formats, format_count); + memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); plane->format_count = format_count; plane->possible_crtcs = possible_crtcs;
@@ -1910,6 +1911,42 @@ out: return ret; }
+/* Original addfb only supported RGB formats, so figure out which one */ +uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) +{ + uint32_t fmt; + + switch (bpp) { + case 8: + fmt = DRM_FOURCC_RGB332; + break; + case 16: + if (depth == 15) + fmt = DRM_FOURCC_RGB555; + else + fmt = DRM_FOURCC_RGB565; + break; + case 24: + fmt = DRM_FOURCC_RGB24; + break; + case 32: + if (depth == 24) + fmt = DRM_FOURCC_RGB24; + else if (depth == 30) + fmt = DRM_INTEL_RGB30; + else + fmt = DRM_FOURCC_RGB32; + break; + default: + DRM_ERROR("bad bpp, assuming RGB24 pixel format\n"); + fmt = DRM_FOURCC_RGB24; + break; + } + + return fmt; +} +EXPORT_SYMBOL(drm_mode_legacy_fb_format); + /** * drm_mode_addfb - add an FB to the graphics configuration * @inode: inode from the ioctl @@ -1930,7 +1967,74 @@ out: int drm_mode_addfb(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_fb_cmd *r = data; + struct drm_mode_fb_cmd *or = data; + struct drm_mode_fb_cmd2 r = {}; + struct drm_mode_config *config = &dev->mode_config; + struct drm_framebuffer *fb; + int ret = 0; + + /* Use new struct with format internally */ + r.fb_id = or->fb_id; + r.width = or->width; + r.height = or->height; + r.pitches[0] = or->pitch; + r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); + r.handles[0] = or->handle; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + if ((config->min_width > r.width) || (r.width > config->max_width)) { + DRM_ERROR("mode new framebuffer width not within limits\n"); + return -EINVAL; + } + if ((config->min_height > r.height) || (r.height > config->max_height)) { + DRM_ERROR("mode new framebuffer height not within limits\n"); + return -EINVAL; + } + + mutex_lock(&dev->mode_config.mutex); + + /* TODO check buffer is sufficiently large */ + /* TODO setup destructor callback */ + + fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); + if (IS_ERR(fb)) { + DRM_ERROR("could not create framebuffer\n"); + ret = PTR_ERR(fb); + goto out; + } + + or->fb_id = fb->base.id; + list_add(&fb->filp_head, &file_priv->fbs); + DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); + +out: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + +/** + * drm_mode_addfb2 - add an FB to the graphics configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Takes mode config lock. + * + * Add a new FB to the specified CRTC, given a user request with format. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_addfb2(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_fb_cmd2 *r = data; struct drm_mode_config *config = &dev->mode_config; struct drm_framebuffer *fb; int ret = 0; @@ -1951,9 +2055,6 @@ int drm_mode_addfb(struct drm_device *dev,
mutex_lock(&dev->mode_config.mutex);
- /* TODO check buffer is sufficiently large */ - /* TODO setup destructor callback */ - fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); if (IS_ERR(fb)) { DRM_ERROR("could not create framebuffer\n"); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index f236644..3e0645c 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -31,6 +31,7 @@
#include "drmP.h" #include "drm_crtc.h" +#include "drm_fourcc.h" #include "drm_crtc_helper.h" #include "drm_fb_helper.h"
@@ -807,14 +808,56 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode) } EXPORT_SYMBOL(drm_helper_connector_dpms);
+/* + * Just need to support RGB formats here for compat with code that doesn't + * use pixel formats directly yet. + */ +void drm_helper_get_fb_bpp_depth(uint32_t format, unsigned int *depth, + int *bpp) +{ + switch (format) { + case DRM_FOURCC_RGB332: + *depth = 8; + *bpp = 8; + break; + case DRM_FOURCC_RGB555: + *depth = 15; + *bpp = 16; + break; + case DRM_FOURCC_RGB565: + *depth = 16; + *bpp = 16; + break; + case DRM_FOURCC_RGB24: + *depth = 24; + *bpp = 32; + break; + case DRM_INTEL_RGB30: + *depth = 30; + *bpp = 32; + break; + case DRM_FOURCC_RGB32: + *depth = 32; + *bpp = 32; + break; + default: + DRM_DEBUG_KMS("unsupported pixel format\n"); + *depth = 0; + *bpp = 0; + break; + } +} +EXPORT_SYMBOL(drm_helper_get_fb_bpp_depth); + int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - struct drm_mode_fb_cmd *mode_cmd) + struct drm_mode_fb_cmd2 *mode_cmd) { fb->width = mode_cmd->width; fb->height = mode_cmd->height; - fb->pitch = mode_cmd->pitch; - fb->bits_per_pixel = mode_cmd->bpp; - fb->depth = mode_cmd->depth; + fb->pitch = mode_cmd->pitches[0]; + drm_helper_get_fb_bpp_depth(mode_cmd->pixel_format, &fb->depth, + &fb->bits_per_pixel); + fb->pixel_format = mode_cmd->pixel_format;
return 0; } diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index d782bd1..6d87a59 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -152,6 +152,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9fa342e..d3b2259 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6279,7 +6279,7 @@ static struct drm_display_mode load_detect_mode = {
static struct drm_framebuffer * intel_framebuffer_create(struct drm_device *dev, - struct drm_mode_fb_cmd *mode_cmd, + struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj) { struct intel_framebuffer *intel_fb; @@ -6321,7 +6321,7 @@ intel_framebuffer_create_for_mode(struct drm_device *dev, int depth, int bpp) { struct drm_i915_gem_object *obj; - struct drm_mode_fb_cmd mode_cmd; + struct drm_mode_fb_cmd2 mode_cmd;
obj = i915_gem_alloc_object(dev, intel_framebuffer_size_for_mode(mode, bpp)); @@ -6330,9 +6330,9 @@ intel_framebuffer_create_for_mode(struct drm_device *dev,
mode_cmd.width = mode->hdisplay; mode_cmd.height = mode->vdisplay; - mode_cmd.depth = depth; - mode_cmd.bpp = bpp; - mode_cmd.pitch = intel_framebuffer_pitch_for_width(mode_cmd.width, bpp); + mode_cmd.pitches[0] = intel_framebuffer_pitch_for_width(mode_cmd.width, + bpp); + mode_cmd.pixel_format = 0;
return intel_framebuffer_create(dev, &mode_cmd, obj); } @@ -7573,7 +7573,7 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = {
int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *intel_fb, - struct drm_mode_fb_cmd *mode_cmd, + struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj) { int ret; @@ -7581,21 +7581,23 @@ int intel_framebuffer_init(struct drm_device *dev, if (obj->tiling_mode == I915_TILING_Y) return -EINVAL;
- if (mode_cmd->pitch & 63) + if (mode_cmd->pitches[0] & 63) return -EINVAL;
- switch (mode_cmd->bpp) { - case 8: - case 16: - /* Only pre-ILK can handle 5:5:5 */ - if (mode_cmd->depth == 15 && !HAS_PCH_SPLIT(dev)) - return -EINVAL; + switch (mode_cmd->pixel_format) { + case DRM_FOURCC_RGB332: + case DRM_FOURCC_RGB565: + case DRM_FOURCC_RGB24: + case DRM_INTEL_RGB30: + /* RGB formats are common across chipsets */ break; - - case 24: - case 32: + case DRM_FOURCC_YUYV: + case DRM_FOURCC_UYVY: + case DRM_FOURCC_YVYU: + case DRM_FOURCC_VYUY: break; default: + DRM_ERROR("unsupported pixel format\n"); return -EINVAL; }
@@ -7613,11 +7615,12 @@ int intel_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * intel_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, - struct drm_mode_fb_cmd *mode_cmd) + struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_i915_gem_object *obj;
- obj = to_intel_bo(drm_gem_object_lookup(dev, filp, mode_cmd->handle)); + obj = to_intel_bo(drm_gem_object_lookup(dev, filp, + mode_cmd->handles[0])); if (&obj->base == NULL) return ERR_PTR(-ENOENT);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bd9a604..23c5622 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -359,7 +359,7 @@ extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
extern int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, - struct drm_mode_fb_cmd *mode_cmd, + struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj); extern int intel_fbdev_init(struct drm_device *dev); extern void intel_fbdev_fini(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index ec49bae..dc1db4f 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -65,7 +65,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, struct drm_i915_private *dev_priv = dev->dev_private; struct fb_info *info; struct drm_framebuffer *fb; - struct drm_mode_fb_cmd mode_cmd; + struct drm_mode_fb_cmd2 mode_cmd; struct drm_i915_gem_object *obj; struct device *device = &dev->pdev->dev; int size, ret; @@ -77,11 +77,12 @@ static int intelfb_create(struct intel_fbdev *ifbdev, mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height;
- mode_cmd.bpp = sizes->surface_bpp; - mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 7) / 8), 64); - mode_cmd.depth = sizes->surface_depth; + mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((sizes->surface_bpp + 7) / + 8), 64); + mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth);
- size = mode_cmd.pitch * mode_cmd.height; + size = mode_cmd.pitches[0] * mode_cmd.height; size = ALIGN(size, PAGE_SIZE); obj = i915_gem_alloc_object(dev, size); if (!obj) { diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index ddbabef..7687a77 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -64,7 +64,7 @@ static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = { int nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nv_fb, - struct drm_mode_fb_cmd *mode_cmd, + struct drm_mode_fb_cmd2 *mode_cmd, struct nouveau_bo *nvbo) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -124,13 +124,13 @@ nouveau_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * nouveau_user_framebuffer_create(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd *mode_cmd) + struct drm_mode_fb_cmd2 *mode_cmd) { struct nouveau_framebuffer *nouveau_fb; struct drm_gem_object *gem; int ret;
- gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); + gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); if (!gem) return ERR_PTR(-ENOENT);
diff --git a/drivers/gpu/drm/nouveau/nouveau_fb.h b/drivers/gpu/drm/nouveau/nouveau_fb.h index 95c843e..f4dd301 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fb.h +++ b/drivers/gpu/drm/nouveau/nouveau_fb.h @@ -45,5 +45,5 @@ nouveau_framebuffer(struct drm_framebuffer *fb) extern const struct drm_mode_config_funcs nouveau_mode_config_funcs;
int nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nouveau_fb, - struct drm_mode_fb_cmd *mode_cmd, struct nouveau_bo *nvbo); + struct drm_mode_fb_cmd2 *mode_cmd, struct nouveau_bo *nvbo); #endif /* __NOUVEAU_FB_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 14a8627..d663065 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -281,7 +281,7 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, struct nouveau_framebuffer *nouveau_fb; struct nouveau_channel *chan; struct nouveau_bo *nvbo; - struct drm_mode_fb_cmd mode_cmd; + struct drm_mode_fb_cmd2 mode_cmd; struct pci_dev *pdev = dev->pdev; struct device *device = &pdev->dev; int size, ret; @@ -289,12 +289,13 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height;
- mode_cmd.bpp = sizes->surface_bpp; - mode_cmd.pitch = mode_cmd.width * (mode_cmd.bpp >> 3); - mode_cmd.pitch = roundup(mode_cmd.pitch, 256); - mode_cmd.depth = sizes->surface_depth; + mode_cmd.pitches[0] = mode_cmd.width * (sizes->surface_bpp >> 3); + mode_cmd.pitches[0] = roundup(mode_cmd.pitches[0], 256);
- size = mode_cmd.pitch * mode_cmd.height; + mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth); + + size = mode_cmd.pitches[0] * mode_cmd.height; size = roundup(size, PAGE_SIZE);
ret = nouveau_gem_new(dev, size, 0, NOUVEAU_GEM_DOMAIN_VRAM, diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 6adb3e5..6caddff 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1113,7 +1113,7 @@ static const struct drm_framebuffer_funcs radeon_fb_funcs = { void radeon_framebuffer_init(struct drm_device *dev, struct radeon_framebuffer *rfb, - struct drm_mode_fb_cmd *mode_cmd, + struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { rfb->obj = obj; @@ -1124,15 +1124,15 @@ radeon_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * radeon_user_framebuffer_create(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd *mode_cmd) + struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *obj; struct radeon_framebuffer *radeon_fb;
- obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); + obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); if (obj == NULL) { dev_err(&dev->pdev->dev, "No GEM object associated to handle 0x%08X, " - "can't create framebuffer\n", mode_cmd->handle); + "can't create framebuffer\n", mode_cmd->handles[0]); return ERR_PTR(-ENOENT); }
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 0b7b486..ea110ad 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -103,7 +103,7 @@ static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj) }
static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, - struct drm_mode_fb_cmd *mode_cmd, + struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **gobj_p) { struct radeon_device *rdev = rfbdev->rdev; @@ -114,13 +114,17 @@ static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, int ret; int aligned_size, size; int height = mode_cmd->height; + u32 bpp, depth; + + drm_helper_get_fb_bpp_depth(mode_cmd->pixel_format, &depth, &bpp);
/* need to align pitch with crtc limits */ - mode_cmd->pitch = radeon_align_pitch(rdev, mode_cmd->width, mode_cmd->bpp, fb_tiled) * ((mode_cmd->bpp + 1) / 8); + mode_cmd->pitches[0] = radeon_align_pitch(rdev, mode_cmd->width, bpp, + fb_tiled) * ((bpp + 1) / 8);
if (rdev->family >= CHIP_R600) height = ALIGN(mode_cmd->height, 8); - size = mode_cmd->pitch * height; + size = mode_cmd->pitches[0] * height; aligned_size = ALIGN(size, PAGE_SIZE); ret = radeon_gem_object_create(rdev, aligned_size, 0, RADEON_GEM_DOMAIN_VRAM, @@ -151,7 +155,7 @@ static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, if (tiling_flags) { ret = radeon_bo_set_tiling_flags(rbo, tiling_flags | RADEON_TILING_SURFACE, - mode_cmd->pitch); + mode_cmd->pitches[0]); if (ret) dev_err(rdev->dev, "FB failed to set tiling flags\n"); } @@ -187,7 +191,7 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev, struct radeon_device *rdev = rfbdev->rdev; struct fb_info *info; struct drm_framebuffer *fb = NULL; - struct drm_mode_fb_cmd mode_cmd; + struct drm_mode_fb_cmd2 mode_cmd; struct drm_gem_object *gobj = NULL; struct radeon_bo *rbo = NULL; struct device *device = &rdev->pdev->dev; @@ -201,8 +205,8 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev, if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev)) sizes->surface_bpp = 32;
- mode_cmd.bpp = sizes->surface_bpp; - mode_cmd.depth = sizes->surface_depth; + mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth);
ret = radeonfb_create_pinned_object(rfbdev, &mode_cmd, &gobj); rbo = gem_to_radeon_bo(gobj); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index ed0178f..dd429a1 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -645,7 +645,7 @@ extern void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green u16 *blue, int regno); void radeon_framebuffer_init(struct drm_device *dev, struct radeon_framebuffer *rfb, - struct drm_mode_fb_cmd *mode_cmd, + struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj);
int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 8b14dfd..a16a84f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -974,7 +974,7 @@ out_err1:
static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd *mode_cmd) + struct drm_mode_fb_cmd2 *mode_cmd2) { struct vmw_private *dev_priv = vmw_priv(dev); struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; @@ -982,16 +982,24 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, struct vmw_surface *surface = NULL; struct vmw_dma_buffer *bo = NULL; struct ttm_base_object *user_obj; + struct drm_mode_fb_cmd mode_cmd; u64 required_size; int ret;
+ mode_cmd.width = mode_cmd2->width; + mode_cmd.height = mode_cmd2->height; + mode_cmd.pitch = mode_cmd2->pitches[0]; + mode_cmd.handle = mode_cmd2->handles[0]; + drm_helper_get_fb_bpp_depth(mode_cmd2->pixel_format, &mode_cmd.depth, + &mode_cmd.bpp); + /** * This code should be conditioned on Screen Objects not being used. * If screen objects are used, we can allocate a GMR to hold the * requested framebuffer. */
- required_size = mode_cmd->pitch * mode_cmd->height; + required_size = mode_cmd.pitch * mode_cmd.height; if (unlikely(required_size > (u64) dev_priv->vram_size)) { DRM_ERROR("VRAM size is too small for requested mode.\n"); return NULL; @@ -1006,7 +1014,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, * command stream using user-space handles. */
- user_obj = ttm_base_object_lookup(tfile, mode_cmd->handle); + user_obj = ttm_base_object_lookup(tfile, mode_cmd.handle); if (unlikely(user_obj == NULL)) { DRM_ERROR("Could not locate requested kms frame buffer.\n"); return ERR_PTR(-ENOENT); @@ -1017,7 +1025,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, */
ret = vmw_user_surface_lookup_handle(dev_priv, tfile, - mode_cmd->handle, &surface); + mode_cmd.handle, &surface); if (ret) goto try_dmabuf;
@@ -1025,7 +1033,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, goto err_not_scanout;
ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, surface, - &vfb, mode_cmd); + &vfb, &mode_cmd);
/* vmw_user_surface_lookup takes one ref so does new_fb */ vmw_surface_unreference(&surface); @@ -1041,14 +1049,14 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, try_dmabuf: DRM_INFO("%s: trying buffer\n", __func__);
- ret = vmw_user_dmabuf_lookup(tfile, mode_cmd->handle, &bo); + ret = vmw_user_dmabuf_lookup(tfile, mode_cmd.handle, &bo); if (ret) { DRM_ERROR("failed to find buffer: %i\n", ret); return ERR_PTR(-ENOENT); }
ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb, - mode_cmd); + &mode_cmd);
/* vmw_user_dmabuf_lookup takes one ref so does new_fb */ vmw_dmabuf_unreference(&bo); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index db0b901..e199adf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -29,6 +29,7 @@ #define VMWGFX_KMS_H_
#include "drmP.h" +#include "drm_crtc_helper.h" #include "vmwgfx_drv.h"
#define VMWGFX_NUM_DISPLAY_UNITS 8 diff --git a/drivers/staging/gma500/framebuffer.c b/drivers/staging/gma500/framebuffer.c index 3f39a37..1e77229 100644 --- a/drivers/staging/gma500/framebuffer.c +++ b/drivers/staging/gma500/framebuffer.c @@ -546,7 +546,7 @@ out_err1: */ static struct drm_framebuffer *psb_user_framebuffer_create (struct drm_device *dev, struct drm_file *filp, - struct drm_mode_fb_cmd *cmd) + struct drm_mode_fb_cmd2 *cmd) { struct gtt_range *r; struct drm_gem_object *obj; diff --git a/include/drm/drm.h b/include/drm/drm.h index 2897967..49d94ed 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h @@ -717,6 +717,7 @@ struct drm_get_cap { #define DRM_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xB5, struct drm_mode_get_plane_res) #define DRM_IOCTL_MODE_GETPLANE DRM_IOWR(0xB6, struct drm_mode_get_plane) #define DRM_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct drm_mode_set_plane) +#define DRM_IOCTL_MODE_ADDFB2 DRM_IOWR(0xB8, struct drm_mode_fb_cmd2)
/** * 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 e20867e..a2fbf33 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -29,9 +29,10 @@ #include <linux/spinlock.h> #include <linux/types.h> #include <linux/idr.h> - #include <linux/fb.h>
+#include <drm/drm_fourcc.h> + struct drm_device; struct drm_mode_set; struct drm_framebuffer; @@ -246,6 +247,7 @@ struct drm_framebuffer { unsigned int depth; int bits_per_pixel; int flags; + uint32_t pixel_format; /* fourcc format */ struct list_head filp_head; /* if you are using the helper */ void *helper_private; @@ -619,7 +621,7 @@ struct drm_mode_set { * struct drm_mode_config_funcs - configure CRTCs for a given screen layout */ struct drm_mode_config_funcs { - struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd); + struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd); void (*output_poll_changed)(struct drm_device *dev); };
@@ -837,6 +839,9 @@ extern int drm_mode_cursor_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_addfb(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_addfb2(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth); extern int drm_mode_rmfb(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_getfb(struct drm_device *dev, diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 73b0712..b4abb33 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -116,8 +116,10 @@ extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder);
extern void drm_helper_connector_dpms(struct drm_connector *connector, int mode);
+extern void drm_helper_get_fb_bpp_depth(uint32_t format, unsigned int *depth, + int *bpp); extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - struct drm_mode_fb_cmd *mode_cmd); + struct drm_mode_fb_cmd2 *mode_cmd);
static inline void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_crtc_helper_funcs *funcs) diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h new file mode 100644 index 0000000..48c3d10 --- /dev/null +++ b/include/drm/drm_fourcc.h @@ -0,0 +1,63 @@ +/* + * Copyright 2011 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef DRM_FOURCC_H +#define DRM_FOURCC_H + +/* + * We don't use the V4L header because + * 1) the fourcc codes are well defined and trivial to construct + * 2) we don't want user apps to have to pull in v4l headers just for fourcc + * 3) the v4l fourcc codes are mixed up with a bunch of other code and are + * part of the v4l API, so changing them to something linux-generic isn't + * feasible + * + * So the below includes the fourcc codes used by the DRM and its drivers, + * along with potential device specific codes. + */ + +#include <linux/types.h> + +#define fourcc_code(a,b,c,d) ((u32)(a) | ((u32)(b) << 8) | \ + ((u32)(c) << 16) | ((u32)(d) << 24)) + +/* RGB codes */ +#define DRM_FOURCC_RGB332 fourcc_code('R','G','B','1') +#define DRM_FOURCC_RGB555 fourcc_code('R','G','B','O') +#define DRM_FOURCC_RGB565 fourcc_code('R','G','B','P') +#define DRM_FOURCC_RGB24 fourcc_code('R','G','B','3') +#define DRM_FOURCC_RGB32 fourcc_code('R','G','B','4') + +#define DRM_FOURCC_BGR24 fourcc_code('B','G','R','3') +#define DRM_FOURCC_BGR32 fourcc_code('B','G','R','4') + +/* YUV codes */ +#define DRM_FOURCC_YUYV fourcc_code('Y', 'U', 'Y', 'V') +#define DRM_FOURCC_YVYU fourcc_code('Y', 'V', 'Y', 'U') +#define DRM_FOURCC_UYVY fourcc_code('U', 'Y', 'V', 'Y') +#define DRM_FOURCC_VYUY fourcc_code('V', 'Y', 'U', 'Y') + +/* DRM specific codes */ +#define DRM_INTEL_RGB30 fourcc_code('R','G','B','0') /* RGB x:10:10:10 */ + +#endif /* DRM_FOURCC_H */ diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index 1e4747c..173aaf7 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -262,6 +262,30 @@ struct drm_mode_fb_cmd { __u32 handle; };
+struct drm_mode_fb_cmd2 { + __u32 fb_id; + __u32 width, height; + __u32 pixel_format; /* fourcc code from videodev2.h */ + + /* + * In case of planar formats, this ioctl allows up to 4 + * buffer objects with offets and pitches per plane. + * The pitch and offset order is dictated by the fourcc, + * e.g. NV12 (http://fourcc.org/yuv.php#NV12) is described as: + * + * YUV 4:2:0 image with a plane of 8 bit Y samples + * followed by an interleaved U/V plane containing + * 8 bit 2x2 subsampled colour difference samples. + * + * So it would consist of Y as offset[0] and UV as + * offeset[1]. Note that offset[0] will generally + * be 0. + */ + __u32 handles[4]; + __u32 pitches[4]; /* pitch for each plane */ + __u32 offsets[4]; /* offset of each plane */ +}; + #define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01 #define DRM_MODE_FB_DIRTY_ANNOTATE_FILL 0x02 #define DRM_MODE_FB_DIRTY_FLAGS 0x03
On Mon, Nov 14, 2011 at 12:21:55PM -0800, Jesse Barnes wrote:
+#define fourcc_code(a,b,c,d) ((u32)(a) | ((u32)(b) << 8) | \
((u32)(c) << 16) | ((u32)(d) << 24))
+/* RGB codes */ +#define DRM_FOURCC_RGB332 fourcc_code('R','G','B','1') +#define DRM_FOURCC_RGB555 fourcc_code('R','G','B','O') +#define DRM_FOURCC_RGB565 fourcc_code('R','G','B','P') +#define DRM_FOURCC_RGB24 fourcc_code('R','G','B','3') +#define DRM_FOURCC_RGB32 fourcc_code('R','G','B','4')
+#define DRM_FOURCC_BGR24 fourcc_code('B','G','R','3') +#define DRM_FOURCC_BGR32 fourcc_code('B','G','R','4')
I'm confused by these. The code suggests RGB/BGR24 are in fact 32bpp formats, so why do we need the RGB/BGR32 variants? If the difference is in the alpha channel, I'd like to document that fact in the name.
Could we call them ARGB8888, XRGB8888, XRGB1555 etc.?
Also the channel and byte order should be documented clearly.
And one other thing. I probably wouldn't call these fourccs since they don't actually match the official fourccs. Not that there is anything sensible defined for RGB formats in the official list anyway. In fact, I'm not sure what we gain by cooking our own fourccs when we know most of them won't match the official list. AFAICS a simple running number would do just as well as the format identifier.
On Mon, 14 Nov 2011 23:16:44 +0200 Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Mon, Nov 14, 2011 at 12:21:55PM -0800, Jesse Barnes wrote:
+#define fourcc_code(a,b,c,d) ((u32)(a) | ((u32)(b) << 8) | \
((u32)(c) << 16) | ((u32)(d) << 24))
+/* RGB codes */ +#define DRM_FOURCC_RGB332 fourcc_code('R','G','B','1') +#define DRM_FOURCC_RGB555 fourcc_code('R','G','B','O') +#define DRM_FOURCC_RGB565 fourcc_code('R','G','B','P') +#define DRM_FOURCC_RGB24 fourcc_code('R','G','B','3') +#define DRM_FOURCC_RGB32 fourcc_code('R','G','B','4')
+#define DRM_FOURCC_BGR24 fourcc_code('B','G','R','3') +#define DRM_FOURCC_BGR32 fourcc_code('B','G','R','4')
I'm confused by these. The code suggests RGB/BGR24 are in fact 32bpp formats, so why do we need the RGB/BGR32 variants? If the difference is in the alpha channel, I'd like to document that fact in the name.
Could we call them ARGB8888, XRGB8888, XRGB1555 etc.?
Yeah, the fourcc naming isn't very good, I'd have no problem changing the names to something more descriptive for 24 and 32. fourcc.org itself seems ambiguous about the 24 bit format....
Also the channel and byte order should be documented clearly.
Supposedly the fourcc code is supposed to provide that?
And one other thing. I probably wouldn't call these fourccs since they don't actually match the official fourccs. Not that there is anything sensible defined for RGB formats in the official list anyway. In fact, I'm not sure what we gain by cooking our own fourccs when we know most of them won't match the official list. AFAICS a simple running number would do just as well as the format identifier.
They seem to match what's at fourcc.org, though I don't see the upper byte documented, and also share values with the v4l stuff, which I was assuming had the right fourcc codes.
If we don't match, we should strive to. I'm just using what I find at fourcc.org and in the v4l code to check...
On Mon, Nov 14, 2011 at 01:22:10PM -0800, Jesse Barnes wrote:
On Mon, 14 Nov 2011 23:16:44 +0200 Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Mon, Nov 14, 2011 at 12:21:55PM -0800, Jesse Barnes wrote:
+#define fourcc_code(a,b,c,d) ((u32)(a) | ((u32)(b) << 8) | \
((u32)(c) << 16) | ((u32)(d) << 24))
+/* RGB codes */ +#define DRM_FOURCC_RGB332 fourcc_code('R','G','B','1') +#define DRM_FOURCC_RGB555 fourcc_code('R','G','B','O') +#define DRM_FOURCC_RGB565 fourcc_code('R','G','B','P') +#define DRM_FOURCC_RGB24 fourcc_code('R','G','B','3') +#define DRM_FOURCC_RGB32 fourcc_code('R','G','B','4')
+#define DRM_FOURCC_BGR24 fourcc_code('B','G','R','3') +#define DRM_FOURCC_BGR32 fourcc_code('B','G','R','4')
I'm confused by these. The code suggests RGB/BGR24 are in fact 32bpp formats, so why do we need the RGB/BGR32 variants? If the difference is in the alpha channel, I'd like to document that fact in the name.
Could we call them ARGB8888, XRGB8888, XRGB1555 etc.?
Yeah, the fourcc naming isn't very good, I'd have no problem changing the names to something more descriptive for 24 and 32. fourcc.org itself seems ambiguous about the 24 bit format....
AFAICS fourcc.org only has three RGB fourccs; RGB2, RGBA and RGBT. None of which specify anything about the bpp or component order. The only thing they seem to specify is which components are present.
Also the channel and byte order should be documented clearly.
Supposedly the fourcc code is supposed to provide that?
As I said the RGB fourccs don't seem to specify either of these. The YUV fourccs generally seem to be specify the byte order. For RGB you typically specify the component order within a pixel. Also AYUV seems to follow the "RGB way", and I think generally three byte 24 bpp RGB formats follow the "YUV way".
But videodev2.h lists big endian variants for 555 and 565 format, which leads me to think they intended everything else to be little endian. Of course I can't be sure because it's not clearly documented. What a mess!
Also reading videodev2.h leads me to think that they intended RGB24/BGR24 to be three byte formats in reality. How I came to that conclusion? Look at the comment about depth. It lists depth=16 for all the 16bpp formats regardless of their actual depth. So I think they meant to write bpp when they wrote depth.
And one other thing. I probably wouldn't call these fourccs since they don't actually match the official fourccs. Not that there is anything sensible defined for RGB formats in the official list anyway. In fact, I'm not sure what we gain by cooking our own fourccs when we know most of them won't match the official list. AFAICS a simple running number would do just as well as the format identifier.
They seem to match what's at fourcc.org, though I don't see the upper byte documented, and also share values with the v4l stuff, which I was assuming had the right fourcc codes.
If we don't match, we should strive to. I'm just using what I find at fourcc.org and in the v4l code to check...
I'm fine with fourccs as long as the defines are named and documented in way that avoids guesswork.
So what I'm thinking is something like this:
DRM_FOURCC_RGB332 ... /* [7:0] R:G:B 3:3:2 */ DRM_FOURCC_XRGB1555 ... /* [15:0] x:R:G:B 1:5:5:5, native endian */ DRM_FOURCC_RGB565 ... /* [15:0] R:G:B 5:6:5, native endian */ DRM_FOURCC_XRGB8888 ... /* [31:0] x:R:G:B 8:8:8:8, native endian */ DRM_FOURCC_XRGB2101010 ... /* [31:0] x:R:G:B 2:10:10:10, native endian */
DRM_FOURCC_RGB888 ... /* [23:0] R:G:B 8:8:8, little endian */ DRM_FOURCC_BGR888 ... /* [23:0] B:G:R 8:8:8, little endian */
DRM_FOURCC_YUYV ... /* [31:0] Cr:Y1:Cb:Y0 8:8:8:8, little endian */ DRM_FOURCC_UYVY ... /* [31:0] Y1:Cr:Y0:Cb 8:8:8:8, little endian */ DRM_FOURCC_YVYU ... /* [31:0] Cb:Y1:Cr:Y0 8:8:8:8, little endian */ DRM_FOURCC_VYUY ... /* [31:0] Y1:Cb:Y0:Cr 8:8:8:8, little endian */
That leaves no room for guesswork.
On Tue, 15 Nov 2011 14:57:02 +0200 Ville Syrjälä ville.syrjala@linux.intel.com wrote:
I'm fine with fourccs as long as the defines are named and documented in way that avoids guesswork.
So what I'm thinking is something like this:
DRM_FOURCC_RGB332 ... /* [7:0] R:G:B 3:3:2 */ DRM_FOURCC_XRGB1555 ... /* [15:0] x:R:G:B 1:5:5:5, native endian */ DRM_FOURCC_RGB565 ... /* [15:0] R:G:B 5:6:5, native endian */ DRM_FOURCC_XRGB8888 ... /* [31:0] x:R:G:B 8:8:8:8, native endian */ DRM_FOURCC_XRGB2101010 ... /* [31:0] x:R:G:B 2:10:10:10, native endian */
DRM_FOURCC_RGB888 ... /* [23:0] R:G:B 8:8:8, little endian */ DRM_FOURCC_BGR888 ... /* [23:0] B:G:R 8:8:8, little endian */
DRM_FOURCC_YUYV ... /* [31:0] Cr:Y1:Cb:Y0 8:8:8:8, little endian */ DRM_FOURCC_UYVY ... /* [31:0] Y1:Cr:Y0:Cb 8:8:8:8, little endian */ DRM_FOURCC_YVYU ... /* [31:0] Cb:Y1:Cr:Y0 8:8:8:8, little endian */ DRM_FOURCC_VYUY ... /* [31:0] Y1:Cb:Y0:Cr 8:8:8:8, little endian */
That leaves no room for guesswork.
Looks great. Want to send Dave an incremental patch? I'll apply the final version to libdrm for use by userland code.
Thanks,
On Tue, Nov 15, 2011 at 08:16:04AM -0800, Jesse Barnes wrote:
On Tue, 15 Nov 2011 14:57:02 +0200 Ville Syrjälä ville.syrjala@linux.intel.com wrote:
I'm fine with fourccs as long as the defines are named and documented in way that avoids guesswork.
So what I'm thinking is something like this:
DRM_FOURCC_RGB332 ... /* [7:0] R:G:B 3:3:2 */ DRM_FOURCC_XRGB1555 ... /* [15:0] x:R:G:B 1:5:5:5, native endian */ DRM_FOURCC_RGB565 ... /* [15:0] R:G:B 5:6:5, native endian */ DRM_FOURCC_XRGB8888 ... /* [31:0] x:R:G:B 8:8:8:8, native endian */ DRM_FOURCC_XRGB2101010 ... /* [31:0] x:R:G:B 2:10:10:10, native endian */
DRM_FOURCC_RGB888 ... /* [23:0] R:G:B 8:8:8, little endian */ DRM_FOURCC_BGR888 ... /* [23:0] B:G:R 8:8:8, little endian */
DRM_FOURCC_YUYV ... /* [31:0] Cr:Y1:Cb:Y0 8:8:8:8, little endian */ DRM_FOURCC_UYVY ... /* [31:0] Y1:Cr:Y0:Cb 8:8:8:8, little endian */ DRM_FOURCC_YVYU ... /* [31:0] Cb:Y1:Cr:Y0 8:8:8:8, little endian */ DRM_FOURCC_VYUY ... /* [31:0] Y1:Cb:Y0:Cr 8:8:8:8, little endian */
That leaves no room for guesswork.
Looks great. Want to send Dave an incremental patch? I'll apply the final version to libdrm for use by userland code.
What I listed there doesn't match what v4l2 has. So I'm not sure what to put in a patch.
It looks like the v4l2 fourccs have explicit endianness (ie. LE or BE). If we follow that, and assuming people still want to use hardware byte swappers, it means user space needs some ifdefs to select the approriate format based on the host endianness. Or, we could do that in the header file itself, so we would provide three definitions for each format LE, BE, and NE (which would point to LE or BE depending on host endianness).
One extra issue I just realized is that the 8bpp and 16bpp v4l2 formats are in fact BGR nor RGB, that is the component order is such that blue occupies the most significant bit, red the lsb. I've never even seen a PC graphics card that supports such formats. Adding insult to injury PIX_FMT_RGB444 is defined the opposite way, ie. matching what most graphics cards would expect.
On Tue, 15 Nov 2011 22:30:36 +0200 Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Tue, Nov 15, 2011 at 08:16:04AM -0800, Jesse Barnes wrote:
On Tue, 15 Nov 2011 14:57:02 +0200 Ville Syrjälä ville.syrjala@linux.intel.com wrote:
I'm fine with fourccs as long as the defines are named and documented in way that avoids guesswork.
So what I'm thinking is something like this:
DRM_FOURCC_RGB332 ... /* [7:0] R:G:B 3:3:2 */ DRM_FOURCC_XRGB1555 ... /* [15:0] x:R:G:B 1:5:5:5, native endian */ DRM_FOURCC_RGB565 ... /* [15:0] R:G:B 5:6:5, native endian */ DRM_FOURCC_XRGB8888 ... /* [31:0] x:R:G:B 8:8:8:8, native endian */ DRM_FOURCC_XRGB2101010 ... /* [31:0] x:R:G:B 2:10:10:10, native endian */
DRM_FOURCC_RGB888 ... /* [23:0] R:G:B 8:8:8, little endian */ DRM_FOURCC_BGR888 ... /* [23:0] B:G:R 8:8:8, little endian */
DRM_FOURCC_YUYV ... /* [31:0] Cr:Y1:Cb:Y0 8:8:8:8, little endian */ DRM_FOURCC_UYVY ... /* [31:0] Y1:Cr:Y0:Cb 8:8:8:8, little endian */ DRM_FOURCC_YVYU ... /* [31:0] Cb:Y1:Cr:Y0 8:8:8:8, little endian */ DRM_FOURCC_VYUY ... /* [31:0] Y1:Cb:Y0:Cr 8:8:8:8, little endian */
That leaves no room for guesswork.
Looks great. Want to send Dave an incremental patch? I'll apply the final version to libdrm for use by userland code.
What I listed there doesn't match what v4l2 has. So I'm not sure what to put in a patch.
It looks like the v4l2 fourccs have explicit endianness (ie. LE or BE). If we follow that, and assuming people still want to use hardware byte swappers, it means user space needs some ifdefs to select the approriate format based on the host endianness. Or, we could do that in the header file itself, so we would provide three definitions for each format LE, BE, and NE (which would point to LE or BE depending on host endianness).
One extra issue I just realized is that the 8bpp and 16bpp v4l2 formats are in fact BGR nor RGB, that is the component order is such that blue occupies the most significant bit, red the lsb. I've never even seen a PC graphics card that supports such formats. Adding insult to injury PIX_FMT_RGB444 is defined the opposite way, ie. matching what most graphics cards would expect.
Heh, well you can just pick whatever makes sense then for RGB, and remove the _FOURCC_ strings to make it clear we're using sane RGB definitions and not some half-specified fourcc stuff.
Thanks,
On Mon, Nov 14, 2011 at 3:16 PM, Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Mon, Nov 14, 2011 at 12:21:55PM -0800, Jesse Barnes wrote:
+#define fourcc_code(a,b,c,d) ((u32)(a) | ((u32)(b) << 8) | \
- ((u32)(c) << 16) | ((u32)(d) << 24))
+/* RGB codes */ +#define DRM_FOURCC_RGB332 fourcc_code('R','G','B','1') +#define DRM_FOURCC_RGB555 fourcc_code('R','G','B','O') +#define DRM_FOURCC_RGB565 fourcc_code('R','G','B','P') +#define DRM_FOURCC_RGB24 fourcc_code('R','G','B','3') +#define DRM_FOURCC_RGB32 fourcc_code('R','G','B','4')
+#define DRM_FOURCC_BGR24 fourcc_code('B','G','R','3') +#define DRM_FOURCC_BGR32 fourcc_code('B','G','R','4')
I'm confused by these. The code suggests RGB/BGR24 are in fact 32bpp formats, so why do we need the RGB/BGR32 variants? If the difference is in the alpha channel, I'd like to document that fact in the name.
Could we call them ARGB8888, XRGB8888, XRGB1555 etc.?
Also the channel and byte order should be documented clearly.
And one other thing. I probably wouldn't call these fourccs since they don't actually match the official fourccs. Not that there is anything sensible defined for RGB formats in the official list anyway. In fact, I'm not sure what we gain by cooking our own fourccs when we know most of them won't match the official list. AFAICS a simple running number would do just as well as the format identifier.
I expect that v4l just made up their own fourcc values for some of the RGB formats.. which isn't a horrible idea, and seems worthwhile to be aligned with names/values that v4l already picked. At least then we don't have two different sets of more or less arbitrary rgb fourcc names..
BR, -R
-- Ville Syrjälä Intel OTC _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
On Mon, Nov 14, 2011 at 12:21:55PM -0800, Jesse Barnes wrote:
+struct drm_mode_fb_cmd2 {
- __u32 fb_id;
- __u32 width, height;
- __u32 pixel_format; /* fourcc code from videodev2.h */
- /*
* In case of planar formats, this ioctl allows up to 4
* buffer objects with offets and pitches per plane.
* The pitch and offset order is dictated by the fourcc,
* e.g. NV12 (http://fourcc.org/yuv.php#NV12) is described as:
*
* YUV 4:2:0 image with a plane of 8 bit Y samples
* followed by an interleaved U/V plane containing
* 8 bit 2x2 subsampled colour difference samples.
*
* So it would consist of Y as offset[0] and UV as
* offeset[1]. Note that offset[0] will generally
* be 0.
*/
- __u32 handles[4];
- __u32 pitches[4]; /* pitch for each plane */
- __u32 offsets[4]; /* offset of each plane */
+};
Hey, what about those interlaced buffers? We talked privately about adding a '__u32 flags' member to both drm_mode_fb_cmd2 and drm_mode_set_plane.
We could stick something like these to those flags: fb_cmd2.flags: #define DRM_MODE_FB_INTERLACED 0x1
set_plane.flags: #define DRM_MODE_PRESENT_TOP_FIELD 0x1 #define DRM_MODE_PRESENT_BOTTOM_FIELD 0x2
On Mon, 14 Nov 2011 23:24:55 +0200 Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Mon, Nov 14, 2011 at 12:21:55PM -0800, Jesse Barnes wrote:
+struct drm_mode_fb_cmd2 {
- __u32 fb_id;
- __u32 width, height;
- __u32 pixel_format; /* fourcc code from videodev2.h */
- /*
* In case of planar formats, this ioctl allows up to 4
* buffer objects with offets and pitches per plane.
* The pitch and offset order is dictated by the fourcc,
* e.g. NV12 (http://fourcc.org/yuv.php#NV12) is described as:
*
* YUV 4:2:0 image with a plane of 8 bit Y samples
* followed by an interleaved U/V plane containing
* 8 bit 2x2 subsampled colour difference samples.
*
* So it would consist of Y as offset[0] and UV as
* offeset[1]. Note that offset[0] will generally
* be 0.
*/
- __u32 handles[4];
- __u32 pitches[4]; /* pitch for each plane */
- __u32 offsets[4]; /* offset of each plane */
+};
Hey, what about those interlaced buffers? We talked privately about adding a '__u32 flags' member to both drm_mode_fb_cmd2 and drm_mode_set_plane.
We could stick something like these to those flags: fb_cmd2.flags: #define DRM_MODE_FB_INTERLACED 0x1
set_plane.flags: #define DRM_MODE_PRESENT_TOP_FIELD 0x1 #define DRM_MODE_PRESENT_BOTTOM_FIELD 0x2
Oh sorry I lost track of the internal discussion.
Are those attributes of the fb or of each object? E.g. could you mix interlaced and non-interlaced buffers in a planar format?
Maybe I need to rename this ioctl to addfb_swissarmyknife :)
On Mon, Nov 14, 2011 at 01:35:57PM -0800, Jesse Barnes wrote:
On Mon, 14 Nov 2011 23:24:55 +0200 Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Mon, Nov 14, 2011 at 12:21:55PM -0800, Jesse Barnes wrote:
+struct drm_mode_fb_cmd2 {
- __u32 fb_id;
- __u32 width, height;
- __u32 pixel_format; /* fourcc code from videodev2.h */
- /*
* In case of planar formats, this ioctl allows up to 4
* buffer objects with offets and pitches per plane.
* The pitch and offset order is dictated by the fourcc,
* e.g. NV12 (http://fourcc.org/yuv.php#NV12) is described as:
*
* YUV 4:2:0 image with a plane of 8 bit Y samples
* followed by an interleaved U/V plane containing
* 8 bit 2x2 subsampled colour difference samples.
*
* So it would consist of Y as offset[0] and UV as
* offeset[1]. Note that offset[0] will generally
* be 0.
*/
- __u32 handles[4];
- __u32 pitches[4]; /* pitch for each plane */
- __u32 offsets[4]; /* offset of each plane */
+};
Hey, what about those interlaced buffers? We talked privately about adding a '__u32 flags' member to both drm_mode_fb_cmd2 and drm_mode_set_plane.
We could stick something like these to those flags: fb_cmd2.flags: #define DRM_MODE_FB_INTERLACED 0x1
set_plane.flags: #define DRM_MODE_PRESENT_TOP_FIELD 0x1 #define DRM_MODE_PRESENT_BOTTOM_FIELD 0x2
Oh sorry I lost track of the internal discussion.
Are those attributes of the fb or of each object? E.g. could you mix interlaced and non-interlaced buffers in a planar format?
I suppose it might be possible that you'd want to treat luma as interlaced and chroma as progressive under some circumstances. But I can't see why simply defining another flag for that wouldn't be enough.
Maybe I need to rename this ioctl to addfb_swissarmyknife :)
Now I'm just waiting for someone to jump in and say that they want independent buffers for each interlaced field :)
Me? I'll be happy with just those two flags members... for now at least ;)
On Tue, 15 Nov 2011 00:37:47 +0200 Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Mon, Nov 14, 2011 at 01:35:57PM -0800, Jesse Barnes wrote:
On Mon, 14 Nov 2011 23:24:55 +0200 Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Mon, Nov 14, 2011 at 12:21:55PM -0800, Jesse Barnes wrote:
+struct drm_mode_fb_cmd2 {
- __u32 fb_id;
- __u32 width, height;
- __u32 pixel_format; /* fourcc code from videodev2.h */
- /*
* In case of planar formats, this ioctl allows up to 4
* buffer objects with offets and pitches per plane.
* The pitch and offset order is dictated by the fourcc,
* e.g. NV12 (http://fourcc.org/yuv.php#NV12) is described as:
*
* YUV 4:2:0 image with a plane of 8 bit Y samples
* followed by an interleaved U/V plane containing
* 8 bit 2x2 subsampled colour difference samples.
*
* So it would consist of Y as offset[0] and UV as
* offeset[1]. Note that offset[0] will generally
* be 0.
*/
- __u32 handles[4];
- __u32 pitches[4]; /* pitch for each plane */
- __u32 offsets[4]; /* offset of each plane */
+};
Hey, what about those interlaced buffers? We talked privately about adding a '__u32 flags' member to both drm_mode_fb_cmd2 and drm_mode_set_plane.
We could stick something like these to those flags: fb_cmd2.flags: #define DRM_MODE_FB_INTERLACED 0x1
set_plane.flags: #define DRM_MODE_PRESENT_TOP_FIELD 0x1 #define DRM_MODE_PRESENT_BOTTOM_FIELD 0x2
Oh sorry I lost track of the internal discussion.
Are those attributes of the fb or of each object? E.g. could you mix interlaced and non-interlaced buffers in a planar format?
I suppose it might be possible that you'd want to treat luma as interlaced and chroma as progressive under some circumstances. But I can't see why simply defining another flag for that wouldn't be enough.
Maybe I need to rename this ioctl to addfb_swissarmyknife :)
Now I'm just waiting for someone to jump in and say that they want independent buffers for each interlaced field :)
Me? I'll be happy with just those two flags members... for now at least ;)
Ok, added, see the latest patchset.
Dave, please pound the gavel on this now and declare it sold before someone asks me to add braille support. :)
Thanks,
On Mon, 2011-11-14 at 12:21 -0800, Jesse Barnes wrote:
Planes 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.
Out of curiosity, lets say you have a *really* stupid hardware overlay that can't do scaling (or even, has limited scaling capabilities), should we provide some way to expose this to userspace?
I've recently looked at the hardware overlay on recent NVIDIA GPUs with the intention of implementing this API in nouveau. However, while there is indeed an overlay, it only accepts a couple of RGB formats and does simple clipping - and *no* scaling that I've found so far.
From traces of VDPAU, NVIDIA themselves appear to do CSC and scaling via
some other method before passing the frame off to the overlay.
Rather disappointing, and seemingly not of too much use. But, I'd like to expose what functionality there is in any case.
Ben.
v2: fix ABI of get_plane - move format_type_ptr to the end
Acked-by: Alan Cox alan@lxorguk.ukuu.org.uk Reviewed-by: Rob Clark rob.clark@linaro.org Reviewed-by: Daniel Vetter daniel.vetter@ffwll.ch Signed-off-by: Jesse Barnes jbarnes@virtuousgeek.org
drivers/gpu/drm/drm_crtc.c | 257 +++++++++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/drm_drv.c | 3 + include/drm/drm.h | 3 + include/drm/drm_crtc.h | 75 +++++++++++++- include/drm/drm_mode.h | 33 ++++++ 5 files changed, 368 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index fe738f0..804ef12 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -321,6 +321,7 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) { struct drm_device *dev = fb->dev; struct drm_crtc *crtc;
- struct drm_plane *plane; struct drm_mode_set set; int ret;
@@ -337,6 +338,15 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) } }
- list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
if (plane->fb == fb) {
/* should turn off the crtc */
ret = plane->funcs->disable_plane(plane);
if (ret)
DRM_ERROR("failed to disable plane with busy fb\n");
}
- }
- drm_mode_object_put(dev, &fb->base); list_del(&fb->head); dev->mode_config.num_fb--;
@@ -535,6 +545,50 @@ void drm_encoder_cleanup(struct drm_encoder *encoder) } EXPORT_SYMBOL(drm_encoder_cleanup);
+int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
unsigned long possible_crtcs,
const struct drm_plane_funcs *funcs,
uint32_t *formats, uint32_t format_count)
+{
- mutex_lock(&dev->mode_config.mutex);
- plane->dev = dev;
- drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
- plane->funcs = funcs;
- plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
GFP_KERNEL);
- if (!plane->format_types) {
DRM_DEBUG_KMS("out of memory when allocating plane\n");
drm_mode_object_put(dev, &plane->base);
return -ENOMEM;
- }
- memcpy(plane->format_types, formats, format_count);
- plane->format_count = format_count;
- plane->possible_crtcs = possible_crtcs;
- list_add_tail(&plane->head, &dev->mode_config.plane_list);
- dev->mode_config.num_plane++;
- mutex_unlock(&dev->mode_config.mutex);
- return 0;
+} +EXPORT_SYMBOL(drm_plane_init);
+void drm_plane_cleanup(struct drm_plane *plane) +{
- struct drm_device *dev = plane->dev;
- mutex_lock(&dev->mode_config.mutex);
- kfree(plane->format_types);
- drm_mode_object_put(dev, &plane->base);
- list_del(&plane->head);
- dev->mode_config.num_plane--;
- mutex_unlock(&dev->mode_config.mutex);
+} +EXPORT_SYMBOL(drm_plane_cleanup);
/**
- drm_mode_create - create a new display mode
- @dev: DRM device
@@ -866,6 +920,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.plane_list); idr_init(&dev->mode_config.crtc_idr);
mutex_lock(&dev->mode_config.mutex);
@@ -942,6 +997,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) struct drm_encoder *encoder, *enct; struct drm_framebuffer *fb, *fbt; struct drm_property *property, *pt;
struct drm_plane *plane, *plt;
list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, head) {
@@ -966,6 +1022,10 @@ void drm_mode_config_cleanup(struct drm_device *dev) crtc->funcs->destroy(crtc); }
- list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
head) {
plane->funcs->destroy(plane);
- }
} EXPORT_SYMBOL(drm_mode_config_cleanup);
@@ -1466,6 +1526,197 @@ out: }
/**
- drm_mode_getplane_res - get plane info
- @dev: DRM device
- @data: ioctl data
- @file_priv: DRM file info
- Return an plane count and set of IDs.
- */
+int drm_mode_getplane_res(struct drm_device *dev, void *data,
struct drm_file *file_priv)
+{
- struct drm_mode_get_plane_res *plane_resp = data;
- struct drm_mode_config *config;
- struct drm_plane *plane;
- uint32_t __user *plane_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_plane &&
(plane_resp->count_planes >= config->num_plane)) {
plane_ptr = (uint32_t *)(unsigned long)plane_resp->plane_id_ptr;
list_for_each_entry(plane, &config->plane_list, head) {
if (put_user(plane->base.id, plane_ptr + copied)) {
ret = -EFAULT;
goto out;
}
copied++;
}
- }
- plane_resp->count_planes = config->num_plane;
+out:
- mutex_unlock(&dev->mode_config.mutex);
- return ret;
+}
+/**
- drm_mode_getplane - get plane info
- @dev: DRM device
- @data: ioctl data
- @file_priv: DRM file info
- Return plane info, including formats supported, gamma size, any
- current fb, etc.
- */
+int drm_mode_getplane(struct drm_device *dev, void *data,
struct drm_file *file_priv)
+{
- struct drm_mode_get_plane *plane_resp = data;
- struct drm_mode_object *obj;
- struct drm_plane *plane;
- 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, plane_resp->plane_id,
DRM_MODE_OBJECT_PLANE);
- if (!obj) {
ret = -ENOENT;
goto out;
- }
- plane = obj_to_plane(obj);
- if (plane->crtc)
plane_resp->crtc_id = plane->crtc->base.id;
- else
plane_resp->crtc_id = 0;
- if (plane->fb)
plane_resp->fb_id = plane->fb->base.id;
- else
plane_resp->fb_id = 0;
- plane_resp->plane_id = plane->base.id;
- plane_resp->possible_crtcs = plane->possible_crtcs;
- plane_resp->gamma_size = plane->gamma_size;
- /*
* This ioctl is called twice, once to determine how much space is
* needed, and the 2nd time to fill it.
*/
- if (plane->format_count &&
(plane_resp->count_format_types >= plane->format_count)) {
format_ptr = (uint32_t *)(unsigned long)plane_resp->format_type_ptr;
if (copy_to_user(format_ptr,
plane->format_types,
sizeof(uint32_t) * plane->format_count)) {
ret = -EFAULT;
goto out;
}
- }
- plane_resp->count_format_types = plane->format_count;
+out:
- mutex_unlock(&dev->mode_config.mutex);
- return ret;
+}
+/**
- drm_mode_setplane - set up or tear down an plane
- @dev: DRM device
- @data: ioctl data*
- @file_prive: DRM file info
- Set plane info, including placement, fb, scaling, and other factors.
- Or pass a NULL fb to disable.
- */
+int drm_mode_setplane(struct drm_device *dev, void *data,
struct drm_file *file_priv)
+{
- struct drm_mode_set_plane *plane_req = data;
- struct drm_mode_object *obj;
- struct drm_plane *plane;
- 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 plane, crtc, and fb objects. If not available,
* we don't bother to call the driver.
*/
- obj = drm_mode_object_find(dev, plane_req->plane_id,
DRM_MODE_OBJECT_PLANE);
- if (!obj) {
DRM_DEBUG_KMS("Unknown plane ID %d\n",
plane_req->plane_id);
ret = -ENOENT;
goto out;
- }
- plane = obj_to_plane(obj);
- /* No fb means shut it down */
- if (!plane_req->fb_id) {
plane->funcs->disable_plane(plane);
goto out;
- }
- obj = drm_mode_object_find(dev, plane_req->crtc_id,
DRM_MODE_OBJECT_CRTC);
- if (!obj) {
DRM_DEBUG_KMS("Unknown crtc ID %d\n",
plane_req->crtc_id);
ret = -ENOENT;
goto out;
- }
- crtc = obj_to_crtc(obj);
- obj = drm_mode_object_find(dev, plane_req->fb_id,
DRM_MODE_OBJECT_FB);
- if (!obj) {
DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
plane_req->fb_id);
ret = -ENOENT;
goto out;
- }
- fb = obj_to_fb(obj);
- ret = plane->funcs->update_plane(plane, crtc, fb,
plane_req->crtc_x, plane_req->crtc_y,
plane_req->crtc_w, plane_req->crtc_h,
plane_req->src_x, plane_req->src_y,
plane_req->src_w, plane_req->src_h);
- if (!ret) {
plane->crtc = crtc;
plane->fb = fb;
- }
+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
@@ -1688,11 +1939,13 @@ int drm_mode_addfb(struct drm_device *dev, return -EINVAL;
if ((config->min_width > r->width) || (r->width > config->max_width)) {
DRM_ERROR("mode new framebuffer width not within limits\n");
DRM_ERROR("bad framebuffer width %d, should be >= %d && <= %d\n",
return -EINVAL; } if ((config->min_height > r->height) || (r->height > config->max_height)) {r->width, config->min_width, config->max_width);
DRM_ERROR("mode new framebuffer height not within limits\n");
DRM_ERROR("bad framebuffer height %d, should be >= %d && <= %d\n",
return -EINVAL; }r->height, config->min_height, config->max_height);
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 7a87e08..d782bd1 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -135,8 +135,11 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED),
diff --git a/include/drm/drm.h b/include/drm/drm.h index 4be33b4..2897967 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_GETPLANERESOURCES DRM_IOWR(0xB5, struct drm_mode_get_plane_res) +#define DRM_IOCTL_MODE_GETPLANE DRM_IOWR(0xB6, struct drm_mode_get_plane) +#define DRM_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct drm_mode_set_plane)
/**
- 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 8020798..e20867e 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_PLANE 0xeeeeeeee
struct drm_mode_object { uint32_t id; @@ -278,6 +279,7 @@ struct drm_crtc; struct drm_connector; struct drm_encoder; struct drm_pending_vblank_event; +struct drm_plane;
/**
- drm_crtc_funcs - control CRTCs for a given device
@@ -536,6 +538,62 @@ struct drm_connector { };
/**
- drm_plane_funcs - driver plane control functions
- @update_plane: update the plane configuration
- @disable_plane: shut down the plane
- @destroy: clean up plane resources
- */
+struct drm_plane_funcs {
- int (*update_plane)(struct drm_plane *plane,
struct drm_crtc *crtc, struct drm_framebuffer *fb,
int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h);
- int (*disable_plane)(struct drm_plane *plane);
- void (*destroy)(struct drm_plane *plane);
+};
+/**
- drm_plane - central DRM plane control structure
- @dev: DRM device this plane belongs to
- @head: for list management
- @base: base mode object
- @possible_crtcs: pipes this plane can be bound to
- @format_types: array of formats supported by this plane
- @format_count: number of formats supported
- @crtc: currently bound CRTC
- @fb: currently bound fb
- @gamma_size: size of gamma table
- @gamma_store: gamma correction table
- @enabled: enabled flag
- @funcs: helper functions
- @helper_private: storage for drver layer
- */
+struct drm_plane {
- struct drm_device *dev;
- struct list_head head;
- struct drm_mode_object base;
- 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_plane_funcs *funcs;
- void *helper_private;
+};
+/**
- struct drm_mode_set
- Represents a single crtc the connectors that it drives with what mode
@@ -589,6 +647,8 @@ struct drm_mode_config { struct list_head connector_list; int num_encoder; struct list_head encoder_list;
int num_plane;
struct list_head plane_list;
int num_crtc; struct list_head crtc_list;
@@ -641,6 +701,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_plane(x) container_of(x, struct drm_plane, base)
extern void drm_crtc_init(struct drm_device *dev, @@ -660,6 +721,13 @@ extern void drm_encoder_init(struct drm_device *dev, const struct drm_encoder_funcs *funcs, int encoder_type);
+extern int drm_plane_init(struct drm_device *dev,
struct drm_plane *plane,
unsigned long possible_crtcs,
const struct drm_plane_funcs *funcs,
uint32_t *formats, uint32_t format_count);
+extern void drm_plane_cleanup(struct drm_plane *plane);
extern void drm_encoder_cleanup(struct drm_encoder *encoder);
extern char *drm_get_connector_name(struct drm_connector *connector); @@ -753,13 +821,18 @@ extern struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, /* IOCTLs */ extern int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int drm_mode_getplane_res(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int drm_mode_getcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_getconnector(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_getplane(struct drm_device *dev,
void *data, struct drm_file *file_priv);
+extern int drm_mode_setplane(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern int drm_mode_cursor_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_addfb(struct drm_device *dev, diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index c4961ea..1e4747c 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -120,6 +120,39 @@ struct drm_mode_crtc { struct drm_mode_modeinfo mode; };
+/* Planes blend with or override other bits on the CRTC */ +struct drm_mode_set_plane {
- __u32 plane_id;
- __u32 crtc_id;
- __u32 fb_id; /* fb object contains surface format type */
- /* Signed dest location allows it to be partially off screen */
- __s32 crtc_x, crtc_y;
- __u32 crtc_w, crtc_h;
- /* Source values are 16.16 fixed point */
- __u32 src_x, src_y;
- __u32 src_h, src_w;
+};
+struct drm_mode_get_plane {
- __u32 plane_id;
- __u32 crtc_id;
- __u32 fb_id;
- __u32 possible_crtcs;
- __u32 gamma_size;
- __u32 count_format_types;
- __u64 format_type_ptr;
+};
+struct drm_mode_get_plane_res {
- __u64 plane_id_ptr;
- __u32 count_planes;
+};
#define DRM_MODE_ENCODER_NONE 0 #define DRM_MODE_ENCODER_DAC 1 #define DRM_MODE_ENCODER_TMDS 2
On Tue, Nov 15, 2011 at 12:40:43PM +1000, Ben Skeggs wrote:
On Mon, 2011-11-14 at 12:21 -0800, Jesse Barnes wrote:
Planes 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.
Out of curiosity, lets say you have a *really* stupid hardware overlay that can't do scaling (or even, has limited scaling capabilities), should we provide some way to expose this to userspace?
I think yes. In fact I'd like drm_plane to replace drm_crtc as far as scanout is concerned. That's how a lot of embedded hardware is laid out already, and I think it's a lot cleaner approach than what we have currently. Stuff like borders then become a simple matter or positioning the "CRTC plane" within the larger active video area, and panel fitters could be exposed through drm_plane scaling.
Se either we need to think ahead more with the GETPLANE ioctl structure, or we could add a PLANE_CAPS ioctl later to expose additional details about the hardware.
On Tue, 15 Nov 2011 13:42:40 +0200 Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Tue, Nov 15, 2011 at 12:40:43PM +1000, Ben Skeggs wrote:
On Mon, 2011-11-14 at 12:21 -0800, Jesse Barnes wrote:
Planes 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.
Out of curiosity, lets say you have a *really* stupid hardware overlay that can't do scaling (or even, has limited scaling capabilities), should we provide some way to expose this to userspace?
I think yes. In fact I'd like drm_plane to replace drm_crtc as far as scanout is concerned. That's how a lot of embedded hardware is laid out already, and I think it's a lot cleaner approach than what we have currently. Stuff like borders then become a simple matter or positioning the "CRTC plane" within the larger active video area, and panel fitters could be exposed through drm_plane scaling.
Se either we need to think ahead more with the GETPLANE ioctl structure, or we could add a PLANE_CAPS ioctl later to expose additional details about the hardware.
There are going to be all sorts of device specific bits we can expose with driver ioctls too (e.g. the alpha blend with restrictions on Intel stuff).
But overall, yes you can definitely support overlays w/o scalers with these interfaces. We could add a plane property to expose the scaling factors supported if that helps, otherwise you could just return -ENOSUPP for any configuration where the crtc size and source size don't match.
dri-devel@lists.freedesktop.org