virgl: Use virgl_staging_mgr
Use an instance of virgl_staging_mgr instead of u_upload_mgr to handle the staging buffer. This removes the need to track the availability of the staging manager, since virgl_staging_mgr can handle concurrent active allocations. Signed-off-by: Alexandros Frantzis <alexandros.frantzis@collabora.com> Reviewed-by: Chia-I Wu <olvaffe@gmail.com>
This commit is contained in:
committed by
Chia-I Wu
parent
790d1a0b17
commit
5388be039b
@@ -62,7 +62,7 @@ static void *virgl_buffer_transfer_map(struct pipe_context *ctx,
|
||||
map_addr = NULL;
|
||||
break;
|
||||
case VIRGL_TRANSFER_MAP_STAGING:
|
||||
map_addr = virgl_transfer_uploader_map(vctx, trans);
|
||||
map_addr = virgl_staging_map(vctx, trans);
|
||||
/* Copy transfers don't make use of hw_res_map at the moment. */
|
||||
trans->hw_res_map = NULL;
|
||||
break;
|
||||
@@ -93,12 +93,9 @@ static void virgl_buffer_transfer_unmap(struct pipe_context *ctx,
|
||||
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, trans);
|
||||
return;
|
||||
}
|
||||
/* We don't transfer the contents of staging resources, since they don't
|
||||
* have any host-side storage. */
|
||||
assert(pipe_to_virgl_bind(vs, res->bind, res->flags) != VIRGL_BIND_STAGING);
|
||||
|
||||
if (trans->base.usage & PIPE_TRANSFER_WRITE) {
|
||||
if (transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) {
|
||||
@@ -114,8 +111,6 @@ static void virgl_buffer_transfer_unmap(struct pipe_context *ctx,
|
||||
|
||||
if (trans->copy_src_hw_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, trans);
|
||||
} else {
|
||||
virgl_transfer_queue_unmap(&vctx->queue, trans);
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "virgl_protocol.h"
|
||||
#include "virgl_resource.h"
|
||||
#include "virgl_screen.h"
|
||||
#include "virgl_staging_mgr.h"
|
||||
|
||||
struct virgl_vertex_elements_state {
|
||||
uint32_t handle;
|
||||
@@ -1372,8 +1373,8 @@ virgl_context_destroy( struct pipe_context *ctx )
|
||||
rs->vws->cmd_buf_destroy(vctx->cbuf);
|
||||
if (vctx->uploader)
|
||||
u_upload_destroy(vctx->uploader);
|
||||
if (vctx->transfer_uploader)
|
||||
u_upload_destroy(vctx->transfer_uploader);
|
||||
if (vctx->supports_staging)
|
||||
virgl_staging_destroy(&vctx->staging);
|
||||
util_primconvert_destroy(vctx->primconvert);
|
||||
virgl_transfer_queue_fini(&vctx->queue);
|
||||
|
||||
@@ -1547,17 +1548,12 @@ struct pipe_context *virgl_context_create(struct pipe_screen *pscreen,
|
||||
goto fail;
|
||||
vctx->base.stream_uploader = vctx->uploader;
|
||||
vctx->base.const_uploader = vctx->uploader;
|
||||
/* Use a custom/staging buffer for the transfer uploader, since we are
|
||||
* using it only for copies to other resources.
|
||||
*/
|
||||
|
||||
/* We use a special staging buffer as the source of copy transfers. */
|
||||
if ((rs->caps.caps.v2.capability_bits & VIRGL_CAP_COPY_TRANSFER) &&
|
||||
vctx->encoded_transfers) {
|
||||
vctx->transfer_uploader = u_upload_create(&vctx->base, 1024 * 1024,
|
||||
PIPE_BIND_CUSTOM,
|
||||
PIPE_USAGE_STAGING,
|
||||
VIRGL_RESOURCE_FLAG_STAGING);
|
||||
if (!vctx->transfer_uploader)
|
||||
goto fail;
|
||||
virgl_staging_init(&vctx->staging, &vctx->base, 1024 * 1024);
|
||||
vctx->supports_staging = true;
|
||||
}
|
||||
|
||||
vctx->hw_sub_ctx_id = rs->sub_ctx_id++;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "util/slab.h"
|
||||
#include "util/list.h"
|
||||
|
||||
#include "virgl_staging_mgr.h"
|
||||
#include "virgl_transfer_queue.h"
|
||||
|
||||
struct pipe_screen;
|
||||
@@ -81,9 +82,9 @@ struct virgl_context {
|
||||
struct slab_child_pool transfer_pool;
|
||||
struct virgl_transfer_queue queue;
|
||||
struct u_upload_mgr *uploader;
|
||||
struct u_upload_mgr *transfer_uploader;
|
||||
bool transfer_uploader_in_use;
|
||||
struct virgl_staging_mgr staging;
|
||||
bool encoded_transfers;
|
||||
bool supports_staging;
|
||||
|
||||
struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS];
|
||||
unsigned num_vertex_buffers;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "virgl_context.h"
|
||||
#include "virgl_resource.h"
|
||||
#include "virgl_screen.h"
|
||||
#include "virgl_staging_mgr.h"
|
||||
|
||||
/* A (soft) limit for the amount of memory we want to allow for queued staging
|
||||
* resources. This is used to decide when we should force a flush, in order to
|
||||
@@ -144,8 +145,7 @@ virgl_resource_transfer_prepare(struct virgl_context *vctx,
|
||||
if (xfer->base.usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
|
||||
can_realloc = virgl_can_rebind_resource(vctx, &res->u.b);
|
||||
} else {
|
||||
can_staging = vctx->transfer_uploader &&
|
||||
!vctx->transfer_uploader_in_use;
|
||||
can_staging = vctx->supports_staging;
|
||||
}
|
||||
|
||||
/* discard implies no readback */
|
||||
@@ -564,20 +564,19 @@ static unsigned virgl_transfer_map_size(struct virgl_transfer *vtransfer,
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Maps a region from the transfer uploader to service the transfer. */
|
||||
void *virgl_transfer_uploader_map(struct virgl_context *vctx,
|
||||
struct virgl_transfer *vtransfer)
|
||||
/* Maps a region from staging to service the transfer. */
|
||||
void *virgl_staging_map(struct virgl_context *vctx,
|
||||
struct virgl_transfer *vtransfer)
|
||||
{
|
||||
struct virgl_resource *vres = virgl_resource(vtransfer->base.resource);
|
||||
struct pipe_resource *copy_src_res = NULL;
|
||||
unsigned size;
|
||||
unsigned align_offset;
|
||||
unsigned stride;
|
||||
unsigned layer_stride;
|
||||
void *map_addr;
|
||||
bool alloc_succeeded;
|
||||
|
||||
assert(vctx->transfer_uploader);
|
||||
assert(!vctx->transfer_uploader_in_use);
|
||||
assert(vctx->supports_staging);
|
||||
|
||||
size = virgl_transfer_map_size(vtransfer, &stride, &layer_stride);
|
||||
|
||||
@@ -598,18 +597,13 @@ void *virgl_transfer_uploader_map(struct virgl_context *vctx,
|
||||
vtransfer->base.box.x % VIRGL_MAP_BUFFER_ALIGNMENT :
|
||||
0;
|
||||
|
||||
u_upload_alloc(vctx->transfer_uploader, 0, size + align_offset,
|
||||
VIRGL_MAP_BUFFER_ALIGNMENT,
|
||||
&vtransfer->copy_src_offset,
|
||||
©_src_res, &map_addr);
|
||||
if (map_addr) {
|
||||
struct virgl_winsys *vws = virgl_screen(vctx->base.screen)->vws;
|
||||
|
||||
/* Extract and reference the hw_res backing the pipe_resource. */
|
||||
vws->resource_reference(vws, &vtransfer->copy_src_hw_res,
|
||||
virgl_resource(copy_src_res)->hw_res);
|
||||
pipe_resource_reference(©_src_res, NULL);
|
||||
|
||||
alloc_succeeded =
|
||||
virgl_staging_alloc(&vctx->staging, size + align_offset,
|
||||
VIRGL_MAP_BUFFER_ALIGNMENT,
|
||||
&vtransfer->copy_src_offset,
|
||||
&vtransfer->copy_src_hw_res,
|
||||
&map_addr);
|
||||
if (alloc_succeeded) {
|
||||
/* Update source offset and address to point to the requested x coordinate
|
||||
* if we have an align_offset (see above for more information). */
|
||||
vtransfer->copy_src_offset += align_offset;
|
||||
@@ -621,10 +615,6 @@ void *virgl_transfer_uploader_map(struct virgl_context *vctx,
|
||||
*/
|
||||
virgl_resource_dirty(vres, vtransfer->base.level);
|
||||
|
||||
/* The pointer returned by u_upload_alloc already has +offset
|
||||
* applied. */
|
||||
vctx->transfer_uploader_in_use = true;
|
||||
|
||||
/* We are using the minimum required size to hold the contents,
|
||||
* possibly using a layout different from the layout of the resource,
|
||||
* so update the transfer strides accordingly.
|
||||
|
||||
@@ -190,8 +190,8 @@ boolean virgl_resource_get_handle(struct pipe_screen *screen,
|
||||
|
||||
void virgl_resource_dirty(struct virgl_resource *res, uint32_t level);
|
||||
|
||||
void *virgl_transfer_uploader_map(struct virgl_context *vctx,
|
||||
struct virgl_transfer *vtransfer);
|
||||
void *virgl_staging_map(struct virgl_context *vctx,
|
||||
struct virgl_transfer *vtransfer);
|
||||
|
||||
bool
|
||||
virgl_resource_realloc(struct virgl_context *vctx,
|
||||
|
||||
@@ -149,7 +149,7 @@ static void *texture_transfer_map_plain(struct pipe_context *ctx,
|
||||
map_addr = NULL;
|
||||
break;
|
||||
case VIRGL_TRANSFER_MAP_STAGING:
|
||||
map_addr = virgl_transfer_uploader_map(vctx, trans);
|
||||
map_addr = virgl_staging_map(vctx, trans);
|
||||
/* Copy transfers don't make use of hw_res_map at the moment. */
|
||||
trans->hw_res_map = NULL;
|
||||
break;
|
||||
@@ -317,12 +317,9 @@ static void virgl_texture_transfer_unmap(struct pipe_context *ctx,
|
||||
struct pipe_resource *res = transfer->resource;
|
||||
bool queue_unmap = false;
|
||||
|
||||
/* 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, trans);
|
||||
return;
|
||||
}
|
||||
/* We don't transfer the contents of staging resources, since they don't
|
||||
* have any host-side storage. */
|
||||
assert(pipe_to_virgl_bind(vs, res->bind, res->flags) != VIRGL_BIND_STAGING);
|
||||
|
||||
if (transfer->usage & PIPE_TRANSFER_WRITE &&
|
||||
(transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) == 0) {
|
||||
@@ -357,8 +354,6 @@ static void virgl_texture_transfer_unmap(struct pipe_context *ctx,
|
||||
if (queue_unmap) {
|
||||
if (trans->copy_src_hw_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, trans);
|
||||
} else {
|
||||
virgl_transfer_queue_unmap(&vctx->queue, trans);
|
||||
|
||||
Reference in New Issue
Block a user