summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gallium/drivers/virgl/virgl_buffer.c5
-rw-r--r--src/gallium/drivers/virgl/virgl_encode.c19
-rw-r--r--src/gallium/drivers/virgl/virgl_resource.c86
-rw-r--r--src/gallium/drivers/virgl/virgl_resource.h2
-rw-r--r--src/gallium/drivers/virgl/virgl_texture.c5
-rw-r--r--src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c7
-rw-r--r--src/virtio/virtio-gpu/virgl_hw.h1
-rw-r--r--src/virtio/virtio-gpu/virgl_protocol.h5
8 files changed, 117 insertions, 13 deletions
diff --git a/src/gallium/drivers/virgl/virgl_buffer.c b/src/gallium/drivers/virgl/virgl_buffer.c
index 039a45f539a..8085839e150 100644
--- a/src/gallium/drivers/virgl/virgl_buffer.c
+++ b/src/gallium/drivers/virgl/virgl_buffer.c
@@ -48,9 +48,12 @@ void virgl_buffer_transfer_unmap(struct pipe_context *ctx,
trans->offset = transfer->box.x;
}
- if (trans->copy_src_hw_res) {
+ if (trans->copy_src_hw_res && trans->direction == VIRGL_TRANSFER_TO_HOST) {
virgl_encode_copy_transfer(vctx, trans);
virgl_resource_destroy_transfer(vctx, trans);
+ } else if (trans->copy_src_hw_res && trans->direction == VIRGL_TRANSFER_FROM_HOST) {
+ // if it is readback, then we have already encoded transfer
+ virgl_resource_destroy_transfer(vctx, trans);
} else {
virgl_transfer_queue_unmap(&vctx->queue, trans);
}
diff --git a/src/gallium/drivers/virgl/virgl_encode.c b/src/gallium/drivers/virgl/virgl_encode.c
index e16f4a6a0d4..bd564333516 100644
--- a/src/gallium/drivers/virgl/virgl_encode.c
+++ b/src/gallium/drivers/virgl/virgl_encode.c
@@ -1515,10 +1515,22 @@ void virgl_encode_copy_transfer(struct virgl_context *ctx,
{
uint32_t command;
struct virgl_screen *vs = virgl_screen(ctx->base.screen);
-
+ // set always synchronized to 1, second bit is used for direction
+ uint32_t direction_and_synchronized = 1;
+
+ if (vs->caps.caps.v2.capability_bits_v2 & VIRGL_CAP_V2_COPY_TRANSFER_BOTH_DIRECTIONS) {
+ if (trans->direction == VIRGL_TRANSFER_TO_HOST) {
+ // do nothing, as 0 means transfer to host
+ } else if (trans->direction == VIRGL_TRANSFER_FROM_HOST) {
+ direction_and_synchronized |= 1 << 1;
+ } else {
+ // something wrong happened here
+ assert(0);
+ }
+ }
assert(trans->copy_src_hw_res);
-
command = VIRGL_CMD0(VIRGL_CCMD_COPY_TRANSFER3D, 0, VIRGL_COPY_TRANSFER3D_SIZE);
+
virgl_encoder_write_cmd_dword(ctx, command);
/* Copy transfers need to explicitly specify the stride, since it may differ
* from the image stride.
@@ -1526,8 +1538,7 @@ void virgl_encode_copy_transfer(struct virgl_context *ctx,
virgl_encoder_transfer3d_common(vs, ctx->cbuf, trans, virgl_transfer3d_explicit_stride);
vs->vws->emit_res(vs->vws, ctx->cbuf, trans->copy_src_hw_res, TRUE);
virgl_encoder_write_dword(ctx->cbuf, trans->copy_src_offset);
- /* At the moment all copy transfers are synchronized. */
- virgl_encoder_write_dword(ctx->cbuf, 1);
+ virgl_encoder_write_dword(ctx->cbuf, direction_and_synchronized);
}
void virgl_encode_end_transfers(struct virgl_cmd_buf *buf)
diff --git a/src/gallium/drivers/virgl/virgl_resource.c b/src/gallium/drivers/virgl/virgl_resource.c
index f4142976d57..c5e8a96de2e 100644
--- a/src/gallium/drivers/virgl/virgl_resource.c
+++ b/src/gallium/drivers/virgl/virgl_resource.c
@@ -28,6 +28,7 @@
#include "virgl_resource.h"
#include "virgl_screen.h"
#include "virgl_staging_mgr.h"
+#include "virgl_encode.h" // for declaration of virgl_encode_copy_transfer
/* 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
@@ -42,12 +43,29 @@ enum virgl_transfer_map_type {
/* Map a range of a staging buffer. The updated contents should be transferred
* with a copy transfer.
*/
- VIRGL_TRANSFER_MAP_STAGING,
+ VIRGL_TRANSFER_MAP_WRITE_TO_STAGING,
/* Reallocate the underlying virgl_hw_res. */
VIRGL_TRANSFER_MAP_REALLOC,
+
+ /* Map type for read of texture data from host to guest
+ * using staging buffer. */
+ VIRGL_TRANSFER_MAP_READ_FROM_STAGING,
};
+/* Check if copy transfer from host can be used:
+ * 1. if resource is a texture
+ * 2. if renderer supports copy transfer from host
+ */
+static bool virgl_can_copy_transfer_from_host(struct virgl_screen *vs,
+ struct virgl_resource *res)
+{
+ if (vs->caps.caps.v2.capability_bits_v2 & VIRGL_CAP_V2_COPY_TRANSFER_BOTH_DIRECTIONS &&
+ res->b.target != PIPE_BUFFER)
+ return true;
+ return false;
+}
+
/* We need to flush to properly sync the transfer with the current cmdbuf.
* But there are cases where the flushing can be skipped:
*
@@ -172,7 +190,7 @@ virgl_resource_transfer_prepare(struct virgl_context *vctx,
if (wait) {
map_type = (can_realloc) ?
VIRGL_TRANSFER_MAP_REALLOC :
- VIRGL_TRANSFER_MAP_STAGING;
+ VIRGL_TRANSFER_MAP_WRITE_TO_STAGING;
wait = false;
/* There is normally no need to flush either, unless the amount of
@@ -183,11 +201,23 @@ virgl_resource_transfer_prepare(struct virgl_context *vctx,
flush = (vctx->queued_staging_res_size >
VIRGL_QUEUED_STAGING_RES_SIZE_LIMIT);
}
+
+ /* We can use staging buffer for texture uploads from guest to host */
+ if (can_staging && res->b.target != PIPE_BUFFER) {
+ map_type = VIRGL_TRANSFER_MAP_WRITE_TO_STAGING;
+ }
}
}
/* readback has some implications */
if (readback) {
+ /* If we are performing readback for textures and renderer supports
+ * copy_transfer_from_host, then we can return here with proper map.
+ */
+ if (virgl_can_copy_transfer_from_host(vs, res) && vctx->supports_staging &&
+ xfer->base.usage & PIPE_MAP_READ) {
+ return VIRGL_TRANSFER_MAP_READ_FROM_STAGING;
+ }
/* Readback is yet another command and is transparent to the state
* trackers. It should be waited for in all cases, including when
* PIPE_MAP_UNSYNCHRONIZED is set.
@@ -330,6 +360,36 @@ virgl_staging_map(struct virgl_context *vctx,
return map_addr;
}
+/* Maps a region from staging to service the transfer from host.
+ * This function should be called only for texture readbacks
+ * from host. */
+static void *
+virgl_staging_read_map(struct virgl_context *vctx,
+ struct virgl_transfer *vtransfer)
+{
+ struct virgl_screen *vscreen = virgl_screen(vctx->base.screen);
+ struct virgl_winsys *vws = vscreen->vws;
+ assert(vtransfer->base.resource->target != PIPE_BUFFER);
+ void *map_addr;
+
+ /* There are two possibilities to perform readback via:
+ * a) calling transfer_get();
+ * b) calling submit_cmd() with encoded transfer inside cmd.
+ *
+ * For b) we need:
+ * 1. select offset from staging buffer
+ * 2. encode this transfer in wire
+ * 3. flush the execbuffer to the host
+ * 4. wait till copy on the host is done
+ */
+ map_addr = virgl_staging_map(vctx, vtransfer);
+ vtransfer->direction = VIRGL_TRANSFER_FROM_HOST;
+ virgl_encode_copy_transfer(vctx, vtransfer);
+ vctx->base.flush(&vctx->base, NULL, 0);
+ vws->resource_wait(vws, vtransfer->copy_src_hw_res);
+ return map_addr;
+}
+
static bool
virgl_resource_realloc(struct virgl_context *vctx, struct virgl_resource *res)
{
@@ -380,7 +440,8 @@ virgl_resource_transfer_map(struct pipe_context *ctx,
struct pipe_transfer **transfer)
{
struct virgl_context *vctx = virgl_context(ctx);
- struct virgl_winsys *vws = virgl_screen(ctx->screen)->vws;
+ struct virgl_screen *vscreen = virgl_screen(ctx->screen);
+ struct virgl_winsys *vws = vscreen->vws;
struct virgl_resource *vres = virgl_resource(resource);
struct virgl_transfer *trans;
enum virgl_transfer_map_type map_type;
@@ -408,10 +469,16 @@ virgl_resource_transfer_map(struct pipe_context *ctx,
else
map_addr = NULL;
break;
- case VIRGL_TRANSFER_MAP_STAGING:
+ case VIRGL_TRANSFER_MAP_WRITE_TO_STAGING:
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;
+ trans->direction = VIRGL_TRANSFER_TO_HOST;
+ break;
+ case VIRGL_TRANSFER_MAP_READ_FROM_STAGING:
+ map_addr = virgl_staging_read_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:
@@ -506,6 +573,7 @@ static struct pipe_resource *virgl_resource_create(struct pipe_screen *screen,
unsigned vbind, vflags;
struct virgl_screen *vs = virgl_screen(screen);
struct virgl_resource *res = CALLOC_STRUCT(virgl_resource);
+ uint32_t alloc_size;
res->b = *templ;
res->b.screen = &vs->base;
@@ -523,6 +591,14 @@ static struct pipe_resource *virgl_resource_create(struct pipe_screen *screen,
vbind |= VIRGL_BIND_PREFER_EMULATED_BGRA;
}
+ // If renderer supports copy transfer from host,
+ // then for textures alloc minimum size of bo
+ // This size is not passed to the host
+ if (virgl_can_copy_transfer_from_host(vs, res))
+ alloc_size = 1;
+ else
+ alloc_size = res->metadata.total_size;
+
res->hw_res = vs->vws->resource_create(vs->vws, templ->target,
templ->format, vbind,
templ->width0,
@@ -532,7 +608,7 @@ static struct pipe_resource *virgl_resource_create(struct pipe_screen *screen,
templ->last_level,
templ->nr_samples,
vflags,
- res->metadata.total_size);
+ alloc_size);
if (!res->hw_res) {
FREE(res);
return NULL;
diff --git a/src/gallium/drivers/virgl/virgl_resource.h b/src/gallium/drivers/virgl/virgl_resource.h
index 31cbd1efd54..24543205351 100644
--- a/src/gallium/drivers/virgl/virgl_resource.h
+++ b/src/gallium/drivers/virgl/virgl_resource.h
@@ -86,6 +86,8 @@ 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;
+ /* copy transfers can be performed to and from host */
+ uint32_t direction;
};
void virgl_resource_destroy(struct pipe_screen *screen,
diff --git a/src/gallium/drivers/virgl/virgl_texture.c b/src/gallium/drivers/virgl/virgl_texture.c
index b4de039f93a..23a26ed1758 100644
--- a/src/gallium/drivers/virgl/virgl_texture.c
+++ b/src/gallium/drivers/virgl/virgl_texture.c
@@ -291,9 +291,12 @@ void virgl_texture_transfer_unmap(struct pipe_context *ctx,
}
if (queue_unmap) {
- if (trans->copy_src_hw_res) {
+ if (trans->copy_src_hw_res && trans->direction == VIRGL_TRANSFER_TO_HOST) {
virgl_encode_copy_transfer(vctx, trans);
virgl_resource_destroy_transfer(vctx, trans);
+ } else if (trans->copy_src_hw_res && trans->direction == VIRGL_TRANSFER_FROM_HOST) {
+ // if it is readback, then we have already encoded transfer
+ virgl_resource_destroy_transfer(vctx, trans);
} else {
virgl_transfer_queue_unmap(&vctx->queue, trans);
}
diff --git a/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c b/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c
index 5c7d73ab097..b452637c194 100644
--- a/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c
+++ b/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c
@@ -564,9 +564,14 @@ static int virgl_vtest_get_caps(struct virgl_winsys *vws,
struct virgl_drm_caps *caps)
{
struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws);
+ int ret;
virgl_ws_fill_new_caps_defaults(caps);
- return virgl_vtest_send_get_caps(vtws, caps);
+ ret = virgl_vtest_send_get_caps(vtws, caps);
+ // vtest doesn't support that
+ if (caps->caps.v2.capability_bits_v2 & VIRGL_CAP_V2_COPY_TRANSFER_BOTH_DIRECTIONS)
+ caps->caps.v2.capability_bits_v2 &= ~VIRGL_CAP_V2_COPY_TRANSFER_BOTH_DIRECTIONS;
+ return ret;
}
static struct pipe_fence_handle *
diff --git a/src/virtio/virtio-gpu/virgl_hw.h b/src/virtio/virtio-gpu/virgl_hw.h
index 88f3209be1e..7714ecf0e96 100644
--- a/src/virtio/virtio-gpu/virgl_hw.h
+++ b/src/virtio/virtio-gpu/virgl_hw.h
@@ -443,6 +443,7 @@ enum virgl_formats {
#define VIRGL_CAP_V2_MEMINFO (1 << 3)
#define VIRGL_CAP_V2_STRING_MARKER (1 << 4)
#define VIRGL_CAP_V2_IMPLICIT_MSAA (1 << 6)
+#define VIRGL_CAP_V2_COPY_TRANSFER_BOTH_DIRECTIONS (1 << 7)
/* virgl bind flags - these are compatible with mesa 10.5 gallium.
* but are fixed, no other should be passed to virgl either.
diff --git a/src/virtio/virtio-gpu/virgl_protocol.h b/src/virtio/virtio-gpu/virgl_protocol.h
index 5052667ad86..4166217a589 100644
--- a/src/virtio/virtio-gpu/virgl_protocol.h
+++ b/src/virtio/virtio-gpu/virgl_protocol.h
@@ -608,11 +608,14 @@ enum virgl_context_cmd {
#define VIRGL_TRANSFER3D_DATA_OFFSET 12
#define VIRGL_TRANSFER3D_DIRECTION 13
-/* Copy transfer */
+/* Copy transfer to host and from host*/
#define VIRGL_COPY_TRANSFER3D_SIZE 14
/* The first 11 dwords are the same as VIRGL_RESOURCE_IW_* */
#define VIRGL_COPY_TRANSFER3D_SRC_RES_HANDLE 12
#define VIRGL_COPY_TRANSFER3D_SRC_RES_OFFSET 13
+/* Second bit of this dword is used to identify the direction
+ * 1 << 1 means transfer from host. 0 << 1 means transfer to host.
+ */
#define VIRGL_COPY_TRANSFER3D_SYNCHRONIZED 14
/* set tweak flags */