drm: add support for tiled/compressed/etc modifier in addfb2
authorRob Clark <robdclark@gmail.com>
Thu, 5 Feb 2015 14:41:52 +0000 (14:41 +0000)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 13 Feb 2015 22:28:12 +0000 (23:28 +0100)
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: Rob Clark <robdclark@gmail.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Acked-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_ioctl.c
include/drm/drm_crtc.h
include/uapi/drm/drm.h
include/uapi/drm/drm_fourcc.h
include/uapi/drm/drm_mode.h

index ad2934ba0bd2acd766c6044af16e831d00e79ce4..b15d720eda4ca5ab94c656ed3faa6858bd38a408 100644 (file)
@@ -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);
                        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;
@@ -3327,7 +3333,7 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
        struct drm_framebuffer *fb;
        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);
                return ERR_PTR(-EINVAL);
        }
@@ -3343,6 +3349,12 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
                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);
        if (ret)
                return ERR_PTR(ret);
index b1979e7bdc8862548d3f483eac109bf7959df27e..3053aab968f9b52ccf7f30976a796ee54262d974 100644 (file)
@@ -837,6 +837,7 @@ void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
        for (i = 0; i < 4; i++) {
                fb->pitches[i] = mode_cmd->pitches[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,
                                    &fb->bits_per_pixel);
index 3785d66721f2f6fdba2d134ba8eaa0c9ab8fb416..a6d773a61c2d2527dd6a8262435f4e8e6b3339cb 100644 (file)
@@ -321,6 +321,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_
                else
                        req->value = 64;
                break;
+       case DRM_CAP_ADDFB2_MODIFIERS:
+               req->value = dev->mode_config.allow_fb_modifiers;
+               break;
        default:
                return -EINVAL;
        }
index 0ebd9286b332aa8139bb2a96e91be9d0ebc3d4da..cee54c45eba916aa614de15e73315a89cfc67a65 100644 (file)
@@ -202,6 +202,7 @@ struct drm_framebuffer {
        const struct drm_framebuffer_funcs *funcs;
        unsigned int pitches[4];
        unsigned int offsets[4];
+       uint64_t modifier[4];
        unsigned int width;
        unsigned int height;
        /* depth can be 15 or 16 */
@@ -1152,6 +1153,9 @@ struct drm_mode_config {
        /* whether async page flip is supported or not */
        bool async_page_flip;
 
+       /* whether the driver supports fb modifiers */
+       bool allow_fb_modifiers;
+
        /* cursor size */
        uint32_t cursor_width, cursor_height;
 };
index 01b2d6d0e35529d534ca5d6bd8c3efcbcbd2d838..ff6ef62d084baea9c735768904ec688e96884700 100644 (file)
@@ -630,6 +630,7 @@ struct drm_gem_open {
  */
 #define DRM_CAP_CURSOR_WIDTH           0x8
 #define DRM_CAP_CURSOR_HEIGHT          0x9
+#define DRM_CAP_ADDFB2_MODIFIERS       0x10
 
 /** DRM_IOCTL_GET_CAP ioctl argument type */
 struct drm_get_cap {
index 646ae5f39f42a75b7ac5dcf2cf7cafd51cf3341b..6221096777477c2d34445bcc9c895c4f00ad776d 100644 (file)
 #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 */
 
+
+/*
+ * 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 */
index ca788e01dab20795ea848b0ab9c70ef3d9487743..dbeba949462a60613e3f75b49b74d13c73471134 100644 (file)
@@ -336,6 +336,7 @@ struct drm_mode_fb_cmd {
 };
 
 #define DRM_MODE_FB_INTERLACED (1<<0) /* for interlaced framebuffers */
+#define DRM_MODE_FB_MODIFIERS  (1<<1) /* enables ->modifer[] */
 
 struct drm_mode_fb_cmd2 {
        __u32 fb_id;
@@ -356,10 +357,18 @@ struct drm_mode_fb_cmd2 {
         * So it would consist of Y as offsets[0] and UV as
         * offsets[1].  Note that offsets[0] will generally
         * 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 pitches[4]; /* pitch for 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