diff options
Diffstat (limited to 'shared-core')
-rw-r--r-- | shared-core/i915_dma.c | 17 | ||||
-rw-r--r-- | shared-core/i915_drv.h | 2 | ||||
-rw-r--r-- | shared-core/i915_irq.c | 119 |
3 files changed, 115 insertions, 23 deletions
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 @@ -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. @@ -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); |