From 9d81cd8e7c0cb44e09cf650da4834a1dc647a4d2 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Thu, 4 Oct 2018 16:40:08 +0200 Subject: [PATCH] virgl: Pass resource size and transfer offsets 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 (v2) Signed-off-by: Gert Wollny Reviewed-by: Gurchetan Singh --- .../winsys/virgl/vtest/virgl_vtest_socket.c | 144 ++++++++++++++++-- .../winsys/virgl/vtest/virgl_vtest_winsys.c | 44 ++++-- .../winsys/virgl/vtest/virgl_vtest_winsys.h | 19 ++- .../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 ce565ee76cf..ff69accf52f 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 6c03a6b3594..a589f694bb0 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; + + virgl_vtest_send_transfer_put(vtws, res->res_handle, level, stride, layer_stride, - box, size); + box, size, buf_offset); ptr = virgl_vtest_resource_map(vws, res); virgl_vtest_send_transfer_put_data(vtws, ptr + buf_offset, size); virgl_vtest_resource_unmap(vws, res); @@ -102,15 +112,22 @@ virgl_vtest_transfer_get(struct virgl_winsys *vws, size = vtest_get_transfer_size(res, box, stride, layer_stride, level, &valid_stride); + /* Don't ask for more pixels than available (see above) */ + if (size + buf_offset > res->size) + size = res->size - buf_offset; - virgl_vtest_send_transfer_cmd(vtws, VCMD_TRANSFER_GET, res->res_handle, + virgl_vtest_send_transfer_get(vtws, res->res_handle, level, stride, layer_stride, - box, size); - + box, size, buf_offset); ptr = virgl_vtest_resource_map(vws, res); + + /* This functions seems to be using a specific transfer resource that + * has exactly the box size and hence its src stride is equal to the target + * stride */ virgl_vtest_recv_transfer_get_data(vtws, ptr + buf_offset, size, - valid_stride, box, res->format); + valid_stride, box, res->format, valid_stride); + virgl_vtest_resource_unmap(vws, res); return 0; } @@ -240,9 +257,10 @@ virgl_vtest_winsys_resource_create(struct virgl_winsys *vws, res->format = format; res->height = height; res->width = width; + res->size = size; virgl_vtest_send_resource_create(vtws, handle, target, format, bind, width, height, depth, array_size, - last_level, nr_samples); + last_level, nr_samples, size); res->res_handle = handle++; pipe_reference_init(&res->reference, 1); @@ -613,10 +631,16 @@ static void virgl_vtest_flush_frontbuffer(struct virgl_winsys *vws, map = vtws->sws->displaytarget_map(vtws->sws, res->dt, 0); /* execute a transfer */ - virgl_vtest_send_transfer_cmd(vtws, VCMD_TRANSFER_GET, res->res_handle, - level, res->stride, 0, &box, size); + virgl_vtest_send_transfer_get(vtws, res->res_handle, + level, res->stride, 0, &box, size, offset); + + /* This functions gets the resource from the hardware backend that may have + * a hardware imposed stride that is different from the IOV stride used to + * get the data. */ virgl_vtest_recv_transfer_get_data(vtws, map + offset, size, valid_stride, - &box, res->format); + &box, res->format, + util_format_get_stride(res->format, res->width)); + vtws->sws->displaytarget_unmap(vtws->sws, res->dt); vtws->sws->displaytarget_display(vtws->sws, res->dt, winsys_drawable_handle, diff --git a/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.h b/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.h index 3628c746444..e51582032a3 100644 --- a/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.h +++ b/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.h @@ -121,20 +121,29 @@ 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); int virgl_vtest_send_resource_unref(struct virgl_vtest_winsys *vws, uint32_t handle); int virgl_vtest_submit_cmd(struct virgl_vtest_winsys *vtws, struct virgl_vtest_cmd_buf *cbuf); -int virgl_vtest_send_transfer_cmd(struct virgl_vtest_winsys *vws, - uint32_t vcmd, +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 data_size, + uint32_t 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); int virgl_vtest_send_transfer_put_data(struct virgl_vtest_winsys *vws, void *data, @@ -144,7 +153,7 @@ 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_width); int virgl_vtest_busy_wait(struct virgl_vtest_winsys *vws, int handle, int flags); diff --git a/src/gallium/winsys/virgl/vtest/vtest_protocol.h b/src/gallium/winsys/virgl/vtest/vtest_protocol.h index 8eb904e73f6..c299c31418d 100644 --- a/src/gallium/winsys/virgl/vtest/vtest_protocol.h +++ b/src/gallium/winsys/virgl/vtest/vtest_protocol.h @@ -58,6 +58,10 @@ #define VCMD_PROTOCOL_VERSION 11 +#define VCMD_RESOURCE_CREATE2 12 +#define VCMD_TRANSFER_GET2 13 +#define VCMD_TRANSFER_PUT2 14 + #define VCMD_RES_CREATE_SIZE 10 #define VCMD_RES_CREATE_RES_HANDLE 0 #define VCMD_RES_CREATE_TARGET 1 @@ -70,6 +74,19 @@ #define VCMD_RES_CREATE_LAST_LEVEL 8 #define VCMD_RES_CREATE_NR_SAMPLES 9 +#define VCMD_RES_CREATE2_SIZE 11 +#define VCMD_RES_CREATE2_RES_HANDLE 0 +#define VCMD_RES_CREATE2_TARGET 1 +#define VCMD_RES_CREATE2_FORMAT 2 +#define VCMD_RES_CREATE2_BIND 3 +#define VCMD_RES_CREATE2_WIDTH 4 +#define VCMD_RES_CREATE2_HEIGHT 5 +#define VCMD_RES_CREATE2_DEPTH 6 +#define VCMD_RES_CREATE2_ARRAY_SIZE 7 +#define VCMD_RES_CREATE2_LAST_LEVEL 8 +#define VCMD_RES_CREATE2_NR_SAMPLES 9 +#define VCMD_RES_CREATE2_DATA_SIZE 10 + #define VCMD_RES_UNREF_SIZE 1 #define VCMD_RES_UNREF_RES_HANDLE 0 @@ -86,6 +103,18 @@ #define VCMD_TRANSFER_DEPTH 9 #define VCMD_TRANSFER_DATA_SIZE 10 +#define VCMD_TRANSFER2_HDR_SIZE 10 +#define VCMD_TRANSFER2_RES_HANDLE 0 +#define VCMD_TRANSFER2_LEVEL 1 +#define VCMD_TRANSFER2_X 2 +#define VCMD_TRANSFER2_Y 3 +#define VCMD_TRANSFER2_Z 4 +#define VCMD_TRANSFER2_WIDTH 5 +#define VCMD_TRANSFER2_HEIGHT 6 +#define VCMD_TRANSFER2_DEPTH 7 +#define VCMD_TRANSFER2_DATA_SIZE 8 +#define VCMD_TRANSFER2_OFFSET 9 + #define VCMD_BUSY_WAIT_FLAG_WAIT 1 #define VCMD_BUSY_WAIT_SIZE 2 -- 2.30.2