[Mesa-dev] [PATCH] gallium/util: Upload manager optimizations
José Fonseca
jfonseca at vmware.com
Fri Mar 11 03:52:58 PST 2011
On Fri, 2011-03-11 at 02:06 -0800, Thomas Hellstrom wrote:
> On 03/10/2011 04:57 PM, José Fonseca wrote:
> > On Thu, 2011-03-10 at 06:01 -0800, Thomas Hellstrom wrote:
> >
> >> Make sure that the upload manager doesn't upload data that's not
> >> dirty. This speeds up the viewperf test proe-04/1 a factor 5 or so on svga.
> >>
> > Sweet!
> >
> > A few comments inline
> >
> >
> >> Also introduce an u_upload_unmap() function that can be used
> >> instead of u_upload_flush() so that we can pack
> >> even more data in upload buffers. With this we can basically reuse the
> >> upload buffer across flushes.
> >>
> >> Signed-off-by: Thomas Hellstrom<thellstrom at vmware.com>
> >> ---
> >> src/gallium/auxiliary/util/u_upload_mgr.c | 41 ++++++++++++++++++++++------
> >> src/gallium/auxiliary/util/u_upload_mgr.h | 10 +++++++
> >> 2 files changed, 42 insertions(+), 9 deletions(-)
> >>
> >> diff --git a/src/gallium/auxiliary/util/u_upload_mgr.c b/src/gallium/auxiliary/util/u_upload_mgr.c
> >> index dcf800a..7768e13 100644
> >> --- a/src/gallium/auxiliary/util/u_upload_mgr.c
> >> +++ b/src/gallium/auxiliary/util/u_upload_mgr.c
> >> @@ -51,6 +51,7 @@ struct u_upload_mgr {
> >> unsigned size; /* Actual size of the upload buffer. */
> >> unsigned offset; /* Aligned offset to the upload buffer, pointing
> >> * at the first unused byte. */
> >> + unsigned uploaded_offs; /* Offset below which data is already uploaded */
> >>
> > It's not clear the difference between offset and uploaded_offs. More
> > about this below.
> >
> >
> >> };
> >>
> >>
> >> @@ -72,6 +73,22 @@ struct u_upload_mgr *u_upload_create( struct pipe_context *pipe,
> >> return upload;
> >> }
> >>
> >> +void u_upload_unmap( struct u_upload_mgr *upload )
> >> +{
> >> + if (upload->transfer) {
> >> + if (upload->size> upload->uploaded_offs) {
> >> + pipe_buffer_flush_mapped_range(upload->pipe, upload->transfer,
> >> + upload->uploaded_offs,
> >> + upload->offset - upload->uploaded_offs);
> >> + }
> >> + pipe_transfer_unmap(upload->pipe, upload->transfer);
> >> + pipe_transfer_destroy(upload->pipe, upload->transfer);
> >> + upload->transfer = NULL;
> >> + upload->uploaded_offs = upload->offset;
> >> + upload->map = NULL;
> >> + }
> >> +}
> >> +
> >> /* Release old buffer.
> >> *
> >> * This must usually be called prior to firing the command stream
> >> @@ -84,17 +101,10 @@ struct u_upload_mgr *u_upload_create( struct pipe_context *pipe,
> >> void u_upload_flush( struct u_upload_mgr *upload )
> >> {
> >> /* Unmap and unreference the upload buffer. */
> >> - if (upload->transfer) {
> >> - if (upload->size) {
> >> - pipe_buffer_flush_mapped_range(upload->pipe, upload->transfer,
> >> - 0, upload->size);
> >> - }
> >> - pipe_transfer_unmap(upload->pipe, upload->transfer);
> >> - pipe_transfer_destroy(upload->pipe, upload->transfer);
> >> - upload->transfer = NULL;
> >> - }
> >> + u_upload_unmap(upload);
> >> pipe_resource_reference(&upload->buffer, NULL );
> >> upload->size = 0;
> >> + upload->uploaded_offs = 0;
> >> }
> >>
> >>
> >> @@ -172,6 +182,19 @@ enum pipe_error u_upload_alloc( struct u_upload_mgr *upload,
> >>
> >> offset = MAX2(upload->offset, alloc_offset);
> >>
> >> + if (!upload->map) {
> >> + upload->map = pipe_buffer_map_range(upload->pipe, upload->buffer,
> >> + 0, upload->size,
> >> + PIPE_TRANSFER_WRITE |
> >> + PIPE_TRANSFER_FLUSH_EXPLICIT |
> >> + PIPE_TRANSFER_UNSYNCHRONIZED,
> >> + &upload->transfer);
> >> +
> >>
> > Instead of the whole range, we should mapping only the area of
> > interest.
> >
> > That is, of [0, upload->size], it should be [upload->uploaded_offs,
> > upload->size - uploaded_offs].
> >
> > This mean that the driver / kernel does not need to populate the bytes
> > from [0, uploaded_offs] in the case where the contents is already gone
> > to VRAM.
> >
> > I think uploaded_offs should be renamed to mapped_offset, i.e., "the
> > offset from which the buffer is currently mapped".
> >
>
> Agreed.
>
>
> >
> >> + assert(offset>= upload->uploaded_offs);
> >> + upload->uploaded_offs = offset;
> >> + }
> >> +
> >> assert(offset< upload->buffer->width0);
> >> assert(offset + size<= upload->buffer->width0);
> >> assert(size);
> >> diff --git a/src/gallium/auxiliary/util/u_upload_mgr.h b/src/gallium/auxiliary/util/u_upload_mgr.h
> >> index c9a2ffe..02426ea 100644
> >> --- a/src/gallium/auxiliary/util/u_upload_mgr.h
> >> +++ b/src/gallium/auxiliary/util/u_upload_mgr.h
> >> @@ -67,6 +67,16 @@ void u_upload_destroy( struct u_upload_mgr *upload );
> >> void u_upload_flush( struct u_upload_mgr *upload );
> >>
> >> /**
> >> + * Unmap upload buffer
> >> + *
> >> + * \param upload Upload manager
> >> + *
> >> + * This is like u_upload_flush() except the upload buffer is kept for
> >> + * re-use across flushes. Allows us to pack more data into upload buffers.
> >> + */
> >> +void u_upload_unmap( struct u_upload_mgr *upload );
> >>
> > These are two very different modes of operation.
> >
> > When doing this, the uploaded buffer should be created with
> > PIPE_USAGE_STREAM and/or PIPE_USAGE_DYNAMIC (need to double check the
> > smantics of this), so that the driver can put this buffer in an
> > appropriate type of memory.
> >
> > When not doing this, then the uploaded buffer should use
> > PIPE_USAGE_STATIC or IMMUTABLE (u_upload_mgr actually gets this wrong
> > now).
> >
> > Instead of a new u_upload_unmap, I think that there should be a new flag
> > a u_upload_mgr create, or this should be done always. Is there really a
> > use case where we do not want to use this?
> >
>
> Yes. IMHO the difference is resource management in the general case.
> Imagine a driver that is short on HW buffers for whatever reason. It
> detects that and calls a context flush to eventually release more
> buffers. That flush should release also the upload buffer, and the
> driver should call u_upload_flush() instead of u_upload_unmap(). My
> initial implementation in the SVGA driver used u_upload_unmap() for
> hwtnl flushes and u_upload_flush for svga context flushes. This is more
> clearly illustrated if the u_upload_manager were to be extended with an
> optional small ring cache of hardware buffers.
I see, good point. Separate u_upload_unmap u_upload_flush as you have
make all sense then.
Jose
More information about the mesa-dev
mailing list