Commit 20988d95 authored by Chia-I Wu's avatar Chia-I Wu
Browse files

virgl: patch transfers into the cmdbuf



When a transfer is added to the transfer queue, we reserve some
space in the cmdbuf.  When the transfer queue is flushed, we patch
the reserved space with the final transfer command for each
transfer.  This allows us to get rid of VIRGL_MAX_TBUF_DWORDS.

Our internal use of u_upload is special.  We expect it to be mapped
persistently and coherently until we flush.  The space for the
transfer command must be reserved at map time rather than at unmap
time.
Signed-off-by: Chia-I Wu's avatarChia-I Wu <olvaffe@gmail.com>
parent 2f0b619e
Pipeline #47710 passed with stages
in 10 minutes and 20 seconds
......@@ -893,7 +893,7 @@ static void virgl_flush_eq(struct virgl_context *ctx, void *closure,
/* skip empty cbuf */
if (ctx->cbuf->cdw == ctx->cbuf_initial_cdw &&
ctx->queue.num_dwords == 0 &&
virgl_transfer_queue_is_empty(&ctx->queue) &&
!fence)
return;
......@@ -907,10 +907,6 @@ static void virgl_flush_eq(struct virgl_context *ctx, void *closure,
virgl_submit_cmd(rs->vws, ctx->cbuf, fence);
/* Reserve some space for transfers. */
if (ctx->encoded_transfers)
ctx->cbuf->cdw = VIRGL_MAX_TBUF_DWORDS;
virgl_encoder_set_sub_ctx(ctx, ctx->hw_sub_ctx_id);
ctx->cbuf_initial_cdw = ctx->cbuf->cdw;
......@@ -1537,13 +1533,11 @@ struct pipe_context *virgl_context_create(struct pipe_screen *pscreen,
vctx->encoded_transfers = (rs->vws->supports_encoded_transfers &&
(rs->caps.caps.v2.capability_bits & VIRGL_CAP_TRANSFER));
/* Reserve some space for transfers. */
if (vctx->encoded_transfers)
vctx->cbuf->cdw = VIRGL_MAX_TBUF_DWORDS;
vctx->primconvert = util_primconvert_create(&vctx->base, rs->caps.caps.v1.prim_mask);
vctx->uploader = u_upload_create(&vctx->base, 1024 * 1024,
PIPE_BIND_INDEX_BUFFER, PIPE_USAGE_STREAM, 0);
PIPE_BIND_INDEX_BUFFER,
PIPE_USAGE_STREAM,
VIRGL_RESOURCE_FLAG_UPLOADER);
if (!vctx->uploader)
goto fail;
vctx->base.stream_uploader = vctx->uploader;
......
......@@ -522,11 +522,11 @@ enum virgl_transfer3d_encode_stride {
static void virgl_encoder_transfer3d_common(struct virgl_screen *vs,
struct virgl_cmd_buf *buf,
struct virgl_transfer *xfer,
const struct virgl_transfer *xfer,
enum virgl_transfer3d_encode_stride encode_stride)
{
struct pipe_transfer *transfer = &xfer->base;
const struct pipe_transfer *transfer = &xfer->base;
unsigned stride;
unsigned layer_stride;
......@@ -1152,16 +1152,38 @@ int virgl_encode_get_query_result_qbo(struct virgl_context *ctx,
return 0;
}
void virgl_encode_transfer(struct virgl_screen *vs, struct virgl_cmd_buf *buf,
struct virgl_transfer *trans, uint32_t direction)
unsigned virgl_encode_transfer_reserve(struct virgl_context *ctx,
const struct virgl_transfer *trans)
{
unsigned command_cdw;
virgl_encoder_write_cmd_dword(ctx,
VIRGL_CMD0(VIRGL_CCMD_END_TRANSFERS, 0, VIRGL_TRANSFER3D_SIZE));
command_cdw = ctx->cbuf->cdw - 1;
ctx->cbuf->cdw += VIRGL_TRANSFER3D_SIZE;
return command_cdw;
}
void virgl_encode_transfer_patch(struct virgl_context *ctx,
const struct virgl_transfer *trans,
uint32_t direction)
{
const unsigned orig_cdw = ctx->cbuf->cdw;
uint32_t command;
assert(trans->cdw + 1 + VIRGL_TRANSFER3D_SIZE <= orig_cdw);
ctx->cbuf->cdw = trans->cdw;
command = VIRGL_CMD0(VIRGL_CCMD_TRANSFER3D, 0, VIRGL_TRANSFER3D_SIZE);
virgl_encoder_write_dword(buf, command);
virgl_encoder_transfer3d_common(vs, buf, trans,
virgl_encoder_write_dword(ctx->cbuf, command);
virgl_encoder_transfer3d_common(virgl_screen(ctx->base.screen),
ctx->cbuf, trans,
virgl_transfer3d_host_inferred_stride);
virgl_encoder_write_dword(buf, trans->offset);
virgl_encoder_write_dword(buf, direction);
virgl_encoder_write_dword(ctx->cbuf, trans->offset);
virgl_encoder_write_dword(ctx->cbuf, direction);
ctx->cbuf->cdw = orig_cdw;
}
void virgl_encode_copy_transfer(struct virgl_context *ctx,
......@@ -1183,13 +1205,3 @@ void virgl_encode_copy_transfer(struct virgl_context *ctx,
/* At the moment all copy transfers are synchronized. */
virgl_encoder_write_dword(ctx->cbuf, 1);
}
void virgl_encode_end_transfers(struct virgl_cmd_buf *buf)
{
uint32_t command, diff;
diff = VIRGL_MAX_TBUF_DWORDS - buf->cdw;
if (diff) {
command = VIRGL_CMD0(VIRGL_CCMD_END_TRANSFERS, 0, diff - 1);
virgl_encoder_write_dword(buf, command);
}
}
......@@ -290,14 +290,16 @@ int virgl_encode_get_query_result_qbo(struct virgl_context *ctx,
uint32_t offset,
uint32_t index);
void virgl_encode_transfer(struct virgl_screen *vs, struct virgl_cmd_buf *buf,
struct virgl_transfer *trans, uint32_t direction);
unsigned virgl_encode_transfer_reserve(struct virgl_context *ctx,
const struct virgl_transfer *trans);
void virgl_encode_transfer_patch(struct virgl_context *ctx,
const struct virgl_transfer *trans,
uint32_t direction);
void virgl_encode_copy_transfer(struct virgl_context *ctx,
struct virgl_transfer *trans);
void virgl_encode_end_transfers(struct virgl_cmd_buf *buf);
int virgl_encode_tweak(struct virgl_context *ctx, enum vrend_tweak_type tweak, uint32_t value);
#endif
......@@ -449,6 +449,8 @@ virgl_resource_transfer_map(struct pipe_context *ctx,
util_range_add(&vres->valid_buffer_range, box->x, box->x + box->width);
}
virgl_transfer_queue_map(&vctx->queue, trans);
*transfer = &trans->base;
return map_addr;
}
......
......@@ -33,6 +33,8 @@
#include "virgl_screen.h"
#define VR_MAX_TEXTURE_2D_LEVELS 15
#define VIRGL_RESOURCE_FLAG_UPLOADER (PIPE_RESOURCE_FLAG_DRV_PRIV << 0)
struct winsys_handle;
struct virgl_screen;
struct virgl_context;
......@@ -80,6 +82,9 @@ struct virgl_transfer {
struct virgl_hw_res *copy_src_hw_res;
/* The offset in the copy source resource to copy data from. */
uint32_t copy_src_offset;
/* the position of the reserved space for transfer command in the cmbuf */
unsigned cdw;
};
void virgl_resource_destroy(struct pipe_screen *screen,
......
......@@ -166,15 +166,14 @@ static void transfer_put(struct virgl_transfer_queue *queue,
remove_transfer(queue, queued);
}
static void transfer_write(struct virgl_transfer_queue *queue,
static void transfer_patch(struct virgl_transfer_queue *queue,
struct list_action_args *args)
{
struct virgl_transfer *queued = args->queued;
struct virgl_cmd_buf *buf = args->data;
// Takes a reference on the HW resource, which is released after
// the exec buffer command.
virgl_encode_transfer(queue->vs, buf, queued, VIRGL_TRANSFER_TO_HOST);
virgl_encode_transfer_patch(queue->vctx, queued, VIRGL_TRANSFER_TO_HOST);
remove_transfer(queue, queued);
}
......@@ -194,29 +193,6 @@ static void perform_action(struct virgl_transfer_queue *queue,
}
}
static void add_internal(struct virgl_transfer_queue *queue,
struct virgl_transfer *transfer)
{
uint32_t dwords = VIRGL_TRANSFER3D_SIZE + 1;
if (queue->tbuf) {
if (queue->num_dwords + dwords >= VIRGL_MAX_TBUF_DWORDS) {
struct list_iteration_args iter;
struct virgl_winsys *vws = queue->vs->vws;
memset(&iter, 0, sizeof(iter));
iter.action = transfer_write;
iter.data = queue->tbuf;
perform_action(queue, &iter);
vws->submit_cmd(vws, queue->tbuf, NULL);
queue->num_dwords = 0;
}
}
list_addtail(&transfer->queue_link, &queue->transfer_list);
queue->num_dwords += dwords;
}
void virgl_transfer_queue_init(struct virgl_transfer_queue *queue,
struct virgl_context *vctx)
{
......@@ -224,31 +200,25 @@ void virgl_transfer_queue_init(struct virgl_transfer_queue *queue,
queue->vs = vs;
queue->vctx = vctx;
queue->num_dwords = 0;
list_inithead(&queue->transfer_list);
if ((vs->caps.caps.v2.capability_bits & VIRGL_CAP_TRANSFER) &&
vs->vws->supports_encoded_transfers)
queue->tbuf = vs->vws->cmd_buf_create(vs->vws, VIRGL_MAX_TBUF_DWORDS);
else
queue->tbuf = NULL;
}
void virgl_transfer_queue_fini(struct virgl_transfer_queue *queue)
{
struct virgl_winsys *vws = queue->vs->vws;
/* the context should have been flushed */
assert(list_empty(&queue->transfer_list));
if (queue->tbuf)
vws->cmd_buf_destroy(queue->tbuf);
queue->vs = NULL;
queue->vctx = NULL;
queue->tbuf = NULL;
queue->num_dwords = 0;
}
void virgl_transfer_queue_map(struct virgl_transfer_queue *queue,
struct virgl_transfer *transfer)
{
if (queue->vctx->encoded_transfers &&
(transfer->base.resource->flags & VIRGL_RESOURCE_FLAG_UPLOADER))
transfer->cdw = virgl_encode_transfer_reserve(queue->vctx, transfer);
}
int virgl_transfer_queue_unmap(struct virgl_transfer_queue *queue,
......@@ -275,7 +245,11 @@ int virgl_transfer_queue_unmap(struct virgl_transfer_queue *queue,
virgl_resource_destroy_transfer(queue->vctx, transfer);
} else {
add_internal(queue, transfer);
if (queue->vctx->encoded_transfers &&
!(transfer->base.resource->flags & VIRGL_RESOURCE_FLAG_UPLOADER))
transfer->cdw = virgl_encode_transfer_reserve(queue->vctx, transfer);
list_addtail(&transfer->queue_link, &queue->transfer_list);
}
return 0;
......@@ -287,23 +261,14 @@ int virgl_transfer_queue_clear(struct virgl_transfer_queue *queue,
struct list_iteration_args iter;
memset(&iter, 0, sizeof(iter));
if (queue->tbuf) {
uint32_t prior_num_dwords = cbuf->cdw;
cbuf->cdw = 0;
iter.action = transfer_write;
iter.data = cbuf;
if (queue->vctx->encoded_transfers) {
iter.action = transfer_patch;
perform_action(queue, &iter);
virgl_encode_end_transfers(cbuf);
cbuf->cdw = prior_num_dwords;
} else {
iter.action = transfer_put;
perform_action(queue, &iter);
}
queue->num_dwords = 0;
return 0;
}
......
......@@ -36,8 +36,6 @@ struct virgl_transfer_queue {
struct list_head transfer_list;
struct virgl_screen *vs;
struct virgl_context *vctx;
struct virgl_cmd_buf *tbuf;
uint32_t num_dwords;
};
void virgl_transfer_queue_init(struct virgl_transfer_queue *queue,
......@@ -45,9 +43,18 @@ void virgl_transfer_queue_init(struct virgl_transfer_queue *queue,
void virgl_transfer_queue_fini(struct virgl_transfer_queue *queue);
void virgl_transfer_queue_map(struct virgl_transfer_queue *queue,
struct virgl_transfer *transfer);
int virgl_transfer_queue_unmap(struct virgl_transfer_queue *queue,
struct virgl_transfer *transfer);
static inline bool virgl_transfer_queue_is_empty(
const struct virgl_transfer_queue *queue)
{
return list_empty(&queue->transfer_list);
}
int virgl_transfer_queue_clear(struct virgl_transfer_queue *queue,
struct virgl_cmd_buf *buf);
......
......@@ -31,8 +31,7 @@ struct pipe_fence_handle;
struct winsys_handle;
struct virgl_hw_res;
#define VIRGL_MAX_TBUF_DWORDS 1024
#define VIRGL_MAX_CMDBUF_DWORDS ((64 * 1024) + VIRGL_MAX_TBUF_DWORDS)
#define VIRGL_MAX_CMDBUF_DWORDS (64 * 1024)
struct virgl_drm_caps {
union virgl_caps caps;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment