summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdrm/xf86drm.h1
-rw-r--r--shared-core/drm.h1
-rw-r--r--shared-core/i915_dma.c143
-rw-r--r--shared-core/i915_drm.h14
-rw-r--r--shared-core/i915_drv.h19
-rw-r--r--shared-core/i915_irq.c150
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);