drm: Add support for tracking drawable information to core
author=?utf-8?q?Michel_D=C3=A4nzer?= <michel@tungstengraphics.com>
Tue, 24 Oct 2006 13:04:19 +0000 (23:04 +1000)
committerairlied <airlied@linux.ie>
Thu, 7 Dec 2006 04:53:28 +0000 (15:53 +1100)
Actually make the existing ioctls for adding and removing drawables do
something useful, and add another ioctl for the X server to update drawable
information. The only kind of drawable information tracked so far is cliprects.

Only reallocate cliprect memory if the number of cliprects changes.
Also improve diagnostic output.

hook up drm ioctl update draw
export drm_get_drawable_info symbol

Signed-off-by: Dave Airlie <airlied@linux.ie>
drivers/char/drm/drm.h
drivers/char/drm/drmP.h
drivers/char/drm/drm_drawable.c
drivers/char/drm/drm_drv.c
drivers/char/drm/drm_stub.c

index 077d0b1914ab5e90a301f5e9617550af31e9864f..07a699029c3eeb5b56d5eb380e4292d2be17ebb8 100644 (file)
@@ -116,6 +116,14 @@ typedef struct drm_clip_rect {
        unsigned short y2;
 } drm_clip_rect_t;
 
+/**
+ * Drawable information.
+ */
+typedef struct drm_drawable_info {
+       unsigned int num_rects;
+       drm_clip_rect_t *rects;
+} drm_drawable_info_t;
+
 /**
  * Texture region,
  */
@@ -443,6 +451,20 @@ typedef struct drm_draw {
        drm_drawable_t handle;
 } drm_draw_t;
 
+/**
+ * DRM_IOCTL_UPDATE_DRAW ioctl argument type.
+ */
+typedef enum {
+       DRM_DRAWABLE_CLIPRECTS,
+} drm_drawable_info_type_t;
+
+typedef struct drm_update_draw {
+       drm_drawable_t handle;
+       unsigned int type;
+       unsigned int num;
+       unsigned long long data;
+} drm_update_draw_t;
+
 /**
  * DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type.
  */
@@ -625,6 +647,8 @@ typedef struct drm_set_version {
 
 #define DRM_IOCTL_WAIT_VBLANK          DRM_IOWR(0x3a, drm_wait_vblank_t)
 
+#define DRM_IOCTL_UPDATE_DRAW          DRM_IOW(0x3f, drm_update_draw_t)
+
 /**
  * Device specific ioctls should only be in their respective headers
  * The device specific ioctl range is from 0x40 to 0x79.
index d7135d41a42a870272bbc2c80831de948f8fa8ea..01e1f252865918dd73a70740c64b472e29c2a185 100644 (file)
@@ -742,6 +742,15 @@ typedef struct drm_device {
        drm_local_map_t *agp_buffer_map;
        unsigned int agp_buffer_token;
        drm_head_t primary;             /**< primary screen head */
+
+       /** \name Drawable information */
+       /*@{ */
+       spinlock_t drw_lock;
+       unsigned int drw_bitfield_length;
+       u32 *drw_bitfield;
+       unsigned int drw_info_length;
+       drm_drawable_info_t **drw_info;
+       /*@} */
 } drm_device_t;
 
 static __inline__ int drm_core_check_feature(struct drm_device *dev,
@@ -889,6 +898,10 @@ extern int drm_adddraw(struct inode *inode, struct file *filp,
                       unsigned int cmd, unsigned long arg);
 extern int drm_rmdraw(struct inode *inode, struct file *filp,
                      unsigned int cmd, unsigned long arg);
+extern int drm_update_drawable_info(struct inode *inode, struct file *filp,
+                      unsigned int cmd, unsigned long arg);
+extern drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev,
+                                                 drm_drawable_t id);
 
                                /* Authentication IOCTL support (drm_auth.h) */
 extern int drm_getmagic(struct inode *inode, struct file *filp,
index 7857453c4f48cbc1caba399280dbc61a2b5f0e2c..e5f97def26bf3162943cd5020e4f629ac345fe38 100644 (file)
@@ -4,6 +4,7 @@
  *
  * \author Rickard E. (Rik) Faith <faith@valinux.com>
  * \author Gareth Hughes <gareth@valinux.com>
+ * \author Michel Dänzer <michel@tungstengraphics.com>
  */
 
 /*
 #include "drmP.h"
 
 /** No-op. */
-int drm_adddraw(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
+int drm_adddraw(DRM_IOCTL_ARGS)
 {
+       DRM_DEVICE;
+       unsigned long irqflags;
+       int i, j = 0;
        drm_draw_t draw;
 
-       draw.handle = 0;        /* NOOP */
+       spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+       for (i = 0; i < dev->drw_bitfield_length; i++) {
+               u32 bitfield = dev->drw_bitfield[i];
+
+               if (bitfield == ~0)
+                       continue;
+
+               for (; j < sizeof(bitfield); j++)
+                       if (!(bitfield & (1 << j)))
+                               goto done;
+       }
+done:
+
+       if (i == dev->drw_bitfield_length) {
+               u32 *new_bitfield = drm_realloc(dev->drw_bitfield, i * 4,
+                                               (i + 1) * 4, DRM_MEM_BUFS);
+
+               if (!new_bitfield) {
+                       DRM_ERROR("Failed to allocate new drawable bitfield\n");
+                       spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+                       return DRM_ERR(ENOMEM);
+               }
+
+               if (32 * (i + 1) > dev->drw_info_length) {
+                       void *new_info = drm_realloc(dev->drw_info,
+                                                    dev->drw_info_length *
+                                                    sizeof(drm_drawable_info_t*),
+                                                    32 * (i + 1) *
+                                                    sizeof(drm_drawable_info_t*),
+                                                    DRM_MEM_BUFS);
+
+                       if (!new_info) {
+                               DRM_ERROR("Failed to allocate new drawable info"
+                                         " array\n");
+
+                               drm_free(new_bitfield, (i + 1) * 4, DRM_MEM_BUFS);
+                               spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+                               return DRM_ERR(ENOMEM);
+                       }
+
+                       dev->drw_info = (drm_drawable_info_t**)new_info;
+               }
+
+               new_bitfield[i] = 0;
+
+               dev->drw_bitfield = new_bitfield;
+               dev->drw_bitfield_length++;
+       }
+
+       dev->drw_bitfield[i] |= 1 << j;
+
+       draw.handle = i * sizeof(u32) + j;
        DRM_DEBUG("%d\n", draw.handle);
-       if (copy_to_user((drm_draw_t __user *) arg, &draw, sizeof(draw)))
-               return -EFAULT;
+
+       dev->drw_info[draw.handle] = NULL;
+
+       spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+       DRM_COPY_TO_USER_IOCTL((drm_draw_t __user *)data, draw, sizeof(draw));
+
        return 0;
 }
 
 /** No-op. */
-int drm_rmdraw(struct inode *inode, struct file *filp,
-              unsigned int cmd, unsigned long arg)
+int drm_rmdraw(DRM_IOCTL_ARGS)
 {
-       return 0;               /* NOOP */
+       DRM_DEVICE;
+       drm_draw_t draw;
+       unsigned int idx, mod;
+       unsigned long irqflags;
+
+       DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data,
+                                sizeof(draw));
+
+       idx = draw.handle / 32;
+       mod = draw.handle % 32;
+
+       spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+       if (idx >= dev->drw_bitfield_length ||
+           !(dev->drw_bitfield[idx] & (1 << mod))) {
+               DRM_DEBUG("No such drawable %d\n", draw.handle);
+               spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+               return 0;
+       }
+
+       dev->drw_bitfield[idx] &= ~(1 << mod);
+
+       if (idx == (dev->drw_bitfield_length - 1)) {
+               while (idx >= 0 && !dev->drw_bitfield[idx])
+                       --idx;
+
+               if (idx != draw.handle / 32) {
+                       u32 *new_bitfield = drm_realloc(dev->drw_bitfield,
+                                                       dev->drw_bitfield_length * 4,
+                                                       (idx + 1) * 4,
+                                                       DRM_MEM_BUFS);
+
+                       if (new_bitfield || idx == -1) {
+                               dev->drw_bitfield = new_bitfield;
+                               dev->drw_bitfield_length = idx + 1;
+                       }
+               }
+       }
+
+       if (32 * dev->drw_bitfield_length < dev->drw_info_length) {
+               void *new_info = drm_realloc(dev->drw_info,
+                                            dev->drw_info_length *
+                                            sizeof(drm_drawable_info_t*),
+                                            32 * dev->drw_bitfield_length *
+                                            sizeof(drm_drawable_info_t*),
+                                            DRM_MEM_BUFS);
+
+               if (new_info || !dev->drw_bitfield_length) {
+                       dev->drw_info = (drm_drawable_info_t**)new_info;
+                       dev->drw_info_length = 32 * dev->drw_bitfield_length;
+               }
+       }
+
+       spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+       DRM_DEBUG("%d\n", draw.handle);
+       return 0;
+}
+
+int drm_update_drawable_info(DRM_IOCTL_ARGS) {
+       DRM_DEVICE;
+       drm_update_draw_t update;
+       unsigned int id, idx, mod;
+       unsigned long irqflags;
+       drm_drawable_info_t *info;
+       void *new_data;
+
+       DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data,
+                                sizeof(update));
+
+       id = update.handle;
+       idx = id / 32;
+       mod = id % 32;
+
+       spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+       if (idx >= dev->drw_bitfield_length ||
+           !(dev->drw_bitfield[idx] & (1 << mod))) {
+               DRM_ERROR("No such drawable %d\n", update.handle);
+               spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+               return DRM_ERR(EINVAL);
+       }
+
+       info = dev->drw_info[id];
+
+       if (!info) {
+               info = drm_calloc(1, sizeof(drm_drawable_info_t), DRM_MEM_BUFS);
+
+               if (!info) {
+                       DRM_ERROR("Failed to allocate drawable info memory\n");
+                       spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+                       return DRM_ERR(ENOMEM);
+               }
+
+               dev->drw_info[id] = info;
+       }
+
+       switch (update.type) {
+       case DRM_DRAWABLE_CLIPRECTS:
+               if (update.num != info->num_rects) {
+                       new_data = drm_alloc(update.num *
+                                            sizeof(drm_clip_rect_t),
+                                            DRM_MEM_BUFS);
+
+                       if (!new_data) {
+                               DRM_ERROR("Can't allocate cliprect memory\n");
+                               spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+                               return DRM_ERR(ENOMEM);
+                       }
+
+                       info->rects = new_data;
+               }
+
+               if (DRM_COPY_FROM_USER(info->rects,
+                                      (drm_clip_rect_t __user *)
+                                      (unsigned long)update.data,
+                                      update.num * sizeof(drm_clip_rect_t))) {
+                       DRM_ERROR("Can't copy cliprects from userspace\n");
+                       spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+                       return DRM_ERR(EFAULT);
+               }
+
+               if (update.num != info->num_rects) {
+                       drm_free(info->rects, info->num_rects *
+                                sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+                       info->num_rects = update.num;
+               }
+
+               DRM_DEBUG("Updated %d cliprects for drawable %d\n",
+                         info->num_rects, id);
+               break;
+       default:
+               DRM_ERROR("Invalid update type %d\n", update.type);
+               spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+               return DRM_ERR(EINVAL);
+       }
+
+       spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+       return 0;
+}
+
+/**
+ * Caller must hold the drawable spinlock!
+ */
+drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) {
+       unsigned int idx = id / 32, mod = id % 32;
+
+       if (idx >= dev->drw_bitfield_length ||
+           !(dev->drw_bitfield[idx] & (1 << mod))) {
+               DRM_DEBUG("No such drawable %d\n", id);
+               return NULL;
+       }
+
+       return dev->drw_info[id];
 }
+EXPORT_SYMBOL(drm_get_drawable_info);
index b366c5b1bd16713345c56a09e389db70b026e727..59de4a01515f2a81acd194239f19095b32f4d206 100644 (file)
@@ -116,6 +116,8 @@ static drm_ioctl_desc_t drm_ioctls[] = {
        [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
 
        [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
+
+       [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
 };
 
 #define DRIVER_IOCTL_COUNT     ARRAY_SIZE( drm_ioctls )
index 7b1d4e8659baa41e71560f8c02d5592baa66ea4a..6f748e194cf937ed3a1cd0102b449f3583d45f72 100644 (file)
@@ -60,6 +60,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
        int retcode;
 
        spin_lock_init(&dev->count_lock);
+       spin_lock_init(&dev->drw_lock);
        init_timer(&dev->timer);
        mutex_init(&dev->struct_mutex);
        mutex_init(&dev->ctxlist_mutex);