From: Marek Olšák Date: Mon, 27 Dec 2010 21:32:31 +0000 (+0100) Subject: u_upload_mgr: new features X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=06286110b4fc0ff80ae21bb3d8ff9909db1f5d47;p=mesa.git u_upload_mgr: new features - Added a parameter to specify a minimum offset that should be returned. r300g needs this to better implement user buffer uploads. This weird requirement comes from the fact that the Radeon DRM doesn't support negative offsets. - Added a parameter to notify a driver that the upload flush occured. A driver may skip buffer validation if there was no flush, resulting in a better performance. - Added a new upload function that returns a pointer to the upload buffer directly, so that the buffer can be filled e.g. by the translate module. --- diff --git a/src/gallium/auxiliary/util/u_upload_mgr.c b/src/gallium/auxiliary/util/u_upload_mgr.c index 4d97bf0377f..80c9b635f0e 100644 --- a/src/gallium/auxiliary/util/u_upload_mgr.c +++ b/src/gallium/auxiliary/util/u_upload_mgr.c @@ -43,7 +43,7 @@ struct u_upload_mgr { unsigned default_size; unsigned alignment; - unsigned usage; + unsigned bind; /* The active buffer: */ @@ -58,7 +58,7 @@ struct u_upload_mgr { struct u_upload_mgr *u_upload_create( struct pipe_context *pipe, unsigned default_size, unsigned alignment, - unsigned usage ) + unsigned bind ) { struct u_upload_mgr *upload = CALLOC_STRUCT( u_upload_mgr ); if (!upload) @@ -67,7 +67,7 @@ struct u_upload_mgr *u_upload_create( struct pipe_context *pipe, upload->pipe = pipe; upload->default_size = default_size; upload->alignment = alignment; - upload->usage = usage; + upload->bind = bind; upload->buffer = NULL; return upload; @@ -115,7 +115,7 @@ u_upload_alloc_buffer( struct u_upload_mgr *upload, size = align(MAX2(upload->default_size, min_size), 4096); upload->buffer = pipe_buffer_create( upload->pipe->screen, - upload->usage, + upload->bind, size ); if (upload->buffer == NULL) goto fail; @@ -135,33 +135,61 @@ fail: return PIPE_ERROR_OUT_OF_MEMORY; } - -enum pipe_error u_upload_data( struct u_upload_mgr *upload, - unsigned size, - const void *data, - unsigned *out_offset, - struct pipe_resource **outbuf ) +enum pipe_error u_upload_alloc( struct u_upload_mgr *upload, + unsigned min_out_offset, + unsigned size, + unsigned *out_offset, + struct pipe_resource **outbuf, + boolean *flushed, + void **ptr ) { unsigned alloc_size = align( size, upload->alignment ); - enum pipe_error ret = PIPE_OK; + unsigned alloc_offset = align(min_out_offset, upload->alignment); + unsigned offset; - if (upload->offset + alloc_size > upload->size) { - ret = u_upload_alloc_buffer( upload, alloc_size ); + if (MAX2(upload->offset, alloc_offset) + alloc_size > upload->size) { + enum pipe_error ret = u_upload_alloc_buffer(upload, + alloc_offset + alloc_size); if (ret) return ret; + + *flushed = TRUE; + } else { + *flushed = FALSE; } - assert(upload->offset < upload->buffer->width0); - assert(upload->offset + size <= upload->buffer->width0); + offset = MAX2(upload->offset, alloc_offset); + + assert(offset < upload->buffer->width0); + assert(offset + size <= upload->buffer->width0); assert(size); - memcpy(upload->map + upload->offset, data, size); + *ptr = upload->map + offset; /* Emit the return values: */ pipe_resource_reference( outbuf, upload->buffer ); - *out_offset = upload->offset; - upload->offset += alloc_size; + *out_offset = offset; + upload->offset = offset + alloc_size; + return PIPE_OK; +} + +enum pipe_error u_upload_data( struct u_upload_mgr *upload, + unsigned min_out_offset, + unsigned size, + const void *data, + unsigned *out_offset, + struct pipe_resource **outbuf, + boolean *flushed ) +{ + uint8_t *ptr; + enum pipe_error ret = u_upload_alloc(upload, min_out_offset, size, + out_offset, outbuf, flushed, + (void**)&ptr); + if (ret) + return ret; + + memcpy(ptr, data, size); return PIPE_OK; } @@ -172,11 +200,13 @@ enum pipe_error u_upload_data( struct u_upload_mgr *upload, * renders or DrawElements calls. */ enum pipe_error u_upload_buffer( struct u_upload_mgr *upload, + unsigned min_out_offset, unsigned offset, unsigned size, struct pipe_resource *inbuf, unsigned *out_offset, - struct pipe_resource **outbuf ) + struct pipe_resource **outbuf, + boolean *flushed ) { enum pipe_error ret = PIPE_OK; struct pipe_transfer *transfer = NULL; @@ -195,13 +225,12 @@ enum pipe_error u_upload_buffer( struct u_upload_mgr *upload, if (0) debug_printf("upload ptr %p ofs %d sz %d\n", map, offset, size); - ret = u_upload_data( upload, + ret = u_upload_data( upload, + min_out_offset, size, map + offset, out_offset, - outbuf ); - if (ret) - goto done; + outbuf, flushed ); done: if (map) diff --git a/src/gallium/auxiliary/util/u_upload_mgr.h b/src/gallium/auxiliary/util/u_upload_mgr.h index de016df02e0..fc8f4d3687a 100644 --- a/src/gallium/auxiliary/util/u_upload_mgr.h +++ b/src/gallium/auxiliary/util/u_upload_mgr.h @@ -32,6 +32,8 @@ #ifndef U_UPLOAD_MGR_H #define U_UPLOAD_MGR_H +#include "pipe/p_compiler.h" + struct pipe_context; struct pipe_resource; @@ -39,7 +41,7 @@ struct pipe_resource; struct u_upload_mgr *u_upload_create( struct pipe_context *pipe, unsigned default_size, unsigned alignment, - unsigned usage ); + unsigned bind ); void u_upload_destroy( struct u_upload_mgr *upload ); @@ -53,20 +55,55 @@ void u_upload_destroy( struct u_upload_mgr *upload ); */ void u_upload_flush( struct u_upload_mgr *upload ); +/** + * Sub-allocate new memory from the upload buffer. + * + * \param upload Upload manager + * \param min_out_offset Minimum offset that should be returned in out_offset. + * \param size Size of the allocation. + * \param out_offset Pointer to where the new buffer offset will be returned. + * \param outbuf Pointer to where the upload buffer will be returned. + * \param flushed Whether the upload buffer was flushed. + * \param ptr Pointer to the allocated memory that is returned. + */ +enum pipe_error u_upload_alloc( struct u_upload_mgr *upload, + unsigned min_out_offset, + unsigned size, + unsigned *out_offset, + struct pipe_resource **outbuf, + boolean *flushed, + void **ptr ); + +/** + * Allocate and write data to the upload buffer. + * + * Same as u_upload_alloc, but in addition to that, it copies "data" + * to the pointer returned from u_upload_alloc. + */ enum pipe_error u_upload_data( struct u_upload_mgr *upload, + unsigned min_out_offset, unsigned size, const void *data, unsigned *out_offset, - struct pipe_resource **outbuf ); + struct pipe_resource **outbuf, + boolean *flushed ); +/** + * Allocate and copy an input buffer to the upload buffer. + * + * Same as u_upload_data, except that the input data comes from a buffer + * instead of a user pointer. + */ enum pipe_error u_upload_buffer( struct u_upload_mgr *upload, + unsigned min_out_offset, unsigned offset, unsigned size, struct pipe_resource *inbuf, unsigned *out_offset, - struct pipe_resource **outbuf ); + struct pipe_resource **outbuf, + boolean *flushed ); diff --git a/src/gallium/drivers/i965/brw_draw_upload.c b/src/gallium/drivers/i965/brw_draw_upload.c index ebeb1e146aa..cf9405470c8 100644 --- a/src/gallium/drivers/i965/brw_draw_upload.c +++ b/src/gallium/drivers/i965/brw_draw_upload.c @@ -89,13 +89,16 @@ static int brw_prepare_vertices(struct brw_context *brw) vb->buffer->width0 - vb->buffer_offset : MAX2(vb->buffer->width0 - vb->buffer_offset, vb->stride * (max_index + 1 - min_index))); + boolean flushed; - ret = u_upload_buffer( brw->vb.upload_vertex, + ret = u_upload_buffer( brw->vb.upload_vertex, + 0, vb->buffer_offset + min_index * vb->stride, size, vb->buffer, &offset, - &upload_buf ); + &upload_buf, + &flushed ); if (ret) return ret; @@ -251,13 +254,16 @@ static int brw_prepare_indices(struct brw_context *brw) /* Turn userbuffer into a proper hardware buffer? */ if (brw_buffer_is_user_buffer(index_buffer)) { + boolean flushed; ret = u_upload_buffer( brw->vb.upload_index, + 0, index_offset, ib_size, index_buffer, &offset, - &upload_buf ); + &upload_buf, + &flushed ); if (ret) return ret; diff --git a/src/gallium/drivers/r300/r300_screen_buffer.c b/src/gallium/drivers/r300/r300_screen_buffer.c index f96998195af..11ad87ed89b 100644 --- a/src/gallium/drivers/r300/r300_screen_buffer.c +++ b/src/gallium/drivers/r300/r300_screen_buffer.c @@ -62,15 +62,16 @@ void r300_upload_index_buffer(struct r300_context *r300, unsigned count) { unsigned index_offset; + boolean flushed; uint8_t *ptr = r300_buffer(*index_buffer)->user_buffer; *index_buffer = NULL; u_upload_data(r300->upload_ib, - count * index_size, + 0, count * index_size, ptr + (*start * index_size), &index_offset, - index_buffer); + index_buffer, &flushed); *start = index_offset / index_size; } @@ -78,6 +79,7 @@ void r300_upload_index_buffer(struct r300_context *r300, void r300_upload_user_buffers(struct r300_context *r300) { int i, nr = r300->velems->count; + boolean flushed; for (i = 0; i < nr; i++) { struct pipe_vertex_buffer *vb = @@ -85,9 +87,9 @@ void r300_upload_user_buffers(struct r300_context *r300) if (r300_buffer_is_user_buffer(vb->buffer)) { u_upload_data(r300->upload_vb, - vb->buffer->width0, + 0, vb->buffer->width0, r300_buffer(vb->buffer)->user_buffer, - &vb->buffer_offset, &vb->buffer); + &vb->buffer_offset, &vb->buffer, &flushed); r300->validate_buffers = TRUE; r300->vertex_arrays_dirty = TRUE; diff --git a/src/gallium/drivers/svga/svga_draw_elements.c b/src/gallium/drivers/svga/svga_draw_elements.c index c7ea014bba5..83527c6ef49 100644 --- a/src/gallium/drivers/svga/svga_draw_elements.c +++ b/src/gallium/drivers/svga/svga_draw_elements.c @@ -120,14 +120,17 @@ svga_hwtnl_simple_draw_range_elements( struct svga_hwtnl *hwtnl, if (index_buffer && svga_buffer_is_user_buffer(index_buffer)) { + boolean flushed; assert( index_buffer->width0 >= index_offset + count * index_size ); ret = u_upload_buffer( hwtnl->upload_ib, + 0, index_offset, count * index_size, index_buffer, &index_offset, - &upload_buffer ); + &upload_buffer, + &flushed ); if (ret) goto done; diff --git a/src/gallium/drivers/svga/svga_state_vdecl.c b/src/gallium/drivers/svga/svga_state_vdecl.c index 3af7bf2b358..958d00393f2 100644 --- a/src/gallium/drivers/svga/svga_state_vdecl.c +++ b/src/gallium/drivers/svga/svga_state_vdecl.c @@ -57,12 +57,14 @@ upload_user_buffers( struct svga_context *svga ) struct svga_buffer *buffer = svga_buffer(svga->curr.vb[i].buffer); if (!buffer->uploaded.buffer) { + boolean flushed; ret = u_upload_buffer( svga->upload_vb, - 0, + 0, 0, buffer->b.b.width0, &buffer->b.b, &buffer->uploaded.offset, - &buffer->uploaded.buffer ); + &buffer->uploaded.buffer, + &flushed); if (ret) return ret;