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
