[Mesa-dev] [PATCH 9/9] svga: Fix multiple uploads of the same user-buffer.
Thomas Hellstrom
thellstrom at vmware.com
Thu Jun 30 00:29:37 PDT 2011
If a user-buffer was referenced twice by a draw command, the affected ranges
were uploaded separately, with only the last one being referenced by the
hardware. Make sure we upload only a single range.
Signed-off-by: Thomas Hellstrom <thellstrom at vmware.com>
---
src/gallium/drivers/svga/svga_pipe_draw.c | 101 ++++++++++++++++++-----
src/gallium/drivers/svga/svga_resource_buffer.h | 13 ++--
src/gallium/drivers/svga/svga_state_vdecl.c | 6 +-
3 files changed, 90 insertions(+), 30 deletions(-)
diff --git a/src/gallium/drivers/svga/svga_pipe_draw.c b/src/gallium/drivers/svga/svga_pipe_draw.c
index 358ef82..0b4d41b 100644
--- a/src/gallium/drivers/svga/svga_pipe_draw.c
+++ b/src/gallium/drivers/svga/svga_pipe_draw.c
@@ -42,22 +42,42 @@
#include "util/u_upload_mgr.h"
/**
- * svga_upload_user_buffers - upload parts of user buffers
+ * Determine the ranges to upload for the user-buffers referenced
+ * by the next draw command.
*
- * This function streams a part of a user buffer to hw and sets
- * svga_buffer::source_offset to the first byte uploaded. After upload
- * also svga_buffer::uploaded::buffer is set to !NULL
+ * TODO: It might be beneficial to support multiple ranges. In that case,
+ * the struct svga_buffer::uploaded member should be made an array or a
+ * list, since we need to account for the possibility that different ranges
+ * may be uploaded to different hardware buffers chosen by the utility
+ * upload manager.
*/
-static int
-svga_upload_user_buffers(struct svga_context *svga,
- unsigned start,
- unsigned count,
- unsigned instance_count)
+static void
+svga_user_buffer_range(struct svga_context *svga,
+ unsigned start,
+ unsigned count,
+ unsigned instance_count)
{
const struct pipe_vertex_element *ve = svga->curr.velems->velem;
- unsigned i;
- int ret;
+ int i;
+
+ /*
+ * Release old uploaded range (if not done already) and
+ * initialize new ranges.
+ */
+
+ for (i=0; i < svga->curr.velems->count; i++) {
+ struct pipe_vertex_buffer *vb =
+ &svga->curr.vb[ve[i].vertex_buffer_index];
+
+ if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
+ struct svga_buffer *buffer = svga_buffer(vb->buffer);
+
+ pipe_resource_reference(&buffer->uploaded.buffer, NULL);
+ buffer->uploaded.start = ~0;
+ buffer->uploaded.end = 0;
+ }
+ }
for (i=0; i < svga->curr.velems->count; i++) {
struct pipe_vertex_buffer *vb =
@@ -66,30 +86,71 @@ svga_upload_user_buffers(struct svga_context *svga,
if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
struct svga_buffer *buffer = svga_buffer(vb->buffer);
unsigned first, size;
- boolean flushed;
unsigned instance_div = ve[i].instance_divisor;
unsigned elemSize = util_format_get_blocksize(ve->src_format);
svga->dirty |= SVGA_NEW_VBUFFER;
if (instance_div) {
- first = 0;
+ first = ve[i].src_offset;
count = (instance_count + instance_div - 1) / instance_div;
size = vb->stride * (count - 1) + elemSize;
} else if (vb->stride) {
- first = vb->stride * start;
+ first = vb->stride * start + ve[i].src_offset;
size = vb->stride * (count - 1) + elemSize;
} else {
/* Only a single vertex!
* Upload with the largest vertex size the hw supports,
* if possible.
*/
- first = 0;
+ first = ve[i].src_offset;
size = MIN2(16, vb->buffer->width0);
}
+ buffer->uploaded.start = MIN2(buffer->uploaded.start, first);
+ buffer->uploaded.end = MAX2(buffer->uploaded.end, first + size);
+ }
+ }
+}
+
+/**
+ * svga_upload_user_buffers - upload parts of user buffers
+ *
+ * This function streams a part of a user buffer to hw and fills
+ * svga_buffer::uploaded with information on the upload.
+ */
+
+static int
+svga_upload_user_buffers(struct svga_context *svga,
+ unsigned start,
+ unsigned count,
+ unsigned instance_count)
+{
+ const struct pipe_vertex_element *ve = svga->curr.velems->velem;
+ unsigned i;
+ int ret;
+
+ svga_user_buffer_range(svga, start, count, instance_count);
+
+ for (i=0; i < svga->curr.velems->count; i++) {
+ struct pipe_vertex_buffer *vb =
+ &svga->curr.vb[ve[i].vertex_buffer_index];
+
+ if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
+ struct svga_buffer *buffer = svga_buffer(vb->buffer);
+ boolean flushed;
+
+ /*
+ * Check if already uploaded. Otherwise go ahead and upload.
+ */
+
+ if (buffer->uploaded.buffer)
+ continue;
+
ret = u_upload_buffer( svga->upload_vb,
- 0, first, size,
+ 0,
+ buffer->uploaded.start,
+ buffer->uploaded.end - buffer->uploaded.start,
&buffer->b.b,
&buffer->uploaded.offset,
&buffer->uploaded.buffer,
@@ -106,11 +167,10 @@ svga_upload_user_buffers(struct svga_context *svga,
buffer,
buffer->uploaded.buffer,
buffer->uploaded.offset,
- first,
- size);
+ buffer->uploaded.start,
+ buffer->uploaded.end - buffer->uploaded.start);
vb->buffer_offset = buffer->uploaded.offset;
- buffer->source_offset = first;
}
}
@@ -143,7 +203,8 @@ svga_release_user_upl_buffers(struct svga_context *svga)
if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
struct svga_buffer *buffer = svga_buffer(vb->buffer);
- buffer->source_offset = 0;
+ buffer->uploaded.start = ~0;
+ buffer->uploaded.end = 0;
if (buffer->uploaded.buffer)
pipe_resource_reference(&buffer->uploaded.buffer, NULL);
}
diff --git a/src/gallium/drivers/svga/svga_resource_buffer.h b/src/gallium/drivers/svga/svga_resource_buffer.h
index 69d6f72..ca8c8d1 100644
--- a/src/gallium/drivers/svga/svga_resource_buffer.h
+++ b/src/gallium/drivers/svga/svga_resource_buffer.h
@@ -129,14 +129,13 @@ struct svga_buffer
* is the relative offset within that buffer.
*/
unsigned offset;
- } uploaded;
- /**
- * For user buffers, this is the offset to the data about to be
- * referenced by the next draw command, and hence the data that needs
- * to be uploaded.
- */
- unsigned source_offset;
+ /**
+ * Range of user buffer that is uploaded in @buffer at @offset.
+ */
+ unsigned start;
+ unsigned end;
+ } uploaded;
/**
* DMA'ble memory.
diff --git a/src/gallium/drivers/svga/svga_state_vdecl.c b/src/gallium/drivers/svga/svga_state_vdecl.c
index 2375a02..47eab1a 100644
--- a/src/gallium/drivers/svga/svga_state_vdecl.c
+++ b/src/gallium/drivers/svga/svga_state_vdecl.c
@@ -82,8 +82,8 @@ static int emit_hw_vs_vdecl( struct svga_context *svga,
continue;
buffer = svga_buffer(vb->buffer);
- if (buffer->source_offset > offset) {
- tmp_neg_bias = buffer->source_offset - offset;
+ if (buffer->uploaded.start > offset) {
+ tmp_neg_bias = buffer->uploaded.start - offset;
if (vb->stride)
tmp_neg_bias = (tmp_neg_bias + vb->stride - 1) / vb->stride;
neg_bias = MAX2(neg_bias, tmp_neg_bias);
@@ -116,7 +116,7 @@ static int emit_hw_vs_vdecl( struct svga_context *svga,
decl.array.offset = (vb->buffer_offset
+ ve[i].src_offset
+ neg_bias * vb->stride
- - buffer->source_offset);
+ - buffer->uploaded.start);
assert(decl.array.offset >= 0);
--
1.6.2.5
More information about the mesa-dev
mailing list