drm/i915: add color key support v4
authorJesse Barnes <jbarnes@virtuousgeek.org>
Tue, 3 Jan 2012 16:05:39 +0000 (08:05 -0800)
committerKeith Packard <keithp@keithp.com>
Tue, 3 Jan 2012 17:31:12 +0000 (09:31 -0800)
Add new ioctls for getting and setting the current destination color
key.  This allows for simple overlay display control by matching a color
key value in the primary plane before blending the overlay on top.

v2: remove unnecessary mutex acquire/release around reg accesses
v3: add support for full color key management
v4: fix copy & paste bug in snb_get_colorkey
    don't bother checking min/max values against docs as the docs are likely
    wrong (how could we handle 10bpc surface formats?)

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_sprite.c
include/drm/i915_drm.h

index a9ae374861e788fe7ced3b6cf8f1f129c6e84c86..77dace6a01f62751dec6c94b5a5cbe91b94d590a 100644 (file)
@@ -2305,6 +2305,8 @@ struct drm_ioctl_desc i915_ioctls[] = {
        DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, intel_sprite_get_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
index d791043c8ec1bf5ac638e104fba1511dbc2dfc16..eb44432d79bf649e7067c5fd10f95a80853de164 100644 (file)
 #define DVSSTRIDE(pipe) _PIPE(pipe, _DVSASTRIDE, _DVSBSTRIDE)
 #define DVSPOS(pipe) _PIPE(pipe, _DVSAPOS, _DVSBPOS)
 #define DVSSURF(pipe) _PIPE(pipe, _DVSASURF, _DVSBSURF)
+#define DVSKEYMAX(pipe) _PIPE(pipe, _DVSAKEYMAXVAL, _DVSBKEYMAXVAL)
 #define DVSSIZE(pipe) _PIPE(pipe, _DVSASIZE, _DVSBSIZE)
 #define DVSSCALE(pipe) _PIPE(pipe, _DVSASCALE, _DVSBSCALE)
 #define DVSTILEOFF(pipe) _PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF)
+#define DVSKEYVAL(pipe) _PIPE(pipe, _DVSAKEYVAL, _DVSBKEYVAL)
+#define DVSKEYMSK(pipe) _PIPE(pipe, _DVSAKEYMSK, _DVSBKEYMSK)
 
 #define _SPRA_CTL              0x70280
 #define   SPRITE_ENABLE                        (1<<31)
index ed65121989bf5780480dc15f967534c715c71651..5ac8a164a1ee43deac78d961216f370ac7d49d01 100644 (file)
@@ -26,6 +26,7 @@
 #define __INTEL_DRV_H__
 
 #include <linux/i2c.h>
+#include "i915_drm.h"
 #include "i915_drv.h"
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
@@ -192,6 +193,10 @@ struct intel_plane {
                             uint32_t x, uint32_t y,
                             uint32_t src_w, uint32_t src_h);
        void (*disable_plane)(struct drm_plane *plane);
+       int (*update_colorkey)(struct drm_plane *plane,
+                              struct drm_intel_sprite_colorkey *key);
+       void (*get_colorkey)(struct drm_plane *plane,
+                            struct drm_intel_sprite_colorkey *key);
 };
 
 #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
@@ -414,4 +419,10 @@ extern void sandybridge_update_wm(struct drm_device *dev);
 extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
                                           uint32_t sprite_width,
                                           int pixel_size);
+
+extern int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
+                                    struct drm_file *file_priv);
+extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
+                                    struct drm_file *file_priv);
+
 #endif /* __INTEL_DRV_H__ */
index 6994e06f897564ed8ecfb80706915b8eb11075c3..b26e7c46a75232593c9e630192cff199c8713565 100644 (file)
@@ -95,6 +95,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        /* must disable */
        sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
        sprctl |= SPRITE_ENABLE;
+       sprctl |= SPRITE_DEST_KEY;
 
        /* Sizes are 0 based */
        src_w--;
@@ -153,6 +154,60 @@ ivb_disable_plane(struct drm_plane *plane)
        POSTING_READ(SPRSURF(pipe));
 }
 
+static int
+ivb_update_colorkey(struct drm_plane *plane,
+                   struct drm_intel_sprite_colorkey *key)
+{
+       struct drm_device *dev = plane->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_plane *intel_plane;
+       u32 sprctl;
+       int ret = 0;
+
+       intel_plane = to_intel_plane(plane);
+
+       I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value);
+       I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value);
+       I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask);
+
+       sprctl = I915_READ(SPRCTL(intel_plane->pipe));
+       sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY);
+       if (key->flags & I915_SET_COLORKEY_DESTINATION)
+               sprctl |= SPRITE_DEST_KEY;
+       else if (key->flags & I915_SET_COLORKEY_SOURCE)
+               sprctl |= SPRITE_SOURCE_KEY;
+       I915_WRITE(SPRCTL(intel_plane->pipe), sprctl);
+
+       POSTING_READ(SPRKEYMSK(intel_plane->pipe));
+
+       return ret;
+}
+
+static void
+ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
+{
+       struct drm_device *dev = plane->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_plane *intel_plane;
+       u32 sprctl;
+
+       intel_plane = to_intel_plane(plane);
+
+       key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe));
+       key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe));
+       key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe));
+       key->flags = 0;
+
+       sprctl = I915_READ(SPRCTL(intel_plane->pipe));
+
+       if (sprctl & SPRITE_DEST_KEY)
+               key->flags = I915_SET_COLORKEY_DESTINATION;
+       else if (sprctl & SPRITE_SOURCE_KEY)
+               key->flags = I915_SET_COLORKEY_SOURCE;
+       else
+               key->flags = I915_SET_COLORKEY_NONE;
+}
+
 static void
 snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
                 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
@@ -278,6 +333,60 @@ intel_disable_primary(struct drm_crtc *crtc)
        I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
 }
 
+static int
+snb_update_colorkey(struct drm_plane *plane,
+                   struct drm_intel_sprite_colorkey *key)
+{
+       struct drm_device *dev = plane->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_plane *intel_plane;
+       u32 dvscntr;
+       int ret = 0;
+
+       intel_plane = to_intel_plane(plane);
+
+       I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value);
+       I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value);
+       I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask);
+
+       dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
+       dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY);
+       if (key->flags & I915_SET_COLORKEY_DESTINATION)
+               dvscntr |= DVS_DEST_KEY;
+       else if (key->flags & I915_SET_COLORKEY_SOURCE)
+               dvscntr |= DVS_SOURCE_KEY;
+       I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr);
+
+       POSTING_READ(DVSKEYMSK(intel_plane->pipe));
+
+       return ret;
+}
+
+static void
+snb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
+{
+       struct drm_device *dev = plane->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_plane *intel_plane;
+       u32 dvscntr;
+
+       intel_plane = to_intel_plane(plane);
+
+       key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe));
+       key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe));
+       key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe));
+       key->flags = 0;
+
+       dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
+
+       if (dvscntr & DVS_DEST_KEY)
+               key->flags = I915_SET_COLORKEY_DESTINATION;
+       else if (dvscntr & DVS_SOURCE_KEY)
+               key->flags = I915_SET_COLORKEY_SOURCE;
+       else
+               key->flags = I915_SET_COLORKEY_NONE;
+}
+
 static int
 intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                   struct drm_framebuffer *fb, int crtc_x, int crtc_y,
@@ -437,6 +546,70 @@ static void intel_destroy_plane(struct drm_plane *plane)
        kfree(intel_plane);
 }
 
+int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv)
+{
+       struct drm_intel_sprite_colorkey *set = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_mode_object *obj;
+       struct drm_plane *plane;
+       struct intel_plane *intel_plane;
+       int ret = 0;
+
+       if (!dev_priv)
+               return -EINVAL;
+
+       /* Make sure we don't try to enable both src & dest simultaneously */
+       if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
+               return -EINVAL;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       plane = obj_to_plane(obj);
+       intel_plane = to_intel_plane(plane);
+       ret = intel_plane->update_colorkey(plane, set);
+
+out_unlock:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv)
+{
+       struct drm_intel_sprite_colorkey *get = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_mode_object *obj;
+       struct drm_plane *plane;
+       struct intel_plane *intel_plane;
+       int ret = 0;
+
+       if (!dev_priv)
+               return -EINVAL;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       plane = obj_to_plane(obj);
+       intel_plane = to_intel_plane(plane);
+       intel_plane->get_colorkey(plane, get);
+
+out_unlock:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
 static const struct drm_plane_funcs intel_plane_funcs = {
        .update_plane = intel_update_plane,
        .disable_plane = intel_disable_plane,
@@ -472,10 +645,14 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe)
                intel_plane->max_downscale = 16;
                intel_plane->update_plane = snb_update_plane;
                intel_plane->disable_plane = snb_disable_plane;
+               intel_plane->update_colorkey = snb_update_colorkey;
+               intel_plane->get_colorkey = snb_get_colorkey;
        } else if (IS_GEN7(dev)) {
                intel_plane->max_downscale = 2;
                intel_plane->update_plane = ivb_update_plane;
                intel_plane->disable_plane = ivb_disable_plane;
+               intel_plane->update_colorkey = ivb_update_colorkey;
+               intel_plane->get_colorkey = ivb_get_colorkey;
        }
 
        intel_plane->pipe = pipe;
index 28c0d114cb52dfaebd9756eec62187e3df56491f..1b4da1a9ec0f6d653cd8e4500e124e418ed78b46 100644 (file)
@@ -198,6 +198,8 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_OVERLAY_PUT_IMAGE     0x27
 #define DRM_I915_OVERLAY_ATTRS 0x28
 #define DRM_I915_GEM_EXECBUFFER2       0x29
+#define DRM_I915_GET_SPRITE_COLORKEY   0x2a
+#define DRM_I915_SET_SPRITE_COLORKEY   0x2b
 
 #define DRM_IOCTL_I915_INIT            DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH           DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -239,6 +241,8 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_GEM_MADVISE     DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise)
 #define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE       DRM_IOW(DRM_COMMAND_BASE + DRM_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image)
 #define DRM_IOCTL_I915_OVERLAY_ATTRS   DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs)
+#define DRM_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
+#define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -844,4 +848,36 @@ struct drm_intel_overlay_attrs {
        __u32 gamma5;
 };
 
+/*
+ * Intel sprite handling
+ *
+ * Color keying works with a min/mask/max tuple.  Both source and destination
+ * color keying is allowed.
+ *
+ * Source keying:
+ * Sprite pixels within the min & max values, masked against the color channels
+ * specified in the mask field, will be transparent.  All other pixels will
+ * be displayed on top of the primary plane.  For RGB surfaces, only the min
+ * and mask fields will be used; ranged compares are not allowed.
+ *
+ * Destination keying:
+ * Primary plane pixels that match the min value, masked against the color
+ * channels specified in the mask field, will be replaced by corresponding
+ * pixels from the sprite plane.
+ *
+ * Note that source & destination keying are exclusive; only one can be
+ * active on a given plane.
+ */
+
+#define I915_SET_COLORKEY_NONE         (1<<0) /* disable color key matching */
+#define I915_SET_COLORKEY_DESTINATION  (1<<1)
+#define I915_SET_COLORKEY_SOURCE       (1<<2)
+struct drm_intel_sprite_colorkey {
+       __u32 plane_id;
+       __u32 min_value;
+       __u32 channel_mask;
+       __u32 max_value;
+       __u32 flags;
+};
+
 #endif                         /* _I915_DRM_H_ */