[Mesa-dev] [PATCH 3/3] swr: Add path to draw directly from client memory without copy.
Bruce Cherniak
bruce.cherniak at intel.com
Wed Jul 12 01:20:38 UTC 2017
If size of client memory copy is too large, don't copy. The draw will
access user-buffer directly and then block. This is faster and more
efficient than queuing many large client draws.
Applications that use large draws from client arrays benefit from this.
VMD is an example.
The threshold for this path defaults to 32KB. This value can be
overridden by setting environment variable SWR_CLIENT_COPY_LIMIT.
---
src/gallium/drivers/swr/swr_context.h | 1 +
src/gallium/drivers/swr/swr_draw.cpp | 9 +++++++++
src/gallium/drivers/swr/swr_screen.cpp | 10 +++++++++
src/gallium/drivers/swr/swr_screen.h | 2 ++
src/gallium/drivers/swr/swr_state.cpp | 37 ++++++++++++++++++++++++----------
5 files changed, 48 insertions(+), 11 deletions(-)
diff --git a/src/gallium/drivers/swr/swr_context.h b/src/gallium/drivers/swr/swr_context.h
index 3ff4bf3e2f..ab3057af96 100644
--- a/src/gallium/drivers/swr/swr_context.h
+++ b/src/gallium/drivers/swr/swr_context.h
@@ -51,6 +51,7 @@
#define SWR_NEW_FRAMEBUFFER (1 << 15)
#define SWR_NEW_CLIP (1 << 16)
#define SWR_NEW_SO (1 << 17)
+#define SWR_LARGE_CLIENT_DRAW (1<<18) // Indicates client draw will block
namespace std
{
diff --git a/src/gallium/drivers/swr/swr_draw.cpp b/src/gallium/drivers/swr/swr_draw.cpp
index f26b8e873c..cbd1558624 100644
--- a/src/gallium/drivers/swr/swr_draw.cpp
+++ b/src/gallium/drivers/swr/swr_draw.cpp
@@ -188,6 +188,15 @@ swr_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
info->instance_count,
info->start,
info->start_instance);
+
+ /* On large client-buffer draw, we used client buffer directly, without
+ * copy. Block until draw is finished.
+ * VMD is an example application that benefits from this. */
+ if (ctx->dirty & SWR_LARGE_CLIENT_DRAW) {
+ struct swr_screen *screen = swr_screen(pipe->screen);
+ swr_fence_submit(ctx, screen->flush_fence);
+ swr_fence_finish(pipe->screen, NULL, screen->flush_fence, 0);
+ }
}
diff --git a/src/gallium/drivers/swr/swr_screen.cpp b/src/gallium/drivers/swr/swr_screen.cpp
index 9b3897ce6b..8be09697e6 100644
--- a/src/gallium/drivers/swr/swr_screen.cpp
+++ b/src/gallium/drivers/swr/swr_screen.cpp
@@ -1066,6 +1066,16 @@ swr_destroy_screen(struct pipe_screen *p_screen)
static void
swr_validate_env_options(struct swr_screen *screen)
{
+ /* The client_copy_limit sets a maximum on the amount of user-buffer memory
+ * copied to scratch space on a draw. Past this, the draw will access
+ * user-buffer directly and then block. This is faster than queuing many
+ * large client draws. */
+ screen->client_copy_limit = 32768;
+ int client_copy_limit =
+ debug_get_num_option("SWR_CLIENT_COPY_LIMIT", 32768);
+ if (client_copy_limit > 0)
+ screen->client_copy_limit = client_copy_limit;
+
/* XXX msaa under development, disable by default for now */
screen->msaa_max_count = 0; /* was SWR_MAX_NUM_MULTISAMPLES; */
diff --git a/src/gallium/drivers/swr/swr_screen.h b/src/gallium/drivers/swr/swr_screen.h
index dc1bb47f02..6d6d1cb87d 100644
--- a/src/gallium/drivers/swr/swr_screen.h
+++ b/src/gallium/drivers/swr/swr_screen.h
@@ -43,8 +43,10 @@ struct swr_screen {
struct sw_winsys *winsys;
+ /* Configurable environment settings */
boolean msaa_force_enable;
uint8_t msaa_max_count;
+ uint32_t client_copy_limit;
HANDLE hJitMgr;
};
diff --git a/src/gallium/drivers/swr/swr_state.cpp b/src/gallium/drivers/swr/swr_state.cpp
index 45c9c213e5..6c406a37ec 100644
--- a/src/gallium/drivers/swr/swr_state.cpp
+++ b/src/gallium/drivers/swr/swr_state.cpp
@@ -1267,12 +1267,20 @@ swr_update_derived(struct pipe_context *pipe,
partial_inbounds = 0;
min_vertex_index = info.min_index;
- /* Copy only needed vertices to scratch space */
size = AlignUp(size, 4);
- const void *ptr = (const uint8_t *) vb->buffer.user + base;
- ptr = (uint8_t *)swr_copy_to_scratch_space(
- ctx, &ctx->scratch->vertex_buffer, ptr, size);
- p_data = (const uint8_t *)ptr - base;
+ /* If size of client memory copy is too large, don't copy. The
+ * draw will access user-buffer directly and then block. This is
+ * faster than queuing many large client draws. */
+ if (size >= screen->client_copy_limit) {
+ post_update_dirty_flags |= SWR_LARGE_CLIENT_DRAW;
+ p_data = (const uint8_t *) vb->buffer.user;
+ } else {
+ /* Copy only needed vertices to scratch space */
+ const void *ptr = (const uint8_t *) vb->buffer.user + base;
+ ptr = (uint8_t *)swr_copy_to_scratch_space(
+ ctx, &ctx->scratch->vertex_buffer, ptr, size);
+ p_data = (const uint8_t *)ptr - base;
+ }
}
swrVertexBuffers[i] = {0};
@@ -1311,12 +1319,19 @@ swr_update_derived(struct pipe_context *pipe,
size = info.count * pitch;
size = AlignUp(size, 4);
-
- /* Copy indices to scratch space */
- const void *ptr = info.index.user;
- ptr = swr_copy_to_scratch_space(
- ctx, &ctx->scratch->index_buffer, ptr, size);
- p_data = (const uint8_t *)ptr;
+ /* If size of client memory copy is too large, don't copy. The
+ * draw will access user-buffer directly and then block. This is
+ * faster than queuing many large client draws. */
+ if (size >= screen->client_copy_limit) {
+ post_update_dirty_flags |= SWR_LARGE_CLIENT_DRAW;
+ p_data = (const uint8_t *) info.index.user;
+ } else {
+ /* Copy indices to scratch space */
+ const void *ptr = info.index.user;
+ ptr = swr_copy_to_scratch_space(
+ ctx, &ctx->scratch->index_buffer, ptr, size);
+ p_data = (const uint8_t *)ptr;
+ }
}
SWR_INDEX_BUFFER_STATE swrIndexBuffer;
--
2.11.0
More information about the mesa-dev
mailing list