summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Olšák <maraeo@gmail.com>2013-02-27 23:50:15 +0100
committerIan Romanick <ian.d.romanick@intel.com>2013-03-05 14:58:04 -0800
commitf6765c6d20519476d9a52033b65e3a6d109a5115 (patch)
tree05475a0ff8d4b8e3abe261e254dbe46b656640f1
parent2c3efd2ee44ae879c3277290474618836918a8be (diff)
r600g: always map uninitialized buffer range as unsynchronized
Any driver can implement this simple and efficient optimization. Team Fortress 2 hits it always. The DISCARD_RANGE codepath is not even used with TF2 anymore, so we avoid a ton of useless buffer copies. Tested-by: Andreas Boll <andreas.boll.dev@gmail.com> NOTE: This is a candidate for the 9.1 branch. (cherry picked from commit 89e2898e9ecfcf93c337b99542b06892a8e30cbe)
-rw-r--r--src/gallium/drivers/r600/evergreen_hw_context.c3
-rw-r--r--src/gallium/drivers/r600/evergreen_state.c4
-rw-r--r--src/gallium/drivers/r600/r600.h11
-rw-r--r--src/gallium/drivers/r600/r600_buffer.c17
-rw-r--r--src/gallium/drivers/r600/r600_hw_context.c6
-rw-r--r--src/gallium/drivers/r600/r600_state_common.c4
6 files changed, 45 insertions, 0 deletions
diff --git a/src/gallium/drivers/r600/evergreen_hw_context.c b/src/gallium/drivers/r600/evergreen_hw_context.c
index bb4753062e5..bb4335347b3 100644
--- a/src/gallium/drivers/r600/evergreen_hw_context.c
+++ b/src/gallium/drivers/r600/evergreen_hw_context.c
@@ -283,4 +283,7 @@ void evergreen_dma_copy(struct r600_context *rctx,
src_offset += csize << shift;
size -= csize;
}
+
+ util_range_add(&rdst->valid_buffer_range, dst_offset,
+ dst_offset + size);
}
diff --git a/src/gallium/drivers/r600/evergreen_state.c b/src/gallium/drivers/r600/evergreen_state.c
index 4407ac5bcc2..33f306c7ef1 100644
--- a/src/gallium/drivers/r600/evergreen_state.c
+++ b/src/gallium/drivers/r600/evergreen_state.c
@@ -1322,6 +1322,10 @@ void evergreen_init_color_surface_rat(struct r600_context *rctx,
* elements. */
surf->cb_color_dim = pipe_buffer->width0;
+ /* Set the buffer range the GPU will have access to: */
+ util_range_add(&r600_resource(pipe_buffer)->valid_buffer_range,
+ 0, pipe_buffer->width0);
+
surf->cb_color_cmask = surf->cb_color_base;
surf->cb_color_cmask_slice = 0;
surf->cb_color_fmask = surf->cb_color_base;
diff --git a/src/gallium/drivers/r600/r600.h b/src/gallium/drivers/r600/r600.h
index 6832bf77d16..0115293a80e 100644
--- a/src/gallium/drivers/r600/r600.h
+++ b/src/gallium/drivers/r600/r600.h
@@ -28,6 +28,7 @@
#include "../../winsys/radeon/drm/radeon_winsys.h"
#include "util/u_double_list.h"
+#include "util/u_range.h"
#include "util/u_transfer.h"
#define R600_ERR(fmt, args...) \
@@ -50,6 +51,16 @@ struct r600_resource {
/* Resource state. */
unsigned domains;
+
+ /* The buffer range which is initialized (with a write transfer,
+ * streamout, DMA, or as a random access target). The rest of
+ * the buffer is considered invalid and can be mapped unsynchronized.
+ *
+ * This allows unsychronized mapping of a buffer range which hasn't
+ * been used yet. It's for applications which forget to use
+ * the unsynchronized map flag and expect the driver to figure it out.
+ */
+ struct util_range valid_buffer_range;
};
#define R600_BLOCK_MAX_BO 32
diff --git a/src/gallium/drivers/r600/r600_buffer.c b/src/gallium/drivers/r600/r600_buffer.c
index 89740359be0..bb85fc17522 100644
--- a/src/gallium/drivers/r600/r600_buffer.c
+++ b/src/gallium/drivers/r600/r600_buffer.c
@@ -34,6 +34,7 @@ static void r600_buffer_destroy(struct pipe_screen *screen,
{
struct r600_resource *rbuffer = r600_resource(buf);
+ util_range_destroy(&rbuffer->valid_buffer_range);
pb_reference(&rbuffer->buf, NULL);
FREE(rbuffer);
}
@@ -98,6 +99,14 @@ static void *r600_buffer_transfer_map(struct pipe_context *ctx,
assert(box->x + box->width <= resource->width0);
+ /* See if the buffer range being mapped has never been initialized,
+ * in which case it can be mapped unsynchronized. */
+ if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED) &&
+ usage & PIPE_TRANSFER_WRITE &&
+ !util_ranges_intersect(&rbuffer->valid_buffer_range, box->x, box->x + box->width)) {
+ usage |= PIPE_TRANSFER_UNSYNCHRONIZED;
+ }
+
if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE &&
!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
assert(usage & PIPE_TRANSFER_WRITE);
@@ -178,6 +187,7 @@ static void r600_buffer_transfer_unmap(struct pipe_context *pipe,
{
struct r600_context *rctx = (struct r600_context*)pipe;
struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
+ struct r600_resource *rbuffer = r600_resource(transfer->resource);
if (rtransfer->staging) {
struct pipe_resource *dst, *src;
@@ -203,6 +213,11 @@ static void r600_buffer_transfer_unmap(struct pipe_context *pipe,
}
pipe_resource_reference((struct pipe_resource**)&rtransfer->staging, NULL);
}
+
+ if (transfer->usage & PIPE_TRANSFER_WRITE) {
+ util_range_add(&rbuffer->valid_buffer_range, transfer->box.x,
+ transfer->box.x + transfer->box.width);
+ }
util_slab_free(&rctx->pool_transfers, transfer);
}
@@ -259,6 +274,7 @@ bool r600_init_resource(struct r600_screen *rscreen,
res->cs_buf = rscreen->ws->buffer_get_cs_handle(res->buf);
res->domains = domains;
+ util_range_set_empty(&res->valid_buffer_range);
return true;
}
@@ -275,6 +291,7 @@ struct pipe_resource *r600_buffer_create(struct pipe_screen *screen,
pipe_reference_init(&rbuffer->b.b.reference, 1);
rbuffer->b.b.screen = screen;
rbuffer->b.vtbl = &r600_buffer_vtbl;
+ util_range_init(&rbuffer->valid_buffer_range);
if (!r600_init_resource(rscreen, rbuffer, templ->width0, alignment, TRUE, templ->usage)) {
FREE(rbuffer);
diff --git a/src/gallium/drivers/r600/r600_hw_context.c b/src/gallium/drivers/r600/r600_hw_context.c
index a415b127896..322381ad098 100644
--- a/src/gallium/drivers/r600/r600_hw_context.c
+++ b/src/gallium/drivers/r600/r600_hw_context.c
@@ -1172,6 +1172,9 @@ void r600_cp_dma_copy_buffer(struct r600_context *rctx,
/* Invalidate the read caches. */
rctx->flags |= R600_CONTEXT_INVAL_READ_CACHES;
+
+ util_range_add(&r600_resource(dst)->valid_buffer_range, dst_offset,
+ dst_offset + size);
}
void r600_need_dma_space(struct r600_context *ctx, unsigned num_dw)
@@ -1218,4 +1221,7 @@ void r600_dma_copy(struct r600_context *rctx,
src_offset += csize << shift;
size -= csize;
}
+
+ util_range_add(&rdst->valid_buffer_range, dst_offset,
+ dst_offset + size);
}
diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c
index 35d26b365b0..f0e9de326f9 100644
--- a/src/gallium/drivers/r600/r600_state_common.c
+++ b/src/gallium/drivers/r600/r600_state_common.c
@@ -982,6 +982,7 @@ r600_create_so_target(struct pipe_context *ctx,
{
struct r600_context *rctx = (struct r600_context *)ctx;
struct r600_so_target *t;
+ struct r600_resource *rbuffer = (struct r600_resource*)buffer;
t = CALLOC_STRUCT(r600_so_target);
if (!t) {
@@ -1001,6 +1002,9 @@ r600_create_so_target(struct pipe_context *ctx,
pipe_resource_reference(&t->b.buffer, buffer);
t->b.buffer_offset = buffer_offset;
t->b.buffer_size = buffer_size;
+
+ util_range_add(&rbuffer->valid_buffer_range, buffer_offset,
+ buffer_offset + buffer_size);
return &t->b;
}