add page flipping support to the DRM, up version number to 1.3.0...
authorDave Airlie <airlied@linux.ie>
Thu, 5 Jun 2003 23:31:40 +0000 (23:31 +0000)
committerDave Airlie <airlied@linux.ie>
Thu, 5 Jun 2003 23:31:40 +0000 (23:31 +0000)
linux-core/i810_dma.c
linux-core/i810_drm.h
linux-core/i810_drv.h
linux/i810.h
linux/i810_dma.c
linux/i810_drm.h
linux/i810_drv.h

index 678610c..8042b7f 100644 (file)
@@ -289,10 +289,12 @@ static int i810_wait_ring(drm_device_t *dev, int n)
                ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
                ring->space = ring->head - (ring->tail+8);
                if (ring->space < 0) ring->space += ring->Size;
-
-               if (ring->head != last_head)
-                  end = jiffies + (HZ*3);
-
+          
+               if (ring->head != last_head) {
+                       end = jiffies + (HZ*3);
+                       last_head = ring->head;
+               }
+         
                iters++;
                if(time_before(end, jiffies)) {
                        DRM_ERROR("space: %d wanted %d\n", ring->space, n);
@@ -410,6 +412,7 @@ static int i810_dma_initialize(drm_device_t *dev,
        dev_priv->pitch = init->pitch;
        dev_priv->back_offset = init->back_offset;
        dev_priv->depth_offset = init->depth_offset;
+       dev_priv->front_offset = init->front_offset;
 
        dev_priv->overlay_offset = init->overlay_offset;
        dev_priv->overlay_physical = init->overlay_physical;
@@ -589,6 +592,8 @@ static void i810EmitState( drm_device_t *dev )
        drm_i810_private_t *dev_priv = dev->dev_private;
        drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
        unsigned int dirty = sarea_priv->dirty;
+       
+       DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);
 
        if (dirty & I810_UPLOAD_BUFFERS) {
                i810EmitDestVerified( dev, sarea_priv->BufferState );
@@ -627,6 +632,14 @@ static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,
        int cpp = 2;
        int i;
        RING_LOCALS;
+       
+       if ( dev_priv->current_page == 1 ) {
+               unsigned int tmp = flags;
+              
+               flags &= ~(I810_FRONT | I810_BACK);
+               if (tmp & I810_FRONT) flags |= I810_BACK;
+               if (tmp & I810_BACK) flags |= I810_FRONT;
+       }
 
        i810_kernel_lost_context(dev);
 
@@ -692,10 +705,11 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )
        drm_clip_rect_t *pbox = sarea_priv->boxes;
        int pitch = dev_priv->pitch;
        int cpp = 2;
-       int ofs = dev_priv->back_offset;
        int i;
        RING_LOCALS;
 
+       DRM_DEBUG("swapbuffers\n");
+
        i810_kernel_lost_context(dev);
 
        if (nbox > I810_NR_SAREA_CLIPRECTS)
@@ -706,7 +720,7 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )
                unsigned int w = pbox->x2 - pbox->x1;
                unsigned int h = pbox->y2 - pbox->y1;
                unsigned int dst = pbox->x1*cpp + pbox->y1*pitch;
-               unsigned int start = ofs + dst;
+               unsigned int start = dst;
 
                if (pbox->x1 > pbox->x2 ||
                    pbox->y1 > pbox->y2 ||
@@ -718,9 +732,15 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )
                OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 );
                OUT_RING( pitch | (0xCC << 16));
                OUT_RING( (h << 16) | (w * cpp));
-               OUT_RING( dst );
+               if (dev_priv->current_page == 0)
+                 OUT_RING(dev_priv->front_offset + start);
+               else
+                 OUT_RING(dev_priv->back_offset + start);
                OUT_RING( pitch );
-               OUT_RING( start );
+               if (dev_priv->current_page == 0)
+                 OUT_RING(dev_priv->back_offset + start);
+               else
+                 OUT_RING(dev_priv->front_offset + start);
                ADVANCE_LP_RING();
        }
 }
@@ -807,6 +827,52 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev,
        }
 }
 
+static void i810_dma_dispatch_flip( drm_device_t *dev )
+{
+        drm_i810_private_t *dev_priv = dev->dev_private;
+       RING_LOCALS;
+       int pitch = dev_priv->pitch;
+
+       DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n", 
+               __FUNCTION__, 
+               dev_priv->current_page,
+               dev_priv->sarea_priv->pf_current_page);
+       
+        i810_kernel_lost_context(dev);
+
+       BEGIN_LP_RING( 2 );
+       OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); 
+       OUT_RING( 0 );
+       ADVANCE_LP_RING();
+
+       BEGIN_LP_RING( I810_DEST_SETUP_SIZE + 2 );
+       /* On i815 at least ASYNC is buggy */
+       /* pitch<<5 is from 11.2.8 p158,
+          its the pitch / 8 then left shifted 8,
+          so (pitch >> 3) << 8 */
+       OUT_RING( CMD_OP_FRONTBUFFER_INFO | (pitch<<5) /*| ASYNC_FLIP */ );
+       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();
+
+       BEGIN_LP_RING(2);
+       OUT_RING( CMD_OP_WAIT_FOR_EVENT | WAIT_FOR_PLANE_A_FLIP );
+       OUT_RING( 0 );
+       ADVANCE_LP_RING();
+
+       /* Increment the frame counter.  The client-side 3D driver must
+        * throttle the framerate by waiting for this value before
+        * performing the swapbuffer ioctl.
+        */
+       dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+
+}
 
 void i810_dma_quiescent(drm_device_t *dev)
 {
@@ -1198,3 +1264,47 @@ int i810_ov0_flip(struct inode *inode, struct file *filp,
 }
 
 
+/* Not sure why this isn't set all the time:
+ */ 
+static void i810_do_init_pageflip( drm_device_t *dev )
+{
+       drm_i810_private_t *dev_priv = dev->dev_private;
+       
+       DRM_DEBUG("%s\n", __FUNCTION__);
+       dev_priv->page_flipping = 1;
+       dev_priv->current_page = 0;
+       dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+}
+
+int i810_do_cleanup_pageflip( drm_device_t *dev )
+{
+       drm_i810_private_t *dev_priv = dev->dev_private;
+
+       DRM_DEBUG("%s\n", __FUNCTION__);
+       if (dev_priv->current_page != 0)
+               i810_dma_dispatch_flip( dev );
+
+       dev_priv->page_flipping = 0;
+       return 0;
+}
+
+int i810_flip_bufs(struct inode *inode, struct file *filp,
+                  unsigned int cmd, unsigned long arg)
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->dev;
+       drm_i810_private_t *dev_priv = dev->dev_private;
+
+       DRM_DEBUG("%s\n", __FUNCTION__);
+
+       if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+               DRM_ERROR("i810_flip_buf called without lock held\n");
+               return -EINVAL;
+       }
+
+       if (!dev_priv->page_flipping) 
+               i810_do_init_pageflip( dev );
+
+       i810_dma_dispatch_flip( dev );
+       return 0;
+}
index f8c27d8..b35593b 100644 (file)
@@ -166,6 +166,9 @@ typedef struct _drm_i810_sarea {
 
        int vertex_prim;
 
+       int pf_enabled;               /* is pageflipping allowed? */
+       int pf_active;
+       int pf_current_page;        /* which buffer is being displayed? */
 } drm_i810_sarea_t;
 
 /* WARNING: If you change any of these defines, make sure to change the
@@ -189,6 +192,7 @@ typedef struct _drm_i810_sarea {
 #define DRM_IOCTL_I810_OV0FLIP         DRM_IO ( 0x4b)
 #define DRM_IOCTL_I810_MC              DRM_IOW( 0x4c, drm_i810_mc_t)
 #define DRM_IOCTL_I810_RSTATUS         DRM_IO ( 0x4d )
+#define DRM_IOCTL_I810_FLIP             DRM_IO ( 0x4e )
 
 typedef struct _drm_i810_clear {
        int clear_color;
index aa82c64..736c20d 100644 (file)
@@ -75,7 +75,20 @@ typedef struct drm_i810_private {
        int overlay_physical;
        int w, h;
        int pitch;
+       int back_pitch;
+       int depth_pitch;
 
+       int do_boxes;
+       int dma_used;
+
+       int current_page;
+       int page_flipping;
+
+       wait_queue_head_t irq_queue;
+       atomic_t irq_received;
+       atomic_t irq_emitted;
+  
+        int front_offset;
 } drm_i810_private_t;
 
                                /* i810_dma.c */
@@ -124,6 +137,8 @@ int i810_swap_bufs(struct inode *inode, struct file *filp,
 int i810_clear_bufs(struct inode *inode, struct file *filp,
                    unsigned int cmd, unsigned long arg);
 
+int i810_flip_bufs(struct inode *inode, struct file *filp,
+                  unsigned int cmd, unsigned long arg);
 
 #define I810_BASE(reg)         ((unsigned long) \
                                dev_priv->mmio_map->handle)
@@ -225,12 +240,15 @@ int i810_clear_bufs(struct inode *inode, struct file *filp,
 #define CMD_OP_Z_BUFFER_INFO     ((0x0<<29)|(0x16<<23))
 #define CMD_OP_DESTBUFFER_INFO   ((0x0<<29)|(0x15<<23))
 #define CMD_OP_FRONTBUFFER_INFO  ((0x0<<29)|(0x14<<23))
+#define CMD_OP_WAIT_FOR_EVENT    ((0x0<<29)|(0x03<<23))
 
 #define BR00_BITBLT_CLIENT   0x40000000
 #define BR00_OP_COLOR_BLT    0x10000000
 #define BR00_OP_SRC_COPY_BLT 0x10C00000
 #define BR13_SOLID_PATTERN   0x80000000
 
-
+#define WAIT_FOR_PLANE_A_SCANLINES (1<<1) 
+#define WAIT_FOR_PLANE_A_FLIP      (1<<2) 
+#define WAIT_FOR_VBLANK (1<<3)
 
 #endif
index bfb760a..ba40892 100644 (file)
@@ -45,7 +45,7 @@
 
 #define DRIVER_NAME            "i810"
 #define DRIVER_DESC            "Intel i810"
-#define DRIVER_DATE            "20020211"
+#define DRIVER_DATE            "20030605"
 
 /* Interface history
  *
  *       - XFree86 4.2
  * 1.2.1 - Disable copying code (leave stub ioctls for backwards compatibility)
  *       - Remove requirement for interrupt (leave stubs again)
+ * 1.3   - Add page flipping.
  */
 #define DRIVER_MAJOR           1
-#define DRIVER_MINOR           2
-#define DRIVER_PATCHLEVEL      1
+#define DRIVER_MINOR           3
+#define DRIVER_PATCHLEVEL      0
 
 #define DRIVER_IOCTLS                                                      \
        [DRM_IOCTL_NR(DRM_IOCTL_I810_INIT)]   = { i810_dma_init,    1, 1 }, \
@@ -73,8 +74,9 @@
        [DRM_IOCTL_NR(DRM_IOCTL_I810_FSTATUS)] = { i810_fstatus,    1, 0 }, \
        [DRM_IOCTL_NR(DRM_IOCTL_I810_OV0FLIP)] = { i810_ov0_flip,   1, 0 }, \
        [DRM_IOCTL_NR(DRM_IOCTL_I810_MC)]      = { i810_dma_mc,     1, 1 }, \
-       [DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus,    1, 0 }
-
+       [DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus,    1, 0 }, \
+       [DRM_IOCTL_NR(DRM_IOCTL_I810_FLIP)] =    { i810_flip_bufs,  1, 0 }
 
 #define __HAVE_COUNTERS         4
 #define __HAVE_COUNTER6         _DRM_STAT_IRQ
index 678610c..8042b7f 100644 (file)
@@ -289,10 +289,12 @@ static int i810_wait_ring(drm_device_t *dev, int n)
                ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
                ring->space = ring->head - (ring->tail+8);
                if (ring->space < 0) ring->space += ring->Size;
-
-               if (ring->head != last_head)
-                  end = jiffies + (HZ*3);
-
+          
+               if (ring->head != last_head) {
+                       end = jiffies + (HZ*3);
+                       last_head = ring->head;
+               }
+         
                iters++;
                if(time_before(end, jiffies)) {
                        DRM_ERROR("space: %d wanted %d\n", ring->space, n);
@@ -410,6 +412,7 @@ static int i810_dma_initialize(drm_device_t *dev,
        dev_priv->pitch = init->pitch;
        dev_priv->back_offset = init->back_offset;
        dev_priv->depth_offset = init->depth_offset;
+       dev_priv->front_offset = init->front_offset;
 
        dev_priv->overlay_offset = init->overlay_offset;
        dev_priv->overlay_physical = init->overlay_physical;
@@ -589,6 +592,8 @@ static void i810EmitState( drm_device_t *dev )
        drm_i810_private_t *dev_priv = dev->dev_private;
        drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
        unsigned int dirty = sarea_priv->dirty;
+       
+       DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);
 
        if (dirty & I810_UPLOAD_BUFFERS) {
                i810EmitDestVerified( dev, sarea_priv->BufferState );
@@ -627,6 +632,14 @@ static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,
        int cpp = 2;
        int i;
        RING_LOCALS;
+       
+       if ( dev_priv->current_page == 1 ) {
+               unsigned int tmp = flags;
+              
+               flags &= ~(I810_FRONT | I810_BACK);
+               if (tmp & I810_FRONT) flags |= I810_BACK;
+               if (tmp & I810_BACK) flags |= I810_FRONT;
+       }
 
        i810_kernel_lost_context(dev);
 
@@ -692,10 +705,11 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )
        drm_clip_rect_t *pbox = sarea_priv->boxes;
        int pitch = dev_priv->pitch;
        int cpp = 2;
-       int ofs = dev_priv->back_offset;
        int i;
        RING_LOCALS;
 
+       DRM_DEBUG("swapbuffers\n");
+
        i810_kernel_lost_context(dev);
 
        if (nbox > I810_NR_SAREA_CLIPRECTS)
@@ -706,7 +720,7 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )
                unsigned int w = pbox->x2 - pbox->x1;
                unsigned int h = pbox->y2 - pbox->y1;
                unsigned int dst = pbox->x1*cpp + pbox->y1*pitch;
-               unsigned int start = ofs + dst;
+               unsigned int start = dst;
 
                if (pbox->x1 > pbox->x2 ||
                    pbox->y1 > pbox->y2 ||
@@ -718,9 +732,15 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )
                OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 );
                OUT_RING( pitch | (0xCC << 16));
                OUT_RING( (h << 16) | (w * cpp));
-               OUT_RING( dst );
+               if (dev_priv->current_page == 0)
+                 OUT_RING(dev_priv->front_offset + start);
+               else
+                 OUT_RING(dev_priv->back_offset + start);
                OUT_RING( pitch );
-               OUT_RING( start );
+               if (dev_priv->current_page == 0)
+                 OUT_RING(dev_priv->back_offset + start);
+               else
+                 OUT_RING(dev_priv->front_offset + start);
                ADVANCE_LP_RING();
        }
 }
@@ -807,6 +827,52 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev,
        }
 }
 
+static void i810_dma_dispatch_flip( drm_device_t *dev )
+{
+        drm_i810_private_t *dev_priv = dev->dev_private;
+       RING_LOCALS;
+       int pitch = dev_priv->pitch;
+
+       DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n", 
+               __FUNCTION__, 
+               dev_priv->current_page,
+               dev_priv->sarea_priv->pf_current_page);
+       
+        i810_kernel_lost_context(dev);
+
+       BEGIN_LP_RING( 2 );
+       OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); 
+       OUT_RING( 0 );
+       ADVANCE_LP_RING();
+
+       BEGIN_LP_RING( I810_DEST_SETUP_SIZE + 2 );
+       /* On i815 at least ASYNC is buggy */
+       /* pitch<<5 is from 11.2.8 p158,
+          its the pitch / 8 then left shifted 8,
+          so (pitch >> 3) << 8 */
+       OUT_RING( CMD_OP_FRONTBUFFER_INFO | (pitch<<5) /*| ASYNC_FLIP */ );
+       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();
+
+       BEGIN_LP_RING(2);
+       OUT_RING( CMD_OP_WAIT_FOR_EVENT | WAIT_FOR_PLANE_A_FLIP );
+       OUT_RING( 0 );
+       ADVANCE_LP_RING();
+
+       /* Increment the frame counter.  The client-side 3D driver must
+        * throttle the framerate by waiting for this value before
+        * performing the swapbuffer ioctl.
+        */
+       dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+
+}
 
 void i810_dma_quiescent(drm_device_t *dev)
 {
@@ -1198,3 +1264,47 @@ int i810_ov0_flip(struct inode *inode, struct file *filp,
 }
 
 
+/* Not sure why this isn't set all the time:
+ */ 
+static void i810_do_init_pageflip( drm_device_t *dev )
+{
+       drm_i810_private_t *dev_priv = dev->dev_private;
+       
+       DRM_DEBUG("%s\n", __FUNCTION__);
+       dev_priv->page_flipping = 1;
+       dev_priv->current_page = 0;
+       dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+}
+
+int i810_do_cleanup_pageflip( drm_device_t *dev )
+{
+       drm_i810_private_t *dev_priv = dev->dev_private;
+
+       DRM_DEBUG("%s\n", __FUNCTION__);
+       if (dev_priv->current_page != 0)
+               i810_dma_dispatch_flip( dev );
+
+       dev_priv->page_flipping = 0;
+       return 0;
+}
+
+int i810_flip_bufs(struct inode *inode, struct file *filp,
+                  unsigned int cmd, unsigned long arg)
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->dev;
+       drm_i810_private_t *dev_priv = dev->dev_private;
+
+       DRM_DEBUG("%s\n", __FUNCTION__);
+
+       if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+               DRM_ERROR("i810_flip_buf called without lock held\n");
+               return -EINVAL;
+       }
+
+       if (!dev_priv->page_flipping) 
+               i810_do_init_pageflip( dev );
+
+       i810_dma_dispatch_flip( dev );
+       return 0;
+}
index f8c27d8..b35593b 100644 (file)
@@ -166,6 +166,9 @@ typedef struct _drm_i810_sarea {
 
        int vertex_prim;
 
+       int pf_enabled;               /* is pageflipping allowed? */
+       int pf_active;
+       int pf_current_page;        /* which buffer is being displayed? */
 } drm_i810_sarea_t;
 
 /* WARNING: If you change any of these defines, make sure to change the
@@ -189,6 +192,7 @@ typedef struct _drm_i810_sarea {
 #define DRM_IOCTL_I810_OV0FLIP         DRM_IO ( 0x4b)
 #define DRM_IOCTL_I810_MC              DRM_IOW( 0x4c, drm_i810_mc_t)
 #define DRM_IOCTL_I810_RSTATUS         DRM_IO ( 0x4d )
+#define DRM_IOCTL_I810_FLIP             DRM_IO ( 0x4e )
 
 typedef struct _drm_i810_clear {
        int clear_color;
index aa82c64..736c20d 100644 (file)
@@ -75,7 +75,20 @@ typedef struct drm_i810_private {
        int overlay_physical;
        int w, h;
        int pitch;
+       int back_pitch;
+       int depth_pitch;
 
+       int do_boxes;
+       int dma_used;
+
+       int current_page;
+       int page_flipping;
+
+       wait_queue_head_t irq_queue;
+       atomic_t irq_received;
+       atomic_t irq_emitted;
+  
+        int front_offset;
 } drm_i810_private_t;
 
                                /* i810_dma.c */
@@ -124,6 +137,8 @@ int i810_swap_bufs(struct inode *inode, struct file *filp,
 int i810_clear_bufs(struct inode *inode, struct file *filp,
                    unsigned int cmd, unsigned long arg);
 
+int i810_flip_bufs(struct inode *inode, struct file *filp,
+                  unsigned int cmd, unsigned long arg);
 
 #define I810_BASE(reg)         ((unsigned long) \
                                dev_priv->mmio_map->handle)
@@ -225,12 +240,15 @@ int i810_clear_bufs(struct inode *inode, struct file *filp,
 #define CMD_OP_Z_BUFFER_INFO     ((0x0<<29)|(0x16<<23))
 #define CMD_OP_DESTBUFFER_INFO   ((0x0<<29)|(0x15<<23))
 #define CMD_OP_FRONTBUFFER_INFO  ((0x0<<29)|(0x14<<23))
+#define CMD_OP_WAIT_FOR_EVENT    ((0x0<<29)|(0x03<<23))
 
 #define BR00_BITBLT_CLIENT   0x40000000
 #define BR00_OP_COLOR_BLT    0x10000000
 #define BR00_OP_SRC_COPY_BLT 0x10C00000
 #define BR13_SOLID_PATTERN   0x80000000
 
-
+#define WAIT_FOR_PLANE_A_SCANLINES (1<<1) 
+#define WAIT_FOR_PLANE_A_FLIP      (1<<2) 
+#define WAIT_FOR_VBLANK (1<<3)
 
 #endif