summaryrefslogtreecommitdiff
path: root/shared-core/i915_dma.c
diff options
context:
space:
mode:
authorMichel Dänzer <michel@tungstengraphics.com>2007-02-19 12:27:54 +0100
committerMichel Dänzer <michel@tungstengraphics.com>2007-02-19 15:08:40 +0100
commit6f89584e136211d7c4c69d88005f0e70393274f8 (patch)
tree70419c2c8a2394c0d6cd96468e1c9d4391e455a4 /shared-core/i915_dma.c
parent34aa3393d04da1201815143c92a5bef83bf0d585 (diff)
i915: Improved page flipping support, including triple buffering.
Pages are tracked independently on each pipe. Bump the minor version for 3D clients to know page flipping is usable, and bump driver date.
Diffstat (limited to 'shared-core/i915_dma.c')
-rw-r--r--shared-core/i915_dma.c113
1 files changed, 90 insertions, 23 deletions
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index 18fe0881..dee381e6 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -165,8 +165,6 @@ 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;
@@ -553,16 +551,74 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev,
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);
@@ -570,24 +626,15 @@ static int i915_dispatch_flip(drm_device_t * dev)
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
@@ -595,7 +642,6 @@ static int i915_dispatch_flip(drm_device_t * dev)
#endif
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
- return 0;
}
static int i915_quiescent(drm_device_t * dev)
@@ -688,10 +734,19 @@ 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 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;
}
@@ -699,12 +754,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);
+
+ return 0;
}