OSDN Git Service

i915: Improved page flipping support, including triple buffering.
authorMichel Dänzer <michel@tungstengraphics.com>
Mon, 19 Feb 2007 11:27:54 +0000 (12:27 +0100)
committerMichel Dänzer <michel@tungstengraphics.com>
Mon, 19 Feb 2007 14:08:40 +0000 (15:08 +0100)
Pages are tracked independently on each pipe.

Bump the minor version for 3D clients to know page flipping is usable, and
bump driver date.

shared-core/i915_dma.c
shared-core/i915_drm.h
shared-core/i915_drv.h
shared-core/i915_irq.c

index 18fe088..dee381e 100644 (file)
@@ -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;
 }
 
 
index 22a81d1..1f32313 100644 (file)
@@ -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.
  */
index a81653a..1b261d6 100644 (file)
@@ -37,7 +37,7 @@
 
 #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__)
@@ -99,8 +100,6 @@ typedef struct drm_i915_private {
        uint32_t counter;
 
        unsigned int cpp;
-       int back_offset;
-       int front_offset;
        int current_page;
        int use_mi_batchbuffer_start;
 
@@ -352,6 +351,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 +359,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)
 
index e373a8d..cd2adbf 100644 (file)
@@ -47,12 +47,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)
@@ -144,6 +144,11 @@ static void i915_vblank_tasklet(drm_device_t *dev)
        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
@@ -161,7 +166,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);
@@ -174,6 +179,9 @@ static void i915_vblank_tasklet(drm_device_t *dev)
                        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);
@@ -187,10 +195,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();
                        }