From: <da...@ke...> - 2006-09-28 13:44:44
|
bsd-core/drm_drawable.c | 52 ------- libdrm/xf86drm.c | 16 ++ libdrm/xf86drm.h | 5 linux-core/Makefile | 4 linux-core/drmP.h | 20 ++ linux-core/drm_core.h | 8 - linux-core/drm_drawable.c | 57 ------- linux-core/drm_drv.c | 14 + linux-core/drm_irq.c | 155 +++++++++++++++++---- linux-core/drm_lock.c | 11 + linux-core/drm_stub.c | 1 linux-core/i915_drv.c | 4 shared-core/drm.h | 30 +++- shared-core/drm_drawable.c | 329 +++++++++++++++++++++++++++++++++++++++++++++ shared-core/i915_dma.c | 2 shared-core/i915_drm.h | 19 ++ shared-core/i915_drv.h | 22 ++- shared-core/i915_irq.c | 263 ++++++++++++++++++++++++++++++++++- 18 files changed, 861 insertions(+), 151 deletions(-) New commits: diff-tree 881ba569929ceafd42e3c86228b0172099083d1d (from 2627131e5d0c8cd5e3f0db06451c2e7ae7569b1b) Author: Michel Dänzer <mi...@tu...> Date: Wed Sep 27 18:22:10 2006 +0200 i915: Avoid mis-counting vblank interrupts when they're only enabled for pipe A. It looks like 'after a while', I915REG_INT_IDENTITY_R for some reason always has VSYNC_PIPEB_FLAG set in the interrupt handler, even though pipe B is disabled. So we only increase dev->vbl_received if the corresponding bit is also set in dev->vblank_pipe. diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 9db3870..fbc6674 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -153,14 +153,19 @@ irqreturn_t i915_driver_irq_handler(DRM_ DRM_WAKEUP(&dev_priv->irq_queue); if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { - if ((dev_priv->vblank_pipe & + int vblank_pipe = dev_priv->vblank_pipe; + + if ((vblank_pipe & (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { if (temp & VSYNC_PIPEA_FLAG) atomic_inc(&dev->vbl_received); if (temp & VSYNC_PIPEB_FLAG) atomic_inc(&dev->vbl_received2); - } else + } else if (((temp & VSYNC_PIPEA_FLAG) && + (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || + ((temp & VSYNC_PIPEB_FLAG) && + (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) atomic_inc(&dev->vbl_received); DRM_WAKEUP(&dev->vbl_queue); diff-tree 2627131e5d0c8cd5e3f0db06451c2e7ae7569b1b (from 0356fe260dcf80f6d2d20e3384f2a1f4ee7f5b30) Author: Michel Dänzer <mi...@tu...> Date: Mon Sep 18 12:15:38 2006 +0200 i915: Bump minor for swap scheduling ioctl and secondary vblank support. diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index dc9bbc5..de7f822 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -46,9 +46,11 @@ * 1.3: Add vblank support * 1.4: Fix cmdbuffer path, add heap destroy * 1.5: Add vblank pipe configuration + * 1.6: - New ioctl for scheduling buffer swaps on vertical blank + * - Support vertical blank on secondary display pipe */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 5 +#define DRIVER_MINOR 6 #define DRIVER_PATCHLEVEL 0 typedef struct _drm_i915_ring_buffer { diff-tree 0356fe260dcf80f6d2d20e3384f2a1f4ee7f5b30 (from 50a0284a61d4415c0ebdb02decee76ef3115007a) Author: Michel Dänzer <mi...@tu...> Date: Wed Sep 13 08:59:35 2006 +0200 i915_vblank_swap: Add support for DRM_VBLANK_NEXTONMISS. diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index d32f592..9db3870 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -399,7 +399,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) sizeof(swap)); if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | - _DRM_VBLANK_SECONDARY)) { + _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) { DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype); return DRM_ERR(EINVAL); } @@ -408,11 +408,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); - if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) { - DRM_DEBUG("Not scheduling swap for current sequence\n"); - return DRM_ERR(EINVAL); - } - if (!(dev_priv->vblank_pipe & (1 << pipe))) { DRM_ERROR("Invalid pipe %d\n", pipe); return DRM_ERR(EINVAL); @@ -430,21 +425,20 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); - spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); - - switch (seqtype) { - case _DRM_VBLANK_RELATIVE: + if (seqtype == _DRM_VBLANK_RELATIVE) swap.sequence += curseq; - break; - case _DRM_VBLANK_ABSOLUTE: - if ((curseq - swap.sequence) <= (1<<23)) { - spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + + if ((curseq - swap.sequence) <= (1<<23)) { + if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) { + swap.sequence = curseq + 1; + } else { DRM_DEBUG("Missed target sequence\n"); return DRM_ERR(EINVAL); } - break; } + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + list_for_each(list, &dev_priv->vbl_swaps.head) { vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); diff-tree 50a0284a61d4415c0ebdb02decee76ef3115007a (from cf6b2c5299e9be3542d4deddfd05d5811f11d2ef) Author: Michel Dänzer <mi...@tu...> Date: Fri Sep 1 11:48:07 2006 +0200 Only return EBUSY after we've established we need to schedule a new swap. diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 9cd8ece..d32f592 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -395,11 +395,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) return DRM_ERR(EINVAL); } - if (dev_priv->swaps_pending >= 100) { - DRM_DEBUG("Too many swaps queued\n"); - return DRM_ERR(EBUSY); - } - DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, sizeof(swap)); @@ -464,6 +459,11 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + if (dev_priv->swaps_pending >= 100) { + DRM_DEBUG("Too many swaps queued\n"); + return DRM_ERR(EBUSY); + } + vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER); if (!vbl_swap) { diff-tree cf6b2c5299e9be3542d4deddfd05d5811f11d2ef (from 89e323e4900af84cc33219ad24eb0b435a039d23) Author: Michel Dänzer <mi...@tu...> Date: Fri Sep 1 11:35:31 2006 +0200 Core vsync: Don't clobber target sequence number when scheduling signal. It looks like this would have caused signals to always get sent on the next vertical blank, regardless of the sequence number. diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index bd8a9c8..d1a6a6b 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -295,8 +295,6 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) ? &dev->vbl_sigs2 : &dev->vbl_sigs; drm_vbl_sig_t *vbl_sig; - vblwait.reply.sequence = seq; - spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Check if this task has already scheduled the same signal @@ -309,6 +307,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) && vbl_sig->task == current) { spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + vblwait.reply.sequence = seq; goto done; } } @@ -339,6 +338,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + + vblwait.reply.sequence = seq; } else { if (flags & _DRM_VBLANK_SECONDARY) { if (dev->driver->vblank_wait2) diff-tree 89e323e4900af84cc33219ad24eb0b435a039d23 (from 7f09f957d9a61ac107f8fd29128d7899a3e8a228) Author: Michel Dänzer <mi...@tu...> Date: Fri Sep 1 11:27:14 2006 +0200 Core vsync: Add flag DRM_VBLANK_NEXTONMISS. When this flag is set and the target sequence is missed, wait for the next vertical blank instead of returning immediately. diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index cda570d..2ad7080 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -252,6 +252,7 @@ typedef struct _drmTextureRegion { typedef enum { DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ } drmVBlankSeqType; diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index fef0e8d..bd8a9c8 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -249,8 +249,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) drm_wait_vblank_t vblwait; struct timeval now; int ret = 0; - unsigned int flags; - atomic_t *seq; + unsigned int flags, seq; if ((!dev->irq) || (!dev->irq_enabled)) return -EINVAL; @@ -272,12 +271,12 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) return -EINVAL; - seq = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 : - &dev->vbl_received; + seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 + : &dev->vbl_received); switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) { case _DRM_VBLANK_RELATIVE: - vblwait.request.sequence += atomic_read(seq); + vblwait.request.sequence += seq; vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; case _DRM_VBLANK_ABSOLUTE: break; @@ -285,13 +284,18 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) return -EINVAL; } + if ((flags & _DRM_VBLANK_NEXTONMISS) && + (seq - vblwait.request.sequence) <= (1<<23)) { + vblwait.request.sequence = seq + 1; + } + if (flags & _DRM_VBLANK_SIGNAL) { unsigned long irqflags; drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_sigs2 : &dev->vbl_sigs; drm_vbl_sig_t *vbl_sig; - vblwait.reply.sequence = atomic_read(seq); + vblwait.reply.sequence = seq; spin_lock_irqsave(&dev->vbl_lock, irqflags); diff --git a/shared-core/drm.h b/shared-core/drm.h index 614422b..7f90a96 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -551,12 +551,14 @@ typedef struct drm_irq_busid { typedef enum { _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ } drm_vblank_seq_type_t; #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) -#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY) +#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY | \ + _DRM_VBLANK_NEXTONMISS) struct drm_wait_vblank_request { drm_vblank_seq_type_t type; diff-tree 7f09f957d9a61ac107f8fd29128d7899a3e8a228 (from c2bdb76814755c9ac6e66a8815f23af0fe4f3a91) Author: Michel Dänzer <mi...@tu...> Date: Fri Sep 1 11:24:38 2006 +0200 Fix 'sequence has passed' condition in i915_vblank_swap(). diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 68e7c66..9cd8ece 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -442,7 +442,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) swap.sequence += curseq; break; case _DRM_VBLANK_ABSOLUTE: - if ((curseq - swap.sequence) > (1<<23)) { + if ((curseq - swap.sequence) <= (1<<23)) { spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Missed target sequence\n"); return DRM_ERR(EINVAL); diff-tree c2bdb76814755c9ac6e66a8815f23af0fe4f3a91 (from 84b38b63f05e04ade8b1ddfb770047fd86de0d64) Author: Michel Dänzer <mi...@tu...> Date: Thu Aug 31 18:33:04 2006 +0200 Add SAREA fileds for determining which pipe to sync window buffer swaps to. diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index 3a39d53..358b11e 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -104,6 +104,15 @@ typedef struct _drm_i915_sarea { unsigned int depth_tiled; unsigned int rotated_tiled; unsigned int rotated2_tiled; + + int pipeA_x; + int pipeA_y; + int pipeA_w; + int pipeA_h; + int pipeB_x; + int pipeB_y; + int pipeB_w; + int pipeB_h; } drm_i915_sarea_t; /* Flags for perf_boxes diff-tree 84b38b63f05e04ade8b1ddfb770047fd86de0d64 (from 87c57cba1a70221fc570b253bf3b24682ef6b894) Author: Michel Dänzer <mi...@tu...> Date: Thu Aug 31 18:32:08 2006 +0200 Add definition of DRM_VBLANK_SECONDARY. diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 9e71eb6..cda570d 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -252,6 +252,7 @@ typedef struct _drmTextureRegion { typedef enum { DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ } drmVBlankSeqType; diff-tree 87c57cba1a70221fc570b253bf3b24682ef6b894 (from d5a0f107511e128658e2d5e15bd7e6215c507f29) Author: Michel Dänzer <mi...@tu...> Date: Thu Aug 31 18:30:55 2006 +0200 Make handling of dev_priv->vblank_pipe more robust. Initialize it to default value if it hasn't been set by the X server yet. In i915_vblank_pipe_set(), only update dev_priv->vblank_pipe and call i915_enable_interrupt() if the argument passed from userspace is valid to avoid corrupting dev_priv->vblank_pipe on invalid arguments. diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 6f00feb..68e7c66 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -307,7 +307,7 @@ int i915_irq_wait(DRM_IOCTL_ARGS) return i915_wait_irq(dev, irqwait.irq_seq); } -static int i915_enable_interrupt (drm_device_t *dev) +static void i915_enable_interrupt (drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u16 flag; @@ -317,13 +317,8 @@ static int i915_enable_interrupt (drm_de flag |= VSYNC_PIPEA_FLAG; if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) flag |= VSYNC_PIPEB_FLAG; - if (dev_priv->vblank_pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { - DRM_ERROR("%s called with invalid pipe 0x%x\n", - __FUNCTION__, dev_priv->vblank_pipe); - return DRM_ERR(EINVAL); - } + I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag); - return 0; } /* Set the vblank monitor pipe @@ -342,8 +337,17 @@ int i915_vblank_pipe_set(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data, sizeof(pipe)); + if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { + DRM_ERROR("%s called with invalid pipe 0x%x\n", + __FUNCTION__, pipe.pipe); + return DRM_ERR(EINVAL); + } + dev_priv->vblank_pipe = pipe.pipe; - return i915_enable_interrupt (dev); + + i915_enable_interrupt (dev); + + return 0; } int i915_vblank_pipe_get(DRM_IOCTL_ARGS) @@ -505,6 +509,8 @@ void i915_driver_irq_postinstall(drm_dev INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); dev_priv->swaps_pending = 0; + if (!dev_priv->vblank_pipe) + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); } diff-tree d5a0f107511e128658e2d5e15bd7e6215c507f29 (from df7551ef7334d728ec0371423661bb403d3e270a) Author: Michel Dänzer <mi...@tu...> Date: Wed Aug 30 19:33:28 2006 +0200 DRM_I915_VBLANK_SWAP ioctl: Take drm_vblank_seq_type_t instead of pipe number. Handle relative as well as absolute target sequence numbers. Return error if target sequence has already passed, so userspace can deal with this situation as it sees fit. On success, return the sequence number of the vertical blank when the buffer swap is expected to take place. Also add DRM_IOCTL_I915_VBLANK_SWAP definition for userspace code that may want to use ioctl() instead of drmCommandWriteRead(). diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index 7e4ba13..3a39d53 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -149,6 +149,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t) #define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t) #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) +#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) /* Allow drivers to submit batchbuffers directly to hardware, relying @@ -249,7 +250,7 @@ typedef struct drm_i915_vblank_pipe { */ typedef struct drm_i915_vblank_swap { drm_drawable_t drawable; - unsigned int pipe; + drm_vblank_seq_type_t seqtype; unsigned int sequence; } drm_i915_vblank_swap_t; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 39d8c38..6f00feb 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -378,7 +378,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_vblank_swap_t swap; drm_i915_vbl_swap_t *vbl_swap; - unsigned int irqflags; + unsigned int pipe, seqtype, irqflags, curseq; struct list_head *list; if (!dev_priv) { @@ -399,8 +399,23 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, sizeof(swap)); - if (swap.pipe > 1 || !(dev_priv->vblank_pipe & (1 << swap.pipe))) { - DRM_ERROR("Invalid pipe %d\n", swap.pipe); + if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | + _DRM_VBLANK_SECONDARY)) { + DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype); + return DRM_ERR(EINVAL); + } + + pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; + + seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); + + if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) { + DRM_DEBUG("Not scheduling swap for current sequence\n"); + return DRM_ERR(EINVAL); + } + + if (!(dev_priv->vblank_pipe & (1 << pipe))) { + DRM_ERROR("Invalid pipe %d\n", pipe); return DRM_ERR(EINVAL); } @@ -414,13 +429,28 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + switch (seqtype) { + case _DRM_VBLANK_RELATIVE: + swap.sequence += curseq; + break; + case _DRM_VBLANK_ABSOLUTE: + if ((curseq - swap.sequence) > (1<<23)) { + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_DEBUG("Missed target sequence\n"); + return DRM_ERR(EINVAL); + } + break; + } + list_for_each(list, &dev_priv->vbl_swaps.head) { vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); if (vbl_swap->drw_id == swap.drawable && - vbl_swap->pipe == swap.pipe && + vbl_swap->pipe == pipe && vbl_swap->sequence == swap.sequence) { spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Already scheduled\n"); @@ -440,7 +470,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) DRM_DEBUG("\n"); vbl_swap->drw_id = swap.drawable; - vbl_swap->pipe = swap.pipe; + vbl_swap->pipe = pipe; vbl_swap->sequence = swap.sequence; spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); @@ -450,6 +480,9 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap, + sizeof(swap)); + return 0; } diff-tree df7551ef7334d728ec0371423661bb403d3e270a (from d04751facea36cb888c7510b126658fdbc4277d5) Author: Michel Dänzer <mi...@tu...> Date: Wed Aug 30 19:24:04 2006 +0200 Change first valid DRM drawable ID to be 1 instead of 0. This makes it easier for userspace to know when it needs to allocate an ID. Also free drawable information memory when it's no longer needed. diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 2c878b6..228c8b8 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -156,6 +156,18 @@ int drm_lastclose(drm_device_t * dev) if (dev->irq_enabled) drm_irq_uninstall(dev); + /* Free drawable information memory */ + for (i = 0; i < dev->drw_bitfield_length / sizeof(*dev->drw_bitfield); + i++) { + drm_drawable_info_t *info = drm_get_drawable_info(dev, i); + + if (info) { + drm_free(info->rects, info->num_rects * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + drm_free(info, sizeof(*info), DRM_MEM_BUFS); + } + } + mutex_lock(&dev->struct_mutex); del_timer(&dev->timer); diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index bbfaf13..5e2fc86 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -92,13 +92,13 @@ done: bitfield[i] = 0; } - draw.handle = i * 8 * sizeof(*bitfield) + j; + draw.handle = i * 8 * sizeof(*bitfield) + j + 1; DRM_DEBUG("%d\n", draw.handle); spin_lock_irqsave(&dev->drw_lock, irqflags); bitfield[i] |= 1 << j; - info[draw.handle] = NULL; + info[draw.handle - 1] = NULL; if (bitfield != dev->drw_bitfield) { memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length * @@ -132,7 +132,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_draw_t draw; - unsigned int idx, shift; + unsigned int id, idx, shift; unsigned int irqflags; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; @@ -142,10 +142,11 @@ int drm_rmdraw(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, sizeof(draw)); - idx = draw.handle / (8 * sizeof(*bitfield)); - shift = draw.handle % (8 * sizeof(*bitfield)); + id = draw.handle - 1; + idx = id / (8 * sizeof(*bitfield)); + shift = id % (8 * sizeof(*bitfield)); - if (idx >= bitfield_length || + if (idx < 0 || idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", draw.handle); return 0; @@ -157,6 +158,12 @@ int drm_rmdraw(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + if (info[id]) { + drm_free(info[id]->rects, info[id]->num_rects * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + drm_free(info[id], sizeof(**info), DRM_MEM_BUFS); + } + /* Can we shrink the arrays? */ if (idx == bitfield_length - 1) { while (idx >= 0 && !bitfield[idx]) @@ -164,7 +171,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) bitfield_length = idx + 1; - if (idx != draw.handle / (8 * sizeof(*bitfield))) + if (idx != id / (8 * sizeof(*bitfield))) bitfield = drm_alloc(bitfield_length * sizeof(*bitfield), DRM_MEM_BUFS); @@ -222,11 +229,12 @@ int drm_update_drawable_info(DRM_IOCTL_A DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, sizeof(update)); - id = update.handle; + id = update.handle - 1; idx = id / (8 * sizeof(*bitfield)); shift = id % (8 * sizeof(*bitfield)); - if (idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) { + if (idx < 0 || idx >= bitfield_length || + !(bitfield[idx] & (1 << shift))) { DRM_ERROR("No such drawable %d\n", update.handle); return DRM_ERR(EINVAL); } @@ -304,10 +312,13 @@ error: */ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { u32 *bitfield = dev->drw_bitfield; - unsigned int idx = id / (8 * sizeof(*bitfield)); - unsigned int shift = id % (8 * sizeof(*bitfield)); + unsigned int idx, shift; + + id--; + idx = id / (8 * sizeof(*bitfield)); + shift = id % (8 * sizeof(*bitfield)); - if (idx >= dev->drw_bitfield_length || + if (idx < 0 || idx >= dev->drw_bitfield_length || !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", id); return NULL; diff-tree d04751facea36cb888c7510b126658fdbc4277d5 (from 257771fa290b62d4d2ad896843cf3a207978d0bb) Author: Michel Dänzer <mi...@tu...> Date: Mon Aug 28 18:19:58 2006 +0200 Add copyright notice. diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 81eb9f0..bbfaf13 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -12,6 +12,7 @@ * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff-tree 257771fa290b62d4d2ad896843cf3a207978d0bb (from 23d2833aaa37a33b9ddcf06cc796f59befc0d360) Author: Michel Dänzer <mi...@tu...> Date: Fri Aug 25 19:01:05 2006 +0200 i915: Add ioctl for scheduling buffer swaps at vertical blanks. This uses the core facility to schedule a driver callback that will be called ASAP after the given vertical blank interrupt with the HW lock held. diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 3863490..be235c1 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -163,6 +163,7 @@ static int i915_initialize(drm_device_t dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + dev_priv->cpp = init->cpp; dev_priv->back_offset = init->back_offset; dev_priv->front_offset = init->front_offset; dev_priv->current_page = 0; @@ -797,6 +798,7 @@ drm_ioctl_desc_t i915_ioctls[] = { [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH }, + [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH}, }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index fcffb25..7e4ba13 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -132,6 +132,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_DESTROY_HEAP 0x0c #define DRM_I915_SET_VBLANK_PIPE 0x0d #define DRM_I915_GET_VBLANK_PIPE 0x0e +#define DRM_I915_VBLANK_SWAP 0x0f #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) @@ -244,4 +245,12 @@ typedef struct drm_i915_vblank_pipe { int pipe; } drm_i915_vblank_pipe_t; +/* Schedule buffer swap at given vertical blank: + */ +typedef struct drm_i915_vblank_swap { + drm_drawable_t drawable; + unsigned int pipe; + unsigned int sequence; +} drm_i915_vblank_swap_t; + #endif /* _I915_DRM_H_ */ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 69cf811..dc9bbc5 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -71,6 +71,13 @@ struct mem_block { DRMFILE filp; /* 0: free, -1: heap, other: real files */ }; +typedef struct _drm_i915_vbl_swap { + struct list_head head; + drm_drawable_t drw_id; + unsigned int pipe; + unsigned int sequence; +} drm_i915_vbl_swap_t; + typedef struct drm_i915_private { drm_local_map_t *sarea; drm_local_map_t *mmio_map; @@ -83,6 +90,7 @@ typedef struct drm_i915_private { dma_addr_t dma_status_page; unsigned long counter; + unsigned int cpp; int back_offset; int front_offset; int current_page; @@ -98,6 +106,10 @@ typedef struct drm_i915_private { struct mem_block *agp_heap; unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; int vblank_pipe; + + spinlock_t swaps_lock; + drm_i915_vbl_swap_t vbl_swaps; + unsigned int swaps_pending; } drm_i915_private_t; extern drm_ioctl_desc_t i915_ioctls[]; @@ -124,6 +136,7 @@ extern void i915_driver_irq_postinstall( extern void i915_driver_irq_uninstall(drm_device_t * dev); extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS); extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS); +extern int i915_vblank_swap(DRM_IOCTL_ARGS); /* i915_mem.c */ extern int i915_mem_alloc(DRM_IOCTL_ARGS); @@ -257,6 +270,10 @@ extern int i915_wait_ring(drm_device_t * #define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) +#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) + #define MI_BATCH_BUFFER ((0x30<<23)|1) #define MI_BATCH_BUFFER_START (0x31<<23) #define MI_BATCH_BUFFER_END (0xA<<23) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 2eac29f..39d8c38 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -37,6 +37,99 @@ #define MAX_NOPID ((u32)~0) +/** + * Emit blits for scheduled buffer swaps. + * + * This function will be called with the HW lock held. + */ +static void i915_vblank_tasklet(drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned int irqflags; + struct list_head *list, *tmp; + + DRM_DEBUG("\n"); + + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + + list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { + drm_i915_vbl_swap_t *vbl_swap = + list_entry(list, drm_i915_vbl_swap_t, head); + atomic_t *counter = vbl_swap->pipe ? &dev->vbl_received2 : + &dev->vbl_received; + + if ((atomic_read(counter) - vbl_swap->sequence) <= (1<<23)) { + drm_drawable_info_t *drw; + + spin_unlock(&dev_priv->swaps_lock); + + spin_lock(&dev->drw_lock); + + drw = drm_get_drawable_info(dev, vbl_swap->drw_id); + + if (drw) { + int i, num_rects = drw->num_rects; + drm_clip_rect_t *rect = drw->rects; + drm_i915_sarea_t *sarea_priv = + dev_priv->sarea_priv; + u32 cpp = dev_priv->cpp; + u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB) + : XY_SRC_COPY_BLT_CMD; + u32 pitchropcpp = (sarea_priv->pitch * cpp) | + (0xcc << 16) | (cpp << 23) | + (1 << 24); + RING_LOCALS; + + i915_kernel_lost_context(dev); + + BEGIN_LP_RING(6); + + OUT_RING(GFX_OP_DRAWRECT_INFO); + OUT_RING(0); + OUT_RING(0); + OUT_RING(sarea_priv->width | + sarea_priv->height << 16); + OUT_RING(sarea_priv->width | + sarea_priv->height << 16); + OUT_RING(0); + + ADVANCE_LP_RING(); + + sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; + + for (i = 0; i < num_rects; i++, rect++) { + BEGIN_LP_RING(8); + + OUT_RING(cmd); + OUT_RING(pitchropcpp); + OUT_RING((rect->y1 << 16) | rect->x1); + OUT_RING((rect->y2 << 16) | rect->x2); + OUT_RING(sarea_priv->front_offset); + OUT_RING((rect->y1 << 16) | rect->x1); + OUT_RING(pitchropcpp & 0xffff); + OUT_RING(sarea_priv->back_offset); + + ADVANCE_LP_RING(); + } + } + + spin_unlock(&dev->drw_lock); + + spin_lock(&dev_priv->swaps_lock); + + list_del(list); + + drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); + + dev_priv->swaps_pending--; + } + } + + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { drm_device_t *dev = (drm_device_t *) arg; @@ -72,6 +165,8 @@ irqreturn_t i915_driver_irq_handler(DRM_ DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); + + drm_locked_tasklet(dev, i915_vblank_tasklet); } return IRQ_HANDLED; @@ -274,6 +369,90 @@ int i915_vblank_pipe_get(DRM_IOCTL_ARGS) return 0; } +/** + * Schedule buffer swap at given vertical blank. + */ +int i915_vblank_swap(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_vblank_swap_t swap; + drm_i915_vbl_swap_t *vbl_swap; + unsigned int irqflags; + struct list_head *list; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __func__); + return DRM_ERR(EINVAL); + } + + if (dev_priv->sarea_priv->rotation) { + DRM_DEBUG("Rotation not supported\n"); + return DRM_ERR(EINVAL); + } + + if (dev_priv->swaps_pending >= 100) { + DRM_DEBUG("Too many swaps queued\n"); + return DRM_ERR(EBUSY); + } + + DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, + sizeof(swap)); + + if (swap.pipe > 1 || !(dev_priv->vblank_pipe & (1 << swap.pipe))) { + DRM_ERROR("Invalid pipe %d\n", swap.pipe); + return DRM_ERR(EINVAL); + } + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (!drm_get_drawable_info(dev, swap.drawable)) { + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + DRM_ERROR("Invalid drawable ID %d\n", swap.drawable); + return DRM_ERR(EINVAL); + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + + list_for_each(list, &dev_priv->vbl_swaps.head) { + vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); + + if (vbl_swap->drw_id == swap.drawable && + vbl_swap->pipe == swap.pipe && + vbl_swap->sequence == swap.sequence) { + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_DEBUG("Already scheduled\n"); + return 0; + } + } + + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + + vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER); + + if (!vbl_swap) { + DRM_ERROR("Failed to allocate memory to queue swap\n"); + return DRM_ERR(ENOMEM); + } + + DRM_DEBUG("\n"); + + vbl_swap->drw_id = swap.drawable; + vbl_swap->pipe = swap.pipe; + vbl_swap->sequence = swap.sequence; + + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + + list_add_tail((struct list_head *)vbl_swap, &dev_priv->vbl_swaps.head); + dev_priv->swaps_pending++; + + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + + return 0; +} + /* drm_dma.h hooks */ void i915_driver_irq_preinstall(drm_device_t * dev) @@ -289,6 +468,10 @@ void i915_driver_irq_postinstall(drm_dev { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + dev_priv->swaps_lock = SPIN_LOCK_UNLOCKED; + INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); + dev_priv->swaps_pending = 0; + i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); } diff-tree 23d2833aaa37a33b9ddcf06cc796f59befc0d360 (from b9f3009160d8bd1a26a77d6f1616f1679c7b969d) Author: Michel Dänzer <mi...@tu...> Date: Fri Aug 25 18:55:55 2006 +0200 Locking and memory management fixes. diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 0a35794..81eb9f0 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -36,70 +36,86 @@ #include "drmP.h" -/** No-op. */ +/** + * Allocate drawable ID and memory to store information about it. + */ int drm_adddraw(DRM_IOCTL_ARGS) { DRM_DEVICE; unsigned int irqflags; - int i, j = 0; + int i, j; + u32 *bitfield = dev->drw_bitfield; + unsigned int bitfield_length = dev->drw_bitfield_length; + drm_drawable_info_t **info = dev->drw_info; + unsigned int info_length = dev->drw_info_length; drm_draw_t draw; - 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) + for (i = 0, j = 0; i < bitfield_length; i++) { + if (bitfield[i] == ~0) continue; - for (; j < sizeof(bitfield); j++) - if (!(bitfield & (1 << j))) + for (; j < 8 * sizeof(*bitfield); j++) + if (!(bitfield[i] & (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 (i == bitfield_length) { + bitfield_length++; + + bitfield = drm_alloc(bitfield_length * sizeof(*bitfield), + DRM_MEM_BUFS); - if (!new_bitfield) { + if (!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 (8 * sizeof(*bitfield) * bitfield_length > info_length) { + info_length += 8 * sizeof(*bitfield); - if (!new_info) { + info = drm_alloc(info_length * sizeof(*info), + DRM_MEM_BUFS); + + if (!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); + drm_free(bitfield, + bitfield_length * sizeof(*bitfield), + DRM_MEM_BUFS); 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++; + bitfield[i] = 0; } - dev->drw_bitfield[i] |= 1 << j; - - draw.handle = i * sizeof(u32) + j; + draw.handle = i * 8 * sizeof(*bitfield) + j; DRM_DEBUG("%d\n", draw.handle); - dev->drw_info[draw.handle] = NULL; + spin_lock_irqsave(&dev->drw_lock, irqflags); + + bitfield[i] |= 1 << j; + info[draw.handle] = NULL; + + if (bitfield != dev->drw_bitfield) { + memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length * + sizeof(*bitfield)); + drm_free(dev->drw_bitfield, sizeof(*bitfield) * + dev->drw_bitfield_length, DRM_MEM_BUFS); + dev->drw_bitfield = bitfield; + dev->drw_bitfield_length = bitfield_length; + } + + if (info != dev->drw_info) { + memcpy(info, dev->drw_info, dev->drw_info_length * + sizeof(*info)); + drm_free(dev->drw_info, sizeof(*info) * dev->drw_info_length, + DRM_MEM_BUFS); + dev->drw_info = info; + dev->drw_info_length = info_length; + } spin_unlock_irqrestore(&dev->drw_lock, irqflags); @@ -108,63 +124,85 @@ done: return 0; } -/** No-op. */ +/** + * Free drawable ID and memory to store information about it. + */ int drm_rmdraw(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_draw_t draw; - unsigned int idx, mod; + unsigned int idx, shift; unsigned int irqflags; + u32 *bitfield = dev->drw_bitfield; + unsigned int bitfield_length = dev->drw_bitfield_length; + drm_drawable_info_t **info = dev->drw_info; + unsigned int info_length = dev->drw_info_length; DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, sizeof(draw)); - idx = draw.handle / 32; - mod = draw.handle % 32; + idx = draw.handle / (8 * sizeof(*bitfield)); + shift = draw.handle % (8 * sizeof(*bitfield)); - spin_lock_irqsave(&dev->drw_lock, irqflags); - - if (idx >= dev->drw_bitfield_length || - !(dev->drw_bitfield[idx] & (1 << mod))) { + if (idx >= bitfield_length || + !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", draw.handle); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return 0; } - dev->drw_bitfield[idx] &= ~(1 << mod); + spin_lock_irqsave(&dev->drw_lock, irqflags); + + bitfield[idx] &= ~(1 << shift); + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); - if (idx == (dev->drw_bitfield_length - 1)) { - while (idx >= 0 && !dev->drw_bitfield[idx]) + /* Can we shrink the arrays? */ + if (idx == bitfield_length - 1) { + while (idx >= 0 && !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; - } + bitfield_length = idx + 1; + + if (idx != draw.handle / (8 * sizeof(*bitfield))) + bitfield = drm_alloc(bitfield_length * + sizeof(*bitfield), DRM_MEM_BUFS); + + if (!bitfield && bitfield_length) { + bitfield = dev->drw_bitfield; + bitfield_length = dev->drw_bitfield_length; } } - 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; + if (bitfield != dev->drw_bitfield) { + info_length = 8 * sizeof(*bitfield) * bitfield_length; + + info = drm_alloc(info_length * sizeof(*info), DRM_MEM_BUFS); + + if (!info && info_length) { + info = dev->drw_info; + info_length = dev->drw_info_length; } - } - spin_unlock_irqrestore(&dev->drw_lock, irqflags); + spin_lock_irqsave(&dev->drw_lock, irqflags); + + memcpy(bitfield, dev->drw_bitfield, bitfield_length * + sizeof(*bitfield)); + drm_free(dev->drw_bitfield, sizeof(*bitfield) * + dev->drw_bitfield_length, DRM_MEM_BUFS); + dev->drw_bitfield = bitfield; + dev->drw_bitfield_length = bitfield_length; + + if (info != dev->drw_info) { + memcpy(info, dev->drw_info, info_length * + sizeof(*info)); + drm_free(dev->drw_info, sizeof(*info) * + dev->drw_info_length, DRM_MEM_BUFS); + dev->drw_info = info; + dev->drw_info_length = info_length; + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + } DRM_DEBUG("%d\n", draw.handle); return 0; @@ -173,24 +211,22 @@ int drm_rmdraw(DRM_IOCTL_ARGS) int drm_update_drawable_info(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_update_draw_t update; - unsigned int id, idx, mod; - unsigned int irqflags; + unsigned int id, idx, shift; + u32 *bitfield = dev->drw_bitfield; + unsigned int irqflags, bitfield_length = dev->drw_bitfield_length; drm_drawable_info_t *info; - void *new_data; + drm_clip_rect_t *rects; + int err; 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); + idx = id / (8 * sizeof(*bitfield)); + shift = id % (8 * sizeof(*bitfield)); - if (idx >= dev->drw_bitfield_length || - !(dev->drw_bitfield[idx] & (1 << mod))) { + if (idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) { DRM_ERROR("No such drawable %d\n", update.handle); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(EINVAL); } @@ -201,66 +237,77 @@ int drm_update_drawable_info(DRM_IOCTL_A 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; + rects = drm_alloc(update.num * sizeof(drm_clip_rect_t), + DRM_MEM_BUFS); + } else + rects = info->rects; + + if (update.num && !rects) { + DRM_ERROR("Failed to allocate cliprect memory\n"); + err = DRM_ERR(ENOMEM); + goto error; } - 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 && DRM_COPY_FROM_USER(rects, + (drm_clip_rect_t __user *) + (unsigned long)update.data, + update.num * + sizeof(*rects))) { + DRM_ERROR("Failed to copy cliprects from userspace\n"); + err = DRM_ERR(EFAULT); + goto error; } - if (update.num != info->num_rects) { + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (rects != info->rects) { drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t), DRM_MEM_BUFS); - info->num_rects = update.num; } + info->rects = rects; + info->num_rects = update.num; + dev->drw_info[id] = info; + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + 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; + +error: + if (!dev->drw_info[id]) + drm_free(info, sizeof(*info), DRM_MEM_BUFS); + else if (rects != dev->drw_info[id]->rects) + drm_free(rects, update.num * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + + return err; } /** * 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; + u32 *bitfield = dev->drw_bitfield; + unsigned int idx = id / (8 * sizeof(*bitfield)); + unsigned int shift = id % (8 * sizeof(*bitfield)); if (idx >= dev->drw_bitfield_length || - !(dev->drw_bitfield[idx] & (1 << mod))) { + !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", id); return NULL; } diff-tree b9f3009160d8bd1a26a77d6f1616f1679c7b969d (from 43f8675534c7e95efbc92eaf2c8cc43aef95f125) Author: Michel Dänzer <mi...@tu...> Date: Fri Aug 25 18:55:06 2006 +0200 Drop tasklet locked driver callback when uninstalling IRQ. diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index b57fffb..fef0e8d 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -176,6 +176,8 @@ int drm_irq_uninstall(drm_device_t * dev free_irq(dev->irq, dev); + dev->locked_tasklet_func = NULL; + return 0; } EXPORT_SYMBOL(drm_irq_uninstall); diff-tree 43f8675534c7e95efbc92eaf2c8cc43aef95f125 (from 98a89504589427a76c3f5cfa2266962a1a212672) Author: Michel Dänzer <mi...@tu...> Date: Wed Aug 23 19:00:26 2006 +0200 Export drm_get_drawable_info symbol from core. diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 511f3ea..0a35794 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -267,3 +267,4 @@ drm_drawable_info_t *drm_get_drawable_in return dev->drw_info[id]; } +EXPORT_SYMBOL(drm_get_drawable_info); diff-tree 98a89504589427a76c3f5cfa2266962a1a212672 (from af48be1096221d551319c67a9e782b50ef58fefd) Author: Michel Dänzer <mi...@tu...> Date: Wed Aug 23 16:05:47 2006 +0200 Hook up DRM_IOCTL_UPDATE_DRAW ioctl. diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 8ccbed4..5c9644e 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -931,6 +931,8 @@ extern int drm_adddraw(struct inode *ino 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); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 5ddcd4c..2c878b6 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -119,6 +119,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 ) diff-tree af48be1096221d551319c67a9e782b50ef58fefd (from 29598e5253ff5c085ccf63580fd24b84db848424) Author: Michel Dänzer <mi...@tu...> Date: Wed Aug 23 16:04:41 2006 +0200 Only reallocate cliprect memory if the number of cliprects changes. Also improve diagnostic output. diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index ca6eb81..511f3ea 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -166,6 +166,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + DRM_DEBUG("%d\n", draw.handle); return 0; } @@ -209,30 +210,42 @@ int drm_update_drawable_info(DRM_IOCTL_A switch (update.type) { case DRM_DRAWABLE_CLIPRECTS: - new_data = drm_alloc(update.num * sizeof(drm_clip_rect_t), - DRM_MEM_BUFS); + 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); + } - if (!new_data) { - DRM_ERROR("Failed to allocate cliprect memory\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - return DRM_ERR(ENOMEM); + info->rects = new_data; } - if (DRM_COPY_FROM_USER(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("Failed to copy cliprects from userspace\n"); + DRM_ERROR("Can't copy cliprects from userspace\n"); spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(EFAULT); } - drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t), - DRM_MEM_BUFS); + 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; + } - info->rects = new_data; - 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); diff-tree 29598e5253ff5c085ccf63580fd24b84db848424 (from d817cc1f30060fcc4a85a05b2de8a2a1687421b5) Author: Michel Dänzer <mi...@tu...> Date: Tue Aug 22 16:40:07 2006 +0200 Add support for tracking drawable information to core 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. diff --git a/bsd-core/drm_drawable.c b/bsd-core/drm_drawable.c deleted file mode 100644 index 379e0aa..d64bbe1 --- a/bsd-core/drm_drawable.c +++ /dev/null @@ -1,51 +0,0 @@ -/* drm_drawable.h -- IOCTLs for drawables -*- linux-c -*- - * Created: Tue Feb 2 08:37:54 1999 by fa...@va... - */ -/*- - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * 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. - * - * Authors: - * Rickard E. (Rik) Faith <fa...@va...> - * Gareth Hughes <ga...@va...> - * - */ - -#include "drmP.h" - -int drm_adddraw(DRM_IOCTL_ARGS) -{ - drm_draw_t draw; - - draw.handle = 0; /* NOOP */ - DRM_DEBUG("%d\n", draw.handle); - - DRM_COPY_TO_USER_IOCTL( (drm_draw_t *)data, draw, sizeof(draw) ); - - return 0; -} - -int drm_rmdraw(DRM_IOCTL_ARGS) -{ - return 0; /* NOOP */ -} diff --git a/bsd-core/drm_drawable.c b/bsd-core/drm_drawable.c new file mode 120000 index 379e0aa..d64bbe1 --- /dev/null +++ b/bsd-core/drm_drawable.c @@ -0,0 +1 @@ +../shared-core/drm_drawable.c \ No newline at end of file diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index c9f1b2d..d4f80b4 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -1397,6 +1397,22 @@ int drmDestroyDrawable(int fd, drm_drawa return 0; } +int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, + drm_drawable_info_type_t type, unsigned int num, + void *data) +{ + drm_update_draw_t update; + + update.handle = handle; + update.type = type; + update.num = num; + update.data = (unsigned long long)(unsigned long)data; + + if (ioctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) return -errno; + + return 0; +} + /** * Acquire the AGP device. * diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 48a18f2..9e71eb6 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -544,6 +544,9 @@ extern int drmSwitchToContext( extern int drmDestroyContext(int fd, drm_context_t handle); extern int drmCreateDrawable(int fd, drm_drawable_t * handle); extern int drmDestroyDrawable(int fd, drm_drawable_t handle); +extern int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, + drm_drawable_info_type_t type, + unsigned int num, void *data); extern int drmCtlInstHandler(int fd, int irq); extern int drmCtlUninstHandler(int fd); diff --git a/linux-core/Makefile b/linux-core/Makefile index 32828d2..3aecec4 100644 --- a/linux-core/Makefile +++ b/linux-core/Makefile @@ -75,8 +75,8 @@ DRM_MODULES ?= $(MODULE_LIST) # These definitions are for handling dependencies in the out of kernel build. -DRMSHARED = drm.h drm_sarea.h -DRMHEADERS = drmP.h drm_compat.h drm_os_linux.h $(DRMSHARED) +DRMSHARED = drm.h drm_sarea.h drm_drawable.c +DRMHEADERS = drmP.h drm_compat.h drm_os_linux.h drm.h drm_sarea.h COREHEADERS = drm_core.h drm_sman.h drm_hashtab.h TDFXHEADERS = tdfx_drv.h $(DRMHEADERS) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index e61be1a..8ccbed4 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -772,6 +772,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, @@ -922,6 +931,8 @@ extern int drm_adddraw(struct inode *ino unsigned int cmd, unsigned long arg); extern int drm_rmdraw(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, diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c deleted file mode 100644 index 7857453..d64bbe1 --- a/linux-core/drm_drawable.c +++ /dev/null @@ -1,56 +0,0 @@ -/** - * \file drm_drawable.c - * IOCTLs for drawables - * - * \author Rickard E. (Rik) Faith <fa...@va...> - * \author Gareth Hughes <ga...@va...> - */ - -/* - * Created: Tue Feb 2 08:37:54 1999 by fa...@va... - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * 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. - */ - -#include "drmP.h" - -/** No-op. */ -int drm_adddraw(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_draw_t draw; - - draw.handle = 0; /* NOOP */ - DRM_DEBUG("%d\n", draw.handle); - if (copy_to_user((drm_draw_t __user *) arg, &draw, sizeof(draw))) - return -EFAULT; - return 0; -} - -/** No-op. */ -int drm_rmdraw(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - return 0; /* NOOP */ -} diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c new file mode 120000 index 7857453..d64bbe1 --- /dev/null +++ b/linux-core/drm_drawable.c @@ -0,0 +1 @@ +../shared-core/drm_drawable.c \ No newline at end of file diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 4708222..ad78dcf 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -61,6 +61,7 @@ static int drm_fill_in_dev(drm_device_t 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); diff --git a/shared-core/drm.h b/shared-core/drm.h index eaeb21e..614422b 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -159,6 +159,14 @@ typedef struct drm_clip_rect { } 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, */ typedef struct drm_tex_region { @@ -508,6 +516,20 @@ typedef struct drm_draw { } 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. */ typedef struct drm_auth { @@ -696,6 +718,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) + /*@}*/ /** diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c new file mode 100644 index 0000000..ca6eb81 --- /dev/null +++ b/shared-core/drm_drawable.c @@ -0,0 +1,256 @@ +/** + * \file drm_drawable.c + * IOCTLs for drawables + * + * \author Rickard E. (Rik) Faith <fa...@va...> + * \author Gareth Hughes <ga...@va...> + * \author Michel Dänzer <mi...@tu...> + */ + +/* + * Created: Tue Feb 2 08:37:54 1999 by fa...@va... + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * 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 li... [truncated message content] |
From: <pin...@ke...> - 2013-08-05 12:21:31
|
tests/modetest/Makefile.am | 4 tests/modetest/buffers.c | 44 + tests/modetest/buffers.h | 5 tests/modetest/modetest.c | 1197 +++++++++++++++++++++++++++++++-------------- 4 files changed, 884 insertions(+), 366 deletions(-) New commits: commit 3c967e715528ee52195c178c4d09d03b643f0c06 Author: Laurent Pinchart <lau...@id...> Date: Fri Jun 14 22:57:49 2013 +0200 modetest: Allocate NV buffers large enough for the two planes Multiple the image height by 1.5 for NV12/NV21 and by 2 for NV16/NV61 to make room for the chroma plane. Signed-off-by: Laurent Pinchart <lau...@id...> diff --git a/tests/modetest/buffers.c b/tests/modetest/buffers.c index 1575bf6..8206ce3 100644 --- a/tests/modetest/buffers.c +++ b/tests/modetest/buffers.c @@ -1038,12 +1038,29 @@ create_test_buffer(struct kms_driver *kms, unsigned int format, unsigned int handles[4], unsigned int pitches[4], unsigned int offsets[4], enum fill_pattern pattern) { + unsigned int virtual_height; struct kms_bo *bo; void *planes[3] = { 0, }; void *virtual; int ret; - bo = allocate_buffer(kms, width, height, &pitches[0]); + switch (format) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + virtual_height = height * 3 / 2; + break; + + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + virtual_height = height * 2; + break; + + default: + virtual_height = height; + break; + } + + bo = allocate_buffer(kms, width, virtual_height, &pitches[0]); if (!bo) return NULL; commit 1ef179d09c465248db47f62f00e718f4911e0e34 Author: Laurent Pinchart <lau...@id...> Date: Fri Jun 14 22:57:30 2013 +0200 modetest: Fix line stride in SMPTE YUV packet pattern generator The line stride passed to the function is expressed in bytes, there's no need to multiply it by 2. Signed-off-by: Laurent Pinchart <lau...@id...> diff --git a/tests/modetest/buffers.c b/tests/modetest/buffers.c index 1ca3be5..1575bf6 100644 --- a/tests/modetest/buffers.c +++ b/tests/modetest/buffers.c @@ -337,13 +337,13 @@ fill_smpte_yuv_packed(const struct yuv_info *yuv, unsigned char *mem, for (y = 0; y < height * 6 / 9; ++y) { for (x = 0; x < width; ++x) y_mem[2*x] = colors_top[x * 7 / width].y; - y_mem += stride * 2; + y_mem += stride; } for (; y < height * 7 / 9; ++y) { for (x = 0; x < width; ++x) y_mem[2*x] = colors_middle[x * 7 / width].y; - y_mem += stride * 2; + y_mem += stride; } for (; y < height; ++y) { @@ -354,7 +354,7 @@ fill_smpte_yuv_packed(const struct yuv_info *yuv, unsigned char *mem, / (width / 7) + 4].y; for (; x < width; ++x) y_mem[2*x] = colors_bottom[7].y; - y_mem += stride * 2; + y_mem += stride; } /* Chroma */ @@ -363,7 +363,7 @@ fill_smpte_yuv_packed(const struct yuv_info *yuv, unsigned char *mem, c_mem[2*x+u] = colors_top[x * 7 / width].u; c_mem[2*x+v] = colors_top[x * 7 / width].v; } - c_mem += stride * 2; + c_mem += stride; } for (; y < height * 7 / 9; ++y) { @@ -371,7 +371,7 @@ fill_smpte_yuv_packed(const struct yuv_info *yuv, unsigned char *mem, c_mem[2*x+u] = colors_middle[x * 7 / width].u; c_mem[2*x+v] = colors_middle[x * 7 / width].v; } - c_mem += stride * 2; + c_mem += stride; } for (; y < height; ++y) { @@ -389,7 +389,7 @@ fill_smpte_yuv_packed(const struct yuv_info *yuv, unsigned char *mem, c_mem[2*x+u] = colors_bottom[7].u; c_mem[2*x+v] = colors_bottom[7].v; } - c_mem += stride * 2; + c_mem += stride; } } commit a4f2f1b9d1c0b6b7f740951525a14b3d328f0acf Author: Laurent Pinchart <lau...@id...> Date: Tue Mar 19 15:36:09 2013 +0100 modetest: Try all possible encoders for a connector When building the pipeline, instead of using only the encoders attached to a connector, take all possible encoders into account to locate a CRTC. Signed-off-by: Laurent Pinchart <lau...@id...> diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index 6687559..f96b930 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -635,6 +635,19 @@ error: return NULL; } +static int get_crtc_index(struct device *dev, uint32_t id) +{ + int i; + + for (i = 0; i < dev->resources->res->count_crtcs; ++i) { + drmModeCrtc *crtc = dev->resources->crtcs[i].crtc; + if (crtc && crtc->crtc_id == id) + return i; + } + + return -1; +} + static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id) { drmModeConnector *connector; @@ -728,26 +741,28 @@ static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe) int j; for (i = 0; i < pipe->num_cons; ++i) { + uint32_t crtcs_for_connector = 0; drmModeConnector *connector; drmModeEncoder *encoder; + int idx; connector = get_connector_by_id(dev, pipe->con_ids[i]); if (!connector) return NULL; - encoder = get_encoder_by_id(dev, connector->encoder_id); - if (!encoder) - return NULL; + for (j = 0; j < connector->count_encoders; ++j) { + encoder = get_encoder_by_id(dev, connector->encoders[j]); + if (!encoder) + continue; - possible_crtcs &= encoder->possible_crtcs; + crtcs_for_connector |= encoder->possible_crtcs; - for (j = 0; j < dev->resources->res->count_crtcs; ++j) { - drmModeCrtc *crtc = dev->resources->crtcs[j].crtc; - if (crtc && crtc->crtc_id == encoder->crtc_id) { - active_crtcs |= 1 << j; - break; - } + idx = get_crtc_index(dev, encoder->crtc_id); + if (idx >= 0) + active_crtcs |= 1 << idx; } + + possible_crtcs &= crtcs_for_connector; } if (!possible_crtcs) commit 2c5ee84d30cbd3fba61a8426b1e6bdd4f385de13 Author: Laurent Pinchart <lau...@id...> Date: Tue Mar 19 13:48:36 2013 +0100 modetest: Support pipes with multiple connectors The -s argument can now take a list of connectors. Configure all of them in cloned mode using a single CRTC. Signed-off-by: Laurent Pinchart <lau...@id...> diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index 561a0e4..6687559 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -40,6 +40,7 @@ #include "config.h" #include <assert.h> +#include <ctype.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -634,6 +635,34 @@ error: return NULL; } +static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id) +{ + drmModeConnector *connector; + int i; + + for (i = 0; i < dev->resources->res->count_connectors; i++) { + connector = dev->resources->connectors[i].connector; + if (connector && connector->connector_id == id) + return connector; + } + + return NULL; +} + +static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id) +{ + drmModeEncoder *encoder; + int i; + + for (i = 0; i < dev->resources->res->count_encoders; i++) { + encoder = dev->resources->encoders[i].encoder; + if (encoder && encoder->encoder_id == id) + return encoder; + } + + return NULL; +} + /* ----------------------------------------------------------------------------- * Pipes and planes */ @@ -646,7 +675,8 @@ error: * can bind it with a free crtc. */ struct pipe_arg { - uint32_t con_id; + uint32_t *con_ids; + unsigned int num_cons; uint32_t crtc_id; char mode_str[64]; char format_str[5]; @@ -669,69 +699,114 @@ struct plane_arg { unsigned int fourcc; }; -static void pipe_find_mode(struct device *dev, struct pipe_arg *pipe) +static drmModeModeInfo * +connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str) { drmModeConnector *connector; - drmModeEncoder *encoder; - int i, j; + drmModeModeInfo *mode; + int i; - /* First, find the connector & mode */ - pipe->mode = NULL; - for (i = 0; i < dev->resources->res->count_connectors; i++) { - connector = dev->resources->connectors[i].connector; + connector = get_connector_by_id(dev, con_id); + if (!connector || !connector->count_modes) + return NULL; + + for (i = 0; i < connector->count_modes; i++) { + mode = &connector->modes[i]; + if (!strcmp(mode->name, mode_str)) + return mode; + } + + return NULL; +} + +static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe) +{ + uint32_t possible_crtcs = ~0; + uint32_t active_crtcs = 0; + unsigned int crtc_idx; + unsigned int i; + int j; + + for (i = 0; i < pipe->num_cons; ++i) { + drmModeConnector *connector; + drmModeEncoder *encoder; + + connector = get_connector_by_id(dev, pipe->con_ids[i]); if (!connector) - continue; + return NULL; - if (!connector->count_modes) - continue; + encoder = get_encoder_by_id(dev, connector->encoder_id); + if (!encoder) + return NULL; - if (connector->connector_id != pipe->con_id) - continue; + possible_crtcs &= encoder->possible_crtcs; - for (j = 0; j < connector->count_modes; j++) { - pipe->mode = &connector->modes[j]; - if (!strcmp(pipe->mode->name, pipe->mode_str)) + for (j = 0; j < dev->resources->res->count_crtcs; ++j) { + drmModeCrtc *crtc = dev->resources->crtcs[j].crtc; + if (crtc && crtc->crtc_id == encoder->crtc_id) { + active_crtcs |= 1 << j; break; + } } - - /* Found it, break out */ - if (pipe->mode) - break; } - if (!pipe->mode) { - fprintf(stderr, "failed to find mode \"%s\"\n", pipe->mode_str); - return; + if (!possible_crtcs) + return NULL; + + /* Return the first possible and active CRTC if one exists, or the first + * possible CRTC otherwise. + */ + if (possible_crtcs & active_crtcs) + crtc_idx = ffs(possible_crtcs & active_crtcs); + else + crtc_idx = ffs(possible_crtcs); + + return &dev->resources->crtcs[crtc_idx - 1]; +} + +static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe) +{ + drmModeModeInfo *mode; + int i; + + pipe->mode = NULL; + + for (i = 0; i < (int)pipe->num_cons; i++) { + mode = connector_find_mode(dev, pipe->con_ids[i], + pipe->mode_str); + if (mode == NULL) { + fprintf(stderr, + "failed to find mode \"%s\" for connector %u\n", + pipe->mode_str, pipe->con_ids[i]); + return -EINVAL; + } } /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise - * locate a CRTC that can be attached to the connector. + * locate a CRTC that can be attached to all the connectors. */ - if (pipe->crtc_id == (uint32_t)-1) { - for (i = 0; i < dev->resources->res->count_encoders; i++) { - encoder = dev->resources->encoders[i].encoder; - if (!encoder) - continue; - - if (encoder->encoder_id == connector->encoder_id) { - pipe->crtc_id = encoder->crtc_id; + if (pipe->crtc_id != (uint32_t)-1) { + for (i = 0; i < dev->resources->res->count_crtcs; i++) { + struct crtc *crtc = &dev->resources->crtcs[i]; + + if (pipe->crtc_id == crtc->crtc->crtc_id) { + pipe->crtc = crtc; break; } } + } else { + pipe->crtc = pipe_find_crtc(dev, pipe); } - if (pipe->crtc_id == (uint32_t)-1) - return; + if (!pipe->crtc) { + fprintf(stderr, "failed to find CRTC for pipe\n"); + return -EINVAL; + } - for (i = 0; i < dev->resources->res->count_crtcs; i++) { - struct crtc *crtc = &dev->resources->crtcs[i]; + pipe->mode = mode; + pipe->crtc->mode = mode; - if (pipe->crtc_id == crtc->crtc->crtc_id) { - crtc->mode = pipe->mode; - pipe->crtc = crtc; - break; - } - } + return 0; } /* ----------------------------------------------------------------------------- @@ -826,7 +901,7 @@ page_flip_handler(int fd, unsigned int frame, else new_fb_id = pipe->fb_id[0]; - drmModePageFlip(fd, pipe->crtc_id, new_fb_id, + drmModePageFlip(fd, pipe->crtc->crtc->crtc_id, new_fb_id, DRM_MODE_PAGE_FLIP_EVENT, pipe); pipe->current_fb_id = new_fb_id; pipe->swap_count++; @@ -929,6 +1004,7 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co unsigned int fb_id; struct kms_bo *bo; unsigned int i; + unsigned int j; int ret, x; dev->mode.width = 0; @@ -937,9 +1013,10 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co for (i = 0; i < count; i++) { struct pipe_arg *pipe = &pipes[i]; - pipe_find_mode(dev, pipe); - if (pipe->mode == NULL) + ret = pipe_find_crtc_and_mode(dev, pipe); + if (ret < 0) continue; + dev->mode.width += pipe->mode->hdisplay; if (dev->mode.height < pipe->mode->vdisplay) dev->mode.height = pipe->mode->vdisplay; @@ -966,12 +1043,15 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co if (pipe->mode == NULL) continue; - printf("setting mode %s@%s on connector %d, crtc %d\n", - pipe->mode_str, pipe->format_str, pipe->con_id, - pipe->crtc_id); + printf("setting mode %s@%s on connectors ", + pipe->mode_str, pipe->format_str); + for (j = 0; j < pipe->num_cons; ++j) + printf("%u, ", pipe->con_ids[j]); + printf("crtc %d\n", pipe->crtc->crtc->crtc_id); - ret = drmModeSetCrtc(dev->fd, pipe->crtc_id, fb_id, x, 0, - &pipe->con_id, 1, pipe->mode); + ret = drmModeSetCrtc(dev->fd, pipe->crtc->crtc->crtc_id, fb_id, + x, 0, pipe->con_ids, pipe->num_cons, + pipe->mode); /* XXX: Actually check if this is needed */ drmModeDirtyFB(dev->fd, fb_id, NULL, 0); @@ -1027,8 +1107,9 @@ static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned if (pipe->mode == NULL) continue; - ret = drmModePageFlip(dev->fd, pipe->crtc_id, other_fb_id, - DRM_MODE_PAGE_FLIP_EVENT, pipe); + ret = drmModePageFlip(dev->fd, pipe->crtc->crtc->crtc_id, + other_fb_id, DRM_MODE_PAGE_FLIP_EVENT, + pipe); if (ret) { fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); return; @@ -1091,13 +1172,35 @@ static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned static int parse_connector(struct pipe_arg *pipe, const char *arg) { unsigned int len; + unsigned int i; const char *p; char *endp; pipe->crtc_id = (uint32_t)-1; strcpy(pipe->format_str, "XR24"); - pipe->con_id = strtoul(arg, &endp, 10); + /* Count the number of connectors and allocate them. */ + pipe->num_cons = 1; + for (p = arg; isdigit(*p) || *p == ','; ++p) { + if (*p == ',') + pipe->num_cons++; + } + + pipe->con_ids = malloc(pipe->num_cons * sizeof *pipe->con_ids); + if (pipe->con_ids == NULL) + return -1; + + /* Parse the connectors. */ + for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) { + pipe->con_ids[i] = strtoul(p, &endp, 10); + if (*endp != ',') + break; + } + + if (i != pipe->num_cons - 1) + return -1; + + /* Parse the remaining parameters. */ if (*endp == '@') { arg = endp + 1; pipe->crtc_id = strtoul(arg, &endp, 10); @@ -1195,7 +1298,7 @@ static void usage(char *name) fprintf(stderr, "\n Test options:\n\n"); fprintf(stderr, "\t-P <crtc_id>:<w>x<h>[+<x>+<y>][@<format>]\tset a plane\n"); - fprintf(stderr, "\t-s <connector_id>[@<crtc_id>]:<mode>[@<format>]\tset a mode\n"); + fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[@<format>]\tset a mode\n"); fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n"); commit b1e0bdeb70b68754c6c4ab1c7d0161709960d49c Author: Laurent Pinchart <lau...@id...> Date: Tue Mar 19 13:47:39 2013 +0100 modetest: Rename struct connector_arg to struct pipe_arg This prepares the code for handling multiple connectors in a single pipeline in a cloned configuration. Signed-off-by: Laurent Pinchart <lau...@id...> diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index 237eac1..561a0e4 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -635,7 +635,7 @@ error: } /* ----------------------------------------------------------------------------- - * Connectors and planes + * Pipes and planes */ /* @@ -645,8 +645,8 @@ error: * Then you need to find the encoder attached to that connector so you * can bind it with a free crtc. */ -struct connector_arg { - uint32_t id; +struct pipe_arg { + uint32_t con_id; uint32_t crtc_id; char mode_str[64]; char format_str[5]; @@ -669,14 +669,14 @@ struct plane_arg { unsigned int fourcc; }; -static void connector_find_mode(struct device *dev, struct connector_arg *c) +static void pipe_find_mode(struct device *dev, struct pipe_arg *pipe) { drmModeConnector *connector; drmModeEncoder *encoder; int i, j; /* First, find the connector & mode */ - c->mode = NULL; + pipe->mode = NULL; for (i = 0; i < dev->resources->res->count_connectors; i++) { connector = dev->resources->connectors[i].connector; if (!connector) @@ -685,50 +685,50 @@ static void connector_find_mode(struct device *dev, struct connector_arg *c) if (!connector->count_modes) continue; - if (connector->connector_id != c->id) + if (connector->connector_id != pipe->con_id) continue; for (j = 0; j < connector->count_modes; j++) { - c->mode = &connector->modes[j]; - if (!strcmp(c->mode->name, c->mode_str)) + pipe->mode = &connector->modes[j]; + if (!strcmp(pipe->mode->name, pipe->mode_str)) break; } /* Found it, break out */ - if (c->mode) + if (pipe->mode) break; } - if (!c->mode) { - fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); + if (!pipe->mode) { + fprintf(stderr, "failed to find mode \"%s\"\n", pipe->mode_str); return; } /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise * locate a CRTC that can be attached to the connector. */ - if (c->crtc_id == (uint32_t)-1) { + if (pipe->crtc_id == (uint32_t)-1) { for (i = 0; i < dev->resources->res->count_encoders; i++) { encoder = dev->resources->encoders[i].encoder; if (!encoder) continue; if (encoder->encoder_id == connector->encoder_id) { - c->crtc_id = encoder->crtc_id; + pipe->crtc_id = encoder->crtc_id; break; } } } - if (c->crtc_id == (uint32_t)-1) + if (pipe->crtc_id == (uint32_t)-1) return; for (i = 0; i < dev->resources->res->count_crtcs; i++) { struct crtc *crtc = &dev->resources->crtcs[i]; - if (c->crtc_id == crtc->crtc->crtc_id) { - crtc->mode = c->mode; - c->crtc = crtc; + if (pipe->crtc_id == crtc->crtc->crtc_id) { + crtc->mode = pipe->mode; + pipe->crtc = crtc; break; } } @@ -815,28 +815,28 @@ static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { - struct connector_arg *c; + struct pipe_arg *pipe; unsigned int new_fb_id; struct timeval end; double t; - c = data; - if (c->current_fb_id == c->fb_id[0]) - new_fb_id = c->fb_id[1]; + pipe = data; + if (pipe->current_fb_id == pipe->fb_id[0]) + new_fb_id = pipe->fb_id[1]; else - new_fb_id = c->fb_id[0]; + new_fb_id = pipe->fb_id[0]; - drmModePageFlip(fd, c->crtc_id, new_fb_id, - DRM_MODE_PAGE_FLIP_EVENT, c); - c->current_fb_id = new_fb_id; - c->swap_count++; - if (c->swap_count == 60) { + drmModePageFlip(fd, pipe->crtc_id, new_fb_id, + DRM_MODE_PAGE_FLIP_EVENT, pipe); + pipe->current_fb_id = new_fb_id; + pipe->swap_count++; + if (pipe->swap_count == 60) { gettimeofday(&end, NULL); t = end.tv_sec + end.tv_usec * 1e-6 - - (c->start.tv_sec + c->start.tv_usec * 1e-6); - fprintf(stderr, "freq: %.02fHz\n", c->swap_count / t); - c->swap_count = 0; - c->start = end; + (pipe->start.tv_sec + pipe->start.tv_usec * 1e-6); + fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t); + pipe->swap_count = 0; + pipe->start = end; } } @@ -923,7 +923,7 @@ static int set_plane(struct device *dev, struct plane_arg *p) return 0; } -static void set_mode(struct device *dev, struct connector_arg *c, unsigned int count) +static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) { uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ unsigned int fb_id; @@ -935,22 +935,24 @@ static void set_mode(struct device *dev, struct connector_arg *c, unsigned int c dev->mode.height = 0; for (i = 0; i < count; i++) { - connector_find_mode(dev, &c[i]); - if (c[i].mode == NULL) + struct pipe_arg *pipe = &pipes[i]; + + pipe_find_mode(dev, pipe); + if (pipe->mode == NULL) continue; - dev->mode.width += c[i].mode->hdisplay; - if (dev->mode.height < c[i].mode->vdisplay) - dev->mode.height = c[i].mode->vdisplay; + dev->mode.width += pipe->mode->hdisplay; + if (dev->mode.height < pipe->mode->vdisplay) + dev->mode.height = pipe->mode->vdisplay; } - bo = create_test_buffer(dev->kms, c->fourcc, + bo = create_test_buffer(dev->kms, pipes[0].fourcc, dev->mode.width, dev->mode.height, handles, pitches, offsets, PATTERN_SMPTE); if (bo == NULL) return; - ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, c->fourcc, - handles, pitches, offsets, &fb_id, 0); + ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, + pipes[0].fourcc, handles, pitches, offsets, &fb_id, 0); if (ret) { fprintf(stderr, "failed to add fb (%ux%u): %s\n", dev->mode.width, dev->mode.height, strerror(errno)); @@ -959,19 +961,22 @@ static void set_mode(struct device *dev, struct connector_arg *c, unsigned int c x = 0; for (i = 0; i < count; i++) { - if (c[i].mode == NULL) + struct pipe_arg *pipe = &pipes[i]; + + if (pipe->mode == NULL) continue; printf("setting mode %s@%s on connector %d, crtc %d\n", - c[i].mode_str, c[i].format_str, c[i].id, c[i].crtc_id); + pipe->mode_str, pipe->format_str, pipe->con_id, + pipe->crtc_id); - ret = drmModeSetCrtc(dev->fd, c[i].crtc_id, fb_id, x, 0, - &c[i].id, 1, c[i].mode); + ret = drmModeSetCrtc(dev->fd, pipe->crtc_id, fb_id, x, 0, + &pipe->con_id, 1, pipe->mode); /* XXX: Actually check if this is needed */ drmModeDirtyFB(dev->fd, fb_id, NULL, 0); - x += c[i].mode->hdisplay; + x += pipe->mode->hdisplay; if (ret) { fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); @@ -993,7 +998,7 @@ static void set_planes(struct device *dev, struct plane_arg *p, unsigned int cou return; } -static void test_page_flip(struct device *dev, struct connector_arg *c, unsigned int count) +static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count) { uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ unsigned int other_fb_id; @@ -1002,34 +1007,37 @@ static void test_page_flip(struct device *dev, struct connector_arg *c, unsigned unsigned int i; int ret; - other_bo = create_test_buffer(dev->kms, c->fourcc, + other_bo = create_test_buffer(dev->kms, pipes[0].fourcc, dev->mode.width, dev->mode.height, handles, pitches, offsets, PATTERN_PLAIN); if (other_bo == NULL) return; - ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, c->fourcc, - handles, pitches, offsets, &other_fb_id, 0); + ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, + pipes[0].fourcc, handles, pitches, offsets, + &other_fb_id, 0); if (ret) { fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); return; } for (i = 0; i < count; i++) { - if (c[i].mode == NULL) + struct pipe_arg *pipe = &pipes[i]; + + if (pipe->mode == NULL) continue; - ret = drmModePageFlip(dev->fd, c[i].crtc_id, other_fb_id, - DRM_MODE_PAGE_FLIP_EVENT, &c[i]); + ret = drmModePageFlip(dev->fd, pipe->crtc_id, other_fb_id, + DRM_MODE_PAGE_FLIP_EVENT, pipe); if (ret) { fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); return; } - gettimeofday(&c[i].start, NULL); - c[i].swap_count = 0; - c[i].fb_id[0] = dev->mode.fb_id; - c[i].fb_id[1] = other_fb_id; - c[i].current_fb_id = other_fb_id; + gettimeofday(&pipe->start, NULL); + pipe->swap_count = 0; + pipe->fb_id[0] = dev->mode.fb_id; + pipe->fb_id[1] = other_fb_id; + pipe->current_fb_id = other_fb_id; } memset(&evctx, 0, sizeof evctx); @@ -1080,19 +1088,19 @@ static void test_page_flip(struct device *dev, struct connector_arg *c, unsigned #define min(a, b) ((a) < (b) ? (a) : (b)) -static int parse_connector(struct connector_arg *c, const char *arg) +static int parse_connector(struct pipe_arg *pipe, const char *arg) { unsigned int len; const char *p; char *endp; - c->crtc_id = (uint32_t)-1; - strcpy(c->format_str, "XR24"); + pipe->crtc_id = (uint32_t)-1; + strcpy(pipe->format_str, "XR24"); - c->id = strtoul(arg, &endp, 10); + pipe->con_id = strtoul(arg, &endp, 10); if (*endp == '@') { arg = endp + 1; - c->crtc_id = strtoul(arg, &endp, 10); + pipe->crtc_id = strtoul(arg, &endp, 10); } if (*endp != ':') return -1; @@ -1100,18 +1108,18 @@ static int parse_connector(struct connector_arg *c, const char *arg) arg = endp + 1; p = strchrnul(arg, '@'); - len = min(sizeof c->mode_str - 1, (unsigned int)(p - arg)); - strncpy(c->mode_str, arg, len); - c->mode_str[len] = '\0'; + len = min(sizeof pipe->mode_str - 1, (unsigned int)(p - arg)); + strncpy(pipe->mode_str, arg, len); + pipe->mode_str[len] = '\0'; if (*p == '@') { - strncpy(c->format_str, p + 1, 4); - c->format_str[4] = '\0'; + strncpy(pipe->format_str, p + 1, 4); + pipe->format_str[4] = '\0'; } - c->fourcc = format_fourcc(c->format_str); - if (c->fourcc == 0) { - fprintf(stderr, "unknown format %s\n", c->format_str); + pipe->fourcc = format_fourcc(pipe->format_str); + if (pipe->fourcc == 0) { + fprintf(stderr, "unknown format %s\n", pipe->format_str); return -1; } @@ -1235,7 +1243,7 @@ int main(int argc, char **argv) unsigned int i; int count = 0, plane_count = 0; unsigned int prop_count = 0; - struct connector_arg *con_args = NULL; + struct pipe_arg *pipe_args = NULL; struct plane_arg *plane_args = NULL; struct property_arg *prop_args = NULL; unsigned int args = 0; @@ -1283,14 +1291,14 @@ int main(int argc, char **argv) planes = 1; break; case 's': - con_args = realloc(con_args, - (count + 1) * sizeof *con_args); - if (con_args == NULL) { + pipe_args = realloc(pipe_args, + (count + 1) * sizeof *pipe_args); + if (pipe_args == NULL) { fprintf(stderr, "memory allocation failed\n"); return 1; } - if (parse_connector(&con_args[count], optarg) < 0) + if (parse_connector(&pipe_args[count], optarg) < 0) usage(argv[0]); count++; @@ -1380,13 +1388,13 @@ int main(int argc, char **argv) } if (count) - set_mode(&dev, con_args, count); + set_mode(&dev, pipe_args, count); if (plane_count) set_planes(&dev, plane_args, plane_count); if (test_vsync) - test_page_flip(&dev, con_args, count); + test_page_flip(&dev, pipe_args, count); if (drop_master) drmDropMaster(dev.fd); commit 3813e0f8e1ee4885823cdd0b50b05970257adddc Author: Laurent Pinchart <lau...@id...> Date: Wed Feb 27 05:35:13 2013 +0100 modetest: Split mode setting and plane setup There's not reason to require setting a mode to test planes. Split the two operations. Signed-off-by: Laurent Pinchart <lau...@id...> diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index 87a00ad..237eac1 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -101,6 +101,14 @@ struct device { struct resources *resources; struct kms_driver *kms; + + struct { + unsigned int width; + unsigned int height; + + unsigned int fb_id; + struct kms_bo *bo; + } mode; }; #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -840,7 +848,7 @@ static int set_plane(struct device *dev, struct plane_arg *p) struct kms_bo *plane_bo; uint32_t plane_flags = 0; int crtc_x, crtc_y, crtc_w, crtc_h; - struct crtc *crtc; + struct crtc *crtc = NULL; unsigned int pipe; unsigned int i; @@ -915,36 +923,37 @@ static int set_plane(struct device *dev, struct plane_arg *p) return 0; } -static void set_mode(struct device *dev, struct connector_arg *c, int count, - struct plane_arg *p, int plane_count, int page_flip) +static void set_mode(struct device *dev, struct connector_arg *c, unsigned int count) { - struct kms_bo *bo, *other_bo; - unsigned int fb_id, other_fb_id; - int i, j, ret, width, height, x; uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ - drmEventContext evctx; + unsigned int fb_id; + struct kms_bo *bo; + unsigned int i; + int ret, x; + + dev->mode.width = 0; + dev->mode.height = 0; - width = 0; - height = 0; for (i = 0; i < count; i++) { connector_find_mode(dev, &c[i]); if (c[i].mode == NULL) continue; - width += c[i].mode->hdisplay; - if (height < c[i].mode->vdisplay) - height = c[i].mode->vdisplay; + dev->mode.width += c[i].mode->hdisplay; + if (dev->mode.height < c[i].mode->vdisplay) + dev->mode.height = c[i].mode->vdisplay; } - bo = create_test_buffer(dev->kms, c->fourcc, width, height, handles, - pitches, offsets, PATTERN_SMPTE); + bo = create_test_buffer(dev->kms, c->fourcc, + dev->mode.width, dev->mode.height, + handles, pitches, offsets, PATTERN_SMPTE); if (bo == NULL) return; - ret = drmModeAddFB2(dev->fd, width, height, c->fourcc, + ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, c->fourcc, handles, pitches, offsets, &fb_id, 0); if (ret) { fprintf(stderr, "failed to add fb (%ux%u): %s\n", - width, height, strerror(errno)); + dev->mode.width, dev->mode.height, strerror(errno)); return; } @@ -968,24 +977,39 @@ static void set_mode(struct device *dev, struct connector_arg *c, int count, fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); return; } - - /* if we have a plane/overlay to show, set that up now: */ - for (j = 0; j < plane_count; j++) - if (p[j].crtc_id == c[i].crtc_id) - if (set_plane(dev, &p[j])) - return; } - if (!page_flip) - return; + dev->mode.bo = bo; + dev->mode.fb_id = fb_id; +} + +static void set_planes(struct device *dev, struct plane_arg *p, unsigned int count) +{ + unsigned int i; + + /* set up planes/overlays */ + for (i = 0; i < count; i++) + if (set_plane(dev, &p[i])) + return; +} + +static void test_page_flip(struct device *dev, struct connector_arg *c, unsigned int count) +{ + uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ + unsigned int other_fb_id; + struct kms_bo *other_bo; + drmEventContext evctx; + unsigned int i; + int ret; - other_bo = create_test_buffer(dev->kms, c->fourcc, width, height, handles, - pitches, offsets, PATTERN_PLAIN); + other_bo = create_test_buffer(dev->kms, c->fourcc, + dev->mode.width, dev->mode.height, + handles, pitches, offsets, PATTERN_PLAIN); if (other_bo == NULL) return; - ret = drmModeAddFB2(dev->fd, width, height, c->fourcc, handles, pitches, offsets, - &other_fb_id, 0); + ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, c->fourcc, + handles, pitches, offsets, &other_fb_id, 0); if (ret) { fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); return; @@ -1003,7 +1027,7 @@ static void set_mode(struct device *dev, struct connector_arg *c, int count, } gettimeofday(&c[i].start, NULL); c[i].swap_count = 0; - c[i].fb_id[0] = fb_id; + c[i].fb_id[0] = dev->mode.fb_id; c[i].fb_id[1] = other_fb_id; c[i].current_fb_id = other_fb_id; } @@ -1051,7 +1075,6 @@ static void set_mode(struct device *dev, struct connector_arg *c, int count, drmHandleEvent(dev->fd, &evctx); } - kms_bo_destroy(&bo); kms_bo_destroy(&other_bo); } @@ -1218,6 +1241,8 @@ int main(int argc, char **argv) unsigned int args = 0; int ret; + memset(&dev, 0, sizeof dev); + opterr = 0; while ((c = getopt(argc, argv, optstr)) != -1) { args++; @@ -1324,6 +1349,11 @@ int main(int argc, char **argv) return -1; } + if (test_vsync && !count) { + fprintf(stderr, "page flipping requires at least one -s option.\n"); + return -1; + } + dev.resources = get_resources(&dev); if (!dev.resources) { drmClose(dev.fd); @@ -1341,7 +1371,7 @@ int main(int argc, char **argv) for (i = 0; i < prop_count; ++i) set_property(&dev, &prop_args[i]); - if (count > 0) { + if (count || plane_count) { ret = kms_create(dev.fd, &dev.kms); if (ret) { fprintf(stderr, "failed to create kms driver: %s\n", @@ -1349,11 +1379,21 @@ int main(int argc, char **argv) return 1; } - set_mode(&dev, con_args, count, plane_args, plane_count, test_vsync); + if (count) + set_mode(&dev, con_args, count); + + if (plane_count) + set_planes(&dev, plane_args, plane_count); + + if (test_vsync) + test_page_flip(&dev, con_args, count); + if (drop_master) drmDropMaster(dev.fd); + kms_bo_destroy(&dev.mode.bo); kms_destroy(&dev.kms); + getchar(); } commit eabf199dffb0d42e959c50aa820b39228196e031 Author: Laurent Pinchart <lau...@id...> Date: Wed Feb 27 05:35:13 2013 +0100 modetest: Give the CRTC ID to the -P option Planes are associated with CRTCs, not connectors. Don't try to be too clever, use the CRTC ID in the -P option. This prepares for splitting CRTC and planes setup. Signed-off-by: Laurent Pinchart <lau...@id...> diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index a7ead01..87a00ad 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -652,7 +652,7 @@ struct connector_arg { }; struct plane_arg { - uint32_t con_id; /* the id of connector to bind to */ + uint32_t crtc_id; /* the id of CRTC to bind to */ bool has_position; int32_t x, y; uint32_t w, h; @@ -832,8 +832,7 @@ page_flip_handler(int fd, unsigned int frame, } } -static int -set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) +static int set_plane(struct device *dev, struct plane_arg *p) { drmModePlane *ovr; uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ @@ -841,6 +840,7 @@ set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) struct kms_bo *plane_bo; uint32_t plane_flags = 0; int crtc_x, crtc_y, crtc_w, crtc_h; + struct crtc *crtc; unsigned int pipe; unsigned int i; @@ -848,14 +848,15 @@ set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) * CRTC index first, then iterate over available planes. */ for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) { - if (c->crtc_id == dev->resources->res->crtcs[i]) { + if (p->crtc_id == dev->resources->res->crtcs[i]) { + crtc = &dev->resources->crtcs[i]; pipe = i; break; } } - if (pipe == (unsigned int)dev->resources->res->count_crtcs) { - fprintf(stderr, "CRTC %u not found\n", c->crtc_id); + if (!crtc) { + fprintf(stderr, "CRTC %u not found\n", p->crtc_id); return -1; } @@ -869,7 +870,8 @@ set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) } if (!plane_id) { - fprintf(stderr, "no unused plane available for CRTC %u\n", c->crtc_id); + fprintf(stderr, "no unused plane available for CRTC %u\n", + crtc->crtc->crtc_id); return -1; } @@ -890,8 +892,8 @@ set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) if (!p->has_position) { /* Default to the middle of the screen */ - crtc_x = (c->crtc->mode->hdisplay - p->w) / 2; - crtc_y = (c->crtc->mode->vdisplay - p->h) / 2; + crtc_x = (crtc->mode->hdisplay - p->w) / 2; + crtc_y = (crtc->mode->vdisplay - p->h) / 2; } else { crtc_x = p->x; crtc_y = p->y; @@ -900,7 +902,7 @@ set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) crtc_h = p->h; /* note src coords (last 4 args) are in Q16 format */ - if (drmModeSetPlane(dev->fd, plane_id, c->crtc_id, p->fb_id, + if (drmModeSetPlane(dev->fd, plane_id, crtc->crtc->crtc_id, p->fb_id, plane_flags, crtc_x, crtc_y, crtc_w, crtc_h, 0, 0, p->w << 16, p->h << 16)) { fprintf(stderr, "failed to enable plane: %s\n", @@ -908,7 +910,7 @@ set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) return -1; } - ovr->crtc_id = c->crtc_id; + ovr->crtc_id = crtc->crtc->crtc_id; return 0; } @@ -969,8 +971,8 @@ static void set_mode(struct device *dev, struct connector_arg *c, int count, /* if we have a plane/overlay to show, set that up now: */ for (j = 0; j < plane_count; j++) - if (p[j].con_id == c[i].id) - if (set_plane(dev, &c[i], &p[j])) + if (p[j].crtc_id == c[i].crtc_id) + if (set_plane(dev, &p[j])) return; } @@ -1099,7 +1101,7 @@ static int parse_plane(struct plane_arg *plane, const char *p) memset(plane, 0, sizeof *plane); - plane->con_id = strtoul(p, &end, 10); + plane->crtc_id = strtoul(p, &end, 10); if (*end != ':') return -EINVAL; @@ -1161,7 +1163,7 @@ static void usage(char *name) fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n"); fprintf(stderr, "\n Test options:\n\n"); - fprintf(stderr, "\t-P <connector_id>:<w>x<h>[+<x>+<y>][@<format>]\tset a plane\n"); + fprintf(stderr, "\t-P <crtc_id>:<w>x<h>[+<x>+<y>][@<format>]\tset a plane\n"); fprintf(stderr, "\t-s <connector_id>[@<crtc_id>]:<mode>[@<format>]\tset a mode\n"); fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n"); commit 56592680bbb1bb73d08bdce317046d0401dcfba0 Author: Laurent Pinchart <lau...@id...> Date: Wed Feb 27 05:35:13 2013 +0100 modetest: Store the mode in the crtc structure This prepares the code for the split in separate functions of CRTC and planes setup. Signed-off-by: Laurent Pinchart <lau...@id...> diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index d25d1f7..a7ead01 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -62,6 +62,7 @@ struct crtc { drmModeCrtc *crtc; drmModeObjectProperties *props; drmModePropertyRes **props_info; + drmModeModeInfo *mode; }; struct encoder { @@ -524,6 +525,7 @@ static void free_resources(struct resources *res) static struct resources *get_resources(struct device *dev) { struct resources *res; + int i; res = malloc(sizeof *res); if (res == 0) @@ -598,6 +600,9 @@ static struct resources *get_resources(struct device *dev) get_properties(res, res, crtc, CRTC); get_properties(res, res, connector, CONNECTOR); + for (i = 0; i < res->res->count_crtcs; ++i) + res->crtcs[i].mode = &res->crtcs[i].crtc->mode; + res->plane_res = drmModeGetPlaneResources(dev->fd); if (!res->plane_res) { fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", @@ -714,6 +719,7 @@ static void connector_find_mode(struct device *dev, struct connector_arg *c) struct crtc *crtc = &dev->resources->crtcs[i]; if (c->crtc_id == crtc->crtc->crtc_id) { + crtc->mode = c->mode; c->crtc = crtc; break; } @@ -884,8 +890,8 @@ set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) if (!p->has_position) { /* Default to the middle of the screen */ - crtc_x = (c->mode->hdisplay - p->w) / 2; - crtc_y = (c->mode->vdisplay - p->h) / 2; + crtc_x = (c->crtc->mode->hdisplay - p->w) / 2; + crtc_y = (c->crtc->mode->vdisplay - p->h) / 2; } else { crtc_x = p->x; crtc_y = p->y; commit a6349d0a0f9d3e017ac761ba912279c7d1e94eb7 Author: Laurent Pinchart <lau...@id...> Date: Wed Feb 27 05:35:13 2013 +0100 modetest: Store the crtc in the connector_arg structure This prepares the code for the split in separate functions of CRTC and planes setup. Signed-off-by: Laurent Pinchart <lau...@id...> diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index 6674598..d25d1f7 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -634,11 +634,12 @@ error: */ struct connector_arg { uint32_t id; + uint32_t crtc_id; char mode_str[64]; char format_str[5]; unsigned int fourcc; drmModeModeInfo *mode; - int crtc; + struct crtc *crtc; unsigned int fb_id[2], current_fb_id; struct timeval start; @@ -690,18 +691,33 @@ static void connector_find_mode(struct device *dev, struct connector_arg *c) return; } - /* Now get the encoder */ - for (i = 0; i < dev->resources->res->count_encoders; i++) { - encoder = dev->resources->encoders[i].encoder; - if (!encoder) - continue; + /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise + * locate a CRTC that can be attached to the connector. + */ + if (c->crtc_id == (uint32_t)-1) { + for (i = 0; i < dev->resources->res->count_encoders; i++) { + encoder = dev->resources->encoders[i].encoder; + if (!encoder) + continue; + + if (encoder->encoder_id == connector->encoder_id) { + c->crtc_id = encoder->crtc_id; + break; + } + } + } + + if (c->crtc_id == (uint32_t)-1) + return; - if (encoder->encoder_id == connector->encoder_id) + for (i = 0; i < dev->resources->res->count_crtcs; i++) { + struct crtc *crtc = &dev->resources->crtcs[i]; + + if (c->crtc_id == crtc->crtc->crtc_id) { + c->crtc = crtc; break; + } } - - if (c->crtc == -1) - c->crtc = encoder->crtc_id; } /* ----------------------------------------------------------------------------- @@ -796,7 +812,7 @@ page_flip_handler(int fd, unsigned int frame, else new_fb_id = c->fb_id[0]; - drmModePageFlip(fd, c->crtc, new_fb_id, + drmModePageFlip(fd, c->crtc_id, new_fb_id, DRM_MODE_PAGE_FLIP_EVENT, c); c->current_fb_id = new_fb_id; c->swap_count++; @@ -826,14 +842,14 @@ set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) * CRTC index first, then iterate over available planes. */ for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) { - if (c->crtc == (int)dev->resources->res->crtcs[i]) { + if (c->crtc_id == dev->resources->res->crtcs[i]) { pipe = i; break; } } if (pipe == (unsigned int)dev->resources->res->count_crtcs) { - fprintf(stderr, "CRTC %u not found\n", c->crtc); + fprintf(stderr, "CRTC %u not found\n", c->crtc_id); return -1; } @@ -847,7 +863,7 @@ set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) } if (!plane_id) { - fprintf(stderr, "no unused plane available for CRTC %u\n", c->crtc); + fprintf(stderr, "no unused plane available for CRTC %u\n", c->crtc_id); return -1; } @@ -878,7 +894,7 @@ set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) crtc_h = p->h; /* note src coords (last 4 args) are in Q16 format */ - if (drmModeSetPlane(dev->fd, plane_id, c->crtc, p->fb_id, + if (drmModeSetPlane(dev->fd, plane_id, c->crtc_id, p->fb_id, plane_flags, crtc_x, crtc_y, crtc_w, crtc_h, 0, 0, p->w << 16, p->h << 16)) { fprintf(stderr, "failed to enable plane: %s\n", @@ -886,7 +902,7 @@ set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) return -1; } - ovr->crtc_id = c->crtc; + ovr->crtc_id = c->crtc_id; return 0; } @@ -930,9 +946,9 @@ static void set_mode(struct device *dev, struct connector_arg *c, int count, continue; printf("setting mode %s@%s on connector %d, crtc %d\n", - c[i].mode_str, c[i].format_str, c[i].id, c[i].crtc); + c[i].mode_str, c[i].format_str, c[i].id, c[i].crtc_id); - ret = drmModeSetCrtc(dev->fd, c[i].crtc, fb_id, x, 0, + ret = drmModeSetCrtc(dev->fd, c[i].crtc_id, fb_id, x, 0, &c[i].id, 1, c[i].mode); /* XXX: Actually check if this is needed */ @@ -971,7 +987,7 @@ static void set_mode(struct device *dev, struct connector_arg *c, int count, if (c[i].mode == NULL) continue; - ret = drmModePageFlip(dev->fd, c[i].crtc, other_fb_id, + ret = drmModePageFlip(dev->fd, c[i].crtc_id, other_fb_id, DRM_MODE_PAGE_FLIP_EVENT, &c[i]); if (ret) { fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); @@ -1039,13 +1055,13 @@ static int parse_connector(struct connector_arg *c, const char *arg) const char *p; char *endp; - c->crtc = -1; + c->crtc_id = (uint32_t)-1; strcpy(c->format_str, "XR24"); c->id = strtoul(arg, &endp, 10); if (*endp == '@') { arg = endp + 1; - c->crtc = strtoul(arg, &endp, 10); + c->crtc_id = strtoul(arg, &endp, 10); } if (*endp != ':') return -1; commit b373de3095e7518d62cfc99a1b22da8dc3435a88 Author: Laurent Pinchart <lau...@id...> Date: Wed Feb 27 05:35:13 2013 +0100 modetest: Remove the struct connector_arg encoder field The field is no needed, make it a local variable where used. Signed-off-by: Laurent Pinchart <lau...@id...> diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index e8f6790..6674598 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -638,7 +638,6 @@ struct connector_arg { char format_str[5]; unsigned int fourcc; drmModeModeInfo *mode; - drmModeEncoder *encoder; int crtc; unsigned int fb_id[2], current_fb_id; struct timeval start; @@ -659,6 +658,7 @@ struct plane_arg { static void connector_find_mode(struct device *dev, struct connector_arg *c) { drmModeConnector *connector; + drmModeEncoder *encoder; int i, j; /* First, find the connector & mode */ @@ -692,16 +692,16 @@ static void connector_find_mode(struct device *dev, struct connector_arg *c) /* Now get the encoder */ for (i = 0; i < dev->resources->res->count_encoders; i++) { - c->encoder = dev->resources->encoders[i].encoder; - if (!c->encoder) + encoder = dev->resources->encoders[i].encoder; + if (!encoder) continue; - if (c->encoder->encoder_id == connector->encoder_id) + if (encoder->encoder_id == connector->encoder_id) break; } if (c->crtc == -1) - c->crtc = c->encoder->crtc_id; + c->crtc = encoder->crtc_id; } /* ----------------------------------------------------------------------------- commit 605efd7e05e94b8d9d742d3a8af1040776e2742d Author: Laurent Pinchart <lau...@id...> Date: Wed Feb 27 05:35:13 2013 +0100 modetest: Compute CRTC pipe number as needed Signed-off-by: Laurent Pinchart <lau...@id...> diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index a1ee787..e8f6790 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -640,7 +640,6 @@ struct connector_arg { drmModeModeInfo *mode; drmModeEncoder *encoder; int crtc; - int pipe; unsigned int fb_id[2], current_fb_id; struct timeval start; @@ -703,15 +702,6 @@ static void connector_find_mode(struct device *dev, struct connector_arg *c) if (c->crtc == -1) c->crtc = c->encoder->crtc_id; - - /* and figure out which crtc index it is: */ - for (i = 0; i < dev->resources->res->count_crtcs; i++) { - if (c->crtc == (int)dev->resources->res->crtcs[i]) { - c->pipe = i; - break; - } - } - } /* ----------------------------------------------------------------------------- @@ -829,15 +819,30 @@ set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) struct kms_bo *plane_bo; uint32_t plane_flags = 0; int crtc_x, crtc_y, crtc_w, crtc_h; + unsigned int pipe; unsigned int i; - /* find an unused plane which can be connected to our crtc */ + /* Find an unused plane which can be connected to our CRTC. Find the + * CRTC index first, then iterate over available planes. + */ + for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) { + if (c->crtc == (int)dev->resources->res->crtcs[i]) { + pipe = i; + break; + } + } + + if (pipe == (unsigned int)dev->resources->res->count_crtcs) { + fprintf(stderr, "CRTC %u not found\n", c->crtc); + return -1; + } + for (i = 0; i < dev->resources->plane_res->count_planes && !plane_id; i++) { ovr = dev->resources->planes[i].plane; if (!ovr) continue; - if ((ovr->possible_crtcs & (1 << c->pipe)) && !ovr->crtc_id) + if ((ovr->possible_crtcs & (1 << pipe)) && !ovr->crtc_id) plane_id = ovr->plane_id; } commit 549fe0ba627a67b6ae1334eb5cf274a3dfb1fd69 Author: Laurent Pinchart <lau...@id...> Date: Wed Feb 27 05:35:13 2013 +0100 modetest: Create a device structure Instead of passing the device fd and resources as global variables group them in a device structure and pass it explictly to all functions that need it. Signed-off-by: Laurent Pinchart <lau...@id...> diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index 1f241c7..a1ee787 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -95,8 +95,12 @@ struct resources { struct plane *planes; }; -struct resources *resources; -int fd; +struct device { + int fd; + + struct resources *resources; + struct kms_driver *kms; +}; #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -197,15 +201,15 @@ static const char *mode_flag_names[] = { static bit_name_fn(mode_flag) -static void dump_encoders(void) +static void dump_encoders(struct device *dev) { drmModeEncoder *encoder; int i; printf("Encoders:\n"); printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); - for (i = 0; i < resources->res->count_encoders; i++) { - encoder = resources->encoders[i].encoder; + for (i = 0; i < dev->resources->res->count_encoders; i++) { + encoder = dev->resources->encoders[i].encoder; if (!encoder) continue; @@ -240,14 +244,13 @@ static void dump_mode(drmModeModeInfo *mode) printf("\n"); } -static void -dump_blob(uint32_t blob_id) +static void dump_blob(struct device *dev, uint32_t blob_id) { uint32_t i; unsigned char *blob_data; drmModePropertyBlobPtr blob; - blob = drmModeGetPropertyBlob(fd, blob_id); + blob = drmModeGetPropertyBlob(dev->fd, blob_id); if (!blob) return; @@ -263,8 +266,8 @@ dump_blob(uint32_t blob_id) drmModeFreePropertyBlob(blob); } -static void -dump_prop(drmModePropertyPtr prop, uint32_t prop_id, uint64_t value) +static void dump_prop(struct device *dev, drmModePropertyPtr prop, + uint32_t prop_id, uint64_t value) { int i; printf("\t%d", prop_id); @@ -316,7 +319,7 @@ dump_prop(drmModePropertyPtr prop, uint32_t prop_id, uint64_t value) if (prop->flags & DRM_MODE_PROP_BLOB) { printf("\t\tblobs:\n"); for (i = 0; i < prop->count_blobs; i++) - dump_blob(prop->blob_ids[i]); + dump_blob(dev, prop->blob_ids[i]); printf("\n"); } else { assert(prop->count_blobs == 0); @@ -324,19 +327,19 @@ dump_prop(drmModePropertyPtr prop, uint32_t prop_id, uint64_t value) printf("\t\tvalue:"); if (prop->flags & DRM_MODE_PROP_BLOB) - dump_blob(value); + dump_blob(dev, value); else printf(" %"PRIu64"\n", value); } -static void dump_connectors(void) +static void dump_connectors(struct device *dev) { int i, j; printf("Connectors:\n"); printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n"); - for (i = 0; i < resources->res->count_connectors; i++) { - struct connector *_connector = &resources->connectors[i]; + for (i = 0; i < dev->resources->res->count_connectors; i++) { + struct connector *_connector = &dev->resources->connectors[i]; drmModeConnector *connector = _connector->connector; if (!connector) continue; @@ -364,7 +367,7 @@ static void dump_connectors(void) if (_connector->props) { printf(" props:\n"); for (j = 0; j < (int)_connector->props->count_props; j++) - dump_prop(_connector->props_info[j], + dump_prop(dev, _connector->props_info[j], _connector->props->props[j], _connector->props->prop_values[j]); } @@ -372,15 +375,15 @@ static void dump_connectors(void) printf("\n"); } -static void dump_crtcs(void) +static void dump_crtcs(struct device *dev) { int i; uint32_t j; printf("CRTCs:\n"); printf("id\tfb\tpos\tsize\n"); - for (i = 0; i < resources->res->count_crtcs; i++) { - struct crtc *_crtc = &resources->crtcs[i]; + for (i = 0; i < dev->resources->res->count_crtcs; i++) { + struct crtc *_crtc = &dev->resources->crtcs[i]; drmModeCrtc *crtc = _crtc->crtc; if (!crtc) continue; @@ -395,7 +398,7 @@ static void dump_crtcs(void) if (_crtc->props) { printf(" props:\n"); for (j = 0; j < _crtc->props->count_props; j++) - dump_prop(_crtc->props_info[j], + dump_prop(dev, _crtc->props_info[j], _crtc->props->props[j], _crtc->props->prop_values[j]); } else { @@ -405,15 +408,15 @@ static void dump_crtcs(void) printf("\n"); } -static void dump_framebuffers(void) +static void dump_framebuffers(struct device *dev) { drmModeFB *fb; int i; printf("Frame buffers:\n"); printf("id\tsize\tpitch\n"); - for (i = 0; i < resources->res->count_fbs; i++) { - fb = resources->fbs[i].fb; + for (i = 0; i < dev->resources->res->count_fbs; i++) { + fb = dev->resources->fbs[i].fb; if (!fb) continue; @@ -425,18 +428,18 @@ static void dump_framebuffers(void) printf("\n"); } -static void dump_planes(void) +static void dump_planes(struct device *dev) { unsigned int i, j; printf("Planes:\n"); printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n"); - if (!resources->plane_res) + if (!dev->resources->plane_res) return; - for (i = 0; i < resources->plane_res->count_planes; i++) { - struct plane *plane = &resources->planes[i]; + for (i = 0; i < dev->resources->plane_res->count_planes; i++) { + struct plane *plane = &dev->resources->planes[i]; drmModePlane *ovr = plane->plane; if (!ovr) continue; @@ -457,7 +460,7 @@ static void dump_planes(void) if (plane->props) { printf(" props:\n"); for (j = 0; j < plane->props->count_props; j++) - dump_prop(plane->props_info[j], + dump_prop(dev, plane->props_info[j], plane->props->props[j], plane->props->prop_values[j]); } else { @@ -518,7 +521,7 @@ static void free_resources(struct resources *res) free(res); } -static struct resources *get_resources(int fd) +static struct resources *get_resources(struct device *dev) { struct resources *res; @@ -528,7 +531,7 @@ static struct resources *get_resources(int fd) memset(res, 0, sizeof *res); - res->res = drmModeGetResources(fd); + res->res = drmModeGetResources(dev->fd); if (!res->res) { fprintf(stderr, "drmModeGetResources failed: %s\n", strerror(errno)); @@ -553,7 +556,7 @@ static struct resources *get_resources(int fd) int i; \ for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ (_res)->type##s[i].type = \ - drmModeGet##Type(fd, (_res)->__res->type##s[i]); \ + drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \ if (!(_res)->type##s[i].type) \ fprintf(stderr, "could not get %s %i: %s\n", \ #type, (_res)->__res->type##s[i], \ @@ -573,7 +576,7 @@ static struct resources *get_resources(int fd) struct type *obj = &res->type##s[i]; \ unsigned int j; \ obj->props = \ - drmModeObjectGetProperties(fd, obj->type->type##_id, \ + drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \ DRM_MODE_OBJECT_##Type); \ if (!obj->props) { \ fprintf(stderr, \ @@ -588,14 +591,14 @@ static struct resources *get_resources(int fd) continue; \ for (j = 0; j < obj->props->count_props; ++j) \ obj->props_info[j] = \ - drmModeGetProperty(fd, obj->props->props[j]); \ + drmModeGetProperty(dev->fd, obj->props->props[j]); \ } \ } while (0) get_properties(res, res, crtc, CRTC); get_properties(res, res, connector, CONNECTOR); - res->plane_res = drmModeGetPlaneResources(fd); + res->plane_res = drmModeGetPlaneResources(dev->fd); if (!res->plane_res) { fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", strerror(errno)); @@ -654,16 +657,15 @@ struct plane_arg { unsigned int fourcc; }; -static void -connector_find_mode(struct connector_arg *c) +static void connector_find_mode(struct device *dev, struct connector_arg *c) { drmModeConnector *connector; int i, j; /* First, find the connector & mode */ c->mode = NULL; - for (i = 0; i < resources->res->count_connectors; i++) { - connector = resources->connectors[i].connector; + for (i = 0; i < dev->resources->res->count_connectors; i++) { + connector = dev->resources->connectors[i].connector; if (!connector) continue; @@ -690,8 +692,8 @@ connector_find_mode(struct connector_arg *c) } /* Now get the encoder */ - for (i = 0; i < resources->res->count_encoders; i++) { - c->encoder = resources->encoders[i].encoder; + for (i = 0; i < dev->resources->res->count_encoders; i++) { + c->encoder = dev->resources->encoders[i].encoder; if (!c->encoder) continue; @@ -703,8 +705,8 @@ connector_find_mode(struct connector_arg *c) c->crtc = c->encoder->crtc_id; /* and figure out which crtc index it is: */ - for (i = 0; i < resources->res->count_crtcs; i++) { - if (c->crtc == (int)resources->res->crtcs[i]) { + for (i = 0; i < dev->resources->res->count_crtcs; i++) { + if (c->crtc == (int)dev->resources->res->crtcs[i]) { c->pipe = i; break; } @@ -724,7 +726,7 @@ struct property_arg { uint64_t value; }; -static void set_property(struct property_arg *p) +static void set_property(struct device *dev, struct property_arg *p) { drmModeObjectProperties *props; drmModePropertyRes **props_info; @@ -748,11 +750,11 @@ static void set_property(struct property_arg *p) } \ } while(0) \ - find_object(resources, res, crtc, CRTC); + find_object(dev->resources, res, crtc, CRTC); if (p->obj_type == 0) - find_object(resources, res, connector, CONNECTOR); + find_object(dev->resources, res, connector, CONNECTOR); if (p->obj_type == 0) - find_object(resources, plane_res, plane, PLANE); + find_object(dev->resources, plane_res, plane, PLANE); if (p->obj_type == 0) { fprintf(stderr, "Object %i not found, can't set property\n", p->obj_id); @@ -780,7 +782,8 @@ static void set_property(struct property_arg *p) p->prop_id = props->props[i]; - ret = drmModeObjectSetProperty(fd, p->obj_id, p->obj_type, p->prop_id, p->value); + ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type, + p->prop_id, p->value); if (ret < 0) fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n", obj_type, p->obj_id, p->name, p->value, strerror(errno)); @@ -818,7 +821,7 @@ page_flip_handler(int fd, unsigned int frame, } static int -set_plane(struct kms_driver *kms, struct connector_arg *c, struct plane_arg *p) +set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p) { drmModePlane *ovr; uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ @@ -829,8 +832,8 @@ set_plane(struct kms_driver *kms, struct connector_arg *c, struct plane_arg *p) unsigned int i; /* find an unused plane which can be connected to our crtc */ - for (i = 0; i < resources->plane_res->count_planes && !plane_id; i++) { - ovr = resources->planes[i].plane; + for (i = 0; i < dev->resources->plane_res->count_planes && !plane_id; i++) { + ovr = dev->resources->planes[i].plane; if (!ovr) continue; @@ -846,13 +849,13 @@ set_plane(struct kms_driver *kms, struct connector_arg *c, struct plane_arg *p) fprintf(stderr, "testing %dx%d@%s overlay plane %u\n", p->w, p->h, p->format_str, plane_id); - plane_bo = create_test_buffer(kms, p->fourcc, p->w, p->h, handles, + plane_bo = create_test_buffer(dev->kms, p->fourcc, p->w, p->h, handles, pitches, offsets, PATTERN_TILES); if (plane_bo == NULL) return -1; /* just use single plane format for now.. */ - if (drmModeAddFB2(fd, p->w, p->h, p->fourcc, + if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc, handles, pitches, offsets, &p->fb_id, plane_flags)) { fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); return -1; @@ -870,7 +873,7 @@ set_plane(struct kms_driver *kms, struct connector_arg *c, struct plane_arg *p) crtc_h = p->h; /* note src coords (last 4 args) are in Q16 format */ - if (drmModeSetPlane(fd, plane_id, c->crtc, p->fb_id, + if (drmModeSetPlane(dev->fd, plane_id, c->crtc, p->fb_id, plane_flags, crtc_x, crtc_y, crtc_w, crtc_h, 0, 0, p->w << 16, p->h << 16)) { fprintf(stderr, "failed to en... [truncated message content] |