summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 5a40c04)
raw | patch | inline | side by side (parent: 5a40c04)
author | Michel Dänzer <michel@tungstengraphics.com> | |
Thu, 22 Feb 2007 16:21:18 +0000 (17:21 +0100) | ||
committer | Michel Dänzer <michel@tungstengraphics.com> | |
Thu, 22 Feb 2007 16:21:18 +0000 (17:21 +0100) |
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.
tearing. So we have to wait for the previous vertical blank and emit a
synchronous flip.
shared-core/i915_dma.c | patch | blob | history | |
shared-core/i915_drv.h | patch | blob | history | |
shared-core/i915_irq.c | patch | blob | history |
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index dee381e6e3149d36ac598c049281cf43e2e87468..883f3b9de14e50146444d8e419f2be7cb38d10ac 100644 (file)
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
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;
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();
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;
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;
if (dev_priv->current_page & (0x3 << (2 * i)))
pipes |= 1 << i;
- i915_dispatch_flip(dev, pipes);
+ i915_dispatch_flip(dev, pipes, 0);
}
return 0;
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 1b261d6f52e1f4bc7380ea77f322e2ecfce3f9fe..cc6c12d185d1f92dcad9d84274405dccc3ec6edb 100644 (file)
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
drm_drawable_t drw_id;
unsigned int pipe;
unsigned int sequence;
+ int flip;
} drm_i915_vbl_swap_t;
typedef struct drm_i915_private {
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 cd2adbf35a84af4e91c35fff462a90ddb72bd0a2..e6c88d2f751ebc054f9c47dc5014ed9a9aea9442 100644 (file)
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
#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.
*
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);
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;
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];
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);
}
}
}
+ 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) {
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;
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);