From 078e4307266bcfdc7d4be1a70df65d35dda4d0d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 2 Feb 2007 17:23:42 +0100 Subject: i915: Unify breadcrumb emission. --- shared-core/i915_dma.c | 26 +++++++++++++------------- shared-core/i915_drv.h | 1 + shared-core/i915_irq.c | 12 ++---------- 3 files changed, 16 insertions(+), 23 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 98a3b7c8..82fde7e7 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -429,22 +429,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 +472,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 +499,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,6 +547,9 @@ 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; } @@ -580,18 +587,11 @@ static int i915_dispatch_flip(drm_device_t * dev) OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP); OUT_RING(0); ADVANCE_LP_RING(); - - dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; - - BEGIN_LP_RING(4); - OUT_RING(CMD_STORE_DWORD_IDX); - OUT_RING(20); - OUT_RING(dev_priv->counter); - OUT_RING(0); - ADVANCE_LP_RING(); + i915_emit_breadcrumb(dev); #ifdef I915_HAVE_FENCE drm_fence_flush_old(dev, 0, dev_priv->counter); #endif + dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; return 0; } diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 3cb1a573..f922d1f5 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -152,6 +152,7 @@ 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 int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush); diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 5ff87880..e373a8df 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -281,17 +281,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(); -- cgit v1.2.3 From 34aa3393d04da1201815143c92a5bef83bf0d585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 2 Feb 2007 17:28:43 +0100 Subject: i915: Page flipping enhancements. Leave it to the client to wait for the flip to complete when necessary, but wait for a previous flip to complete before emitting another one. This should help avoid unnecessary stalling of the ring due to pending flips. Call i915_do_cleanup_pageflip() unconditionally in preclose. --- shared-core/i915_dma.c | 14 +++++++------- shared-core/i915_drv.h | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 82fde7e7..18fe0881 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -570,6 +570,12 @@ static int i915_dispatch_flip(drm_device_t * dev) OUT_RING(0); ADVANCE_LP_RING(); + /* Wait for a pending flip to take effect */ + BEGIN_LP_RING(2); + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP); + OUT_RING(0); + ADVANCE_LP_RING(); + BEGIN_LP_RING(6); OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP); OUT_RING(0); @@ -583,10 +589,6 @@ static int i915_dispatch_flip(drm_device_t * dev) 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(); i915_emit_breadcrumb(dev); #ifdef I915_HAVE_FENCE drm_fence_flush_old(dev, 0, dev_priv->counter); @@ -856,9 +858,7 @@ 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_do_cleanup_pageflip(dev); i915_mem_release(dev, filp, dev_priv->agp_heap); } } diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index f922d1f5..a81653a7 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -102,7 +102,6 @@ typedef struct drm_i915_private { int back_offset; int front_offset; int current_page; - int page_flipping; int use_mi_batchbuffer_start; wait_queue_head_t irq_queue; -- cgit v1.2.3 From 6f89584e136211d7c4c69d88005f0e70393274f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 19 Feb 2007 12:27:54 +0100 Subject: i915: Improved page flipping support, including triple buffering. Pages are tracked independently on each pipe. Bump the minor version for 3D clients to know page flipping is usable, and bump driver date. --- shared-core/i915_dma.c | 113 +++++++++++++++++++++++++++++++++++++++---------- shared-core/i915_drm.h | 14 +++++- shared-core/i915_drv.h | 10 +++-- shared-core/i915_irq.c | 18 +++++--- 4 files changed, 122 insertions(+), 33 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 18fe0881..dee381e6 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -165,8 +165,6 @@ 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; @@ -553,16 +551,74 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev, return 0; } -static int i915_dispatch_flip(drm_device_t * dev) +static void i915_do_dispatch_flip(drm_device_t * dev, int pipe) { 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", + /* Calculate display base offset */ + num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; + current_page = (dev_priv->current_page >> shift) & 0x3; + next_page = (current_page + 1) % num_pages; + + 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; + } + + if (pipe == 0) { + x = dev_priv->sarea_priv->pipeA_x; + y = dev_priv->sarea_priv->pipeA_y; + } else { + x = dev_priv->sarea_priv->pipeB_x; + y = dev_priv->sarea_priv->pipeB_y; + } + + dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp; + + DRM_DEBUG("pipe=%d current_page=%d dspbase=0x%x\n", pipe, current_page, + dspbase); + + BEGIN_LP_RING(4); + OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP | + (pipe ? DISPLAY_PLANE_B : DISPLAY_PLANE_A)); + OUT_RING(0); + OUT_RING(dspbase); + OUT_RING(0); + ADVANCE_LP_RING(); + + dev_priv->current_page &= ~(0x3 << shift); + dev_priv->current_page |= next_page << shift; +} + +static void i915_dispatch_flip(drm_device_t * dev, int pipes) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 mi_wait = MI_WAIT_FOR_EVENT; + int i; + RING_LOCALS; + + DRM_DEBUG("%s: pipes=0x%x page=%d pfCurrentPage=%d\n", __FUNCTION__, - dev_priv->current_page, + pipes, dev_priv->current_page, dev_priv->sarea_priv->pf_current_page); + if (pipes & 0x1) + mi_wait |= MI_WAIT_FOR_PLANE_A_FLIP; + + if (pipes & 0x2) + mi_wait |= MI_WAIT_FOR_PLANE_B_FLIP; + i915_kernel_lost_context(dev); BEGIN_LP_RING(2); @@ -570,24 +626,15 @@ static int i915_dispatch_flip(drm_device_t * dev) OUT_RING(0); ADVANCE_LP_RING(); - /* Wait for a pending flip to take effect */ + /* Wait for pending flips to take effect */ BEGIN_LP_RING(2); - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP); + OUT_RING(mi_wait); OUT_RING(0); ADVANCE_LP_RING(); - 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; - } else { - OUT_RING(dev_priv->front_offset); - dev_priv->current_page = 0; - } - OUT_RING(0); - ADVANCE_LP_RING(); + for (i = 0; i < 2; i++) + if (pipes & (1 << i)) + i915_do_dispatch_flip(dev, i); i915_emit_breadcrumb(dev); #ifdef I915_HAVE_FENCE @@ -595,7 +642,6 @@ static int i915_dispatch_flip(drm_device_t * dev) #endif dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; - return 0; } static int i915_quiescent(drm_device_t * dev) @@ -688,10 +734,19 @@ 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 j; DRM_DEBUG("%s\n", __FUNCTION__); - if (dev_priv->current_page != 0) - i915_dispatch_flip(dev); + + for (j = 0; j < 2 && dev_priv->current_page != 0; j++) { + int i, pipes; + + for (i = 0, pipes = 0; i < 2; i++) + if (dev_priv->current_page & (0x3 << (2 * i))) + pipes |= 1 << i; + + i915_dispatch_flip(dev, pipes); + } return 0; } @@ -699,12 +754,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); + + return 0; } 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 a81653a7..1b261d6f 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__) @@ -99,8 +100,6 @@ typedef struct drm_i915_private { uint32_t counter; unsigned int cpp; - int back_offset; - int front_offset; int current_page; int use_mi_batchbuffer_start; @@ -352,6 +351,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 +359,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 e373a8df..cd2adbf3 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -47,12 +47,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) @@ -144,6 +144,11 @@ static void i915_vblank_tasklet(drm_device_t *dev) 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 @@ -161,7 +166,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); @@ -174,6 +179,9 @@ static void i915_vblank_tasklet(drm_device_t *dev) top = upper[pipe]; bottom = lower[pipe]; + front = (dev_priv->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 +195,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(); } -- cgit v1.2.3 From 5a40c043ccf965b1c3c74c80828090d2bc4438d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 22 Feb 2007 17:19:30 +0100 Subject: Add DRM_VBLANK_FLIP. Used to request that a scheduled buffer swap be done as a flip instead of a blit. --- shared-core/drm.h | 1 + 1 file changed, 1 insertion(+) (limited to 'shared-core') diff --git a/shared-core/drm.h b/shared-core/drm.h index 6fccec39..3a5d6346 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 */ -- cgit v1.2.3 From 1a0d890a42bee78177ad45d5e5956d2c3c4fcdc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 22 Feb 2007 17:21:18 +0100 Subject: i915: Add support for scheduled buffer swaps to be done as flips. Unfortunately, emitting asynchronous flips during vertical blank results in tearing. So we have to wait for the previous vertical blank and emit a synchronous flip. --- shared-core/i915_dma.c | 17 +++---- shared-core/i915_drv.h | 2 + shared-core/i915_irq.c | 119 ++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 115 insertions(+), 23 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index dee381e6..883f3b9d 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -551,7 +551,7 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev, return 0; } -static void i915_do_dispatch_flip(drm_device_t * dev, int pipe) +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; @@ -590,9 +590,9 @@ static void i915_do_dispatch_flip(drm_device_t * dev, int pipe) dspbase); BEGIN_LP_RING(4); - OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP | + OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) | (pipe ? DISPLAY_PLANE_B : DISPLAY_PLANE_A)); - OUT_RING(0); + OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp); OUT_RING(dspbase); OUT_RING(0); ADVANCE_LP_RING(); @@ -601,7 +601,7 @@ static void i915_do_dispatch_flip(drm_device_t * dev, int pipe) dev_priv->current_page |= next_page << shift; } -static void i915_dispatch_flip(drm_device_t * dev, int pipes) +void i915_dispatch_flip(drm_device_t * dev, int pipes, int sync) { drm_i915_private_t *dev_priv = dev->dev_private; u32 mi_wait = MI_WAIT_FOR_EVENT; @@ -634,11 +634,12 @@ static void i915_dispatch_flip(drm_device_t * dev, int pipes) for (i = 0; i < 2; i++) if (pipes & (1 << i)) - i915_do_dispatch_flip(dev, 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; @@ -745,7 +746,7 @@ static int i915_do_cleanup_pageflip(drm_device_t * dev) if (dev_priv->current_page & (0x3 << (2 * i))) pipes |= 1 << i; - i915_dispatch_flip(dev, pipes); + i915_dispatch_flip(dev, pipes, 0); } return 0; @@ -769,7 +770,7 @@ static int i915_flip_bufs(DRM_IOCTL_ARGS) return DRM_ERR(EINVAL); } - i915_dispatch_flip(dev, param.pipes); + i915_dispatch_flip(dev, param.pipes, 0); return 0; } diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 1b261d6f..cc6c12d1 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -85,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 { @@ -151,6 +152,7 @@ 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); diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index cd2adbf3..e6c88d2f 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -37,6 +37,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. * @@ -125,19 +169,6 @@ 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); @@ -159,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; @@ -174,8 +207,31 @@ 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]; @@ -523,7 +579,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 +618,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 +653,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 +679,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); -- cgit v1.2.3 From fd0fed3f1e10d7ff1205a485621767b650c6f5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 28 Feb 2007 12:33:56 +0100 Subject: i915: Fix test for synchronous flip affecting both pipes. --- shared-core/i915_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index e6c88d2f..e17eec5d 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -70,8 +70,8 @@ i915_dispatch_vsync_flip(drm_device_t *dev, drm_drawable_info_t *drw, int pipe) 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))) { + if (!(rect[i].x1 >= x2 || rect[i].y1 >= y2 || + rect[i].x2 <= x1 || rect[i].y2 <= y1)) { pf_pipes = 0x3; break; -- cgit v1.2.3 From 1cdc1b6fbabffc0dd4d3c1f8405d9372a45480a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 28 Feb 2007 15:23:19 +0100 Subject: i915: Don't emit waits for pending flips before emitting synchronous flips. The assumption is that synchronous flips are not isolated usually, and waiting for all of them could result in stalling the pipeline for long periods of time. Also use i915_emit_mi_flush() instead of an old-fashioned way to achieve the same effect. --- shared-core/i915_dma.c | 28 +++++++++++++--------------- shared-core/i915_drv.h | 4 ---- 2 files changed, 13 insertions(+), 19 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 883f3b9d..7078ec94 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -604,7 +604,6 @@ static void i915_do_dispatch_flip(drm_device_t * dev, int pipe, int sync) void i915_dispatch_flip(drm_device_t * dev, int pipes, int sync) { drm_i915_private_t *dev_priv = dev->dev_private; - u32 mi_wait = MI_WAIT_FOR_EVENT; int i; RING_LOCALS; @@ -613,24 +612,23 @@ void i915_dispatch_flip(drm_device_t * dev, int pipes, int sync) pipes, dev_priv->current_page, dev_priv->sarea_priv->pf_current_page); - if (pipes & 0x1) - mi_wait |= MI_WAIT_FOR_PLANE_A_FLIP; + i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH); - if (pipes & 0x2) - mi_wait |= MI_WAIT_FOR_PLANE_B_FLIP; + if (!sync) { + u32 mi_wait = MI_WAIT_FOR_EVENT; - i915_kernel_lost_context(dev); + /* Wait for pending flips to take effect */ + if (pipes & 0x1) + mi_wait |= MI_WAIT_FOR_PLANE_A_FLIP; - BEGIN_LP_RING(2); - OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); - OUT_RING(0); - ADVANCE_LP_RING(); + if (pipes & 0x2) + mi_wait |= MI_WAIT_FOR_PLANE_B_FLIP; - /* Wait for pending flips to take effect */ - BEGIN_LP_RING(2); - OUT_RING(mi_wait); - OUT_RING(0); - ADVANCE_LP_RING(); + BEGIN_LP_RING(2); + OUT_RING(mi_wait); + OUT_RING(0); + ADVANCE_LP_RING(); + } for (i = 0; i < 2; i++) if (pipes & (1 << i)) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index cc6c12d1..de9105ad 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -252,10 +252,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) -- cgit v1.2.3 From 074e10b384c893a256fcf964676562792fdf93c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 28 Feb 2007 15:57:08 +0100 Subject: i915: Only clean up page flipping when the last client goes away, not any one. --- shared-core/i915_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-core') diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 7078ec94..282d4b80 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -915,6 +915,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); @@ -924,7 +925,6 @@ void i915_driver_preclose(drm_device_t * dev, DRMFILE filp) { if (dev->dev_private) { drm_i915_private_t *dev_priv = dev->dev_private; - i915_do_cleanup_pageflip(dev); i915_mem_release(dev, filp, dev_priv->agp_heap); } } -- cgit v1.2.3 From a33859184aa852777a50ea83f9dfa013f63f806f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 28 Feb 2007 17:48:56 +0100 Subject: i915: Eliminate dev_priv->current_page. Always use dev_priv->sarea_priv->pf_current_page directly. This allows clients to modify it as well while they hold the HW lock, e.g. in order to sync pages between pipes. --- shared-core/i915_dma.c | 32 +++++++++++++++----------------- shared-core/i915_drv.h | 1 - shared-core/i915_irq.c | 3 ++- 3 files changed, 17 insertions(+), 19 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 282d4b80..b9dea8a7 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -165,8 +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->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. @@ -560,7 +559,7 @@ static void i915_do_dispatch_flip(drm_device_t * dev, int pipe, int sync) /* Calculate display base offset */ num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; - current_page = (dev_priv->current_page >> shift) & 0x3; + current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3; next_page = (current_page + 1) % num_pages; switch (next_page) { @@ -597,8 +596,8 @@ static void i915_do_dispatch_flip(drm_device_t * dev, int pipe, int sync) OUT_RING(0); ADVANCE_LP_RING(); - dev_priv->current_page &= ~(0x3 << shift); - dev_priv->current_page |= next_page << shift; + 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) @@ -607,10 +606,9 @@ void i915_dispatch_flip(drm_device_t * dev, int pipes, int sync) int i; RING_LOCALS; - DRM_DEBUG("%s: pipes=0x%x page=%d pfCurrentPage=%d\n", + DRM_DEBUG("%s: pipes=0x%x pfCurrentPage=%d\n", __FUNCTION__, - pipes, dev_priv->current_page, - dev_priv->sarea_priv->pf_current_page); + pipes, dev_priv->sarea_priv->pf_current_page); i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH); @@ -639,8 +637,6 @@ void i915_dispatch_flip(drm_device_t * dev, int pipes, int sync) if (!sync) drm_fence_flush_old(dev, 0, dev_priv->counter); #endif - - dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; } static int i915_quiescent(drm_device_t * dev) @@ -733,19 +729,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 j; + int i, pipes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; DRM_DEBUG("%s\n", __FUNCTION__); - for (j = 0; j < 2 && dev_priv->current_page != 0; j++) { - int i, pipes; + 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); - for (i = 0, pipes = 0; i < 2; i++) - if (dev_priv->current_page & (0x3 << (2 * i))) - pipes |= 1 << i; + pipes |= 1 << i; + } + if (pipes) i915_dispatch_flip(dev, pipes, 0); - } return 0; } diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index de9105ad..a3736160 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -101,7 +101,6 @@ typedef struct drm_i915_private { uint32_t counter; unsigned int cpp; - int current_page; int use_mi_batchbuffer_start; wait_queue_head_t irq_queue; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index e17eec5d..5da54107 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -235,7 +235,8 @@ static void i915_vblank_tasklet(drm_device_t *dev) top = upper[pipe]; bottom = lower[pipe]; - front = (dev_priv->current_page >> (2 * pipe)) & 0x3; + 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++) { -- cgit v1.2.3 From 0741064df4b913189d26a184a7c5dcc7827152be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 9 Mar 2007 16:39:13 +0100 Subject: i915: Do not wait for pending flips on both pipes at the same time. The MI_WAIT_FOR_EVENT instruction does not support waiting for several events at once, so this should fix the lockups with page flipping when both pipes are enabled. --- shared-core/i915_dma.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index b9dea8a7..14e01179 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -589,11 +589,12 @@ static void i915_do_dispatch_flip(drm_device_t * dev, int pipe, int sync) dspbase); BEGIN_LP_RING(4); + OUT_RING(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); - OUT_RING(0); ADVANCE_LP_RING(); dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift); @@ -604,7 +605,6 @@ void i915_dispatch_flip(drm_device_t * dev, int pipes, int sync) { drm_i915_private_t *dev_priv = dev->dev_private; int i; - RING_LOCALS; DRM_DEBUG("%s: pipes=0x%x pfCurrentPage=%d\n", __FUNCTION__, @@ -612,22 +612,6 @@ void i915_dispatch_flip(drm_device_t * dev, int pipes, int sync) i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH); - if (!sync) { - u32 mi_wait = MI_WAIT_FOR_EVENT; - - /* Wait for pending flips to take effect */ - if (pipes & 0x1) - mi_wait |= MI_WAIT_FOR_PLANE_A_FLIP; - - if (pipes & 0x2) - mi_wait |= MI_WAIT_FOR_PLANE_B_FLIP; - - BEGIN_LP_RING(2); - OUT_RING(mi_wait); - OUT_RING(0); - ADVANCE_LP_RING(); - } - for (i = 0; i < 2; i++) if (pipes & (1 << i)) i915_do_dispatch_flip(dev, i, sync); -- cgit v1.2.3 From d734992e6a8a5757dc360ab6a5e7c80ebc03b1cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 9 Mar 2007 23:34:11 +0100 Subject: i915: Only wait for pending flips before asynchronous flips again. --- shared-core/i915_dma.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 14e01179..c8b7e588 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -589,8 +589,9 @@ static void i915_do_dispatch_flip(drm_device_t * dev, int pipe, int sync) dspbase); BEGIN_LP_RING(4); - OUT_RING(MI_WAIT_FOR_EVENT | (pipe ? MI_WAIT_FOR_PLANE_B_FLIP : - MI_WAIT_FOR_PLANE_A_FLIP)); + 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); -- cgit v1.2.3