diff options
author | Alexandros Frantzis <[email protected]> | 2019-05-08 12:10:21 +0300 |
---|---|---|
committer | Chia-I Wu <[email protected]> | 2019-06-07 21:45:39 -0700 |
commit | a22c5df0794515369ce0c2b35ef8cd089b6975f3 (patch) | |
tree | c9e680d71d25ae20b44dbf5a4df670149a0c1f22 /src/gallium/drivers/virgl/virgl_buffer.c | |
parent | 6e7726e50c44c28969b20dc79e5c6f7a26eb6edd (diff) |
virgl: Use buffer copy transfers to avoid waiting when mapping
We typically need to wait for a buffer to become ready before mapping,
so that we don't write new contents while the host is still using the
old contents. However, if we are allowed to discard the contents of the
mapped buffer range, then we can avoid waiting by using a staging buffer
range which we guarantee to never be busy, copying from the staging
buffer range to the target buffer in the host.
This commit implements this optimization by utilizing a dedicated
u_upload_mgr for the staging buffer.
Performance results:
Twilight Struggle (Steam/Proton), qemu before: 7 FPS after: 25 FPS
glmark2 ubo, qemu before: 38 FPS after: 331 FPS
Signed-off-by: Alexandros Frantzis <[email protected]>
Suggested-by: Gurchetan Singh <[email protected]>
Reviewed-by: Chia-I Wu <[email protected]>
Diffstat (limited to 'src/gallium/drivers/virgl/virgl_buffer.c')
-rw-r--r-- | src/gallium/drivers/virgl/virgl_buffer.c | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/src/gallium/drivers/virgl/virgl_buffer.c b/src/gallium/drivers/virgl/virgl_buffer.c index 284eeca4d8f..882fae2f8ba 100644 --- a/src/gallium/drivers/virgl/virgl_buffer.c +++ b/src/gallium/drivers/virgl/virgl_buffer.c @@ -24,6 +24,7 @@ #include "util/u_inlines.h" #include "util/u_memory.h" #include "virgl_context.h" +#include "virgl_encode.h" #include "virgl_resource.h" #include "virgl_screen.h" @@ -39,6 +40,7 @@ static void *virgl_buffer_transfer_map(struct pipe_context *ctx, struct virgl_resource *vbuf = virgl_resource(resource); struct virgl_transfer *trans; enum virgl_transfer_map_type map_type; + void *map_addr; trans = virgl_resource_create_transfer(&vctx->transfer_pool, resource, &vbuf->metadata, level, usage, box); @@ -47,14 +49,24 @@ static void *virgl_buffer_transfer_map(struct pipe_context *ctx, switch (map_type) { case VIRGL_TRANSFER_MAP_HW_RES: trans->hw_res_map = vs->vws->resource_map(vs->vws, vbuf->hw_res); + if (trans->hw_res_map) + map_addr = trans->hw_res_map + trans->offset; + else + map_addr = NULL; + break; + case VIRGL_TRANSFER_MAP_STAGING: + map_addr = virgl_transfer_uploader_map(vctx, trans); + /* Copy transfers don't make use of hw_res_map at the moment. */ + trans->hw_res_map = NULL; break; case VIRGL_TRANSFER_MAP_ERROR: default: trans->hw_res_map = NULL; + map_addr = NULL; break; } - if (!trans->hw_res_map) { + if (!map_addr) { virgl_resource_destroy_transfer(&vctx->transfer_pool, trans); return NULL; } @@ -63,7 +75,7 @@ static void *virgl_buffer_transfer_map(struct pipe_context *ctx, util_range_add(&vbuf->valid_buffer_range, box->x, box->x + box->width); *transfer = &trans->base; - return trans->hw_res_map + trans->offset; + return map_addr; } static void virgl_buffer_transfer_unmap(struct pipe_context *ctx, @@ -71,6 +83,15 @@ static void virgl_buffer_transfer_unmap(struct pipe_context *ctx, { struct virgl_context *vctx = virgl_context(ctx); struct virgl_transfer *trans = virgl_transfer(transfer); + struct virgl_screen *vs = virgl_screen(ctx->screen); + struct pipe_resource *res = transfer->resource; + + /* We don't need to transfer the contents of staging buffers, since they + * don't have any host-side storage. */ + if (pipe_to_virgl_bind(vs, res->bind, res->flags) == VIRGL_BIND_STAGING) { + virgl_resource_destroy_transfer(&vctx->transfer_pool, trans); + return; + } if (trans->base.usage & PIPE_TRANSFER_WRITE) { if (transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) { @@ -84,7 +105,14 @@ static void virgl_buffer_transfer_unmap(struct pipe_context *ctx, trans->offset = transfer->box.x; } - virgl_transfer_queue_unmap(&vctx->queue, trans); + if (trans->copy_src_res) { + virgl_encode_copy_transfer(vctx, trans); + /* It's now safe for other mappings to use the transfer_uploader. */ + vctx->transfer_uploader_in_use = false; + virgl_resource_destroy_transfer(&vctx->transfer_pool, trans); + } else { + virgl_transfer_queue_unmap(&vctx->queue, trans); + } } else virgl_resource_destroy_transfer(&vctx->transfer_pool, trans); } |