From: Tomeu Vizoso <tomeu.viz...@collabora.com>
Pass the size of a resource when creating it so a backing can be kept in
the other side.
Also pass the required offset to transfer commands.
This moves vtest closer to how virtio-gpu works, making it more useful
for testing.
v2: - Use new messages for creation and transfers, as changing the
behavior of the existing messages would be messy given that we don't
want to break compatibility with older servers.
v3: - Use correct strides: The resource corresponding to the output display
might have a differnt line stride then the IOVs, so when reading back
to this resource take the resource stride and the the IOV stride
into account.
v4: Fix transfer size calculation (Andrey Simiklit)
v5: Add comment about transfer size value in the PUT commend (Gurchetan).
Add a comment about the size correction for transfers for reading and
writing the resource. Fixing this by correctly evaluating the size
upfront will need some work also on the virglrenderer side.
Signed-off-by: Tomeu Vizoso <tomeu.viz...@collabora.com> (v2)
Signed-off-by: Gert Wollny <gert.wol...@collabora.com>
---
.../winsys/virgl/vtest/virgl_vtest_socket.c | 144 +++++++++++++++++++--
.../winsys/virgl/vtest/virgl_vtest_winsys.c | 44 +++++--
.../winsys/virgl/vtest/virgl_vtest_winsys.h | 19 ++-
src/gallium/winsys/virgl/vtest/vtest_protocol.h | 29 +++++
4 files changed, 208 insertions(+), 28 deletions(-)
diff --git a/src/gallium/winsys/virgl/vtest/virgl_vtest_socket.c
b/src/gallium/winsys/virgl/vtest/virgl_vtest_socket.c
index ce565ee76c..ff69accf52 100644
--- a/src/gallium/winsys/virgl/vtest/virgl_vtest_socket.c
+++ b/src/gallium/winsys/virgl/vtest/virgl_vtest_socket.c
@@ -221,6 +221,42 @@ int virgl_vtest_send_get_caps(struct virgl_vtest_winsys
*vws,
return 0;
}
+static int virgl_vtest_send_resource_create2(struct virgl_vtest_winsys *vws,
+ uint32_t handle,
+ enum pipe_texture_target target,
+ uint32_t format,
+ uint32_t bind,
+ uint32_t width,
+ uint32_t height,
+ uint32_t depth,
+ uint32_t array_size,
+ uint32_t last_level,
+ uint32_t nr_samples,
+ uint32_t size)
+{
+ uint32_t res_create_buf[VCMD_RES_CREATE2_SIZE], vtest_hdr[VTEST_HDR_SIZE];
+
+ vtest_hdr[VTEST_CMD_LEN] = VCMD_RES_CREATE2_SIZE;
+ vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_CREATE2;
+
+ res_create_buf[VCMD_RES_CREATE2_RES_HANDLE] = handle;
+ res_create_buf[VCMD_RES_CREATE2_TARGET] = target;
+ res_create_buf[VCMD_RES_CREATE2_FORMAT] = format;
+ res_create_buf[VCMD_RES_CREATE2_BIND] = bind;
+ res_create_buf[VCMD_RES_CREATE2_WIDTH] = width;
+ res_create_buf[VCMD_RES_CREATE2_HEIGHT] = height;
+ res_create_buf[VCMD_RES_CREATE2_DEPTH] = depth;
+ res_create_buf[VCMD_RES_CREATE2_ARRAY_SIZE] = array_size;
+ res_create_buf[VCMD_RES_CREATE2_LAST_LEVEL] = last_level;
+ res_create_buf[VCMD_RES_CREATE2_NR_SAMPLES] = nr_samples;
+ res_create_buf[VCMD_RES_CREATE2_DATA_SIZE] = size;
+
+ virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
+ virgl_block_write(vws->sock_fd, &res_create_buf, sizeof(res_create_buf));
+
+ return 0;
+}
+
int virgl_vtest_send_resource_create(struct virgl_vtest_winsys *vws,
uint32_t handle,
enum pipe_texture_target target,
@@ -231,10 +267,17 @@ int virgl_vtest_send_resource_create(struct
virgl_vtest_winsys *vws,
uint32_t depth,
uint32_t array_size,
uint32_t last_level,
- uint32_t nr_samples)
+ uint32_t nr_samples,
+ uint32_t size)
{
uint32_t res_create_buf[VCMD_RES_CREATE_SIZE], vtest_hdr[VTEST_HDR_SIZE];
+ if (vws->protocol_version >= 1)
+ return virgl_vtest_send_resource_create2(vws, handle, target, format,
+ bind, width, height, depth,
+ array_size, last_level,
+ nr_samples, size);
+
vtest_hdr[VTEST_CMD_LEN] = VCMD_RES_CREATE_SIZE;
vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_CREATE;
@@ -282,7 +325,7 @@ int virgl_vtest_send_resource_unref(struct
virgl_vtest_winsys *vws,
return 0;
}
-int virgl_vtest_send_transfer_cmd(struct virgl_vtest_winsys *vws,
+static int virgl_vtest_send_transfer_cmd(struct virgl_vtest_winsys *vws,
uint32_t vcmd,
uint32_t handle,
uint32_t level, uint32_t stride,
@@ -317,6 +360,74 @@ int virgl_vtest_send_transfer_cmd(struct
virgl_vtest_winsys *vws,
return 0;
}
+static int virgl_vtest_send_transfer_cmd2(struct virgl_vtest_winsys *vws,
+ uint32_t vcmd,
+ uint32_t handle,
+ uint32_t level,
+ const struct pipe_box *box,
+ uint32_t data_size,
+ uint32_t offset)
+{
+ uint32_t vtest_hdr[VTEST_HDR_SIZE];
+ uint32_t cmd[VCMD_TRANSFER2_HDR_SIZE];
+ vtest_hdr[VTEST_CMD_LEN] = VCMD_TRANSFER2_HDR_SIZE;
+ vtest_hdr[VTEST_CMD_ID] = vcmd;
+
+ /* The host expects the size in dwords so calculate the rounded up
+ * value here. */
+ if (vcmd == VCMD_TRANSFER_PUT2)
+ vtest_hdr[VTEST_CMD_LEN] += (data_size + 3) / 4;
+
+ cmd[VCMD_TRANSFER2_RES_HANDLE] = handle;
+ cmd[VCMD_TRANSFER2_LEVEL] = level;
+ cmd[VCMD_TRANSFER2_X] = box->x;
+ cmd[VCMD_TRANSFER2_Y] = box->y;
+ cmd[VCMD_TRANSFER2_Z] = box->z;
+ cmd[VCMD_TRANSFER2_WIDTH] = box->width;
+ cmd[VCMD_TRANSFER2_HEIGHT] = box->height;
+ cmd[VCMD_TRANSFER2_DEPTH] = box->depth;
+ cmd[VCMD_TRANSFER2_DATA_SIZE] = data_size;
+ cmd[VCMD_TRANSFER2_OFFSET] = offset;
+ virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
+ virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd));
+
+ return 0;
+}
+
+int virgl_vtest_send_transfer_get(struct virgl_vtest_winsys *vws,
+ uint32_t handle,
+ uint32_t level, uint32_t stride,
+ uint32_t layer_stride,
+ const struct pipe_box *box,
+ uint32_t data_size,
+ uint32_t offset)
+{
+ if (vws->protocol_version < 1)
+ return virgl_vtest_send_transfer_cmd(vws, VCMD_TRANSFER_GET, handle,
+ level, stride, layer_stride, box,
+ data_size);
+
+ return virgl_vtest_send_transfer_cmd2(vws, VCMD_TRANSFER_GET2, handle,
+ level, box, data_size, offset);
+}
+
+int virgl_vtest_send_transfer_put(struct virgl_vtest_winsys *vws,
+ uint32_t handle,
+ uint32_t level, uint32_t stride,
+ uint32_t layer_stride,
+ const struct pipe_box *box,
+ uint32_t data_size,
+ uint32_t offset)
+{
+ if (vws->protocol_version < 1)
+ return virgl_vtest_send_transfer_cmd(vws, VCMD_TRANSFER_PUT, handle,
+ level, stride, layer_stride, box,
+ data_size);
+
+ return virgl_vtest_send_transfer_cmd2(vws, VCMD_TRANSFER_PUT2, handle,
+ level, box, data_size, offset);
+}
+
int virgl_vtest_send_transfer_put_data(struct virgl_vtest_winsys *vws,
void *data,
uint32_t data_size)
@@ -329,20 +440,27 @@ int virgl_vtest_recv_transfer_get_data(struct
virgl_vtest_winsys *vws,
uint32_t data_size,
uint32_t stride,
const struct pipe_box *box,
- uint32_t format)
+ uint32_t format, uint32_t res_stride)
{
- void *line;
- void *ptr = data;
- int hblocks = util_format_get_nblocksy(format, box->height);
-
- line = malloc(stride);
- while (hblocks) {
- virgl_block_read(vws->sock_fd, line, stride);
- memcpy(ptr, line, util_format_get_stride(format, box->width));
+ char *ptr = data;
+ uint32_t bytes_to_read = data_size;
+ char dump[1024];
+
+ /* Copy the date from the IOV to the target resource respecting
+ * the different strides */
+ for (int y = 0 ; y < box->height && bytes_to_read > 0; ++y) {
+ uint32_t btr = MIN2(res_stride, bytes_to_read);
+ virgl_block_read(vws->sock_fd, ptr, btr);
ptr += stride;
- hblocks--;
+ bytes_to_read -= btr;
+ }
+
+ /* It seems that there may be extra bytes that need to be read */
+ while (bytes_to_read > 0 && bytes_to_read < data_size) {
+ uint32_t btr = MIN2(sizeof(dump), bytes_to_read);
+ virgl_block_read(vws->sock_fd, dump, btr);
+ bytes_to_read -= btr;
}
- free(line);
return 0;
}
diff --git a/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c
b/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c
index 6c03a6b359..a589f694bb 100644
--- a/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c
+++ b/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c
@@ -79,9 +79,19 @@ virgl_vtest_transfer_put(struct virgl_winsys *vws,
size = vtest_get_transfer_size(res, box, stride, layer_stride, level,
&valid_stride);
- virgl_vtest_send_transfer_cmd(vtws, VCMD_TRANSFER_PUT, res->res_handle,
+ /* The size calculated above is the full box size, but if this box origin
+ * is not zero we may have to correct the transfer size to not read past the
+ * end of the resource. The correct adjustment depends on various factors
+ * that are not documented, so instead of going though all the hops to get
+ * the size right up-front, we just make sure we don't read past the end.
+ * FIXME: figure out what it takes to actually get this right.
+ */
+ if (size + buf_offset > res->size)
+ size = res->size - buf_offset;