xf86-video-ati: Branch 'master'

Dave Airlie airlied at kemper.freedesktop.org
Mon Nov 30 19:42:08 PST 2009


 src/Makefile.am                |    2 
 src/r600_exa.c                 |   37 ++++---
 src/r600_state.h               |   22 ----
 src/r600_textured_videofuncs.c |    8 +
 src/r6xx_accel.c               |  119 +++++++++++------------
 src/radeon.h                   |   21 +++-
 src/radeon_kms.c               |   32 ++++--
 src/radeon_vbo.c               |  206 +++++++++++++++++++++++++++++++++++++++++
 src/radeon_vbo.h               |   62 ++++++++++++
 src/simple_list.h              |  202 ++++++++++++++++++++++++++++++++++++++++
 10 files changed, 598 insertions(+), 113 deletions(-)

New commits:
commit 88a50a30df11a06263209340a42251851f8e2334
Author: Dave Airlie <airlied at redhat.com>
Date:   Mon Nov 30 15:32:12 2009 +1000

    r600: fix multi-operation in single batch support.
    
    This ports the mesa DMA buffer handling with the 3 lists,
    
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/src/Makefile.am b/src/Makefile.am
index 93f237c..a431d2e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -66,7 +66,7 @@ XMODE_SRCS=\
         modes/xf86DiDGA.c
 
 if XF86DRM_MODE
-RADEON_KMS_SRCS=radeon_dri2.c radeon_kms.c drmmode_display.c
+RADEON_KMS_SRCS=radeon_dri2.c radeon_kms.c drmmode_display.c radeon_vbo.c
 endif
 
 if USE_EXA
diff --git a/src/r600_exa.c b/src/r600_exa.c
index 16d217d..634e6ca 100644
--- a/src/r600_exa.c
+++ b/src/r600_exa.c
@@ -38,7 +38,7 @@
 #include "r600_shader.h"
 #include "r600_reg.h"
 #include "r600_state.h"
-
+#include "radeon_vbo.h"
 
 #define RADEON_TRACE_FALL 0
 #define RADEON_TRACE_DRAW 0
@@ -217,6 +217,7 @@ R600PrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg)
 	   pPix->drawable.bitsPerPixel, exaGetPixmapPitch(pPix));
 #endif
 
+    radeon_vbo_check(pScrn, 16);
     r600_cp_start(pScrn);
 
     set_default_state(pScrn, accel_state->ib);
@@ -360,11 +361,9 @@ static void
 R600Solid(PixmapPtr pPix, int x1, int y1, int x2, int y2)
 {
     ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
-    RADEONInfoPtr info = RADEONPTR(pScrn);
-    struct radeon_accel_state *accel_state = info->accel_state;
     float *vb;
 
-    vb = r600_vb_space(pScrn, 8);
+    vb = radeon_vbo_space(pScrn, 8);
 
     vb[0] = (float)x1;
     vb[1] = (float)y1;
@@ -375,7 +374,7 @@ R600Solid(PixmapPtr pPix, int x1, int y1, int x2, int y2)
     vb[4] = (float)x2;
     vb[5] = (float)y2;
 
-    r600_vb_update(accel_state, 8);
+    radeon_vbo_commit(pScrn);
 }
 
 static void
@@ -424,6 +423,7 @@ R600DoPrepareCopy(ScrnInfoPtr pScrn,
     accel_state->dst_bpp = dst_bpp;
     accel_state->dst_bo = dst_bo;
 
+    radeon_vbo_check(pScrn, 16);
     r600_cp_start(pScrn);
 
     set_default_state(pScrn, accel_state->ib);
@@ -592,11 +592,9 @@ R600AppendCopyVertex(ScrnInfoPtr pScrn,
 		     int dstX, int dstY,
 		     int w, int h)
 {
-    RADEONInfoPtr info = RADEONPTR(pScrn);
-    struct radeon_accel_state *accel_state = info->accel_state;
     float *vb;
 
-    vb = r600_vb_space(pScrn, 16);
+    vb = radeon_vbo_space(pScrn, 16);
 
     vb[0] = (float)dstX;
     vb[1] = (float)dstY;
@@ -613,7 +611,7 @@ R600AppendCopyVertex(ScrnInfoPtr pScrn,
     vb[10] = (float)(srcX + w);
     vb[11] = (float)(srcY + h);
 
-    r600_vb_update(accel_state, 16);
+    radeon_vbo_commit(pScrn);
 }
 
 static Bool
@@ -1585,6 +1583,11 @@ static Bool R600PrepareComposite(int op, PicturePtr pSrcPicture,
     CLEAR (vs_conf);
     CLEAR (ps_conf);
 
+    if (pMask)
+        radeon_vbo_check(pScrn, 24);
+    else
+        radeon_vbo_check(pScrn, 16);
+
     r600_cp_start(pScrn);
 
     set_default_state(pScrn, accel_state->ib);
@@ -1768,7 +1771,7 @@ static void R600Composite(PixmapPtr pDst,
 
     if (accel_state->msk_pic) {
 
-	vb = r600_vb_space(pScrn, 24);
+	vb = radeon_vbo_space(pScrn, 24);
 
 	vb[0] = (float)dstX;
 	vb[1] = (float)dstY;
@@ -1791,10 +1794,11 @@ static void R600Composite(PixmapPtr pDst,
 	vb[16] = (float)(maskX + w);
 	vb[17] = (float)(maskY + h);
 
-	r600_vb_update(accel_state, 24);
+	radeon_vbo_commit(pScrn);
+		       
     } else {
 
-	vb = r600_vb_space(pScrn, 16);
+	vb = radeon_vbo_space(pScrn, 16);
 
 	vb[0] = (float)dstX;
 	vb[1] = (float)dstY;
@@ -1811,7 +1815,7 @@ static void R600Composite(PixmapPtr pDst,
 	vb[10] = (float)(srcX + w);
 	vb[11] = (float)(srcY + h);
 
-	r600_vb_update(accel_state, 16);
+	radeon_vbo_commit(pScrn);
     }
 
 
@@ -2422,8 +2426,11 @@ R600DrawInit(ScreenPtr pScreen)
     info->accel_state->src_bo[1] = NULL;
     info->accel_state->dst_bo = NULL;
     info->accel_state->copy_area_bo = NULL;
-    info->accel_state->vb_bo[0] = NULL;
-    info->accel_state->vb_bo[1] = NULL;
+    info->accel_state->vb_start_op = -1;
+
+#ifdef XF86DRM_MODE
+    radeon_vbo_init_lists(pScrn);
+#endif
 
     if (!R600AllocShaders(pScrn, pScreen))
 	return FALSE;
diff --git a/src/r600_state.h b/src/r600_state.h
index 6cd47dc..0ee480b 100644
--- a/src/r600_state.h
+++ b/src/r600_state.h
@@ -206,7 +206,7 @@ do {                                                                    \
     }									\
 } while (0)
 #else
-#define BEGIN_BATCH(n) do {} while(0)
+#define BEGIN_BATCH(n) do {(void)info;} while(0)
 #define END_BATCH() do {} while(0)
 #define RELOC_BATCH(bo, wd, rd) do {} while(0)
 #define E32(ib, dword)                                                  \
@@ -336,24 +336,4 @@ extern struct radeon_bo *radeon_get_pixmap_bo(PixmapPtr pPix);
 extern Bool RADEONEXAPixmapIsOffscreen(PixmapPtr pPix);
 
 
-static inline float *
-r600_vb_space(ScrnInfoPtr pScrn, int vert_size)
-{
-    RADEONInfoPtr info = RADEONPTR(pScrn);
-    struct radeon_accel_state *accel_state = info->accel_state;
-    float *vb;
-
-    if ((accel_state->vb_offset + (3 * vert_size)) > accel_state->vb_total) {
-	r600_finish_op(pScrn, vert_size);
-	if (info->cs)
-	    radeon_cs_flush_indirect(pScrn);
-	r600_cp_start(pScrn);
-    }
-    vb = (pointer)((char *)accel_state->vb_ptr + accel_state->vb_offset);
-    return vb;
-}
-
-#define r600_vb_update(accel_state, vert_size) do { (accel_state)->vb_offset += (3 * (vert_size)); } while(0)
-
-
 #endif
diff --git a/src/r600_textured_videofuncs.c b/src/r600_textured_videofuncs.c
index b962ae7..69deb81 100644
--- a/src/r600_textured_videofuncs.c
+++ b/src/r600_textured_videofuncs.c
@@ -45,6 +45,8 @@
 
 #include "damage.h"
 
+#include "radeon_vbo.h"
+
 /* Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces
    note the difference to the parameters used in overlay are due
    to 10bit vs. float calcs */
@@ -206,6 +208,7 @@ R600DisplayTexturedVideo(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv)
     dstyoff = 0;
 #endif
 
+    radeon_vbo_check(pScrn, 16);
     r600_cp_start(pScrn);
 
     set_default_state(pScrn, accel_state->ib);
@@ -534,7 +537,6 @@ R600DisplayTexturedVideo(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv)
 	int dstX, dstY, dstw, dsth;
 	float *vb;
 
-	vb = r600_vb_space(pScrn, 16);
 
 	dstX = pBox->x1 + dstxoff;
 	dstY = pBox->y1 + dstyoff;
@@ -551,6 +553,8 @@ R600DisplayTexturedVideo(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv)
 	srcw = (pPriv->src_w * dstw) / pPriv->dst_w;
 	srch = (pPriv->src_h * dsth) / pPriv->dst_h;
 
+	vb = radeon_vbo_space(pScrn, 16);
+
 	vb[0] = (float)dstX;
 	vb[1] = (float)dstY;
 	vb[2] = (float)srcX;
@@ -566,7 +570,7 @@ R600DisplayTexturedVideo(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv)
 	vb[10] = (float)(srcX + srcw);
 	vb[11] = (float)(srcY + srch);
 
-	r600_vb_update(accel_state, 16);
+	radeon_vbo_commit(pScrn);
 
 	pBox++;
     }
diff --git a/src/r6xx_accel.c b/src/r6xx_accel.c
index 69e17e4..0ca942e 100644
--- a/src/r6xx_accel.c
+++ b/src/r6xx_accel.c
@@ -38,16 +38,11 @@
 #include "r600_state.h"
 
 #include "radeon_drm.h"
+#include "radeon_vbo.h"
 
 /* we try and batch operations together under KMS -
    but it doesn't work yet without misrendering */
-#define KMS_MULTI_OP 0
-
-#if KMS_MULTI_OP
-#define VBO_SIZE (16*1024)
-#else
-#define VBO_SIZE (4*1024)
-#endif
+#define KMS_MULTI_OP 1
 
 /* Flush the indirect buffer to the kernel for submission to the card */
 void R600CPFlushIndirect(ScrnInfoPtr pScrn, drmBufPtr ib)
@@ -100,11 +95,12 @@ void R600IBDiscard(ScrnInfoPtr pScrn, drmBufPtr ib)
 	    return;
 	}
 	if (info->accel_state->vb_ptr) {
-	    radeon_bo_unmap(info->accel_state->vb_bo[info->accel_state->vb_bo_index]);
 	    info->accel_state->vb_ptr = NULL;
-	    info->accel_state->vb_offset = 0;
-	    info->accel_state->vb_start_op = 0;
-        }
+	}
+
+	info->accel_state->vb_offset = 0;
+	info->accel_state->vb_start_op = -1;
+
 	if (CS_FULL(info->cs)) {
 	    radeon_cs_flush_indirect(pScrn);
 	    return;
@@ -1173,52 +1169,27 @@ r600_vb_get(ScrnInfoPtr pScrn)
 {
     RADEONInfoPtr info = RADEONPTR(pScrn);
     struct radeon_accel_state *accel_state = info->accel_state;
-#if defined(XF86DRM_MODE)
-    int ret;
-    if (info->cs) {
-	if (accel_state->vb_bo[0] == NULL) {
-	    accel_state->vb_bo[0] = radeon_bo_open(info->bufmgr, 0, VBO_SIZE,
-						0, RADEON_GEM_DOMAIN_GTT, 0);
-	    if (accel_state->vb_bo[0] == NULL)
-		return FALSE;
-	    accel_state->vb_mc_addr = 0;
-	    accel_state->vb_total = VBO_SIZE;
-	    accel_state->vb_bo_index = 1;
-	}
-	if (accel_state->vb_bo[1] == NULL) {
-	    accel_state->vb_bo[1] = radeon_bo_open(info->bufmgr, 0, VBO_SIZE,
-						   0, RADEON_GEM_DOMAIN_GTT, 0);
-	    if (accel_state->vb_bo[1] == NULL)
-		return FALSE;
-	}
-	if (!accel_state->vb_ptr) {
-	    accel_state->vb_bo_index = !(accel_state->vb_bo_index);
-	    ret = radeon_bo_map(accel_state->vb_bo[accel_state->vb_bo_index], 1);
-	    if (ret) {
-		FatalError("failed to vb %d\n", ret);
-		return FALSE;
-	    }
-	    accel_state->vb_ptr = accel_state->vb_bo[accel_state->vb_bo_index]->ptr;
-	}
-    } else
-#endif
-    {
-	accel_state->vb_mc_addr = info->gartLocation + info->dri->bufStart +
-	    (accel_state->ib->idx*accel_state->ib->total)+
-	    (accel_state->ib->total / 2);
-	accel_state->vb_total = (accel_state->ib->total / 2);
-	accel_state->vb_ptr = (pointer)((char*)accel_state->ib->address +
-					(accel_state->ib->total / 2));
-	accel_state->vb_offset = 0;
-    }
+
+    accel_state->vb_mc_addr = info->gartLocation + info->dri->bufStart +
+	(accel_state->ib->idx*accel_state->ib->total)+
+	(accel_state->ib->total / 2);
+    accel_state->vb_total = (accel_state->ib->total / 2);
+    accel_state->vb_ptr = (pointer)((char*)accel_state->ib->address +
+				    (accel_state->ib->total / 2));
+    accel_state->vb_offset = 0;
     return TRUE;
 }
 
 void
 r600_vb_discard(ScrnInfoPtr pScrn)
 {
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+
+    info->accel_state->vb_start_op = -1;
 }
 
+
+
 int
 r600_cp_start(ScrnInfoPtr pScrn)
 {
@@ -1227,17 +1198,9 @@ r600_cp_start(ScrnInfoPtr pScrn)
 
 #if defined(XF86DRM_MODE)
     if (info->cs) {
-
 	if (CS_FULL(info->cs)) {
 	    radeon_cs_flush_indirect(pScrn);
 	}
-	if (!r600_vb_get(pScrn))
-	    return -1;
-	if (accel_state->vb_bo[accel_state->vb_bo_index])
-	  radeon_cs_space_add_persistent_bo(info->cs, accel_state->vb_bo[accel_state->vb_bo_index],
-					    RADEON_GEM_DOMAIN_GTT, 0);
-
-	radeon_cs_space_check(info->cs);
 	accel_state->ib_reset_op = info->cs->cdw;
 	accel_state->vb_start_op = accel_state->vb_offset;
     } else
@@ -1247,6 +1210,7 @@ r600_cp_start(ScrnInfoPtr pScrn)
 	if (!r600_vb_get(pScrn)) {
 	    return -1;
 	}
+	accel_state->vb_start_op = accel_state->vb_offset;
     }
     return 0;
 }
@@ -1257,7 +1221,10 @@ void r600_finish_op(ScrnInfoPtr pScrn, int vtx_size)
     struct radeon_accel_state *accel_state = info->accel_state;
     draw_config_t   draw_conf;
     vtx_resource_t  vtx_res;
-    
+
+    if (accel_state->vb_start_op == -1)
+	return;
+
     CLEAR (draw_conf);
     CLEAR (vtx_res);
 
@@ -1275,12 +1242,12 @@ void r600_finish_op(ScrnInfoPtr pScrn, int vtx_size)
 	(info->ChipFamily == CHIP_FAMILY_RV710))
 	cp_set_surface_sync(pScrn, accel_state->ib, TC_ACTION_ENA_bit,
 			    accel_state->vb_offset, accel_state->vb_mc_addr,
-			    accel_state->vb_bo[accel_state->vb_bo_index],
+			    accel_state->vb_bo,
 			    RADEON_GEM_DOMAIN_GTT, 0);
     else
 	cp_set_surface_sync(pScrn, accel_state->ib, VC_ACTION_ENA_bit,
 			    accel_state->vb_offset, accel_state->vb_mc_addr,
-			    accel_state->vb_bo[accel_state->vb_bo_index],
+			    accel_state->vb_bo,
 			    RADEON_GEM_DOMAIN_GTT, 0);
 
     /* Vertex buffer setup */
@@ -1290,7 +1257,7 @@ void r600_finish_op(ScrnInfoPtr pScrn, int vtx_size)
     vtx_res.vtx_num_entries = accel_state->vb_size / 4;
     vtx_res.mem_req_size    = 1;
     vtx_res.vb_addr         = accel_state->vb_mc_addr + accel_state->vb_start_op;
-    vtx_res.bo              = accel_state->vb_bo[accel_state->vb_bo_index];
+    vtx_res.bo              = accel_state->vb_bo;
     set_vtx_resource        (pScrn, accel_state->ib, &vtx_res);
 
     /* Draw */
@@ -1309,7 +1276,9 @@ void r600_finish_op(ScrnInfoPtr pScrn, int vtx_size)
 			accel_state->dst_size, accel_state->dst_mc_addr,
 			accel_state->dst_bo, RADEON_GEM_DOMAIN_VRAM, 0);
 
-    accel_state->vb_start_op = 0;
+    wait_3d_idle_clean(pScrn, accel_state->ib);
+
+    accel_state->vb_start_op = -1;
     accel_state->ib_reset_op = 0;
 
 #if KMS_MULTI_OP
@@ -1318,3 +1287,29 @@ void r600_finish_op(ScrnInfoPtr pScrn, int vtx_size)
 	R600CPFlushIndirect(pScrn, accel_state->ib);
 }
 
+void r600_vb_no_space(ScrnInfoPtr pScrn, int vert_size)
+{
+#ifdef XF86DRM_MODE
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    struct radeon_accel_state *accel_state = info->accel_state; 
+
+    if (info->cs) {
+	if (accel_state->vb_bo) {
+	    if (accel_state->vb_start_op != accel_state->vb_offset) { 
+		r600_finish_op(pScrn, vert_size);
+		accel_state->ib_reset_op = info->cs->cdw;
+	    }
+	    
+	    /* release the current VBO */
+	    radeon_vbo_put(pScrn);
+	}
+	
+	/* get a new one */
+	radeon_vbo_get(pScrn);
+	return;
+    }
+#endif 
+
+    r600_finish_op(pScrn, vert_size);
+    r600_cp_start(pScrn);
+}
diff --git a/src/radeon.h b/src/radeon.h
index 5eec147..1b8ae3c 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -100,6 +100,7 @@
 #include "picturestr.h"
 #endif
 
+#include "simple_list.h"
 #include "atipcirename.h"
 
 #ifndef MAX
@@ -652,6 +653,14 @@ struct radeon_dri {
 };
 #endif
 
+#define DMA_BO_FREE_TIME 1000
+
+struct radeon_dma_bo {
+    struct radeon_dma_bo *next, *prev;
+    struct radeon_bo  *bo;
+    int expire_counter;
+};
+
 struct radeon_accel_state {
     /* common accel data */
     int               fifo_slots;       /* Free slots in the FIFO (64 max)   */
@@ -708,11 +717,17 @@ struct radeon_accel_state {
     int               vb_total;
     void              *vb_ptr;
     uint32_t          vb_size;
-    struct radeon_bo  *vb_bo[2];
-    int               vb_bo_index;
-    uint32_t          vb_start_op;
+    uint32_t          vb_op_vert_size;
+    int32_t           vb_start_op;
     /* where to discard IB from if we cancel operation */
     uint32_t          ib_reset_op;
+    struct radeon_bo *vb_bo;
+#ifdef XF86DRM_MODE
+    struct radeon_dma_bo bo_free;
+    struct radeon_dma_bo bo_wait;
+    struct radeon_dma_bo bo_reserved;
+    Bool use_vbos;
+#endif
 
     // shader storage
     ExaOffscreenArea  *shaders;
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index f6c41d9..c06b832 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -41,7 +41,6 @@
 #include "atipciids.h"
 
 
-
 #ifdef XF86DRM_MODE
 
 #include "radeon_chipset_gen.h"
@@ -52,6 +51,8 @@
 
 #include "radeon_bo_gem.h"
 #include "radeon_cs_gem.h"
+#include "radeon_vbo.h"
+
 static Bool radeon_setup_kernel_mem(ScreenPtr pScreen);
 
 const OptionInfoRec RADEONOptions_KMS[] = {
@@ -74,31 +75,41 @@ const OptionInfoRec RADEONOptions_KMS[] = {
 void radeon_cs_flush_indirect(ScrnInfoPtr pScrn)
 {
     RADEONInfoPtr  info = RADEONPTR(pScrn);
+    struct radeon_accel_state *accel_state = info->accel_state;
     int ret;
 
     if (!info->cs->cdw)
 	return;
 
-    if (info->accel_state->vb_ptr) {
-      radeon_bo_unmap(info->accel_state->vb_bo[info->accel_state->vb_bo_index]);
+    if (info->accel_state->vb_ptr)
       info->accel_state->vb_ptr = NULL;
-      info->accel_state->vb_start_op = 0;
-      info->accel_state->vb_offset = 0;
+
+    /* release the current VBO so we don't block on mapping it later */
+    if (info->accel_state->vb_offset && info->accel_state->vb_bo) {
+        radeon_vbo_put(pScrn);
+        info->accel_state->vb_start_op = -1;
     }
 
     radeon_cs_emit(info->cs);
     radeon_cs_erase(info->cs);
 
-    ret = radeon_cs_space_check(info->cs);
+    if (accel_state->use_vbos)
+        radeon_vbo_flush_bos(pScrn);
+
+    ret = radeon_cs_space_check_with_bo(info->cs,
+					accel_state->vb_bo,
+					RADEON_GEM_DOMAIN_GTT, 0);
     if (ret)
       ErrorF("space check failed in flush\n");
 
     if (info->reemit_current2d && info->state_2d.op)
-      info->reemit_current2d(pScrn, info->state_2d.op);
+        info->reemit_current2d(pScrn, info->state_2d.op);
+
     if (info->dri2.enabled) {
-      info->accel_state->XInited3D = FALSE;
-      info->accel_state->engineMode = EXA_ENGINEMODE_UNKNOWN;
+        info->accel_state->XInited3D = FALSE;
+        info->accel_state->engineMode = EXA_ENGINEMODE_UNKNOWN;
     }
+
 }
 
 void radeon_ddx_cs_start(ScrnInfoPtr pScrn,
@@ -548,6 +559,9 @@ static Bool RADEONCloseScreen_KMS(int scrnIndex, ScreenPtr pScreen)
 	info->accel_state->exa = NULL;
     }
 
+    if (info->accel_state->use_vbos)
+        radeon_vbo_free_lists(pScrn);
+
     drmDropMaster(info->dri->drmFD);
 
     if (info->cursor) xf86DestroyCursorInfoRec(info->cursor);
diff --git a/src/radeon_vbo.c b/src/radeon_vbo.c
new file mode 100644
index 0000000..ad650b2
--- /dev/null
+++ b/src/radeon_vbo.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright © 2009 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Dave Airlie <airlied at redhat.com>
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include "radeon.h"
+#include "radeon_bo.h"
+#include "radeon_cs.h"
+
+#define VBO_SIZE (16*1024)
+
+/* KMS vertex buffer support - for R600 only but could be used on previous gpus */
+
+#ifdef XF86DRM_MODE
+
+static struct radeon_bo *radeon_vbo_get_bo(ScrnInfoPtr pScrn);
+
+void radeon_vbo_put(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    struct radeon_accel_state *accel_state = info->accel_state;
+    
+    if (accel_state->vb_bo) {
+	radeon_bo_unmap(accel_state->vb_bo);
+	radeon_bo_unref(accel_state->vb_bo);
+	accel_state->vb_bo = NULL;
+	accel_state->vb_total = 0;
+    }
+
+    accel_state->vb_offset = 0;
+}
+
+void radeon_vbo_get(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    struct radeon_accel_state *accel_state = info->accel_state;
+
+    accel_state->vb_bo = radeon_vbo_get_bo(pScrn);
+
+    accel_state->vb_total = VBO_SIZE;
+    accel_state->vb_offset = 0;
+    accel_state->vb_start_op = accel_state->vb_offset;
+}
+
+/* these functions could migrate to libdrm and
+   be shared with the radeon 3D driver */
+static int radeon_bo_is_idle(struct radeon_bo *bo)
+{
+    uint32_t domain;
+    int ret = radeon_bo_is_busy(bo, &domain);
+    return ret != -EBUSY;
+}
+
+void radeon_vbo_init_lists(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    struct radeon_accel_state *accel_state = info->accel_state; 
+
+    accel_state->use_vbos = TRUE;
+    make_empty_list(&accel_state->bo_free);
+    make_empty_list(&accel_state->bo_wait);
+    make_empty_list(&accel_state->bo_reserved);
+}
+
+void radeon_vbo_free_lists(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    struct radeon_accel_state *accel_state = info->accel_state; 
+    struct radeon_dma_bo *dma_bo, *temp;
+
+    foreach_s(dma_bo, temp, &accel_state->bo_free) {
+	remove_from_list(dma_bo);
+	radeon_bo_unref(dma_bo->bo);
+	xfree(dma_bo);
+    }
+
+    foreach_s(dma_bo, temp, &accel_state->bo_wait) {
+	remove_from_list(dma_bo);
+	radeon_bo_unref(dma_bo->bo);
+	xfree(dma_bo);
+    }
+
+    foreach_s(dma_bo, temp, &accel_state->bo_reserved) {
+	remove_from_list(dma_bo);
+	radeon_bo_unref(dma_bo->bo);
+	xfree(dma_bo);
+    }
+}
+
+void radeon_vbo_flush_bos(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    struct radeon_accel_state *accel_state = info->accel_state; 
+    struct radeon_dma_bo *dma_bo, *temp;
+    const int expire_at = ++accel_state->bo_free.expire_counter + DMA_BO_FREE_TIME;
+    const int time = accel_state->bo_free.expire_counter;
+
+    foreach_s(dma_bo, temp, &accel_state->bo_wait) {
+	if (dma_bo->expire_counter == time) {
+	    ErrorF("leaking dma buffer\n");
+	    while ((dma_bo->bo = radeon_bo_unref(dma_bo->bo))) {}
+	    remove_from_list(dma_bo);
+	    xfree(dma_bo);
+	    continue;
+	}
+
+	if (!radeon_bo_is_idle(dma_bo->bo))
+	    continue;
+
+	remove_from_list(dma_bo);
+	dma_bo->expire_counter = expire_at;
+	insert_at_tail(&accel_state->bo_free, dma_bo);
+    }
+
+    /* move reserved to wait list */
+    foreach_s(dma_bo, temp, &accel_state->bo_reserved) {
+	remove_from_list(dma_bo);
+	dma_bo->expire_counter = expire_at;
+	insert_at_tail(&accel_state->bo_wait, dma_bo);
+    }
+
+    /* free bos that have been unused */
+    foreach_s(dma_bo, temp, &accel_state->bo_free) {
+	if (dma_bo->expire_counter != time)
+	    break;
+	/* always keep one hanging around at end */
+	if (at_end(&accel_state->bo_free, dma_bo)) {
+	    dma_bo->expire_counter = time + DMA_BO_FREE_TIME;
+	    break;
+	}
+
+	remove_from_list(dma_bo);
+	radeon_bo_unref(dma_bo->bo);
+	xfree(dma_bo);
+    }
+}
+
+static struct radeon_bo *radeon_vbo_get_bo(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    struct radeon_accel_state *accel_state = info->accel_state; 
+    struct radeon_dma_bo *dma_bo = NULL;
+    struct radeon_bo *bo;
+
+    if (is_empty_list(&accel_state->bo_free)) {
+	dma_bo = xcalloc(1, sizeof(struct radeon_dma_bo));
+	if (!dma_bo)
+	    return NULL;
+
+again_alloc:
+	dma_bo->bo = radeon_bo_open(info->bufmgr, 0, VBO_SIZE,
+				    0, RADEON_GEM_DOMAIN_GTT, 0);
+
+	if (!dma_bo->bo) {
+	    ErrorF("failure to allocate DMA BO\n");
+	    return NULL;
+	}
+	insert_at_head(&accel_state->bo_reserved, dma_bo);
+    } else {
+	dma_bo = last_elem(&accel_state->bo_free);
+	remove_from_list(dma_bo);
+	insert_at_head(&accel_state->bo_reserved, dma_bo);
+    }
+
+    /* need a space check */
+    if (radeon_cs_space_check_with_bo(info->cs,
+				      first_elem(&accel_state->bo_reserved)->bo,
+				      RADEON_GEM_DOMAIN_GTT, 0))
+	fprintf(stderr,"failed to revalidated\n");
+
+    if (is_empty_list(&accel_state->bo_reserved)) {
+	goto again_alloc;
+    }
+
+    bo = first_elem(&accel_state->bo_reserved)->bo;
+    radeon_bo_ref(bo);
+    return bo;
+}
+
+#endif
diff --git a/src/radeon_vbo.h b/src/radeon_vbo.h
new file mode 100644
index 0000000..a8c70b3
--- /dev/null
+++ b/src/radeon_vbo.h
@@ -0,0 +1,62 @@
+
+#ifndef RADEON_VBO_H
+#define RADEON_VBO_H
+
+extern void r600_vb_no_space(ScrnInfoPtr pScrn, int vert_size);
+extern void radeon_vbo_init_lists(ScrnInfoPtr pScrn);
+extern void radeon_vbo_free_lists(ScrnInfoPtr pScrn);
+extern void radeon_vbo_flush_bos(ScrnInfoPtr pScrn);
+extern void radeon_vbo_get(ScrnInfoPtr pScrn);
+extern void radeon_vbo_put(ScrnInfoPtr pScrn);
+
+static inline void radeon_vbo_check(ScrnInfoPtr pScrn, int vert_size)
+{
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    struct radeon_accel_state *accel_state = info->accel_state;
+
+    if ((accel_state->vb_offset + (3 * vert_size)) > accel_state->vb_total) {
+	r600_vb_no_space(pScrn, vert_size);
+    }
+}
+
+static inline void *
+radeon_vbo_space(ScrnInfoPtr pScrn, int vert_size)
+{
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    struct radeon_accel_state *accel_state = info->accel_state;
+    void *vb;
+    
+    /* we've ran out of space in the vertex buffer - need to get a
+       new one */
+    if ((accel_state->vb_offset + (3 * vert_size)) > accel_state->vb_total) {
+	r600_vb_no_space(pScrn, vert_size);
+    }
+    accel_state->vb_op_vert_size = vert_size;
+#if defined(XF86DRM_MODE)
+    if (info->cs) {
+	int ret;
+	struct radeon_bo *bo = accel_state->vb_bo;
+
+	if (!bo->ptr) {
+	    ret = radeon_bo_map(bo, 1);
+	    if (ret) {
+		FatalError("Failed to map vb %d\n", ret);
+		return NULL;
+	    }
+	}
+	vb = (pointer)((char *)bo->ptr + accel_state->vb_offset);
+    } else
+#endif
+	vb = (pointer)((char *)accel_state->vb_ptr + accel_state->vb_offset);
+    return vb;
+}
+
+static inline void radeon_vbo_commit(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    struct radeon_accel_state *accel_state = info->accel_state;
+
+    accel_state->vb_offset += 3 * accel_state->vb_op_vert_size;
+}
+
+#endif
diff --git a/src/simple_list.h b/src/simple_list.h
new file mode 100644
index 0000000..ff7f888
--- /dev/null
+++ b/src/simple_list.h
@@ -0,0 +1,202 @@
+/**
+ * \file simple_list.h
+ * Simple macros for type-safe, intrusive lists.
+ *
+ *  Intended to work with a list sentinal which is created as an empty
+ *  list.  Insert & delete are O(1).
+ *  
+ * \author
+ *  (C) 1997, Keith Whitwell
+ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ *
+ * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _SIMPLE_LIST_H
+#define _SIMPLE_LIST_H
+
+struct simple_node {
+   struct simple_node *next;
+   struct simple_node *prev;
+};
+
+/**
+ * Remove an element from list.
+ *
+ * \param elem element to remove.
+ */
+#define remove_from_list(elem)			\
+do {						\
+   (elem)->next->prev = (elem)->prev;		\
+   (elem)->prev->next = (elem)->next;		\
+} while (0)
+
+/**
+ * Insert an element to the list head.
+ *
+ * \param list list.
+ * \param elem element to insert.
+ */
+#define insert_at_head(list, elem)		\
+do {						\
+   (elem)->prev = list;				\
+   (elem)->next = (list)->next;			\
+   (list)->next->prev = elem;			\
+   (list)->next = elem;				\
+} while(0)
+
+/**
+ * Insert an element to the list tail.
+ *
+ * \param list list.
+ * \param elem element to insert.
+ */
+#define insert_at_tail(list, elem)		\
+do {						\
+   (elem)->next = list;				\
+   (elem)->prev = (list)->prev;			\
+   (list)->prev->next = elem;			\
+   (list)->prev = elem;				\
+} while(0)
+
+/**
+ * Move an element to the list head.
+ *
+ * \param list list.
+ * \param elem element to move.
+ */
+#define move_to_head(list, elem)		\
+do {						\
+   remove_from_list(elem);			\
+   insert_at_head(list, elem);			\
+} while (0)
+
+/**
+ * Move an element to the list tail.
+ *
+ * \param list list.
+ * \param elem element to move.
+ */
+#define move_to_tail(list, elem)		\
+do {						\
+   remove_from_list(elem);			\
+   insert_at_tail(list, elem);			\
+} while (0)
+
+/**
+ * Make a empty list empty.
+ *
+ * \param sentinal list (sentinal element).
+ */
+#define make_empty_list(sentinal)		\
+do {						\
+   (sentinal)->next = sentinal;			\
+   (sentinal)->prev = sentinal;			\
+} while (0)
+
+/**
+ * Get list first element.
+ *
+ * \param list list.
+ *
+ * \return pointer to first element.
+ */
+#define first_elem(list)       ((list)->next)
+
+/**
+ * Get list last element.
+ *
+ * \param list list.
+ *
+ * \return pointer to last element.
+ */
+#define last_elem(list)        ((list)->prev)
+
+/**
+ * Get next element.
+ *
+ * \param elem element.
+ *
+ * \return pointer to next element.
+ */
+#define next_elem(elem)        ((elem)->next)
+
+/**
+ * Get previous element.
+ *
+ * \param elem element.
+ *
+ * \return pointer to previous element.
+ */
+#define prev_elem(elem)        ((elem)->prev)
+
+/**
+ * Test whether element is at end of the list.
+ * 
+ * \param list list.
+ * \param elem element.
+ * 
+ * \return non-zero if element is at end of list, or zero otherwise.
+ */
+#define at_end(list, elem)     ((elem) == (list))
+
+/**
+ * Test if a list is empty.
+ * 
+ * \param list list.
+ * 
+ * \return non-zero if list empty, or zero otherwise.
+ */
+#define is_empty_list(list)    ((list)->next == (list))
+
+/**
+ * Walk through the elements of a list.
+ *
+ * \param ptr pointer to the current element.
+ * \param list list.
+ *
+ * \note It should be followed by a { } block or a single statement, as in a \c
+ * for loop.
+ */
+#define foreach(ptr, list)     \
+        for( ptr=(list)->next ;  ptr!=list ;  ptr=(ptr)->next )
+
+/**
+ * Walk through the elements of a list.
+ *
+ * Same as #foreach but lets you unlink the current value during a list
+ * traversal.  Useful for freeing a list, element by element.
+ * 
+ * \param ptr pointer to the current element.
+ * \param t temporary pointer.
+ * \param list list.
+ *
+ * \note It should be followed by a { } block or a single statement, as in a \c
+ * for loop.
+ */
+#define foreach_s(ptr, t, list)   \
+        for(ptr=(list)->next,t=(ptr)->next; list != ptr; ptr=t, t=(t)->next)
+
+#endif


More information about the xorg-commit mailing list