Michel DÃnzer wrote:
fixed a copy & paste error in the non-core drm version, and it actually auto-refreshes the screen when switching between a tiled and untiled resolution...
Nice.
What happened to Stephane's surface allocator, BTW? If you just whack the surface registers directly from the X server, it becomes hard if not impossible to introduce such an allocator, at least for the surfaces touched directly by the X server...
Ok, I'm late, but here it is. Also attached is the small patch for the ddx.
It is supposed to be used with the drmCommand interface, btw :
drmRadeonSurfaceAlloc drmalloc_front;
drmalloc_front.lower=(info->frontOffset) &~0x3ff ;
drmalloc_front.size=bufferSize -1 ;
drmalloc_front.flags=pitch | RADEON_SURF_TILE_COLOR_MACRO;
drmCommandWrite(info->drmFD, DRM_RADEON_SURF_ALLOC, &drmalloc_front,sizeof(drmalloc_front));
Stephane
Index: shared/radeon.h =================================================================== RCS file: /cvs/dri/drm/shared/radeon.h,v retrieving revision 1.34 diff -u -r1.34 radeon.h --- shared/radeon.h 8 Dec 2004 16:43:00 -0000 1.34 +++ shared/radeon.h 20 Jan 2005 01:43:05 -0000 @@ -84,6 +84,8 @@ * (No 3D support yet - just microcode loading). * 1.13- Add packet R200_EMIT_TCL_POINT_SPRITE_CNTL for ARB_point_parameters * - Add hyperz support, add hyperz flags to clear ioctl. + * 1.14- Add support for color tiling + * - Add R100/R200 surface allocation/free support */ #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \ @@ -112,5 +114,7 @@ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)] = { radeon_irq_emit, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SETPARAM)] = { radeon_cp_setparam, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SURF_ALLOC)] = { radeon_surface_alloc,1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SURF_FREE)] = { radeon_surface_free ,1, 0 }, \ #endif Index: shared/radeon_cp.c =================================================================== RCS file: /cvs/dri/drm/shared/radeon_cp.c,v retrieving revision 1.46 diff -u -r1.46 radeon_cp.c --- shared/radeon_cp.c 8 Dec 2004 16:43:00 -0000 1.46 +++ shared/radeon_cp.c 20 Jan 2005 01:43:05 -0000 @@ -1267,6 +1267,7 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) { + int i; drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "\n" ); @@ -1520,6 +1521,11 @@ dev_priv->last_buf = 0; + for(i=0;i<RADEON_MAX_SURFACES;i++) + dev_priv->surfaces[i].refcount = 0; + for(i=0;i<2*RADEON_MAX_SURFACES;i++) + dev_priv->virt_surfaces[i].filp = 0; + radeon_do_engine_reset( dev ); return 0; Index: shared/radeon_drm.h =================================================================== RCS file: /cvs/dri/drm/shared/radeon_drm.h,v retrieving revision 1.25 diff -u -r1.25 radeon_drm.h --- shared/radeon_drm.h 8 Dec 2004 16:43:00 -0000 1.25 +++ shared/radeon_drm.h 20 Jan 2005 01:43:06 -0000 @@ -231,6 +231,8 @@ #define RADEON_MAX_TEXTURE_LEVELS 12 #define RADEON_MAX_TEXTURE_UNITS 3 +#define RADEON_MAX_SURFACES 8 + /* Blits have strict offset rules. All blit offset must be aligned on * a 1K-byte boundary. */ @@ -403,6 +405,8 @@ #define DRM_RADEON_IRQ_WAIT 0x17 #define DRM_RADEON_CP_RESUME 0x18 #define DRM_RADEON_SETPARAM 0x19 +#define DRM_RADEON_SURF_ALLOC 0x1a +#define DRM_RADEON_SURF_FREE 0x1b #define DRM_IOCTL_RADEON_CP_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t) #define DRM_IOCTL_RADEON_CP_START DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_START) @@ -429,6 +433,8 @@ #define DRM_IOCTL_RADEON_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_IRQ_WAIT, drm_radeon_irq_wait_t) #define DRM_IOCTL_RADEON_CP_RESUME DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_RESUME) #define DRM_IOCTL_RADEON_SETPARAM DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SETPARAM, drm_radeon_setparam_t) +#define DRM_IOCTL_RADEON_SURF_ALLOC DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_SURF_ALLOC, drm_radeon_surface_alloc_t) +#define DRM_IOCTL_RADEON_SURF_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_FREE, drm_radeon_surface_free_t) typedef struct drm_radeon_init { enum { @@ -630,5 +636,19 @@ #define RADEON_SETPARAM_FB_LOCATION 1 /* determined framebuffer location */ +/* 1.14: Clients can allocate/free a surface + */ + +typedef struct drm_radeon_surface_alloc { + unsigned int lower; + unsigned int size; + unsigned int flags; +} drm_radeon_surface_alloc_t; + +typedef struct drm_radeon_surface_free { + unsigned int lower; +} drm_radeon_surface_free_t; + + #endif Index: shared/radeon_drv.h =================================================================== RCS file: /cvs/dri/drm/shared/radeon_drv.h,v retrieving revision 1.38 diff -u -r1.38 radeon_drv.h --- shared/radeon_drv.h 8 Dec 2004 16:43:00 -0000 1.38 +++ shared/radeon_drv.h 20 Jan 2005 01:43:06 -0000 @@ -112,6 +112,21 @@ DRMFILE filp; /* 0: free, -1: heap, other: real files */ }; +struct radeon_surface { + int refcount; + u32 lower; + u32 upper; + u32 flags; +}; + +struct radeon_virt_surface { + int surface_index; + u32 lower; + u32 upper; + u32 flags; + DRMFILE filp; +}; + typedef struct drm_radeon_private { drm_radeon_ring_buffer_t ring; @@ -192,6 +207,10 @@ /* starting from here on, data is preserved accross an open */ uint32_t flags; /* see radeon_chip_flags */ + + struct radeon_surface surfaces[RADEON_MAX_SURFACES]; + struct radeon_virt_surface virt_surfaces[2*RADEON_MAX_SURFACES]; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) struct radeon_i2c_chan i2c[4]; #endif @@ -240,6 +259,8 @@ extern int radeon_mem_init_heap( DRM_IOCTL_ARGS ); extern void radeon_mem_takedown( struct mem_block **heap ); extern void radeon_mem_release( DRMFILE filp, struct mem_block *heap ); +extern int radeon_surface_alloc( DRM_IOCTL_ARGS ); +extern int radeon_surface_free( DRM_IOCTL_ARGS ); /* radeon_irq.c */ extern int radeon_irq_emit( DRM_IOCTL_ARGS ); @@ -511,6 +532,7 @@ # define RADEON_SURF_TILE_MODE_32BIT_Z (2 << 16) # define RADEON_SURF_TILE_MODE_16BIT_Z (3 << 16) #define RADEON_SURFACE0_LOWER_BOUND 0x0b04 +# define RADEON_SURF_ADDRESS_FIXED_MASK (0x03ff << 0) #define RADEON_SURFACE0_UPPER_BOUND 0x0b08 #define RADEON_SURFACE1_INFO 0x0b1c #define RADEON_SURFACE1_LOWER_BOUND 0x0b14 Index: shared/radeon_state.c =================================================================== RCS file: /cvs/dri/drm/shared/radeon_state.c,v retrieving revision 1.40 diff -u -r1.40 radeon_state.c --- shared/radeon_state.c 8 Dec 2004 16:43:00 -0000 1.40 +++ shared/radeon_state.c 20 Jan 2005 01:43:08 -0000 @@ -1706,11 +1706,199 @@ ADVANCE_RING(); } +static void radeon_apply_surface_regs(int surf_index, drm_radeon_private_t *dev_priv) +{ + if (!dev_priv->mmio) + return; + + radeon_do_wait_for_idle(dev_priv); + + RADEON_WRITE( RADEON_SURFACE0_INFO+16*surf_index, dev_priv->surfaces[surf_index].flags ); + RADEON_WRITE( RADEON_SURFACE0_LOWER_BOUND+16*surf_index, dev_priv->surfaces[surf_index].lower ); + RADEON_WRITE( RADEON_SURFACE0_UPPER_BOUND+16*surf_index, dev_priv->surfaces[surf_index].upper ); +} + +/* Allocates a virtual surface + * doesn't always allocate a real surface, will stretch an existing + * surface when possible. + * + * Note that refcount can be at most 2, since during a free refcount=3 + * might mean we have to allocate a new surface which might not always + * be available. + * For example : we allocate three contigous surfaces ABC. If B is + * freed, we suddenly need two surfaces to store A and C, which might + * not always be available. + */ +static int alloc_surface(drm_radeon_surface_alloc_t* new, drm_radeon_private_t *dev_priv, DRMFILE filp) +{ + struct radeon_virt_surface *s; + int i; + int virt_surface_index; + uint32_t new_upper; + + new_upper=new->lower + new->size; + + /* sanity check */ + if ((new->lower >= new_upper)||(new->flags==0)|| + ((new_upper&RADEON_SURF_ADDRESS_FIXED_MASK)!=RADEON_SURF_ADDRESS_FIXED_MASK)|| + ((new->lower&RADEON_SURF_ADDRESS_FIXED_MASK)!=0)) + return -1; + + /* make sure there is no overlap with existing surfaces */ + for(i=0;i<RADEON_MAX_SURFACES;i++) { + if ((dev_priv->surfaces[i].refcount!=0) && + (( (new->lower>=dev_priv->surfaces[i].lower) && (new->lower<dev_priv->surfaces[i].upper) ) || + ( (new_upper>dev_priv->surfaces[i].lower) && (new_upper<=dev_priv->surfaces[i].upper) ) || + ( (new->lower<dev_priv->surfaces[i].lower) && (new_upper>dev_priv->surfaces[i].upper) )) ) + return -1; + } + + /* find a virtual surface */ + for(i=0;i<2*RADEON_MAX_SURFACES;i++) + if (dev_priv->virt_surfaces[i].filp==0) + break; + if (i==2*RADEON_MAX_SURFACES) + return -1; + virt_surface_index=i; + + /* try to reuse an existing surface */ + for(i=0;i<RADEON_MAX_SURFACES;i++) { + /* extend before */ + if ((dev_priv->surfaces[i].refcount==1) && + (new->flags==dev_priv->surfaces[i].flags) && + (new_upper+1==dev_priv->surfaces[i].lower)) { + s=&(dev_priv->virt_surfaces[virt_surface_index]); + s->surface_index=i; + s->lower=new->lower; + s->upper=new_upper; + s->flags=new->flags; + s->filp=filp; + dev_priv->surfaces[i].refcount++; + dev_priv->surfaces[i].lower=s->lower; + radeon_apply_surface_regs(s->surface_index, dev_priv); + return virt_surface_index; + } + + /* extend after */ + if ((dev_priv->surfaces[i].refcount==1) && + (new->flags==dev_priv->surfaces[i].flags) && + (new->lower==dev_priv->surfaces[i].upper+1)) { + s=&(dev_priv->virt_surfaces[virt_surface_index]); + s->surface_index=i; + s->lower=new->lower; + s->upper=new_upper; + s->flags=new->flags; + s->filp=filp; + dev_priv->surfaces[i].refcount++; + dev_priv->surfaces[i].upper=s->upper; + radeon_apply_surface_regs(s->surface_index, dev_priv); + return virt_surface_index; + } + } + + /* okay, we need a new one */ + for(i=0;i<RADEON_MAX_SURFACES;i++) { + if (dev_priv->surfaces[i].refcount==0) { + s=&(dev_priv->virt_surfaces[virt_surface_index]); + s->surface_index=i; + s->lower=new->lower; + s->upper=new_upper; + s->flags=new->flags; + s->filp=filp; + dev_priv->surfaces[i].refcount=1; + dev_priv->surfaces[i].lower=s->lower; + dev_priv->surfaces[i].upper=s->upper; + dev_priv->surfaces[i].flags=s->flags; + radeon_apply_surface_regs(s->surface_index, dev_priv); + return virt_surface_index; + } + } + + /* we didn't find anything */ + return -1; +} + +static int free_surface(DRMFILE filp, drm_radeon_private_t *dev_priv, int lower) +{ + struct radeon_virt_surface *s; + int i; + /* find the virtual surface */ + for(i=0;i<2*RADEON_MAX_SURFACES;i++) { + s=&(dev_priv->virt_surfaces[i]); + if (s->filp) { + if ((lower==s->lower) && (filp==s->filp)) { + if (dev_priv->surfaces[s->surface_index].lower==s->lower) + dev_priv->surfaces[s->surface_index].lower=s->upper; + + if (dev_priv->surfaces[s->surface_index].upper==s->upper) + dev_priv->surfaces[s->surface_index].upper=s->lower; + + dev_priv->surfaces[s->surface_index].refcount--; + if (dev_priv->surfaces[s->surface_index].refcount==0) + dev_priv->surfaces[s->surface_index].flags=0; + s->filp=0; + radeon_apply_surface_regs(s->surface_index, dev_priv); + return 0; + } + } + } + return 1; +} + +static void radeon_surfaces_release(DRMFILE filp, drm_radeon_private_t *dev_priv) +{ + int i; + for(i=0;i<2*RADEON_MAX_SURFACES;i++) + { + if (dev_priv->virt_surfaces[i].filp==filp) + free_surface(filp,dev_priv,dev_priv->virt_surfaces[i].lower); + } +} /* ================================================================ * IOCTL functions */ +int radeon_surface_alloc( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_surface_alloc_t alloc; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL( alloc, (drm_radeon_surface_alloc_t __user *)data, + sizeof(alloc) ); + + if (alloc_surface(&alloc,dev_priv,filp)==-1) + return DRM_ERR(EINVAL); + else + return 0; +} + +int radeon_surface_free( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_surface_free_t memfree; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL( memfree, (drm_radeon_mem_free_t __user *)data, + sizeof(memfree) ); + + if (free_surface(filp,dev_priv,memfree.lower)) + return DRM_ERR(EINVAL); + else + return 0; +} + int radeon_cp_clear( DRM_IOCTL_ARGS ) { DRM_DEVICE; @@ -2724,6 +2912,7 @@ /* When a client dies: * - Check for and clean up flipped page state * - Free any alloced GART memory. + * - Free any alloced radeon surfaces. * * DRM infrastructure takes care of reclaiming dma buffers. */ @@ -2736,6 +2925,7 @@ } radeon_mem_release( filp, dev_priv->gart_heap ); radeon_mem_release( filp, dev_priv->fb_heap ); + radeon_surfaces_release( filp, dev_priv ); } }
Index: radeon_common.h =================================================================== RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_common.h,v retrieving revision 1.4 diff -u -r1.4 radeon_common.h --- radeon_common.h 12 Dec 2004 16:05:35 -0000 1.4 +++ radeon_common.h 20 Jan 2005 01:59:57 -0000 @@ -74,6 +74,8 @@ #define DRM_RADEON_IRQ_WAIT 0x17 #define DRM_RADEON_CP_RESUME 0x18 #define DRM_RADEON_SETPARAM 0x19 +#define DRM_RADEON_SURF_ALLOC 0x1a +#define DRM_RADEON_SURF_FREE 0x1b #define DRM_RADEON_MAX_DRM_COMMAND_INDEX 0x39 @@ -470,6 +472,22 @@ } drmRadeonSetParam; #define RADEON_SETPARAM_FB_LOCATION 1 +#define RADEON_SETPARAM_SWITCH_TILING 2 +#define RADEON_SETPARAM_CRT1_USESAREA 3 + +/* 1.14: Clients can allocate/free a surface + */ + +typedef struct drm_radeon_surface_alloc { + unsigned int lower; + unsigned int size; + unsigned int flags; +} drmRadeonSurfaceAlloc; + +typedef struct drm_radeon_surface_free { + unsigned int lower; +} drmRadeonSurfaceFree; + #endif Index: radeon_reg.h =================================================================== RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_reg.h,v retrieving revision 1.13 diff -u -r1.13 radeon_reg.h --- radeon_reg.h 12 Dec 2004 02:00:48 -0000 1.13 +++ radeon_reg.h 20 Jan 2005 01:59:59 -0000 @@ -1280,6 +1280,7 @@ # define RADEON_NONSURF_AP1_SWP_32BPP (1 << 23) #define RADEON_SURFACE0_INFO 0x0b0c #define RADEON_SURFACE0_LOWER_BOUND 0x0b04 +# define RADEON_SURF_ADDRESS_FIXED_MASK (0x03ff << 0) #define RADEON_SURFACE0_UPPER_BOUND 0x0b08 #define RADEON_SURFACE1_INFO 0x0b1c #define RADEON_SURFACE1_LOWER_BOUND 0x0b14