From 0d76bb5d4c5c867155f7fb381c46018e1560b790 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 17 Sep 2010 14:01:50 +1000 Subject: r600g: add upload manager support. this add support for the upload manager for uploading user vbo/index buffers. this provides a considerable speedup in q3 type games. --- src/gallium/drivers/r600/r600_buffer.c | 183 ++++++++++++++++++++++++++------- 1 file changed, 144 insertions(+), 39 deletions(-) (limited to 'src/gallium/drivers/r600/r600_buffer.c') diff --git a/src/gallium/drivers/r600/r600_buffer.c b/src/gallium/drivers/r600/r600_buffer.c index a38c013e16..dc3fc812e1 100644 --- a/src/gallium/drivers/r600/r600_buffer.c +++ b/src/gallium/drivers/r600/r600_buffer.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "state_tracker/drm_driver.h" #include "r600_screen.h" #include "r600_context.h" @@ -67,66 +68,69 @@ struct pipe_resource *r600_buffer_create(struct pipe_screen *screen, const struct pipe_resource *templ) { struct r600_screen *rscreen = r600_screen(screen); - struct r600_resource *rbuffer; + struct r600_resource_buffer *rbuffer; struct radeon_ws_bo *bo; /* XXX We probably want a different alignment for buffers and textures. */ unsigned alignment = 4096; - rbuffer = CALLOC_STRUCT(r600_resource); + rbuffer = CALLOC_STRUCT(r600_resource_buffer); if (rbuffer == NULL) return NULL; - rbuffer->base.b = *templ; - pipe_reference_init(&rbuffer->base.b.reference, 1); - rbuffer->base.b.screen = screen; - rbuffer->base.vtbl = &r600_buffer_vtbl; - rbuffer->size = rbuffer->base.b.width0; - rbuffer->domain = r600_domain_from_usage(rbuffer->base.b.bind); - bo = radeon_ws_bo(rscreen->rw, rbuffer->base.b.width0, alignment, rbuffer->base.b.bind); + rbuffer->magic = R600_BUFFER_MAGIC; + rbuffer->user_buffer = NULL; + rbuffer->num_ranges = 0; + rbuffer->r.base.b = *templ; + pipe_reference_init(&rbuffer->r.base.b.reference, 1); + rbuffer->r.base.b.screen = screen; + rbuffer->r.base.vtbl = &r600_buffer_vtbl; + rbuffer->r.size = rbuffer->r.base.b.width0; + rbuffer->r.domain = r600_domain_from_usage(rbuffer->r.base.b.bind); + bo = radeon_ws_bo(rscreen->rw, rbuffer->r.base.b.width0, alignment, rbuffer->r.base.b.bind); if (bo == NULL) { FREE(rbuffer); return NULL; } - rbuffer->bo = bo; - return &rbuffer->base.b; + rbuffer->r.bo = bo; + return &rbuffer->r.base.b; } struct pipe_resource *r600_user_buffer_create(struct pipe_screen *screen, void *ptr, unsigned bytes, unsigned bind) { - struct r600_resource *rbuffer; - struct r600_screen *rscreen = r600_screen(screen); - struct pipe_resource templ; - void *data; - - memset(&templ, 0, sizeof(struct pipe_resource)); - templ.target = PIPE_BUFFER; - templ.format = PIPE_FORMAT_R8_UNORM; - templ.usage = PIPE_USAGE_IMMUTABLE; - templ.bind = bind; - templ.width0 = bytes; - templ.height0 = 1; - templ.depth0 = 1; - - rbuffer = (struct r600_resource*)r600_buffer_create(screen, &templ); - if (rbuffer == NULL) { + struct r600_resource_buffer *rbuffer; + + rbuffer = CALLOC_STRUCT(r600_resource_buffer); + if (rbuffer == NULL) return NULL; - } - data = radeon_ws_bo_map(rscreen->rw, rbuffer->bo, 0, NULL); - memcpy(data, ptr, bytes); - radeon_ws_bo_unmap(rscreen->rw, rbuffer->bo); - return &rbuffer->base.b; + + rbuffer->magic = R600_BUFFER_MAGIC; + pipe_reference_init(&rbuffer->r.base.b.reference, 1); + rbuffer->r.base.vtbl = &r600_buffer_vtbl; + rbuffer->r.base.b.screen = screen; + rbuffer->r.base.b.target = PIPE_BUFFER; + rbuffer->r.base.b.format = PIPE_FORMAT_R8_UNORM; + rbuffer->r.base.b.usage = PIPE_USAGE_IMMUTABLE; + rbuffer->r.base.b.bind = bind; + rbuffer->r.base.b.width0 = bytes; + rbuffer->r.base.b.height0 = 1; + rbuffer->r.base.b.depth0 = 1; + rbuffer->r.base.b.flags = 0; + rbuffer->num_ranges = 0; + rbuffer->r.bo = NULL; + rbuffer->user_buffer = ptr; + return &rbuffer->r.base.b; } static void r600_buffer_destroy(struct pipe_screen *screen, struct pipe_resource *buf) { - struct r600_resource *rbuffer = (struct r600_resource*)buf; + struct r600_resource_buffer *rbuffer = r600_buffer(buf); struct r600_screen *rscreen = r600_screen(screen); - if (rbuffer->bo) { - radeon_ws_bo_reference(rscreen->rw, &rbuffer->bo, NULL); + if (rbuffer->r.bo) { + radeon_ws_bo_reference(rscreen->rw, &rbuffer->r.bo, NULL); } FREE(rbuffer); } @@ -134,18 +138,40 @@ static void r600_buffer_destroy(struct pipe_screen *screen, static void *r600_buffer_transfer_map(struct pipe_context *pipe, struct pipe_transfer *transfer) { - struct r600_resource *rbuffer = (struct r600_resource*)transfer->resource; + struct r600_context *rctx = r600_context(pipe); + struct r600_resource_buffer *rbuffer = r600_buffer(transfer->resource); struct r600_screen *rscreen = r600_screen(pipe->screen); int write = 0; uint8_t *data; + int i; + boolean flush = FALSE; + + if (rbuffer->user_buffer) + return (uint8_t*)rbuffer->user_buffer + transfer->box.x; + if (transfer->usage & PIPE_TRANSFER_DISCARD) { + for (i = 0; i < rbuffer->num_ranges; i++) { + if ((transfer->box.x >= rbuffer->ranges[i].start) && + (transfer->box.x < rbuffer->ranges[i].end)) + flush = TRUE; + + if (flush) { + radeon_ws_bo_reference(rscreen->rw, &rbuffer->r.bo, NULL); + rbuffer->num_ranges = 0; + rbuffer->r.bo = radeon_ws_bo(rscreen->rw, + rbuffer->r.base.b.width0, 0, + rbuffer->r.base.b.bind); + break; + } + } + } if (transfer->usage & PIPE_TRANSFER_DONTBLOCK) { /* FIXME */ } if (transfer->usage & PIPE_TRANSFER_WRITE) { write = 1; } - data = radeon_ws_bo_map(rscreen->rw, rbuffer->bo, transfer->usage, r600_context(pipe)); + data = radeon_ws_bo_map(rscreen->rw, rbuffer->r.bo, transfer->usage, rctx); if (!data) return NULL; @@ -155,16 +181,39 @@ static void *r600_buffer_transfer_map(struct pipe_context *pipe, static void r600_buffer_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *transfer) { - struct r600_resource *rbuffer = (struct r600_resource*)transfer->resource; + struct r600_resource_buffer *rbuffer = r600_buffer(transfer->resource); struct r600_screen *rscreen = r600_screen(pipe->screen); - radeon_ws_bo_unmap(rscreen->rw, rbuffer->bo); + if (rbuffer->r.bo) + radeon_ws_bo_unmap(rscreen->rw, rbuffer->r.bo); } static void r600_buffer_transfer_flush_region(struct pipe_context *pipe, struct pipe_transfer *transfer, const struct pipe_box *box) { + struct r600_resource_buffer *rbuffer = r600_buffer(transfer->resource); + unsigned i; + unsigned offset = transfer->box.x + box->x; + unsigned length = box->width; + + assert(box->x + box->width <= transfer->box.width); + + if (rbuffer->user_buffer) + return; + + /* mark the range as used */ + for(i = 0; i < rbuffer->num_ranges; ++i) { + if(offset <= rbuffer->ranges[i].end && rbuffer->ranges[i].start <= (offset+box->width)) { + rbuffer->ranges[i].start = MIN2(rbuffer->ranges[i].start, offset); + rbuffer->ranges[i].end = MAX2(rbuffer->ranges[i].end, (offset+length)); + return; + } + } + + rbuffer->ranges[rbuffer->num_ranges].start = offset; + rbuffer->ranges[rbuffer->num_ranges].end = offset+length; + rbuffer->num_ranges++; } unsigned r600_buffer_is_referenced_by_cs(struct pipe_context *context, @@ -213,3 +262,59 @@ struct u_resource_vtbl r600_buffer_vtbl = r600_buffer_transfer_unmap, /* transfer_unmap */ u_default_transfer_inline_write /* transfer_inline_write */ }; + +int r600_upload_index_buffer(struct r600_context *rctx, + struct r600_draw *draw) +{ + struct pipe_resource *upload_buffer = NULL; + unsigned index_offset = draw->index_buffer_offset; + int ret = 0; + + if (r600_buffer_is_user_buffer(draw->index_buffer)) { + ret = u_upload_buffer(rctx->upload_ib, + index_offset, + draw->count * draw->index_size, + draw->index_buffer, + &index_offset, + &upload_buffer); + if (ret) { + goto done; + } + draw->index_buffer_offset = index_offset; + draw->index_buffer = upload_buffer; + } + +done: + return ret; +} + +int r600_upload_user_buffers(struct r600_context *rctx) +{ + enum pipe_error ret = PIPE_OK; + int i, nr; + + nr = rctx->vertex_elements->count; + + for (i = 0; i < nr; i++) { + struct pipe_vertex_buffer *vb = + &rctx->vertex_buffer[rctx->vertex_elements->elements[i].vertex_buffer_index]; + + if (r600_buffer_is_user_buffer(vb->buffer)) { + struct pipe_resource *upload_buffer = NULL; + unsigned offset = 0; /*vb->buffer_offset * 4;*/ + unsigned size = vb->buffer->width0; + unsigned upload_offset; + ret = u_upload_buffer(rctx->upload_vb, + offset, size, + vb->buffer, + &upload_offset, &upload_buffer); + if (ret) + return ret; + + pipe_resource_reference(&vb->buffer, NULL); + vb->buffer = upload_buffer; + vb->buffer_offset = upload_offset; + } + } + return ret; +} -- cgit v1.2.3