diff options
author | Dave Airlie <airlied@redhat.com> | 2009-11-30 15:32:12 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-12-01 13:40:45 +1000 |
commit | 88a50a30df11a06263209340a42251851f8e2334 (patch) | |
tree | 7a8ee4323f5f9ed91ff96e73986343315e0232e0 /src | |
parent | b2597deea3a3953ff50d54ff37e3c043eac409f4 (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.am | 2 | ||||
-rw-r--r-- | src/r600_exa.c | 37 | ||||
-rw-r--r-- | src/r600_state.h | 22 | ||||
-rw-r--r-- | src/r600_textured_videofuncs.c | 8 | ||||
-rw-r--r-- | src/r6xx_accel.c | 119 | ||||
-rw-r--r-- | src/radeon.h | 21 | ||||
-rw-r--r-- | src/radeon_kms.c | 32 | ||||
-rw-r--r-- | src/radeon_vbo.c | 206 | ||||
-rw-r--r-- | src/radeon_vbo.h | 62 | ||||
-rw-r--r-- | src/simple_list.h | 202 |
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 |