From 05ef8effbffaab3b4005e938617d0a37d9db855a Mon Sep 17 00:00:00 2001 From: Gareth Hughes Date: Fri, 20 Oct 2000 00:48:07 +0000 Subject: [PATCH] Latest development work. Should be reasonably stable with the DRIScreenInit locking fix. Usual caveats apply to using development code. Includes: - ctx->Texture.Enabled to ctx->Texture.ReallyEnabled fix - More useful information in GL_RENDERER string - More indirect buffer support work --- linux-core/r128_drv.c | 3 +- linux/drm.h | 3 +- linux/r128_cce.c | 12 ++- linux/r128_drm.h | 25 ++++- linux/r128_drv.c | 3 +- linux/r128_drv.h | 36 ++++++- linux/r128_state.c | 224 ++++++++++++++++++++++++++++++++++++++++-- shared-core/drm.h | 3 +- shared/drm.h | 3 +- 9 files changed, 290 insertions(+), 22 deletions(-) diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c index dafb50a2..6f07b5bb 100644 --- a/linux-core/r128_drv.c +++ b/linux-core/r128_drv.c @@ -37,7 +37,7 @@ #define R128_NAME "r128" #define R128_DESC "ATI Rage 128" -#define R128_DATE "20001016" +#define R128_DATE "20001019" #define R128_MAJOR 1 #define R128_MINOR 1 #define R128_PATCHLEVEL 0 @@ -117,6 +117,7 @@ static drm_ioctl_desc_t r128_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_R128_SWAP)] = { r128_cce_swap, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_CLEAR)] = { r128_cce_clear, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_cce_vertex, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_BLIT)] = { r128_cce_blit, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_PACKET)] = { r128_cce_packet, 1, 0 }, }; #define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls) diff --git a/linux/drm.h b/linux/drm.h index 35a6f27b..cf0618e4 100644 --- a/linux/drm.h +++ b/linux/drm.h @@ -371,6 +371,7 @@ typedef struct drm_agp_info { #define DRM_IOCTL_R128_SWAP DRM_IO( 0x46) #define DRM_IOCTL_R128_CLEAR DRM_IOW( 0x47, drm_r128_clear_t) #define DRM_IOCTL_R128_VERTEX DRM_IOW( 0x48, drm_r128_vertex_t) -#define DRM_IOCTL_R128_PACKET DRM_IOWR(0x49, drm_r128_packet_t) +#define DRM_IOCTL_R128_BLIT DRM_IOW( 0x49, drm_r128_blit_t) +#define DRM_IOCTL_R128_PACKET DRM_IOWR(0x50, drm_r128_packet_t) #endif diff --git a/linux/r128_cce.c b/linux/r128_cce.c index 92793659..1b95c2d7 100644 --- a/linux/r128_cce.c +++ b/linux/r128_cce.c @@ -491,7 +491,8 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) R128_WRITE( R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame ); dev_priv->sarea_priv->last_dispatch = 0; - R128_WRITE( R128_LAST_VB_REG, dev_priv->sarea_priv->last_dispatch ); + R128_WRITE( R128_LAST_DISPATCH_REG, + dev_priv->sarea_priv->last_dispatch ); r128_cce_init_ring_buffer( dev ); r128_cce_load_microcode( dev_priv ); @@ -732,11 +733,12 @@ drm_buf_t *r128_freelist_get( drm_device_t *dev ) for ( i = 0 ; i < dma->buf_count ; i++ ) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - if ( buf->pid == 0 ) return buf; + if ( buf->pid == 0 ) + return buf; } for ( t = 0 ; t < dev_priv->usec_timeout ; t++ ) { - u32 done_age = R128_READ( R128_LAST_VB_REG ); + u32 done_age = R128_READ( R128_LAST_DISPATCH_REG ); for ( i = 0 ; i < dma->buf_count ; i++ ) { buf = dma->buflist[i]; @@ -752,7 +754,7 @@ drm_buf_t *r128_freelist_get( drm_device_t *dev ) udelay( 1 ); } - DRM_ERROR( "%s: returning NULL!\n", __FUNCTION__ ); + DRM_ERROR( "returning NULL!\n" ); return NULL; } @@ -1152,7 +1154,7 @@ static int r128_cce_get_buffers( drm_device_t *dev, drm_dma_t *d ) for ( i = d->granted_count ; i < d->request_count ; i++ ) { buf = r128_freelist_get( dev ); - if ( !buf ) break; + if ( !buf ) return -EAGAIN; buf->pid = current->pid; diff --git a/linux/r128_drm.h b/linux/r128_drm.h index 17d3d3f4..7ee6d7ce 100644 --- a/linux/r128_drm.h +++ b/linux/r128_drm.h @@ -58,6 +58,14 @@ #define R128_BACK 0x2 #define R128_DEPTH 0x4 +/* Vertex/indirect buffer size + */ +#define R128_BUFFER_SIZE 16384 + +/* 2048x2048 @ 32bpp texture requires this many indirect buffers + */ +#define R128_MAX_BLIT_BUFFERS 256 + /* Keep these small for testing. */ #define R128_NR_SAREA_CLIPRECTS 12 @@ -195,11 +203,26 @@ typedef struct drm_r128_clear { } drm_r128_clear_t; typedef struct drm_r128_vertex { - int index; /* Index of vertex buffer */ + int idx; /* Index of vertex buffer */ int used; /* Amount of buffer used */ int discard; /* Client finished with buffer? */ } drm_r128_vertex_t; +typedef struct drm_r128_blit_rect { + int index; + unsigned short x, y; + unsigned short width, height; + int padding; +} drm_r128_blit_rect_t; + +typedef struct drm_r128_blit { + int pitch; + int offset; + int format; + drm_r128_blit_rect_t *rects; + int count; +} drm_r128_blit_t; + typedef struct drm_r128_packet { unsigned int *buffer; int count; diff --git a/linux/r128_drv.c b/linux/r128_drv.c index dafb50a2..6f07b5bb 100644 --- a/linux/r128_drv.c +++ b/linux/r128_drv.c @@ -37,7 +37,7 @@ #define R128_NAME "r128" #define R128_DESC "ATI Rage 128" -#define R128_DATE "20001016" +#define R128_DATE "20001019" #define R128_MAJOR 1 #define R128_MINOR 1 #define R128_PATCHLEVEL 0 @@ -117,6 +117,7 @@ static drm_ioctl_desc_t r128_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_R128_SWAP)] = { r128_cce_swap, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_CLEAR)] = { r128_cce_clear, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_cce_vertex, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_BLIT)] = { r128_cce_blit, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_PACKET)] = { r128_cce_packet, 1, 0 }, }; #define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls) diff --git a/linux/r128_drv.h b/linux/r128_drv.h index d931ca52..98182284 100644 --- a/linux/r128_drv.h +++ b/linux/r128_drv.h @@ -100,6 +100,20 @@ typedef struct drm_r128_buf_priv { drm_r128_freelist_t *list_entry; } drm_r128_buf_priv_t; +#define R128_BLIT_PACKET_DATA_SIZE ((R128_BUFFER_SIZE / sizeof(u32)) - 8) + +typedef struct drm_r128_blit_packet { + u32 header; + u32 gui_master_cntl; + u32 dst_pitch_offset; + u32 fg_color; + u32 bg_color; + u16 x, y; /* HACK: endian specific */ + u16 width, height; + u32 dwords; + u32 data[R128_BLIT_PACKET_DATA_SIZE]; +} drm_r128_blit_packet_t; + /* r128_drv.c */ extern int r128_version( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); @@ -143,6 +157,8 @@ extern int r128_cce_swap( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); extern int r128_cce_vertex( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); +extern int r128_cce_blit( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); /* r128_bufs.c */ extern int r128_addbufs(struct inode *inode, struct file *filp, @@ -207,11 +223,14 @@ extern int r128_context_switch_complete(drm_device_t *dev, int new); #define R128_CONSTANT_COLOR_C 0x1d34 #define R128_DP_GUI_MASTER_CNTL 0x146c +# define R128_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) +# define R128_GMC_DST_PITCH_OFFSET_CNTL (1 << 1) # define R128_GMC_BRUSH_SOLID_COLOR (13 << 4) # define R128_GMC_BRUSH_NONE (15 << 4) # define R128_GMC_DST_16BPP (4 << 8) # define R128_GMC_DST_24BPP (5 << 8) # define R128_GMC_DST_32BPP (6 << 8) +# define R128_GMC_DST_DATATYPE_SHIFT 8 # define R128_GMC_SRC_DATATYPE_COLOR (3 << 12) # define R128_DP_SRC_SOURCE_MEMORY (2 << 24) # define R128_DP_SRC_SOURCE_HOST_DATA (3 << 24) @@ -242,7 +261,10 @@ extern int r128_context_switch_complete(drm_device_t *dev, int new); # define R128_FORCE_PIPE3D_CP (1 << 17) # define R128_FORCE_RCP (1 << 18) +#define R128_PC_GUI_CTLSTAT 0x1748 #define R128_PC_NGUI_CTLSTAT 0x0184 +# define R128_PC_FLUSH_GUI (3 << 0) +# define R128_PC_RI_GUI (1 << 2) # define R128_PC_FLUSH_ALL 0x00ff # define R128_PC_BUSY (1 << 31) @@ -289,6 +311,9 @@ extern int r128_context_switch_complete(drm_device_t *dev, int new); #define R128_PM4_VC_FPU_SETUP 0x071c +#define R128_PM4_IW_INDOFF 0x0738 +#define R128_PM4_IW_INDSIZE 0x073c + #define R128_PM4_STAT 0x07b8 # define R128_PM4_FIFOCNT_MASK 0x0fff # define R128_PM4_BUSY (1 << 16) @@ -337,6 +362,15 @@ extern int r128_context_switch_complete(drm_device_t *dev, int new); #define R128_CCE_VC_CNTL_PRIM_WALK_RING 0x00000030 #define R128_CCE_VC_CNTL_NUM_SHIFT 16 +#define R128_DATATYPE_CI8 2 +#define R128_DATATYPE_ARGB1555 3 +#define R128_DATATYPE_RGB565 4 +#define R128_DATATYPE_RGB888 5 +#define R128_DATATYPE_ARGB8888 6 +#define R128_DATATYPE_RGB332 7 +#define R128_DATATYPE_RGB8 9 +#define R128_DATATYPE_ARGB4444 15 + /* Constants */ #define R128_AGP_OFFSET 0x02000000 @@ -348,7 +382,7 @@ extern int r128_context_switch_complete(drm_device_t *dev, int new); #define R128_MAX_USEC_TIMEOUT 100000 /* 100 ms */ #define R128_LAST_FRAME_REG R128_GUI_SCRATCH_REG0 -#define R128_LAST_VB_REG R128_GUI_SCRATCH_REG1 +#define R128_LAST_DISPATCH_REG R128_GUI_SCRATCH_REG1 #define R128_MAX_VB_AGE 0xffffffff diff --git a/linux/r128_state.c b/linux/r128_state.c index 0a211a69..a8320486 100644 --- a/linux/r128_state.c +++ b/linux/r128_state.c @@ -558,19 +558,18 @@ static void r128_cce_dispatch_vertex( drm_device_t *dev, } if ( buf_priv->discard ) { + buf_priv->age = dev_priv->sarea_priv->last_dispatch; + /* Emit the vertex buffer age */ BEGIN_RING( 2 ); - - OUT_RING( CCE_PACKET0( R128_LAST_VB_REG, 0 ) ); - OUT_RING( dev_priv->sarea_priv->last_dispatch ); - + OUT_RING( CCE_PACKET0( R128_LAST_DISPATCH_REG, 0 ) ); + OUT_RING( buf_priv->age ); ADVANCE_RING(); buf->pending = 1; /* FIXME: Check dispatched field */ buf_priv->dispatched = 0; - buf_priv->age = dev_priv->sarea_priv->last_dispatch; } dev_priv->sarea_priv->last_dispatch++; @@ -586,6 +585,175 @@ static void r128_cce_dispatch_vertex( drm_device_t *dev, } + + +static void r128_cce_dispatch_indirect( drm_device_t *dev, drm_buf_t *buf ) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + drm_r128_buf_priv_t *buf_priv = buf->dev_private; + int offset = dev_priv->buffers->offset + buf->offset - dev->agp->base; + int size = ((buf->used / sizeof(u32)) + 1) & ~0x1; + RING_LOCALS; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + r128_update_ring_snapshot( dev_priv ); + + if ( buf->used ) { + DRM_DEBUG( "%s: offset=0x%x size=%d used=%d\n", + __FUNCTION__, offset, size, buf->used ); + buf_priv->dispatched = 1; + + /* Fire off the indirect buffer */ + BEGIN_RING( 3 ); + + OUT_RING( CCE_PACKET0( R128_PM4_IW_INDOFF, 1 ) ); + OUT_RING( offset ); + OUT_RING( size ); + + ADVANCE_RING(); + } + + if ( buf_priv->discard ) { + buf_priv->age = dev_priv->sarea_priv->last_dispatch; + + /* Emit the indirect buffer age */ + BEGIN_RING( 2 ); + + OUT_RING( CCE_PACKET0( R128_LAST_DISPATCH_REG, 0 ) ); + OUT_RING( buf_priv->age ); + + ADVANCE_RING(); + + buf->pending = 1; + + /* FIXME: Check dispatched field */ + buf_priv->dispatched = 0; + } + + dev_priv->sarea_priv->last_dispatch++; + +#if 0 + if ( dev_priv->submit_age == R128_MAX_VB_AGE ) { + ret = r128_do_cce_idle( dev_priv ); + if ( ret < 0 ) return ret; + dev_priv->submit_age = 0; + r128_freelist_reset( dev ); + } +#endif +} + +static int r128_cce_dispatch_blit( drm_device_t *dev, + int offset, int pitch, int format, + drm_r128_blit_rect_t *rects, int count ) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_r128_buf_priv_t *buf_priv; + drm_r128_blit_rect_t *rect; + drm_r128_blit_packet_t *blit; + int dword_shift, dwords; + int i; + RING_LOCALS; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + switch ( format ) { + case R128_DATATYPE_ARGB1555: + case R128_DATATYPE_RGB565: + case R128_DATATYPE_ARGB4444: + dword_shift = 1; + break; + case R128_DATATYPE_ARGB8888: + dword_shift = 0; + break; + default: + DRM_ERROR( "invalid blit format %d\n", format ); + return -EINVAL; + } + + /* Flush the pixel cache, and mark the contents as Read Invalid. + * This ensures no pixel data gets mixed up with the texture + * data from the host data blit, otherwise part of the texture + * image may be corrupted. + */ + BEGIN_RING( 2 ); + + OUT_RING( CCE_PACKET0( R128_PC_GUI_CTLSTAT, 0 ) ); + OUT_RING( R128_PC_RI_GUI | R128_PC_FLUSH_GUI ); + + ADVANCE_RING(); + + /* Dispatch each of the indirect buffers. + */ + for ( i = 0 ; i < count ; i++ ) { + rect = &rects[i]; + buf = dma->buflist[rect->index]; + buf_priv = buf->dev_private; + + if ( buf->pid != current->pid ) { + DRM_ERROR( "process %d using buffer owned by %d\n", + current->pid, buf->pid ); + return -EINVAL; + } + if ( buf->pending ) { + DRM_ERROR( "sending pending buffer %d\n", + rect->index ); + return -EINVAL; + } + + buf_priv->discard = 1; + + dwords = (rect->width * rect->height) >> dword_shift; + + blit = (drm_r128_blit_packet_t *) + ((char *)dev_priv->buffers->handle + buf->offset); + + blit->header = CCE_PACKET3( R128_CNTL_HOSTDATA_BLT, + dwords + 6 ); + blit->gui_master_cntl = ( R128_GMC_DST_PITCH_OFFSET_CNTL + | R128_GMC_BRUSH_NONE + | (format << 8) + | R128_GMC_SRC_DATATYPE_COLOR + | R128_ROP3_S + | R128_DP_SRC_SOURCE_HOST_DATA + | R128_GMC_CLR_CMP_CNTL_DIS + | R128_GMC_AUX_CLIP_DIS + | R128_GMC_WR_MSK_DIS ); + + blit->dst_pitch_offset = (pitch << 21) | (offset >> 5); + blit->fg_color = 0xffffffff; + blit->bg_color = 0xffffffff; + blit->x = rect->x; + blit->y = rect->y; + blit->width = rect->width; + blit->height = rect->height; + blit->dwords = dwords; + + /* FIXME: This should really go in the function call... + */ + if ( dwords & 1 ) { + blit->data[dwords++] = R128_CCE_PACKET2; + } + buf->used = (dwords + 8) * sizeof(u32); + + r128_cce_dispatch_indirect( dev, buf ); + } + + /* Flush the pixel cache after the blit completes. This ensures + * the texture data is written out to memory before rendering + * continues. + */ + BEGIN_RING( 2 ); + + OUT_RING( CCE_PACKET0( R128_PC_GUI_CTLSTAT, 0 ) ); + OUT_RING( R128_PC_FLUSH_GUI ); + + ADVANCE_RING(); + + return 0; +} + + /* ================================================================ * */ @@ -679,15 +847,15 @@ int r128_cce_vertex( struct inode *inode, struct file *filp, DRM_DEBUG( "%s: pid=%d index=%d used=%d discard=%d\n", __FUNCTION__, current->pid, - vertex.index, vertex.used, vertex.discard ); + vertex.idx, vertex.used, vertex.discard ); - if ( vertex.index < 0 || vertex.index >= dma->buf_count ) { + if ( vertex.idx < 0 || vertex.idx >= dma->buf_count ) { DRM_ERROR( "buffer index %d (of %d max)\n", - vertex.index, dma->buf_count - 1 ); + vertex.idx, dma->buf_count - 1 ); return -EINVAL; } - buf = dma->buflist[vertex.index]; + buf = dma->buflist[vertex.idx]; buf_priv = buf->dev_private; if ( buf->pid != current->pid ) { @@ -696,7 +864,7 @@ int r128_cce_vertex( struct inode *inode, struct file *filp, return -EINVAL; } if ( buf->pending ) { - DRM_ERROR( "sending pending buffer %d\n", vertex.index ); + DRM_ERROR( "sending pending buffer %d\n", vertex.idx ); return -EINVAL; } @@ -707,3 +875,39 @@ int r128_cce_vertex( struct inode *inode, struct file *filp, return 0; } + +int r128_cce_blit( 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_device_dma_t *dma = dev->dma; + drm_r128_blit_t blit; + drm_r128_blit_rect_t rects[R128_MAX_BLIT_BUFFERS]; + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + + if ( copy_from_user( &blit, (drm_r128_blit_t *)arg, + sizeof(blit) ) ) + return -EFAULT; + + DRM_DEBUG( "%s: pid=%d count=%d\n", + __FUNCTION__, current->pid, blit.count ); + + if ( blit.count < 0 || blit.count > dma->buf_count ) { + DRM_ERROR( "sending %d buffers (of %d max)\n", + blit.count, dma->buf_count ); + return -EINVAL; + } + + if ( copy_from_user( &rects, blit.rects, + blit.count * sizeof(drm_r128_blit_rect_t) ) ) + return -EFAULT; + + return r128_cce_dispatch_blit( dev, blit.offset, blit.pitch, + blit.format, rects, blit.count ); +} diff --git a/shared-core/drm.h b/shared-core/drm.h index 35a6f27b..cf0618e4 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -371,6 +371,7 @@ typedef struct drm_agp_info { #define DRM_IOCTL_R128_SWAP DRM_IO( 0x46) #define DRM_IOCTL_R128_CLEAR DRM_IOW( 0x47, drm_r128_clear_t) #define DRM_IOCTL_R128_VERTEX DRM_IOW( 0x48, drm_r128_vertex_t) -#define DRM_IOCTL_R128_PACKET DRM_IOWR(0x49, drm_r128_packet_t) +#define DRM_IOCTL_R128_BLIT DRM_IOW( 0x49, drm_r128_blit_t) +#define DRM_IOCTL_R128_PACKET DRM_IOWR(0x50, drm_r128_packet_t) #endif diff --git a/shared/drm.h b/shared/drm.h index 35a6f27b..cf0618e4 100644 --- a/shared/drm.h +++ b/shared/drm.h @@ -371,6 +371,7 @@ typedef struct drm_agp_info { #define DRM_IOCTL_R128_SWAP DRM_IO( 0x46) #define DRM_IOCTL_R128_CLEAR DRM_IOW( 0x47, drm_r128_clear_t) #define DRM_IOCTL_R128_VERTEX DRM_IOW( 0x48, drm_r128_vertex_t) -#define DRM_IOCTL_R128_PACKET DRM_IOWR(0x49, drm_r128_packet_t) +#define DRM_IOCTL_R128_BLIT DRM_IOW( 0x49, drm_r128_blit_t) +#define DRM_IOCTL_R128_PACKET DRM_IOWR(0x50, drm_r128_packet_t) #endif