Pages are tracked independently on each pipe.
Bump the minor version for 3D clients to know page flipping is usable, and
bump driver date.
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;
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);
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
#endif
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
- return 0;
}
static int i915_quiescent(drm_device_t * dev)
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;
}
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;
}
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.
#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)
#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.
*/
#define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics"
-#define DRIVER_DATE "20060929"
+#define DRIVER_DATE "20070209"
/* Interface history:
*
* 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__)
uint32_t counter;
unsigned int cpp;
- int back_offset;
- int front_offset;
int current_page;
int use_mi_batchbuffer_start;
#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)
#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)
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)
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
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);
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);
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();
}