diff -uNr r300/Makefile r300.user/Makefile
--- r300/Makefile	Sun Sep 25 12:45:42 2005
+++ r300.user/Makefile	Thu Oct  6 20:58:55 2005
@@ -25,6 +25,7 @@
 		 radeon_lock.c \
 		 radeon_span.c \
 		 radeon_state.c \
+		 radeon_mm.c \
 		 \
 		 r300_context.c \
 		 r300_ioctl.c \
diff -uNr r300/r300_context.c r300.user/r300_context.c
--- r300/r300_context.c	Sun Sep 25 13:20:38 2005
+++ r300.user/r300_context.c	Wed Oct  5 17:29:44 2005
@@ -64,8 +64,8 @@
 #include "xmlpool.h"		/* for symbolic values of enum-type options */
 
 /* hw_tcl_on derives from future_hw_tcl_on when its safe to change it. */
-int future_hw_tcl_on=0;
-int hw_tcl_on=0;
+int future_hw_tcl_on=1;
+int hw_tcl_on=1;
 
 #define need_GL_ARB_multisample
 #define need_GL_ARB_texture_compression
@@ -83,8 +83,7 @@
   {"GL_ARB_multitexture",		NULL},
   {"GL_ARB_texture_border_clamp",	NULL},
   {"GL_ARB_texture_compression",	GL_ARB_texture_compression_functions},
-/* disable until we support it, fixes a few things in ut2004 */
-/*	{"GL_ARB_texture_cube_map",	NULL}, */
+  {"GL_ARB_texture_cube_map",		NULL}, 
   {"GL_ARB_texture_env_add",		NULL},
   {"GL_ARB_texture_env_combine",	NULL},
   {"GL_ARB_texture_env_crossbar",	NULL},
@@ -155,6 +154,7 @@
 	0,
 };
 
+#ifdef USER_BUFFERS
 static void r300BufferData(GLcontext *ctx, GLenum target, GLsizeiptrARB size,
 		const GLvoid *data, GLenum usage, struct gl_buffer_object *obj)
 {
@@ -164,33 +164,11 @@
 
 	/* Free previous buffer */
 	if (obj->OnCard) {
-		drm_radeon_mem_free_t memfree;
-		
-		memfree.region = RADEON_MEM_REGION_GART;
-		memfree.region_offset = (char *)obj->Data - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
-
-		ret = drmCommandWrite(rmesa->radeon.radeonScreen->driScreen->fd,
-				      DRM_RADEON_FREE, &memfree, sizeof(memfree));
-
-		if (ret) {
-			WARN_ONCE("Failed to free GART memroy!\n");
-		}
+		radeon_mm_free(rmesa, obj->Data);
 		obj->OnCard = GL_FALSE;
 	}
-	
-	alloc.region = RADEON_MEM_REGION_GART;
-	alloc.alignment = 4;
-	alloc.size = size;
-	alloc.region_offset = &offset;
-
-	ret = drmCommandWriteRead( rmesa->radeon.dri.fd, DRM_RADEON_ALLOC, &alloc, sizeof(alloc));
-   	if (ret) {
-		WARN_ONCE("Ran out of GART memory!\n");
-		obj->Data = NULL;
-		_mesa_buffer_data(ctx, target, size, data, usage, obj);
-		return ;
-	}
-	obj->Data = ((GLubyte *)rmesa->radeon.radeonScreen->gartTextures.map) + offset;
+	//id = radeon_mm_alloc(rmesa, 4, size);
+	//obj->Data = radeon_mm_ptr(rmesa, id);
 	
 	if (data)
 		memcpy(obj->Data, data, size);
@@ -207,23 +185,11 @@
 {
 	r300ContextPtr rmesa = R300_CONTEXT(ctx);
 	
-	if(r300IsGartMemory(rmesa, obj->Data, obj->Size)){
-		drm_radeon_mem_free_t memfree;
-		int ret;
-		
-		memfree.region = RADEON_MEM_REGION_GART;
-		memfree.region_offset = (char *)obj->Data - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
-
-		ret = drmCommandWrite(rmesa->radeon.radeonScreen->driScreen->fd,
-				      DRM_RADEON_FREE, &memfree, sizeof(memfree));
-
-		if(ret){
-			WARN_ONCE("Failed to free GART memroy!\n");
-		}
-		obj->Data = NULL;
-	}
+	//radeon_mm_free(rmesa, int id);
+	obj->Data = NULL;
 	_mesa_delete_buffer_object(ctx, obj);
 }
+#endif
 
 /* Create the device specific rendering context.
  */
@@ -263,13 +229,18 @@
 	r300InitTextureFuncs(&functions);
 	r300InitShaderFuncs(&functions);
 	
+	
+#ifdef USER_BUFFERS
+	radeon_mm_init(r300);
+#endif
+#ifdef USER_BUFFERS
 #if 0 /* Needs various Mesa changes... */
 	if (hw_tcl_on) {
 		functions.BufferData = r300BufferData;
 		functions.DeleteBuffer = r300DeleteBuffer;
 	}
 #endif
-	
+#endif	
 	if (!radeonInitContext(&r300->radeon, &functions,
 			       glVisual, driContextPriv, sharedContextPrivate)) {
 		FREE(r300);
@@ -331,6 +302,11 @@
 	ctx->Const.MinLineWidthAA = 1.0;
 	ctx->Const.MaxLineWidth = R300_LINESIZE_MAX;
 	ctx->Const.MaxLineWidthAA = R300_LINESIZE_MAX;
+	
+#ifdef USER_BUFFERS
+	/* Needs further modifications */
+	//ctx->Const.MaxArrayLockSize = (512*1024) / (4*4);
+#endif
 
 	/* Initialize the software rasterizer and helper modules.
 	 */
diff -uNr r300/r300_context.h r300.user/r300_context.h
--- r300/r300_context.h	Thu Jul 21 02:24:55 2005
+++ r300.user/r300_context.h	Wed Oct  5 18:34:48 2005
@@ -48,6 +48,7 @@
 #include "radeon_context.h"
 
 #define USE_ARB_F_P 1
+#define USER_BUFFERS
 
 struct r300_context;
 typedef struct r300_context r300ContextRec;
@@ -109,12 +110,15 @@
 struct r300_dma_buffer {
 	int refcount;		/* the number of retained regions in buf */
 	drmBufPtr buf;
+	int id;
 };
-
+#ifdef USER_BUFFERS
+#define GET_START(rvb) (r300GartOffsetFromVirtual(rmesa, (rvb)->address+(rvb)->start))
+#else
 #define GET_START(rvb) (rmesa->radeon.radeonScreen->gart_buffer_offset +		\
 			(rvb)->address - rmesa->dma.buf0_address +	\
 			(rvb)->start)
-
+#endif
 /* A retained region, eg vertices for indexed vertices.
  */
 struct r300_dma_region {
@@ -523,11 +527,11 @@
 
 /* Vertex shader state */
 
-/* Tested with rv350 and verified from misc web pages. */
+/* Perhaps more if we store programs in vmem? */
 #define VSF_MAX_FRAGMENT_LENGTH (256*4)
 	
-/* Tested with rv350 and verified from misc web pages. */
-#define VSF_MAX_FRAGMENT_TEMPS (32)
+/* Can be tested with colormat currently. */
+#define VSF_MAX_FRAGMENT_TEMPS (14)
 
 
 struct r300_vertex_shader_fragment {
@@ -815,6 +819,12 @@
 	GLuint TexGenInputs;
 	GLuint TexGenCompSel;
 	GLmatrix tmpmat;
+#ifdef USER_BUFFERS
+	key_t mm_ipc_key;
+	int mm_shm_id;
+	int mm_sem_id;
+	struct radeon_memory_manager *rmm;
+#endif
 };
 
 #define R300_CONTEXT(ctx)		((r300ContextPtr)(ctx->DriverCtx))
diff -uNr r300/r300_ioctl.c r300.user/r300_ioctl.c
--- r300/r300_ioctl.c	Thu Jul 21 00:35:27 2005
+++ r300.user/r300_ioctl.c	Thu Oct  6 20:57:42 2005
@@ -572,6 +572,104 @@
 		r300FlushCmdBuf(r300, __FUNCTION__);
 }
 
+#ifdef USER_BUFFERS
+#include "radeon_mm.h"
+
+void r300RefillCurrentDmaRegion(r300ContextPtr rmesa)
+{
+	struct r300_dma_buffer *dmabuf;
+	int fd = rmesa->radeon.dri.fd;
+	int index = 0;
+	int size = 0;
+	drmDMAReq dma;
+	int ret;
+	
+	if (RADEON_DEBUG & (DEBUG_IOCTL | DEBUG_DMA))
+		fprintf(stderr, "%s\n", __FUNCTION__);
+
+	if (rmesa->dma.flush) {
+		rmesa->dma.flush(rmesa);
+	}
+
+	if (rmesa->dma.current.buf)
+		r300ReleaseDmaRegion(rmesa, &rmesa->dma.current, __FUNCTION__);
+
+	if (rmesa->dma.nr_released_bufs > 4)
+		r300FlushCmdBuf(rmesa, __FUNCTION__);
+	
+	dmabuf = CALLOC_STRUCT(r300_dma_buffer);
+	dmabuf->buf = (void *)1; /* hack */
+	dmabuf->refcount = 1;
+
+	dmabuf->id = radeon_mm_alloc(rmesa, 4, RADEON_BUFFER_SIZE);
+			
+	rmesa->dma.current.buf = dmabuf;
+	rmesa->dma.current.address = radeon_mm_ptr(rmesa, dmabuf->id);
+	rmesa->dma.current.end = RADEON_BUFFER_SIZE;
+	rmesa->dma.current.start = 0;
+	rmesa->dma.current.ptr = 0;
+}
+
+void r300ReleaseDmaRegion(r300ContextPtr rmesa,
+			  struct r300_dma_region *region, const char *caller)
+{
+	if (RADEON_DEBUG & DEBUG_IOCTL)
+		fprintf(stderr, "%s from %s\n", __FUNCTION__, caller);
+
+	if (!region->buf)
+		return;
+
+	if (rmesa->dma.flush)
+		rmesa->dma.flush(rmesa);
+
+	if (--region->buf->refcount == 0) {
+		radeon_mm_free(rmesa, region->buf->id);
+		FREE(region->buf);
+		rmesa->dma.nr_released_bufs++;
+	}
+
+	region->buf = 0;
+	region->start = 0;
+}
+
+/* Allocates a region from rmesa->dma.current.  If there isn't enough
+ * space in current, grab a new buffer (and discard what was left of current)
+ */
+void r300AllocDmaRegion(r300ContextPtr rmesa,
+			struct r300_dma_region *region,
+			int bytes, int alignment)
+{
+	if (RADEON_DEBUG & DEBUG_IOCTL)
+		fprintf(stderr, "%s %d\n", __FUNCTION__, bytes);
+
+	if (rmesa->dma.flush)
+		rmesa->dma.flush(rmesa);
+
+	if (region->buf)
+		r300ReleaseDmaRegion(rmesa, region, __FUNCTION__);
+
+	alignment--;
+	rmesa->dma.current.start = rmesa->dma.current.ptr =
+	    (rmesa->dma.current.ptr + alignment) & ~alignment;
+
+	if (rmesa->dma.current.ptr + bytes > rmesa->dma.current.end)
+		r300RefillCurrentDmaRegion(rmesa);
+
+	region->start = rmesa->dma.current.start;
+	region->ptr = rmesa->dma.current.start;
+	region->end = rmesa->dma.current.start + bytes;
+	region->address = rmesa->dma.current.address;
+	region->buf = rmesa->dma.current.buf;
+	region->buf->refcount++;
+
+	rmesa->dma.current.ptr += bytes;	/* bug - if alignment > 7 */
+	rmesa->dma.current.start =
+	    rmesa->dma.current.ptr = (rmesa->dma.current.ptr + 0x7) & ~0x7;
+
+	assert(rmesa->dma.current.ptr <= rmesa->dma.current.end);
+}
+
+#else
 void r300RefillCurrentDmaRegion(r300ContextPtr rmesa)
 {
 	struct r300_dma_buffer *dmabuf;
@@ -713,6 +811,8 @@
 
 	assert(rmesa->dma.current.ptr <= rmesa->dma.current.end);
 }
+
+#endif
 
 /* Called via glXGetMemoryOffsetMESA() */
 GLuint r300GetMemoryOffsetMESA(__DRInativeDisplay * dpy, int scrn,
diff -uNr r300/r300_maos.c r300.user/r300_maos.c
--- r300/r300_maos.c	Thu Jul 21 00:35:27 2005
+++ r300.user/r300_maos.c	Mon Oct  3 20:36:13 2005
@@ -174,8 +174,8 @@
 			__FUNCTION__, count, size, stride);
 
 	if(r300IsGartMemory(rmesa, data, size*stride)){
-		rvb->address = rmesa->radeon.radeonScreen->gartTextures.map;
-		rvb->start = (char *)data - rvb->address;
+		rvb->address = rmesa->radeon.radeonScreen->gartTextures.map + ((char *)data - rvb->address);
+		rvb->start = 0;
 		rvb->aos_offset = r300GartOffsetFromVirtual(rmesa, data);
 		
 		if(stride == 0)
@@ -226,26 +226,52 @@
 
 }
 
-void r300EmitElts(GLcontext * ctx, GLuint *elts, unsigned long n_elts)
+void r300EmitElts(GLcontext * ctx, void *elts, unsigned long n_elts, int elt_size, int cutoff)
 {
 	r300ContextPtr rmesa = R300_CONTEXT(ctx);
 	struct r300_dma_region *rvb=&rmesa->state.elt_dma;
 	unsigned short int *out;
 	int i;
 	
-	if(r300IsGartMemory(rmesa, elts, n_elts*sizeof(unsigned short int))){
+	/*if(elt_size == 0)
+		exit(0);*/
+	
+	if(r300IsGartMemory(rmesa, elts, /*n_elts*elt_size*/1)){
+		unsigned long *ptr=elts;
+		//fprintf(stderr, "address %p is GART\n", elts);
+		//fprintf(stderr, "%d elts, size %d\n", n_elts, elt_size);
+		/*fprintf(stderr, "driver side: ");
+		for(i=0; i < n_elts; i++)
+			fprintf(stderr, "%d ", ptr[i]);
+		fprintf(stderr, "\n");*/
+		
 		rvb->address = rmesa->radeon.radeonScreen->gartTextures.map;
-		rvb->start = (char *)elts - rvb->address;
+		rvb->start = ((char *)elts) - rvb->address;
 		rvb->aos_offset = rmesa->radeon.radeonScreen->gart_texture_offset + rvb->start;
 		return ;
+	}else if(r300IsGartMemory(rmesa, elts, 1)){
+		WARN_ONCE("Pointer not within GART memory!\n");
+		exit(1);
+	} else {
+		/*fprintf(stderr, "elts are not GART!\n");
+		exit(1);*/
 	}
 	
-	r300AllocDmaRegion(rmesa, rvb, n_elts*sizeof(unsigned short int), 2);
+	//fprintf(stderr, "n_elts=%d, elt_size=%d\n", n_elts, elt_size);
+	//fprintf(stderr, "address %p is not GART\n", elts);
 	
-	out = (unsigned short int *)(rvb->address + rvb->start);
-	
-	for(i=0; i < n_elts; i++)
-		out[i]=(unsigned short int)elts[i];
+	r300AllocDmaRegion(rmesa, rvb, n_elts*(elt_size == 0 ? 2 : elt_size),
+			elt_size == 0 ? 2 : elt_size/*elt_size*/);
+	rvb->aos_offset	= GET_START(rvb);
+	if (elt_size == 0){
+		unsigned long *u_elts=elts;
+		out = (unsigned short int *)(rvb->address + rvb->start);
+		for(i=0; i < n_elts; i++)
+			out[i]=(unsigned short int)u_elts[i]-cutoff;
+	} else {
+		out = (unsigned short int *)(rvb->address + rvb->start);
+		memcpy(out, elts, n_elts * elt_size);
+	}
 }
 
 /* Emit vertex data to GART memory (unless immediate mode)
@@ -548,6 +574,24 @@
 
 	rmesa->state.aos_count = nr;
 }
+
+#ifdef USER_BUFFERS
+void r300UseArrays(GLcontext * ctx)
+{
+	r300ContextPtr rmesa = R300_CONTEXT(ctx);
+	int i;
+	
+	if(rmesa->state.elt_dma.buf)
+		radeon_mm_use(rmesa, rmesa->state.elt_dma.buf->id/*rmesa->state.elt_dma.address*/);
+
+	//r300ReleaseDmaRegion(rmesa, &rmesa->state.elt_dma, __FUNCTION__);
+	for (i=0;i<rmesa->state.aos_count;i++) {
+		if(rmesa->state.aos[i].buf)
+		radeon_mm_use(rmesa, rmesa->state.aos[i].buf->id/*rmesa->state.aos[i].address*/);
+		//r300ReleaseDmaRegion(rmesa, &rmesa->state.aos[i], __FUNCTION__);
+	}
+}
+#endif
 
 void r300ReleaseArrays(GLcontext * ctx)
 {
diff -uNr r300/r300_maos.h r300.user/r300_maos.h
--- r300/r300_maos.h	Thu Jul 21 00:35:27 2005
+++ r300.user/r300_maos.h	Sat Oct  1 22:56:33 2005
@@ -40,7 +40,7 @@
 
 #include "r300_context.h"
 
-extern void r300EmitElts(GLcontext * ctx, GLuint *elts, unsigned long n_elts);
+extern void r300EmitElts(GLcontext * ctx, void *elts, unsigned long n_elts, int elt_size, int cutoff);
 extern void r300EmitArrays(GLcontext * ctx, GLboolean immd);
 extern void r300ReleaseArrays(GLcontext * ctx);
 
diff -uNr r300/r300_reg.h r300.user/r300_reg.h
--- r300/r300_reg.h	Thu Jul 21 00:35:27 2005
+++ r300.user/r300_reg.h	Sat Sep 17 16:00:02 2005
@@ -727,6 +727,7 @@
 #	define R300_TX_FORMAT_G8R8_G8B8	    	    0x15     /* no swizzle */
 						  /* 0x16 - some 16 bit green format.. ?? */
 #	define R300_TX_FORMAT_UNK25		   (1 << 25) /* no swizzle */
+#	define R300_TX_FORMAT_CUBIC_MAP		   (1 << 26)
 
 	/* gap */
 	/* Floating point formats */
diff -uNr r300/r300_render.c r300.user/r300_render.c
--- r300/r300_render.c	Thu Jul 21 02:24:55 2005
+++ r300.user/r300_render.c	Thu Oct  6 21:13:04 2005
@@ -476,7 +476,7 @@
 		WARN_ONCE("Too many elts\n");
 		return;
 	}
-	r300EmitElts(ctx, rmesa->state.Elts+start, num_verts);
+	r300EmitElts(ctx, rmesa->state.Elts+start, num_verts, 0, 0);
 	fire_EB(PASS_PREFIX GET_START(&(rmesa->state.elt_dma)), num_verts, type);
 #endif
    }else{
@@ -500,7 +500,7 @@
 
    	r300ReleaseArrays(ctx);
 	r300EmitArrays(ctx, GL_FALSE);
-
+	
 //	LOCK_HARDWARE(&(rmesa->radeon));
 
 	reg_start(R300_RB3D_DSTCACHE_CTLSTAT,0);
@@ -526,6 +526,9 @@
 	reg_start(0x4f18,0);
 	e32(0x00000003);
 
+#ifdef USER_BUFFERS
+	r300UseArrays(ctx);
+#endif
 //	end_3d(PASS_PREFIX_VOID);
 
    /* Flush state - we are done drawing.. */
diff -uNr r300/r300_tex.c r300.user/r300_tex.c
--- r300/r300_tex.c	Sun Sep 25 13:20:38 2005
+++ r300.user/r300_tex.c	Mon Oct  3 15:20:02 2005
@@ -220,10 +220,10 @@
 			t->filter |= R300_TX_MIN_FILTER_NEAREST_MIP_NEAREST;
 			break;
 		case GL_NEAREST_MIPMAP_LINEAR:
-			t->filter |= R300_TX_MIN_FILTER_LINEAR_MIP_NEAREST;
+			t->filter |= R300_TX_MIN_FILTER_NEAREST_MIP_LINEAR;
 			break;
 		case GL_LINEAR_MIPMAP_NEAREST:
-			t->filter |= R300_TX_MIN_FILTER_NEAREST_MIP_LINEAR;
+			t->filter |= R300_TX_MIN_FILTER_LINEAR_MIP_NEAREST;
 			break;
 		case GL_LINEAR_MIPMAP_LINEAR:
 			t->filter |= R300_TX_MIN_FILTER_LINEAR_MIP_LINEAR;
@@ -951,9 +951,9 @@
 				R200_STATECHANGE(rmesa, tf);
 				rmesa->hw.tf.cmd[TF_TFACTOR_0 + unit] =
 				    envColor;
-			}
+			}*/
 			break;
-		*/}
+		}
 
 	case GL_TEXTURE_LOD_BIAS_EXT:{
 			GLfloat bias, min;
diff -uNr r300/r300_texstate.c r300.user/r300_texstate.c
--- r300/r300_texstate.c	Wed Oct  5 04:48:08 2005
+++ r300.user/r300_texstate.c	Thu Oct  6 21:35:07 2005
@@ -341,9 +341,8 @@
 		t->format_x |= R200_TEXCOORD_VOLUME;
 	} else if (tObj->Target == GL_TEXTURE_CUBE_MAP) {
 		ASSERT(log2Width == log2Height);
-		t->format |= ((log2Width << R200_TXFORMAT_F5_WIDTH_SHIFT) |
-				   (log2Height << R200_TXFORMAT_F5_HEIGHT_SHIFT)
-				   | (R200_TXFORMAT_CUBIC_MAP_ENABLE));
+		t->format |= R300_TX_FORMAT_CUBIC_MAP;
+		
 		t->format_x |= R200_TEXCOORD_CUBIC_ENV;
 		t->pp_cubic_faces = ((log2Width << R200_FACE_WIDTH_1_SHIFT) |
 				     (log2Height << R200_FACE_HEIGHT_1_SHIFT) |
diff -uNr r300/r300_vertexprog.c r300.user/r300_vertexprog.c
--- r300/r300_vertexprog.c	Thu Jul 21 02:24:55 2005
+++ r300.user/r300_vertexprog.c	Sat Sep 17 23:18:29 2005
@@ -597,6 +597,7 @@
 		   Ops that need temp vars should probably be given reg indexes starting at the end of tmp area. */
 		switch(vpi->Opcode){
 		case VP_OPCODE_MOV://ADD RESULT 1.X Y Z W PARAM 0{} {X Y Z W} PARAM 0{} {ZERO ZERO ZERO ZERO} 
+#if 1
 			o_inst->op=MAKE_VSF_OP(R300_VPI_OUT_OP_ADD, t_dst_index(vp, &vpi->DstReg),
 					t_dst_mask(vpi->DstReg.WriteMask), t_dst_class(vpi->DstReg.File));
 			o_inst->src1=t_src(vp, &src[0]);
@@ -606,6 +607,23 @@
 					t_src_class(src[0].File), VSF_FLAG_NONE);
 
 			o_inst->src3=0;
+#else
+			hw_op=(src[0].File == PROGRAM_TEMPORARY) ? R300_VPI_OUT_OP_MAD_2 : R300_VPI_OUT_OP_MAD;
+			
+			o_inst->op=MAKE_VSF_OP(hw_op, t_dst_index(vp, &vpi->DstReg),
+				t_dst_mask(vpi->DstReg.WriteMask), t_dst_class(vpi->DstReg.File));
+			o_inst->src1=t_src(vp, &src[0]);
+			o_inst->src2=MAKE_VSF_SOURCE(t_src_index(vp, &src[0]),
+					SWIZZLE_ONE, SWIZZLE_ONE,
+					SWIZZLE_ONE, SWIZZLE_ONE,
+					t_src_class(src[0].File), VSF_FLAG_NONE);
+
+
+			o_inst->src3=MAKE_VSF_SOURCE(t_src_index(vp, &src[0]),
+					SWIZZLE_ZERO, SWIZZLE_ZERO,
+					SWIZZLE_ZERO, SWIZZLE_ZERO,
+					t_src_class(src[0].File), VSF_FLAG_NONE);
+#endif			
 
 			goto next;
 			
diff -uNr r300/radeon_mm.c r300.user/radeon_mm.c
--- r300/radeon_mm.c	Thu Jan  1 02:00:00 1970
+++ r300.user/radeon_mm.c	Thu Oct  6 21:03:19 2005
@@ -0,0 +1,224 @@
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/types.h>
+#include <sys/sem.h>
+
+#include "r300_context.h"
+#include "r300_cmdbuf.h"
+#include "radeon_mm.h"
+
+void radeon_mm_init(r300ContextPtr rmesa)
+{
+	
+	rmesa->mm_ipc_key = 0xdeadbeef; //ftok("/tmp/.r300.mm_lock", "x");
+	if(rmesa->mm_ipc_key == -1){
+		perror("ftok");
+		exit(1);
+	}
+	
+	rmesa->mm_shm_id = shmget(rmesa->mm_ipc_key, sizeof(struct radeon_memory_manager), 0644);
+	if (rmesa->mm_shm_id == -1) {
+		rmesa->mm_shm_id = shmget(rmesa->mm_ipc_key, sizeof(struct radeon_memory_manager), 0644 | IPC_CREAT);
+		
+		rmesa->rmm = shmat(rmesa->mm_shm_id, (void *)0, 0);
+		if (rmesa->rmm == (char *)(-1)) {
+			perror("shmat");
+			exit(1);
+		}
+		
+		memset(rmesa->rmm, 0, sizeof(struct radeon_memory_manager));
+		
+		rmesa->rmm->u_size = 128;
+		
+		rmesa->mm_sem_id = semget(rmesa->mm_ipc_key, 2, 0666 | IPC_CREAT);
+		if (rmesa->mm_sem_id == -1) {
+			perror("semget");
+			exit(1);
+		}
+		
+		return ;
+	}
+	
+	rmesa->rmm = shmat(rmesa->mm_shm_id, (void *)0, 0);
+	if (rmesa->rmm == (char *)(-1)) {
+		perror("shmat");
+		exit(1);
+	}
+
+	rmesa->mm_sem_id = semget(rmesa->mm_ipc_key, 2, 0666);
+	if (rmesa->mm_sem_id == -1) {
+		perror("semget");
+		exit(1);
+	}
+}
+
+static void radeon_mm_lock(r300ContextPtr rmesa, int sem)
+{
+	struct sembuf sb = { 0, 1, 0 };
+	
+	sb.sem_num = sem;
+	if (semop(rmesa->mm_sem_id, &sb, 1) == -1) {
+		perror("semop");
+		exit(1);
+	}	
+}
+
+static void radeon_mm_unlock(r300ContextPtr rmesa, int sem)
+{
+	struct sembuf sb = { 0, -1, 0 };
+	
+	sb.sem_num = sem;
+			
+	if (semop(rmesa->mm_sem_id, &sb, 1) == -1) {
+		perror("semop");
+		exit(1);
+	}	
+}
+
+void *radeon_mm_ptr(r300ContextPtr rmesa, int id)
+{
+	return rmesa->rmm->u_list[id].ptr;
+}
+		
+int radeon_mm_alloc(r300ContextPtr rmesa, int alignment, int size)
+{
+	drm_radeon_mem_alloc_t alloc;
+	int offset, ret;
+	int i, end, free=-1;
+	int done_age;
+	drm_radeon_mem_free_t memfree;
+	int tries=0;
+	
+	memfree.region = RADEON_MEM_REGION_GART;
+			
+	radeon_mm_lock(rmesa, RADEON_MM_UL);
+	
+	again:
+	
+	done_age = rmesa->radeon.radeonScreen->scratch[2];
+	
+	i = 1; //rmesa->rmm->u_head + 1;
+	//i &= rmesa->rmm->u_size - 1;
+	
+	end = i + rmesa->rmm->u_size;
+	//end &= rmesa->rmm->u_size - 1;
+	
+	for (; i != end; i ++/*, i &= rmesa->rmm->u_size-1*/) {
+		if (rmesa->rmm->u_list[i].ptr == NULL){
+			free = i;
+			continue;
+		}
+		
+		if (rmesa->rmm->u_list[i].pending && rmesa->rmm->u_list[i].age < done_age) {
+			memfree.region_offset = (char *)rmesa->rmm->u_list[i].ptr -
+						(char *)rmesa->radeon.radeonScreen->gartTextures.map;
+
+			ret = drmCommandWrite(rmesa->radeon.radeonScreen->driScreen->fd,
+					      DRM_RADEON_FREE, &memfree, sizeof(memfree));
+
+			if (ret) {
+				//fprintf(stderr, "Failed to free at %p\n", rmesa->rmm->u_list[i].ptr);
+				//fprintf(stderr, "ret = %s\n", strerror(-ret));
+				
+				//radeon_mm_unlock(rmesa, RADEON_MM_UL);
+				//exit(1);
+			}else{
+				rmesa->rmm->u_list[i].pending = 0;
+				rmesa->rmm->u_list[i].ptr = NULL;
+				free = i;
+				///fprintf(stderr, "Freed at %p\n", rmesa->rmm->u_list[i].ptr);
+				
+			}
+		}
+	}
+	rmesa->rmm->u_head = i;
+	
+	if (free == -1) {
+		usleep(100);
+		goto again;
+	}
+		
+	alloc.region = RADEON_MEM_REGION_GART;
+	alloc.alignment = alignment;
+	alloc.size = size;
+	alloc.region_offset = &offset;
+
+	ret = drmCommandWriteRead( rmesa->radeon.dri.fd, DRM_RADEON_ALLOC, &alloc, sizeof(alloc));
+   	if (ret) {
+		
+		usleep(100);
+		tries++;
+		if(tries>100){
+			WARN_ONCE("Ran out of GART memory!\n");
+			exit(1);
+		}
+		goto again;
+	}
+	
+	
+	i = free;
+	rmesa->rmm->u_list[i].ptr = ((GLubyte *)rmesa->radeon.radeonScreen->gartTextures.map) + offset;
+	rmesa->rmm->u_list[i].size = size;
+	rmesa->rmm->u_list[i].age = ~0; /* Presistent until drm fills in the correct value. */
+	
+	{
+		drm_r300_cmd_header_t *cmd;
+		
+		cmd = r300AllocCmdBuf(rmesa, 4, __FUNCTION__);
+		cmd[0].scratch.cmd_type = R300_CMD_SCRATCH;
+		cmd[0].scratch.reg = 2;
+		cmd[0].scratch.n_bufs = 1;
+		cmd[0].scratch.flags = 0;
+		cmd[1].u = (unsigned long)(&rmesa->rmm->vb_age);
+		cmd[2].u = (unsigned long)(&rmesa->rmm->u_list[i].age);
+		cmd[3].u = /*i*/0;
+	}
+	
+	radeon_mm_unlock(rmesa, RADEON_MM_UL);
+	
+	return i;
+}
+
+void radeon_mm_use(r300ContextPtr rmesa, int id)
+{
+	drm_r300_cmd_header_t *cmd;
+	
+	if(id == 0)
+		return;
+	
+	radeon_mm_lock(rmesa, RADEON_MM_UL);
+		
+	cmd = r300AllocCmdBuf(rmesa, 4, __FUNCTION__);
+	cmd[0].scratch.cmd_type = R300_CMD_SCRATCH;
+	cmd[0].scratch.reg = 2;
+	cmd[0].scratch.n_bufs = 1;
+	cmd[0].scratch.flags = 0;
+	cmd[1].u = (unsigned long)(&rmesa->rmm->vb_age);
+	cmd[2].u = (unsigned long)(&rmesa->rmm->u_list[id].age);
+	cmd[3].u = /*id*/0;
+			
+	radeon_mm_unlock(rmesa, RADEON_MM_UL);
+}
+
+void radeon_mm_free(r300ContextPtr rmesa, int id)
+{
+	
+	if(id == 0)
+		return;
+	
+	radeon_mm_lock(rmesa, RADEON_MM_UL);
+	if(rmesa->rmm->u_list[id].ptr == NULL){
+		radeon_mm_unlock(rmesa, RADEON_MM_UL);
+		WARN_ONCE("Not allocated!\n");
+		return ;
+	}
+	
+	if(rmesa->rmm->u_list[id].pending){
+		radeon_mm_unlock(rmesa, RADEON_MM_UL);
+		WARN_ONCE("%p already pended!\n", rmesa->rmm->u_list[id].ptr);
+		return ;
+	}
+			
+	rmesa->rmm->u_list[id].pending = 1;
+	radeon_mm_unlock(rmesa, RADEON_MM_UL);
+}
diff -uNr r300/radeon_mm.h r300.user/radeon_mm.h
--- r300/radeon_mm.h	Thu Jan  1 02:00:00 1970
+++ r300.user/radeon_mm.h	Thu Oct  6 20:57:27 2005
@@ -0,0 +1,27 @@
+#ifndef __RADEON_MM_H__
+#define __RADEON_MM_H__
+
+//#define RADEON_MM_PDL 0
+#define RADEON_MM_UL 1
+
+struct radeon_memory_manager {
+	uint32_t vb_age;
+	/*uint32_t ages[1024];*/
+	
+	struct {
+		void *ptr;
+		uint32_t size;
+		uint32_t age;
+		int pending;
+	} u_list[1024];
+	int u_head, u_tail, u_size;
+	
+};
+
+extern void radeon_mm_init(r300ContextPtr rmesa);
+extern void *radeon_mm_ptr(r300ContextPtr rmesa, int id);
+extern int radeon_mm_alloc(r300ContextPtr rmesa, int alignment, int size);
+extern void radeon_mm_use(r300ContextPtr rmesa, int id);
+extern void radeon_mm_free(r300ContextPtr rmesa, int id);
+
+#endif
