From 8eaa2d245077d5e949679e48897b57f8dc505a25 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2003 23:31:40 +0000 Subject: add page flipping support to the DRM, up version number to 1.3.0... --- linux-core/i810_dma.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++---- linux-core/i810_drm.h | 4 ++ linux-core/i810_drv.h | 20 +++++++- linux/i810.h | 12 +++-- linux/i810_dma.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++---- linux/i810_drm.h | 4 ++ linux/i810_drv.h | 20 +++++++- 7 files changed, 289 insertions(+), 23 deletions(-) diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index 678610c6..8042b7fc 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -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; +} diff --git a/linux-core/i810_drm.h b/linux-core/i810_drm.h index f8c27d83..b35593bd 100644 --- a/linux-core/i810_drm.h +++ b/linux-core/i810_drm.h @@ -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; diff --git a/linux-core/i810_drv.h b/linux-core/i810_drv.h index aa82c647..736c20d7 100644 --- a/linux-core/i810_drv.h +++ b/linux-core/i810_drv.h @@ -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 diff --git a/linux/i810.h b/linux/i810.h index bfb760ab..ba40892f 100644 --- a/linux/i810.h +++ b/linux/i810.h @@ -45,7 +45,7 @@ #define DRIVER_NAME "i810" #define DRIVER_DESC "Intel i810" -#define DRIVER_DATE "20020211" +#define DRIVER_DATE "20030605" /* Interface history * @@ -54,10 +54,11 @@ * - 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 diff --git a/linux/i810_dma.c b/linux/i810_dma.c index 678610c6..8042b7fc 100644 --- a/linux/i810_dma.c +++ b/linux/i810_dma.c @@ -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; +} diff --git a/linux/i810_drm.h b/linux/i810_drm.h index f8c27d83..b35593bd 100644 --- a/linux/i810_drm.h +++ b/linux/i810_drm.h @@ -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; diff --git a/linux/i810_drv.h b/linux/i810_drv.h index aa82c647..736c20d7 100644 --- a/linux/i810_drv.h +++ b/linux/i810_drv.h @@ -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 -- cgit v1.2.3