u_upload_mgr: keep the upload buffer mapped until it is flushed

The map/unmap overhead can be significant even though there is no waiting on busy
buffers. There is simply a huge number of uploads.

This is a performance optimization for Torcs, a car racing game.
This commit is contained in:
Marek Olšák
2010-12-24 13:47:32 +01:00
parent 8fd8de3995
commit 8b7bd3ce88

View File

@@ -48,6 +48,8 @@ struct u_upload_mgr {
/* The active buffer:
*/
struct pipe_resource *buffer;
struct pipe_transfer *transfer;
uint8_t *map;
unsigned size;
unsigned offset;
};
@@ -71,48 +73,6 @@ struct u_upload_mgr *u_upload_create( struct pipe_context *pipe,
return upload;
}
/* Slightly specialized version of buffer_write designed to maximize
* chances of the driver consolidating successive writes into a single
* upload.
*
* dirty_size may be slightly greater than size to cope with
* alignment. We don't want to leave holes between succesively mapped
* regions as that may prevent the driver from consolidating uploads.
*
* Note that the 'data' pointer has probably come from the application
* and we cannot read even a byte past its end without risking
* segfaults, or at least complaints from valgrind..
*/
static INLINE enum pipe_error
my_buffer_write(struct pipe_context *pipe,
struct pipe_resource *buf,
unsigned offset, unsigned size, unsigned dirty_size,
const void *data)
{
struct pipe_transfer *transfer = NULL;
uint8_t *map;
assert(offset < buf->width0);
assert(offset + size <= buf->width0);
assert(dirty_size >= size);
assert(size);
map = pipe_buffer_map_range(pipe, buf, offset, dirty_size,
PIPE_TRANSFER_WRITE |
PIPE_TRANSFER_FLUSH_EXPLICIT |
PIPE_TRANSFER_DISCARD |
PIPE_TRANSFER_UNSYNCHRONIZED,
&transfer);
if (map == NULL)
return PIPE_ERROR_OUT_OF_MEMORY;
memcpy(map + offset, data, size);
pipe_buffer_flush_mapped_range(pipe, transfer, offset, dirty_size);
pipe_buffer_unmap(pipe, transfer);
return PIPE_OK;
}
/* Release old buffer.
*
* This must usually be called prior to firing the command stream
@@ -124,6 +84,10 @@ my_buffer_write(struct pipe_context *pipe,
*/
void u_upload_flush( struct u_upload_mgr *upload )
{
if (upload->transfer) {
pipe_transfer_unmap(upload->pipe, upload->transfer);
upload->transfer = NULL;
}
pipe_resource_reference( &upload->buffer, NULL );
upload->size = 0;
}
@@ -155,6 +119,9 @@ u_upload_alloc_buffer( struct u_upload_mgr *upload,
size );
if (upload->buffer == NULL)
goto fail;
upload->map = pipe_buffer_map(upload->pipe, upload->buffer,
PIPE_TRANSFER_WRITE, &upload->transfer);
upload->size = size;
@@ -184,16 +151,11 @@ enum pipe_error u_upload_data( struct u_upload_mgr *upload,
return ret;
}
/* Copy the data, using map_range if available:
*/
ret = my_buffer_write( upload->pipe,
upload->buffer,
upload->offset,
size,
alloc_size,
data );
if (ret)
return ret;
assert(upload->offset < upload->buffer->width0);
assert(upload->offset + size <= upload->buffer->width0);
assert(size);
memcpy(upload->map + upload->offset, data, size);
/* Emit the return values:
*/