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.
This commit is contained in:
Marek Olšák 2010-12-27 22:32:31 +01:00
parent 8b7bd3ce88
commit 06286110b4
6 changed files with 115 additions and 36 deletions

View File

@ -43,7 +43,7 @@ struct u_upload_mgr {
unsigned default_size; unsigned default_size;
unsigned alignment; unsigned alignment;
unsigned usage; unsigned bind;
/* The active buffer: /* The active buffer:
*/ */
@ -58,7 +58,7 @@ struct u_upload_mgr {
struct u_upload_mgr *u_upload_create( struct pipe_context *pipe, struct u_upload_mgr *u_upload_create( struct pipe_context *pipe,
unsigned default_size, unsigned default_size,
unsigned alignment, unsigned alignment,
unsigned usage ) unsigned bind )
{ {
struct u_upload_mgr *upload = CALLOC_STRUCT( u_upload_mgr ); struct u_upload_mgr *upload = CALLOC_STRUCT( u_upload_mgr );
if (!upload) if (!upload)
@ -67,7 +67,7 @@ struct u_upload_mgr *u_upload_create( struct pipe_context *pipe,
upload->pipe = pipe; upload->pipe = pipe;
upload->default_size = default_size; upload->default_size = default_size;
upload->alignment = alignment; upload->alignment = alignment;
upload->usage = usage; upload->bind = bind;
upload->buffer = NULL; upload->buffer = NULL;
return upload; return upload;
@ -115,7 +115,7 @@ u_upload_alloc_buffer( struct u_upload_mgr *upload,
size = align(MAX2(upload->default_size, min_size), 4096); size = align(MAX2(upload->default_size, min_size), 4096);
upload->buffer = pipe_buffer_create( upload->pipe->screen, upload->buffer = pipe_buffer_create( upload->pipe->screen,
upload->usage, upload->bind,
size ); size );
if (upload->buffer == NULL) if (upload->buffer == NULL)
goto fail; goto fail;
@ -135,33 +135,61 @@ fail:
return PIPE_ERROR_OUT_OF_MEMORY; return PIPE_ERROR_OUT_OF_MEMORY;
} }
enum pipe_error u_upload_alloc( struct u_upload_mgr *upload,
enum pipe_error u_upload_data( struct u_upload_mgr *upload, unsigned min_out_offset,
unsigned size, unsigned size,
const void *data, unsigned *out_offset,
unsigned *out_offset, struct pipe_resource **outbuf,
struct pipe_resource **outbuf ) boolean *flushed,
void **ptr )
{ {
unsigned alloc_size = align( size, upload->alignment ); 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) { if (MAX2(upload->offset, alloc_offset) + alloc_size > upload->size) {
ret = u_upload_alloc_buffer( upload, alloc_size ); enum pipe_error ret = u_upload_alloc_buffer(upload,
alloc_offset + alloc_size);
if (ret) if (ret)
return ret; return ret;
*flushed = TRUE;
} else {
*flushed = FALSE;
} }
assert(upload->offset < upload->buffer->width0); offset = MAX2(upload->offset, alloc_offset);
assert(upload->offset + size <= upload->buffer->width0);
assert(offset < upload->buffer->width0);
assert(offset + size <= upload->buffer->width0);
assert(size); assert(size);
memcpy(upload->map + upload->offset, data, size); *ptr = upload->map + offset;
/* Emit the return values: /* Emit the return values:
*/ */
pipe_resource_reference( outbuf, upload->buffer ); pipe_resource_reference( outbuf, upload->buffer );
*out_offset = upload->offset; *out_offset = offset;
upload->offset += alloc_size; 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; return PIPE_OK;
} }
@ -172,11 +200,13 @@ enum pipe_error u_upload_data( struct u_upload_mgr *upload,
* renders or DrawElements calls. * renders or DrawElements calls.
*/ */
enum pipe_error u_upload_buffer( struct u_upload_mgr *upload, enum pipe_error u_upload_buffer( struct u_upload_mgr *upload,
unsigned min_out_offset,
unsigned offset, unsigned offset,
unsigned size, unsigned size,
struct pipe_resource *inbuf, struct pipe_resource *inbuf,
unsigned *out_offset, unsigned *out_offset,
struct pipe_resource **outbuf ) struct pipe_resource **outbuf,
boolean *flushed )
{ {
enum pipe_error ret = PIPE_OK; enum pipe_error ret = PIPE_OK;
struct pipe_transfer *transfer = NULL; struct pipe_transfer *transfer = NULL;
@ -195,13 +225,12 @@ enum pipe_error u_upload_buffer( struct u_upload_mgr *upload,
if (0) if (0)
debug_printf("upload ptr %p ofs %d sz %d\n", map, offset, size); 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, size,
map + offset, map + offset,
out_offset, out_offset,
outbuf ); outbuf, flushed );
if (ret)
goto done;
done: done:
if (map) if (map)

View File

@ -32,6 +32,8 @@
#ifndef U_UPLOAD_MGR_H #ifndef U_UPLOAD_MGR_H
#define U_UPLOAD_MGR_H #define U_UPLOAD_MGR_H
#include "pipe/p_compiler.h"
struct pipe_context; struct pipe_context;
struct pipe_resource; struct pipe_resource;
@ -39,7 +41,7 @@ struct pipe_resource;
struct u_upload_mgr *u_upload_create( struct pipe_context *pipe, struct u_upload_mgr *u_upload_create( struct pipe_context *pipe,
unsigned default_size, unsigned default_size,
unsigned alignment, unsigned alignment,
unsigned usage ); unsigned bind );
void u_upload_destroy( struct u_upload_mgr *upload ); 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 ); 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, enum pipe_error u_upload_data( struct u_upload_mgr *upload,
unsigned min_out_offset,
unsigned size, unsigned size,
const void *data, const void *data,
unsigned *out_offset, 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, enum pipe_error u_upload_buffer( struct u_upload_mgr *upload,
unsigned min_out_offset,
unsigned offset, unsigned offset,
unsigned size, unsigned size,
struct pipe_resource *inbuf, struct pipe_resource *inbuf,
unsigned *out_offset, unsigned *out_offset,
struct pipe_resource **outbuf ); struct pipe_resource **outbuf,
boolean *flushed );

View File

@ -89,13 +89,16 @@ static int brw_prepare_vertices(struct brw_context *brw)
vb->buffer->width0 - vb->buffer_offset : vb->buffer->width0 - vb->buffer_offset :
MAX2(vb->buffer->width0 - vb->buffer_offset, MAX2(vb->buffer->width0 - vb->buffer_offset,
vb->stride * (max_index + 1 - min_index))); 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, vb->buffer_offset + min_index * vb->stride,
size, size,
vb->buffer, vb->buffer,
&offset, &offset,
&upload_buf ); &upload_buf,
&flushed );
if (ret) if (ret)
return ret; return ret;
@ -251,13 +254,16 @@ static int brw_prepare_indices(struct brw_context *brw)
/* Turn userbuffer into a proper hardware buffer? /* Turn userbuffer into a proper hardware buffer?
*/ */
if (brw_buffer_is_user_buffer(index_buffer)) { if (brw_buffer_is_user_buffer(index_buffer)) {
boolean flushed;
ret = u_upload_buffer( brw->vb.upload_index, ret = u_upload_buffer( brw->vb.upload_index,
0,
index_offset, index_offset,
ib_size, ib_size,
index_buffer, index_buffer,
&offset, &offset,
&upload_buf ); &upload_buf,
&flushed );
if (ret) if (ret)
return ret; return ret;

View File

@ -62,15 +62,16 @@ void r300_upload_index_buffer(struct r300_context *r300,
unsigned count) unsigned count)
{ {
unsigned index_offset; unsigned index_offset;
boolean flushed;
uint8_t *ptr = r300_buffer(*index_buffer)->user_buffer; uint8_t *ptr = r300_buffer(*index_buffer)->user_buffer;
*index_buffer = NULL; *index_buffer = NULL;
u_upload_data(r300->upload_ib, u_upload_data(r300->upload_ib,
count * index_size, 0, count * index_size,
ptr + (*start * index_size), ptr + (*start * index_size),
&index_offset, &index_offset,
index_buffer); index_buffer, &flushed);
*start = index_offset / index_size; *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) void r300_upload_user_buffers(struct r300_context *r300)
{ {
int i, nr = r300->velems->count; int i, nr = r300->velems->count;
boolean flushed;
for (i = 0; i < nr; i++) { for (i = 0; i < nr; i++) {
struct pipe_vertex_buffer *vb = 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)) { if (r300_buffer_is_user_buffer(vb->buffer)) {
u_upload_data(r300->upload_vb, u_upload_data(r300->upload_vb,
vb->buffer->width0, 0, vb->buffer->width0,
r300_buffer(vb->buffer)->user_buffer, r300_buffer(vb->buffer)->user_buffer,
&vb->buffer_offset, &vb->buffer); &vb->buffer_offset, &vb->buffer, &flushed);
r300->validate_buffers = TRUE; r300->validate_buffers = TRUE;
r300->vertex_arrays_dirty = TRUE; r300->vertex_arrays_dirty = TRUE;

View File

@ -120,14 +120,17 @@ svga_hwtnl_simple_draw_range_elements( struct svga_hwtnl *hwtnl,
if (index_buffer && if (index_buffer &&
svga_buffer_is_user_buffer(index_buffer)) svga_buffer_is_user_buffer(index_buffer))
{ {
boolean flushed;
assert( index_buffer->width0 >= index_offset + count * index_size ); assert( index_buffer->width0 >= index_offset + count * index_size );
ret = u_upload_buffer( hwtnl->upload_ib, ret = u_upload_buffer( hwtnl->upload_ib,
0,
index_offset, index_offset,
count * index_size, count * index_size,
index_buffer, index_buffer,
&index_offset, &index_offset,
&upload_buffer ); &upload_buffer,
&flushed );
if (ret) if (ret)
goto done; goto done;

View File

@ -57,12 +57,14 @@ upload_user_buffers( struct svga_context *svga )
struct svga_buffer *buffer = svga_buffer(svga->curr.vb[i].buffer); struct svga_buffer *buffer = svga_buffer(svga->curr.vb[i].buffer);
if (!buffer->uploaded.buffer) { if (!buffer->uploaded.buffer) {
boolean flushed;
ret = u_upload_buffer( svga->upload_vb, ret = u_upload_buffer( svga->upload_vb,
0, 0, 0,
buffer->b.b.width0, buffer->b.b.width0,
&buffer->b.b, &buffer->b.b,
&buffer->uploaded.offset, &buffer->uploaded.offset,
&buffer->uploaded.buffer ); &buffer->uploaded.buffer,
&flushed);
if (ret) if (ret)
return ret; return ret;