Commit e3eb3250 authored by Rob Clark's avatar Rob Clark Committed by Daniel Vetter

drm: add support for tiled/compressed/etc modifier in addfb2

In DRM/KMS we are lacking a good way to deal with tiled/compressed
formats.  Especially in the case of dmabuf/prime buffer sharing, where
we cannot always rely on under-the-hood flags passed to driver specific
gem-create ioctl to pass around these extra flags.

The proposal is to add a per-plane format modifier.  This allows to, if
necessary, use different tiling patters for sub-sampled planes, etc.
The format modifiers are added at the end of the ioctl struct, so for
legacy userspace it will be zero padded.

v1: original
v1.5: increase modifier to 64b

v2: Incorporate review comments from the big thread, plus a few more.

- Add a getcap so that userspace doesn't have to jump through hoops.
- Allow modifiers only when a flag is set. That way drivers know when
  they're dealing with old userspace and need to fish out e.g. tiling
  from other information.
- After rolling out checks for ->modifier to all drivers I've decided
  that this is way too fragile and needs an explicit opt-in flag. So
  do that instead.
- Add a define (just for documentation really) for the "NONE"
  modifier. Imo we don't need to add mask #defines since drivers
  really should only do exact matches against values defined with
  fourcc_mod_code.
- Drop the Samsung tiling modifier on Rob's request since he's not yet
  sure whether that one is accurate.

v3:
- Also add a new ->modifier[] array to struct drm_framebuffer and fill
  it in drm_helper_mode_fill_fb_struct. Requested by Tvrkto Uruslin.
- Remove TODO in comment and add code comment that modifiers should be
  properly documented, requested by Rob.

Cc: Rob Clark <robdclark@gmail.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Daniel Stone <daniel@fooishbar.org>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Michel Dänzer <michel@daenzer.net>
Signed-off-by: Rob Clark <robdclark@gmail.com> (v1.5)
Reviewed-by: default avatarRob Clark <robdclark@gmail.com>
Reviewed-by: default avatarDaniel Stone <daniels@collabora.com>
Acked-by: default avatarDave Airlie <airlied@redhat.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@intel.com>
parent 17d5538d
...@@ -3314,6 +3314,12 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) ...@@ -3314,6 +3314,12 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
return -EINVAL; return -EINVAL;
} }
if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) {
DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n",
r->modifier[i], i);
return -EINVAL;
}
} }
return 0; return 0;
...@@ -3327,7 +3333,7 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, ...@@ -3327,7 +3333,7 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
int ret; int ret;
if (r->flags & ~DRM_MODE_FB_INTERLACED) { if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) {
DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
...@@ -3343,6 +3349,12 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, ...@@ -3343,6 +3349,12 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
if (r->flags & DRM_MODE_FB_MODIFIERS &&
!dev->mode_config.allow_fb_modifiers) {
DRM_DEBUG_KMS("driver does not support fb modifiers\n");
return ERR_PTR(-EINVAL);
}
ret = framebuffer_check(r); ret = framebuffer_check(r);
if (ret) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
......
...@@ -837,6 +837,7 @@ void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, ...@@ -837,6 +837,7 @@ void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
fb->pitches[i] = mode_cmd->pitches[i]; fb->pitches[i] = mode_cmd->pitches[i];
fb->offsets[i] = mode_cmd->offsets[i]; fb->offsets[i] = mode_cmd->offsets[i];
fb->modifier[i] = mode_cmd->modifier[i];
} }
drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth, drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth,
&fb->bits_per_pixel); &fb->bits_per_pixel);
......
...@@ -321,6 +321,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_ ...@@ -321,6 +321,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_
else else
req->value = 64; req->value = 64;
break; break;
case DRM_CAP_ADDFB2_MODIFIERS:
req->value = dev->mode_config.allow_fb_modifiers;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
......
...@@ -202,6 +202,7 @@ struct drm_framebuffer { ...@@ -202,6 +202,7 @@ struct drm_framebuffer {
const struct drm_framebuffer_funcs *funcs; const struct drm_framebuffer_funcs *funcs;
unsigned int pitches[4]; unsigned int pitches[4];
unsigned int offsets[4]; unsigned int offsets[4];
uint64_t modifier[4];
unsigned int width; unsigned int width;
unsigned int height; unsigned int height;
/* depth can be 15 or 16 */ /* depth can be 15 or 16 */
...@@ -1152,6 +1153,9 @@ struct drm_mode_config { ...@@ -1152,6 +1153,9 @@ struct drm_mode_config {
/* whether async page flip is supported or not */ /* whether async page flip is supported or not */
bool async_page_flip; bool async_page_flip;
/* whether the driver supports fb modifiers */
bool allow_fb_modifiers;
/* cursor size */ /* cursor size */
uint32_t cursor_width, cursor_height; uint32_t cursor_width, cursor_height;
}; };
......
...@@ -630,6 +630,7 @@ struct drm_gem_open { ...@@ -630,6 +630,7 @@ struct drm_gem_open {
*/ */
#define DRM_CAP_CURSOR_WIDTH 0x8 #define DRM_CAP_CURSOR_WIDTH 0x8
#define DRM_CAP_CURSOR_HEIGHT 0x9 #define DRM_CAP_CURSOR_HEIGHT 0x9
#define DRM_CAP_ADDFB2_MODIFIERS 0x10
/** DRM_IOCTL_GET_CAP ioctl argument type */ /** DRM_IOCTL_GET_CAP ioctl argument type */
struct drm_get_cap { struct drm_get_cap {
......
...@@ -132,4 +132,36 @@ ...@@ -132,4 +132,36 @@
#define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ #define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */
#define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ #define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */
/*
* Format Modifiers:
*
* Format modifiers describe, typically, a re-ordering or modification
* of the data in a plane of an FB. This can be used to express tiled/
* swizzled formats, or compression, or a combination of the two.
*
* The upper 8 bits of the format modifier are a vendor-id as assigned
* below. The lower 56 bits are assigned as vendor sees fit.
*/
/* Vendor Ids: */
#define DRM_FORMAT_MOD_NONE 0
#define DRM_FORMAT_MOD_VENDOR_INTEL 0x01
#define DRM_FORMAT_MOD_VENDOR_AMD 0x02
#define DRM_FORMAT_MOD_VENDOR_NV 0x03
#define DRM_FORMAT_MOD_VENDOR_SAMSUNG 0x04
#define DRM_FORMAT_MOD_VENDOR_QCOM 0x05
/* add more to the end as needed */
#define fourcc_mod_code(vendor, val) \
((((u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | (val & 0x00ffffffffffffffL))
/*
* Format Modifier tokens:
*
* When adding a new token please document the layout with a code comment,
* similar to the fourcc codes above. drm_fourcc.h is considered the
* authoritative source for all of these.
*/
#endif /* DRM_FOURCC_H */ #endif /* DRM_FOURCC_H */
...@@ -336,6 +336,7 @@ struct drm_mode_fb_cmd { ...@@ -336,6 +336,7 @@ struct drm_mode_fb_cmd {
}; };
#define DRM_MODE_FB_INTERLACED (1<<0) /* for interlaced framebuffers */ #define DRM_MODE_FB_INTERLACED (1<<0) /* for interlaced framebuffers */
#define DRM_MODE_FB_MODIFIERS (1<<1) /* enables ->modifer[] */
struct drm_mode_fb_cmd2 { struct drm_mode_fb_cmd2 {
__u32 fb_id; __u32 fb_id;
...@@ -356,10 +357,18 @@ struct drm_mode_fb_cmd2 { ...@@ -356,10 +357,18 @@ struct drm_mode_fb_cmd2 {
* So it would consist of Y as offsets[0] and UV as * So it would consist of Y as offsets[0] and UV as
* offsets[1]. Note that offsets[0] will generally * offsets[1]. Note that offsets[0] will generally
* be 0 (but this is not required). * be 0 (but this is not required).
*
* To accommodate tiled, compressed, etc formats, a per-plane
* modifier can be specified. The default value of zero
* indicates "native" format as specified by the fourcc.
* Vendor specific modifier token. This allows, for example,
* different tiling/swizzling pattern on different planes.
* See discussion above of DRM_FORMAT_MOD_xxx.
*/ */
__u32 handles[4]; __u32 handles[4];
__u32 pitches[4]; /* pitch for each plane */ __u32 pitches[4]; /* pitch for each plane */
__u32 offsets[4]; /* offset of each plane */ __u32 offsets[4]; /* offset of each plane */
__u64 modifier[4]; /* ie, tiling, compressed (per plane) */
}; };
#define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01 #define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment