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.
parent
5a40c043cc
commit
1a0d890a42
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue