Mesa (master): u_upload_mgr: new features

Marek Olšák mareko at kemper.freedesktop.org
Thu Jan 6 07:27:40 PST 2011


Module: Mesa
Branch: master
Commit: 06286110b4fc0ff80ae21bb3d8ff9909db1f5d47
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=06286110b4fc0ff80ae21bb3d8ff9909db1f5d47

Author: Marek Olšák <maraeo at gmail.com>
Date:   Mon Dec 27 22:32:31 2010 +0100

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.

---

 src/gallium/auxiliary/util/u_upload_mgr.c     |   75 +++++++++++++++++--------
 src/gallium/auxiliary/util/u_upload_mgr.h     |   43 +++++++++++++-
 src/gallium/drivers/i965/brw_draw_upload.c    |   12 +++-
 src/gallium/drivers/r300/r300_screen_buffer.c |   10 ++-
 src/gallium/drivers/svga/svga_draw_elements.c |    5 +-
 src/gallium/drivers/svga/svga_state_vdecl.c   |    6 +-
 6 files changed, 115 insertions(+), 36 deletions(-)

diff --git a/src/gallium/auxiliary/util/u_upload_mgr.c b/src/gallium/auxiliary/util/u_upload_mgr.c
index 4d97bf0..80c9b63 100644
--- a/src/gallium/auxiliary/util/u_upload_mgr.c
+++ b/src/gallium/auxiliary/util/u_upload_mgr.c
@@ -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)
diff --git a/src/gallium/auxiliary/util/u_upload_mgr.h b/src/gallium/auxiliary/util/u_upload_mgr.h
index de016df..fc8f4d3 100644
--- a/src/gallium/auxiliary/util/u_upload_mgr.h
+++ b/src/gallium/auxiliary/util/u_upload_mgr.h
@@ -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 );
 
 
 
diff --git a/src/gallium/drivers/i965/brw_draw_upload.c b/src/gallium/drivers/i965/brw_draw_upload.c
index ebeb1e1..cf94054 100644
--- a/src/gallium/drivers/i965/brw_draw_upload.c
+++ b/src/gallium/drivers/i965/brw_draw_upload.c
@@ -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;
 
diff --git a/src/gallium/drivers/r300/r300_screen_buffer.c b/src/gallium/drivers/r300/r300_screen_buffer.c
index f969981..11ad87e 100644
--- a/src/gallium/drivers/r300/r300_screen_buffer.c
+++ b/src/gallium/drivers/r300/r300_screen_buffer.c
@@ -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;
diff --git a/src/gallium/drivers/svga/svga_draw_elements.c b/src/gallium/drivers/svga/svga_draw_elements.c
index c7ea014..83527c6 100644
--- a/src/gallium/drivers/svga/svga_draw_elements.c
+++ b/src/gallium/drivers/svga/svga_draw_elements.c
@@ -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;
 
diff --git a/src/gallium/drivers/svga/svga_state_vdecl.c b/src/gallium/drivers/svga/svga_state_vdecl.c
index 3af7bf2..958d003 100644
--- a/src/gallium/drivers/svga/svga_state_vdecl.c
+++ b/src/gallium/drivers/svga/svga_state_vdecl.c
@@ -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;
 



More information about the mesa-commit mailing list