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 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)

View File

@ -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 );

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;