diff options
-rw-r--r-- | libdrm/xf86drm.h | 1 | ||||
-rw-r--r-- | shared-core/drm.h | 1 | ||||
-rw-r--r-- | shared-core/i915_dma.c | 143 | ||||
-rw-r--r-- | shared-core/i915_drm.h | 14 | ||||
-rw-r--r-- | shared-core/i915_drv.h | 19 | ||||
-rw-r--r-- | shared-core/i915_irq.c | 150 |
6 files changed, 240 insertions, 88 deletions
diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 34c9ec0e..e84b23d7 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -270,6 +270,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_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ 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 */ diff --git a/shared-core/drm.h b/shared-core/drm.h index 447065c7..bcb3eedf 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -561,6 +561,7 @@ 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_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ _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 */ diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 98a3b7c8..c8b7e588 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -165,10 +165,7 @@ static int i915_initialize(drm_device_t * dev, 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; - dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; + dev_priv->sarea_priv->pf_current_page = 0; /* We are using separate values as placeholders for mechanisms for * private backbuffer/depthbuffer usage. @@ -429,22 +426,22 @@ static int i915_emit_box(drm_device_t * dev, * emit. For now, do it in both places: */ -static void i915_emit_breadcrumb(drm_device_t *dev) +void i915_emit_breadcrumb(drm_device_t *dev) { drm_i915_private_t *dev_priv = dev->dev_private; RING_LOCALS; dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter; + if (dev_priv->counter > 0x7FFFFFFFUL) + dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1; + BEGIN_LP_RING(4); OUT_RING(CMD_STORE_DWORD_IDX); OUT_RING(20); OUT_RING(dev_priv->counter); OUT_RING(0); ADVANCE_LP_RING(); -#ifdef I915_HAVE_FENCE - drm_fence_flush_old(dev, 0, dev_priv->counter); -#endif } @@ -472,6 +469,7 @@ int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush) static int i915_dispatch_cmdbuffer(drm_device_t * dev, drm_i915_cmdbuffer_t * cmd) { + drm_i915_private_t *dev_priv = dev->dev_private; int nbox = cmd->num_cliprects; int i = 0, count, ret; @@ -498,6 +496,9 @@ static int i915_dispatch_cmdbuffer(drm_device_t * dev, } i915_emit_breadcrumb( dev ); +#ifdef I915_HAVE_FENCE + drm_fence_flush_old(dev, 0, dev_priv->counter); +#endif return 0; } @@ -543,57 +544,84 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev, } i915_emit_breadcrumb( dev ); +#ifdef I915_HAVE_FENCE + drm_fence_flush_old(dev, 0, dev_priv->counter); +#endif return 0; } -static int i915_dispatch_flip(drm_device_t * dev) +static void i915_do_dispatch_flip(drm_device_t * dev, int pipe, int sync) { drm_i915_private_t *dev_priv = dev->dev_private; + u32 num_pages, current_page, next_page, dspbase; + int shift = 2 * pipe, x, y; RING_LOCALS; - DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", - __FUNCTION__, - dev_priv->current_page, - dev_priv->sarea_priv->pf_current_page); - - i915_kernel_lost_context(dev); + /* Calculate display base offset */ + num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; + current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3; + next_page = (current_page + 1) % num_pages; - BEGIN_LP_RING(2); - OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); - OUT_RING(0); - ADVANCE_LP_RING(); + switch (next_page) { + default: + case 0: + dspbase = dev_priv->sarea_priv->front_offset; + break; + case 1: + dspbase = dev_priv->sarea_priv->back_offset; + break; + case 2: + dspbase = dev_priv->sarea_priv->third_offset; + break; + } - BEGIN_LP_RING(6); - OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP); - OUT_RING(0); - if (dev_priv->current_page == 0) { - OUT_RING(dev_priv->back_offset); - dev_priv->current_page = 1; + if (pipe == 0) { + x = dev_priv->sarea_priv->pipeA_x; + y = dev_priv->sarea_priv->pipeA_y; } else { - OUT_RING(dev_priv->front_offset); - dev_priv->current_page = 0; + x = dev_priv->sarea_priv->pipeB_x; + y = dev_priv->sarea_priv->pipeB_y; } - OUT_RING(0); - ADVANCE_LP_RING(); - BEGIN_LP_RING(2); - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP); - OUT_RING(0); - ADVANCE_LP_RING(); + dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp; - dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; + DRM_DEBUG("pipe=%d current_page=%d dspbase=0x%x\n", pipe, current_page, + dspbase); BEGIN_LP_RING(4); - OUT_RING(CMD_STORE_DWORD_IDX); - OUT_RING(20); - OUT_RING(dev_priv->counter); - OUT_RING(0); + OUT_RING(sync ? 0 : + (MI_WAIT_FOR_EVENT | (pipe ? MI_WAIT_FOR_PLANE_B_FLIP : + MI_WAIT_FOR_PLANE_A_FLIP))); + OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) | + (pipe ? DISPLAY_PLANE_B : DISPLAY_PLANE_A)); + OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp); + OUT_RING(dspbase); ADVANCE_LP_RING(); + + dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift); + dev_priv->sarea_priv->pf_current_page |= next_page << shift; +} + +void i915_dispatch_flip(drm_device_t * dev, int pipes, int sync) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int i; + + DRM_DEBUG("%s: pipes=0x%x pfCurrentPage=%d\n", + __FUNCTION__, + pipes, dev_priv->sarea_priv->pf_current_page); + + i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH); + + for (i = 0; i < 2; i++) + if (pipes & (1 << i)) + i915_do_dispatch_flip(dev, i, sync); + + i915_emit_breadcrumb(dev); #ifdef I915_HAVE_FENCE - drm_fence_flush_old(dev, 0, dev_priv->counter); + if (!sync) + drm_fence_flush_old(dev, 0, dev_priv->counter); #endif - dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; - return 0; } static int i915_quiescent(drm_device_t * dev) @@ -686,10 +714,21 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS) static int i915_do_cleanup_pageflip(drm_device_t * dev) { drm_i915_private_t *dev_priv = dev->dev_private; + int i, pipes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; DRM_DEBUG("%s\n", __FUNCTION__); - if (dev_priv->current_page != 0) - i915_dispatch_flip(dev); + + for (i = 0, pipes = 0; i < 2; i++) + if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) { + dev_priv->sarea_priv->pf_current_page = + (dev_priv->sarea_priv->pf_current_page & + ~(0x3 << (2 * i))) | (num_pages - 1) << (2 * i); + + pipes |= 1 << i; + } + + if (pipes) + i915_dispatch_flip(dev, pipes, 0); return 0; } @@ -697,12 +736,24 @@ static int i915_do_cleanup_pageflip(drm_device_t * dev) static int i915_flip_bufs(DRM_IOCTL_ARGS) { DRM_DEVICE; + drm_i915_flip_t param; DRM_DEBUG("%s\n", __FUNCTION__); LOCK_TEST_WITH_RETURN(dev, filp); - return i915_dispatch_flip(dev); + DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_flip_t __user *) data, + sizeof(param)); + + if (param.pipes & ~0x3) { + DRM_ERROR("Invalid pipes 0x%x, only <= 0x3 is valid\n", + param.pipes); + return DRM_ERR(EINVAL); + } + + i915_dispatch_flip(dev, param.pipes, 0); + + return 0; } @@ -847,6 +898,7 @@ void i915_driver_lastclose(drm_device_t * dev) { if (dev->dev_private) { drm_i915_private_t *dev_priv = dev->dev_private; + i915_do_cleanup_pageflip(dev); i915_mem_takedown(&(dev_priv->agp_heap)); } i915_dma_cleanup(dev); @@ -856,9 +908,6 @@ void i915_driver_preclose(drm_device_t * dev, DRMFILE filp) { if (dev->dev_private) { drm_i915_private_t *dev_priv = dev->dev_private; - if (dev_priv->page_flipping) { - i915_do_cleanup_pageflip(dev); - } i915_mem_release(dev, filp, dev_priv->agp_heap); } } diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index 22a81d14..1f32313e 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -113,6 +113,12 @@ typedef struct _drm_i915_sarea { int pipeB_y; int pipeB_w; int pipeB_h; + + /* Triple buffering */ + drm_handle_t third_handle; + int third_offset; + int third_size; + unsigned int third_tiled; } drm_i915_sarea_t; /* Driver specific fence types and classes. @@ -156,7 +162,7 @@ typedef struct _drm_i915_sarea { #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) -#define DRM_IOCTL_I915_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLIP) +#define DRM_IOCTL_I915_FLIP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FLIP, drm_i915_flip_t) #define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t) #define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t) #define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t) @@ -172,6 +178,12 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) +/* Asynchronous page flipping: + */ +typedef struct drm_i915_flip { + int pipes; +} drm_i915_flip_t; + /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. */ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 3cb1a573..a3736160 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -37,7 +37,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20060929" +#define DRIVER_DATE "20070209" /* Interface history: * @@ -49,9 +49,10 @@ * 1.6: - New ioctl for scheduling buffer swaps on vertical blank * - Support vertical blank on secondary display pipe * 1.8: New ioctl for ARB_Occlusion_Query + * 1.9: Usable page flipping and triple buffering */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 8 +#define DRIVER_MINOR 9 #define DRIVER_PATCHLEVEL 0 #if defined(__linux__) @@ -84,6 +85,7 @@ typedef struct _drm_i915_vbl_swap { drm_drawable_t drw_id; unsigned int pipe; unsigned int sequence; + int flip; } drm_i915_vbl_swap_t; typedef struct drm_i915_private { @@ -99,10 +101,6 @@ typedef struct drm_i915_private { uint32_t counter; unsigned int cpp; - int back_offset; - int front_offset; - int current_page; - int page_flipping; int use_mi_batchbuffer_start; wait_queue_head_t irq_queue; @@ -152,6 +150,8 @@ extern void i915_driver_preclose(drm_device_t * dev, DRMFILE filp); extern int i915_driver_device_is_agp(drm_device_t * dev); extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +extern void i915_emit_breadcrumb(drm_device_t *dev); +extern void i915_dispatch_flip(drm_device_t * dev, int pipes, int sync); extern int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush); @@ -251,10 +251,6 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1) #define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1) -#define INST_PARSER_CLIENT 0x00000000 -#define INST_OP_FLUSH 0x02000000 -#define INST_FLUSH_MAP_CACHE 0x00000001 - #define CMD_MI_FLUSH (0x04 << 23) #define MI_NO_WRITE_FLUSH (1 << 2) #define MI_READ_FLUSH (1 << 0) @@ -352,6 +348,7 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define MI_BATCH_NON_SECURE (1) #define MI_WAIT_FOR_EVENT ((0x3<<23)) +#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6) #define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) #define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) @@ -359,6 +356,8 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2) #define ASYNC_FLIP (1<<22) +#define DISPLAY_PLANE_A (0<<20) +#define DISPLAY_PLANE_B (1<<20) #define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 5ff87880..5da54107 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -38,6 +38,50 @@ #define MAX_NOPID ((u32)~0) /** + * Emit a synchronous flip. + * + * This function must be called with the drawable spinlock held. + */ +static void +i915_dispatch_vsync_flip(drm_device_t *dev, drm_drawable_info_t *drw, int pipe) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; + u16 x1, y1, x2, y2; + int pf_pipes = 1 << pipe; + + /* If the window is visible on the other pipe, we have to flip on that + * pipe as well. + */ + if (pipe == 1) { + x1 = sarea_priv->pipeA_x; + y1 = sarea_priv->pipeA_y; + x2 = x1 + sarea_priv->pipeA_w; + y2 = y1 + sarea_priv->pipeA_h; + } else { + x1 = sarea_priv->pipeB_x; + y1 = sarea_priv->pipeB_y; + x2 = x1 + sarea_priv->pipeB_w; + y2 = y1 + sarea_priv->pipeB_h; + } + + if (x2 > 0 && y2 > 0) { + int i, num_rects = drw->num_rects; + drm_clip_rect_t *rect = drw->rects; + + for (i = 0; i < num_rects; i++) + if (!(rect[i].x1 >= x2 || rect[i].y1 >= y2 || + rect[i].x2 <= x1 || rect[i].y2 <= y1)) { + pf_pipes = 0x3; + + break; + } + } + + i915_dispatch_flip(dev, pf_pipes, 1); +} + +/** * Emit blits for scheduled buffer swaps. * * This function will be called with the HW lock held. @@ -47,12 +91,12 @@ static void i915_vblank_tasklet(drm_device_t *dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; struct list_head *list, *tmp, hits, *hit; - int nhits, nrects, slice[2], upper[2], lower[2], i; + int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages; unsigned counter[2] = { atomic_read(&dev->vbl_received), atomic_read(&dev->vbl_received2) }; drm_drawable_info_t *drw; drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; - u32 cpp = dev_priv->cpp; + u32 cpp = dev_priv->cpp, offsets[3]; u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB) @@ -125,25 +169,17 @@ static void i915_vblank_tasklet(drm_device_t *dev) 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; - upper[0] = upper[1] = 0; slice[0] = max(sarea_priv->pipeA_h / nhits, 1); slice[1] = max(sarea_priv->pipeB_h / nhits, 1); lower[0] = sarea_priv->pipeA_y + slice[0]; lower[1] = sarea_priv->pipeB_y + slice[0]; + offsets[0] = sarea_priv->front_offset; + offsets[1] = sarea_priv->back_offset; + offsets[2] = sarea_priv->third_offset; + num_pages = sarea_priv->third_handle ? 3 : 2; + spin_lock(&dev->drw_lock); /* Emit blits for buffer swaps, partitioning both outputs into as many @@ -154,6 +190,8 @@ static void i915_vblank_tasklet(drm_device_t *dev) for (i = 0; i++ < nhits; upper[0] = lower[0], lower[0] += slice[0], upper[1] = lower[1], lower[1] += slice[1]) { + int init_drawrect = 1; + if (i == nhits) lower[0] = lower[1] = sarea_priv->height; @@ -161,7 +199,7 @@ static void i915_vblank_tasklet(drm_device_t *dev) drm_i915_vbl_swap_t *swap_hit = list_entry(hit, drm_i915_vbl_swap_t, head); drm_clip_rect_t *rect; - int num_rects, pipe; + int num_rects, pipe, front, back; unsigned short top, bottom; drw = drm_get_drawable_info(dev, swap_hit->drw_id); @@ -169,11 +207,38 @@ static void i915_vblank_tasklet(drm_device_t *dev) if (!drw) continue; - rect = drw->rects; pipe = swap_hit->pipe; + + if (swap_hit->flip) { + i915_dispatch_vsync_flip(dev, drw, pipe); + continue; + } + + if (init_drawrect) { + 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; + + init_drawrect = 0; + } + + rect = drw->rects; top = upper[pipe]; bottom = lower[pipe]; + front = (dev_priv->sarea_priv->pf_current_page >> + (2 * pipe)) & 0x3; + back = (front + 1) % num_pages; + for (num_rects = drw->num_rects; num_rects--; rect++) { int y1 = max(rect->y1, top); int y2 = min(rect->y2, bottom); @@ -187,10 +252,10 @@ static void i915_vblank_tasklet(drm_device_t *dev) OUT_RING(pitchropcpp); OUT_RING((y1 << 16) | rect->x1); OUT_RING((y2 << 16) | rect->x2); - OUT_RING(sarea_priv->front_offset); + OUT_RING(offsets[front]); OUT_RING((y1 << 16) | rect->x1); OUT_RING(pitchropcpp & 0xffff); - OUT_RING(sarea_priv->back_offset); + OUT_RING(offsets[back]); ADVANCE_LP_RING(); } @@ -281,17 +346,9 @@ int i915_emit_irq(drm_device_t * dev) DRM_DEBUG("%s\n", __FUNCTION__); - dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter; + i915_emit_breadcrumb(dev); - if (dev_priv->counter > 0x7FFFFFFFUL) - dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1; - - BEGIN_LP_RING(6); - OUT_RING(CMD_STORE_DWORD_IDX); - OUT_RING(20); - OUT_RING(dev_priv->counter); - - OUT_RING(0); + BEGIN_LP_RING(2); OUT_RING(0); OUT_RING(GFX_OP_USER_INTERRUPT); ADVANCE_LP_RING(); @@ -523,7 +580,8 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) sizeof(swap)); if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | - _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) { + _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS | + _DRM_VBLANK_FLIP)) { DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype); return DRM_ERR(EINVAL); } @@ -561,6 +619,33 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) } } + if (swap.seqtype & _DRM_VBLANK_FLIP) { + swap.sequence--; + + if ((curseq - swap.sequence) <= (1<<23)) { + drm_drawable_info_t *drw; + + LOCK_TEST_WITH_RETURN(dev, filp); + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + drw = drm_get_drawable_info(dev, swap.drawable); + + if (!drw) { + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + DRM_DEBUG("Invalid drawable ID %d\n", + swap.drawable); + return DRM_ERR(EINVAL); + } + + i915_dispatch_vsync_flip(dev, drw, pipe); + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + return 0; + } + } + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); list_for_each(list, &dev_priv->vbl_swaps.head) { @@ -569,6 +654,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) if (vbl_swap->drw_id == swap.drawable && vbl_swap->pipe == pipe && vbl_swap->sequence == swap.sequence) { + vbl_swap->flip = (swap.seqtype & _DRM_VBLANK_FLIP); spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Already scheduled\n"); return 0; @@ -594,6 +680,10 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) vbl_swap->drw_id = swap.drawable; vbl_swap->pipe = pipe; vbl_swap->sequence = swap.sequence; + vbl_swap->flip = (swap.seqtype & _DRM_VBLANK_FLIP); + + if (vbl_swap->flip) + swap.sequence++; spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); |