diff options
author | Michel Dänzer <michel@tungstengraphics.com> | 2007-02-19 12:27:54 +0100 |
---|---|---|
committer | Michel Dänzer <michel@tungstengraphics.com> | 2007-02-19 15:08:40 +0100 |
commit | 6f89584e136211d7c4c69d88005f0e70393274f8 (patch) | |
tree | 70419c2c8a2394c0d6cd96468e1c9d4391e455a4 /shared-core/i915_dma.c | |
parent | 34aa3393d04da1201815143c92a5bef83bf0d585 (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.c | 113 |
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; } |