summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2009-11-30 15:32:12 +1000
committerDave Airlie <airlied@redhat.com>2009-12-01 13:40:45 +1000
commit88a50a30df11a06263209340a42251851f8e2334 (patch)
tree7a8ee4323f5f9ed91ff96e73986343315e0232e0 /src
parentb2597deea3a3953ff50d54ff37e3c043eac409f4 (diff)
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@redhat.com>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/r600_exa.c37
-rw-r--r--src/r600_state.h22
-rw-r--r--src/r600_textured_videofuncs.c8
-rw-r--r--src/r6xx_accel.c119
-rw-r--r--src/radeon.h21
-rw-r--r--src/radeon_kms.c32
-rw-r--r--src/radeon_vbo.c206
-rw-r--r--src/radeon_vbo.h62
-rw-r--r--src/simple_list.h202
10 files changed, 598 insertions, 113 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 93f237cb..a431d2e5 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 16d217db..634e6cac 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 6cd47dcc..0ee480bc 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 b962ae7a..69deb815 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 69e17e49..0ca942ef 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 5eec147a..1b8ae3cd 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 f6c41d9b..c06b8328 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 00000000..ad650b2d
--- /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@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 00000000..a8c70b30
--- /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 00000000..ff7f8882
--- /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