From 210b468722ae4d4a97ccd788ad9de58858a0c7fa Mon Sep 17 00:00:00 2001 From: Keith Whitwell Date: Fri, 20 Mar 2009 15:08:59 +0000 Subject: gallium/util: add upload manager helper module Add a module that will manage uploading and coalescing multiple user-buffers, malloc-buffers and other random data that doesn't happen to be in a GPU buffer already. The module stuffs multiple little uploads into larger GPU buffers to reduce create/destroy overheads, etc. --- src/gallium/auxiliary/util/Makefile | 1 + src/gallium/auxiliary/util/SConscript | 1 + src/gallium/auxiliary/util/u_upload_mgr.c | 220 ++++++++++++++++++++++++++++++ src/gallium/auxiliary/util/u_upload_mgr.h | 75 ++++++++++ 4 files changed, 297 insertions(+) create mode 100644 src/gallium/auxiliary/util/u_upload_mgr.c create mode 100644 src/gallium/auxiliary/util/u_upload_mgr.h (limited to 'src') diff --git a/src/gallium/auxiliary/util/Makefile b/src/gallium/auxiliary/util/Makefile index 160df8dfa7..d68bdeadcc 100644 --- a/src/gallium/auxiliary/util/Makefile +++ b/src/gallium/auxiliary/util/Makefile @@ -24,6 +24,7 @@ C_SOURCES = \ u_tile.c \ u_time.c \ u_timed_winsys.c \ + u_upload_mgr.c \ u_simple_screen.c include ../../Makefile.template diff --git a/src/gallium/auxiliary/util/SConscript b/src/gallium/auxiliary/util/SConscript index 9d5dd006f0..0f15c632c3 100644 --- a/src/gallium/auxiliary/util/SConscript +++ b/src/gallium/auxiliary/util/SConscript @@ -26,6 +26,7 @@ util = env.ConvenienceLibrary( 'u_tile.c', 'u_time.c', 'u_timed_winsys.c', + 'u_upload_mgr.c', 'u_simple_screen.c', ]) diff --git a/src/gallium/auxiliary/util/u_upload_mgr.c b/src/gallium/auxiliary/util/u_upload_mgr.c new file mode 100644 index 0000000000..d9c0d7afa8 --- /dev/null +++ b/src/gallium/auxiliary/util/u_upload_mgr.c @@ -0,0 +1,220 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Helper utility for uploading user buffers & other data, and + * coalescing small buffers into larger ones. + */ + +#include "pipe/p_error.h" +#include "pipe/p_inlines.h" +#include "pipe/p_screen.h" +#include "util/u_memory.h" +#include "util/u_math.h" + +#include "u_upload_mgr.h" + + +struct u_upload_mgr { + struct pipe_screen *screen; + + unsigned default_size; + unsigned alignment; + unsigned usage; + + /* The active buffer: + */ + struct pipe_buffer *buffer; + unsigned size; + unsigned offset; +}; + + +struct u_upload_mgr *u_upload_create( struct pipe_screen *screen, + unsigned default_size, + unsigned alignment, + unsigned usage ) +{ + struct u_upload_mgr *upload = CALLOC_STRUCT( u_upload_mgr ); + + upload->default_size = default_size; + upload->screen = screen; + upload->alignment = alignment; + upload->usage = usage; + upload->buffer = NULL; + + return upload; +} + + +static INLINE void +my_buffer_write(struct pipe_screen *screen, + struct pipe_buffer *buf, + unsigned offset, unsigned size, unsigned dirty_size, + const void *data) +{ + uint8_t *map; + + assert(offset < buf->size); + assert(offset + size <= buf->size); + assert(dirty_size >= size); + assert(size); + + map = pipe_buffer_map_range(screen, buf, offset, size, PIPE_BUFFER_USAGE_CPU_WRITE); + assert(map); + if(map) { + memcpy(map + offset, data, size); + pipe_buffer_flush_mapped_range(screen, buf, offset, dirty_size); + pipe_buffer_unmap(screen, buf); + } +} + +/* Release old buffer. + * + * This must usually be called prior to firing the command stream + * which references the upload buffer, as many memory managers will + * cause subsequent maps of a fired buffer to wait. + * + * Can improve this with a change to pipe_buffer_write to use the + * DONT_WAIT bit, but for now, it's easiest just to grab a new buffer. + */ +void u_upload_flush( struct u_upload_mgr *upload ) +{ + pipe_buffer_reference( &upload->buffer, NULL ); + upload->size = 0; +} + + +void u_upload_destroy( struct u_upload_mgr *upload ) +{ + u_upload_flush( upload ); + FREE( upload ); +} + + +static enum pipe_error +u_upload_alloc_buffer( struct u_upload_mgr *upload, + unsigned min_size ) +{ + /* Release old buffer, if present: + */ + u_upload_flush( upload ); + + /* Allocate a new one: + */ + upload->size = align(MAX2(upload->default_size, min_size), 4096); + + upload->buffer = pipe_buffer_create( upload->screen, + upload->alignment, + upload->usage | PIPE_BUFFER_USAGE_CPU_WRITE, + upload->size ); + if (upload->buffer == NULL) + goto fail; + + upload->offset = 0; + return 0; + +fail: + if (upload->buffer) + pipe_buffer_reference( &upload->buffer, NULL ); + + 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_buffer **outbuf ) +{ + unsigned alloc_size = align( size, upload->alignment ); + enum pipe_error ret = PIPE_OK; + + if (upload->offset + alloc_size > upload->size) { + ret = u_upload_alloc_buffer( upload, alloc_size ); + if (ret) + return ret; + } + + /* Copy the data, using map_range if available: + */ + my_buffer_write( upload->screen, + upload->buffer, + upload->offset, + size, + alloc_size, + data ); + + /* Emit the return values: + */ + pipe_buffer_reference( outbuf, upload->buffer ); + *out_offset = upload->offset; + upload->offset += alloc_size; + return PIPE_OK; +} + + +/* As above, but upload the full contents of a buffer. Useful for + * uploading user buffers, avoids generating an explosion of GPU + * buffers if you have an app that does lots of small vertex buffer + * renders or DrawElements calls. + */ +enum pipe_error u_upload_buffer( struct u_upload_mgr *upload, + unsigned offset, + unsigned size, + struct pipe_buffer *inbuf, + unsigned *out_offset, + struct pipe_buffer **outbuf ) +{ + enum pipe_error ret = PIPE_OK; + const char *map = NULL; + + map = (const char *)pipe_buffer_map( + upload->screen, inbuf, PIPE_BUFFER_USAGE_CPU_READ ); + + if (map == NULL) { + ret = PIPE_ERROR_OUT_OF_MEMORY; + goto done; + } + + if (0) + debug_printf("upload ptr %p ofs %d sz %d\n", map, offset, size); + + ret = u_upload_data( upload, + size, + map + offset, + out_offset, + outbuf ); + if (ret) + goto done; + +done: + if (map) + pipe_buffer_unmap( upload->screen, inbuf ); + + return ret; +} diff --git a/src/gallium/auxiliary/util/u_upload_mgr.h b/src/gallium/auxiliary/util/u_upload_mgr.h new file mode 100644 index 0000000000..745b5834af --- /dev/null +++ b/src/gallium/auxiliary/util/u_upload_mgr.h @@ -0,0 +1,75 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Helper utility for uploading user buffers & other data, and + * coalescing small buffers into larger ones. + */ + +#ifndef U_UPLOAD_MGR_H +#define U_UPLOAD_MGR_H + +struct pipe_screen; +struct pipe_buffer; +struct u_upload_mgr; + + +struct u_upload_mgr *u_upload_create( struct pipe_screen *screen, + unsigned default_size, + unsigned alignment, + unsigned usage ); + +void u_upload_destroy( struct u_upload_mgr *upload ); + +/* Unmap and release old buffer. + * + * This must usually be called prior to firing the command stream + * which references the upload buffer, as many memory managers either + * don't like firing a mapped buffer or cause subsequent maps of a + * fired buffer to wait. For now, it's easiest just to grab a new + * buffer. + */ +void u_upload_flush( struct u_upload_mgr *upload ); + + +enum pipe_error u_upload_data( struct u_upload_mgr *upload, + unsigned size, + const void *data, + unsigned *out_offset, + struct pipe_buffer **outbuf ); + + +enum pipe_error u_upload_buffer( struct u_upload_mgr *upload, + unsigned offset, + unsigned size, + struct pipe_buffer *inbuf, + unsigned *out_offset, + struct pipe_buffer **outbuf ); + + + +#endif + -- cgit v1.2.3