svga: Fix multiple uploads of the same user-buffer.
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@vmware.com>
This commit is contained in:
parent
a8cf4b6acf
commit
542194251c
|
@ -41,12 +41,83 @@
|
|||
#include "svga_resource_buffer.h"
|
||||
#include "util/u_upload_mgr.h"
|
||||
|
||||
/**
|
||||
* Determine the ranges to upload for the user-buffers referenced
|
||||
* by the next draw command.
|
||||
*
|
||||
* 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 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;
|
||||
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 =
|
||||
&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);
|
||||
unsigned first, size;
|
||||
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 = 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 + 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 = 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 sets
|
||||
* svga_buffer::source_offset to the first byte uploaded. After upload
|
||||
* also svga_buffer::uploaded::buffer is set to !NULL
|
||||
* This function streams a part of a user buffer to hw and fills
|
||||
* svga_buffer::uploaded with information on the upload.
|
||||
*/
|
||||
|
||||
static int
|
||||
|
@ -59,37 +130,27 @@ svga_upload_user_buffers(struct svga_context *svga,
|
|||
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);
|
||||
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;
|
||||
/*
|
||||
* Check if already uploaded. Otherwise go ahead and upload.
|
||||
*/
|
||||
|
||||
if (instance_div) {
|
||||
first = 0;
|
||||
count = (instance_count + instance_div - 1) / instance_div;
|
||||
size = vb->stride * (count - 1) + elemSize;
|
||||
} else if (vb->stride) {
|
||||
first = vb->stride * start;
|
||||
size = vb->stride * (count - 1) + elemSize;
|
||||
} else {
|
||||
/* Only a single vertex!
|
||||
* Upload with the largest vertex size the hw supports,
|
||||
* if possible.
|
||||
*/
|
||||
first = 0;
|
||||
size = MIN2(16, vb->buffer->width0);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue