diff --git a/src/iov.c b/src/iov.c index 76a3e54..9f9df91 100644 --- a/src/iov.c +++ b/src/iov.c @@ -39,6 +39,8 @@ #include #include +#include +#include #include "vrend_iov.h" size_t vrend_get_iovec_size(const struct iovec *iov, int iovlen) { @@ -140,3 +142,63 @@ size_t vrend_read_from_iovec_cb(const struct iovec *iov, int iovlen, } + +/** + * Copy data from one iovec to another iovec. + * + * TODO: Implement iovec copy without copy to intermediate buffer. + * + * \param src_iov The source iov. + * \param src_iovlen The number of memory regions in the source iov. + * \param src_offset The byte offset in the source iov to start reading from. + * \param dst_iov The destination iov. + * \param dst_iovlen The number of memory regions in the destination iov. + * \param dst_offset The byte offset in the destination iov to start writing to. + * \param count The number of bytes to copy + * \param buf If not NULL, a pointer to a buffer of at least count size + * to use a temporary storage for the copy operation. + * \return -1 on failure, 0 on success + */ +int vrend_copy_iovec(const struct iovec *src_iov, int src_iovlen, size_t src_offset, + const struct iovec *dst_iov, int dst_iovlen, size_t dst_offset, + size_t count, char *buf) +{ + int ret = 0; + bool needs_free; + size_t nread; + size_t nwritten; + + if (src_iov == NULL || dst_iov == NULL) + return -1; + + if (src_iov == dst_iov && src_offset == dst_offset) + return 0; + + if (!buf) { + buf = malloc(count); + needs_free = true; + } else { + needs_free = false; + } + + if (!buf) + return -1; + + nread = vrend_read_from_iovec(src_iov, src_iovlen, src_offset, buf, count); + if (nread != count) { + ret = -1; + goto out; + } + + nwritten = vrend_write_to_iovec(dst_iov, dst_iovlen, dst_offset, buf, count); + if (nwritten != count) { + ret = -1; + goto out; + } + +out: + if (needs_free) + free(buf); + + return ret; +} diff --git a/src/vrend_iov.h b/src/vrend_iov.h index 1d59e85..31341ca 100644 --- a/src/vrend_iov.h +++ b/src/vrend_iov.h @@ -46,4 +46,8 @@ size_t vrend_write_to_iovec(const struct iovec *iov, int iov_cnt, size_t vrend_read_from_iovec_cb(const struct iovec *iov, int iov_cnt, size_t offset, size_t bytes, iov_cb iocb, void *cookie); +int vrend_copy_iovec(const struct iovec *src_iov, int src_iovlen, size_t src_offset, + const struct iovec *dst_iov, int dst_iovlen, size_t dst_offset, + size_t count, char *buf); + #endif diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index fa5ac97..9aac565 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -5818,7 +5818,7 @@ int vrend_renderer_resource_attach_iov(int res_handle, struct iovec *iov, res->iov = iov; res->num_iovs = num_iovs; - if (res->storage == VREND_RESOURCE_STORAGE_IOVEC) { + if (res->storage == VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM) { vrend_write_to_iovec(res->iov, res->num_iovs, 0, res->ptr, res->base.width0); } @@ -5840,7 +5840,7 @@ void vrend_renderer_resource_detach_iov(int res_handle, if (num_iovs_p) *num_iovs_p = res->num_iovs; - if (res->storage == VREND_RESOURCE_STORAGE_IOVEC) { + if (res->storage == VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM) { vrend_read_from_iovec(res->iov, res->num_iovs, 0, res->ptr, res->base.width0); } @@ -6154,7 +6154,7 @@ int vrend_renderer_resource_create(struct vrend_renderer_resource_create_args *a if (args->bind == VIRGL_BIND_CUSTOM) { assert(args->target == PIPE_BUFFER); /* use iovec directly when attached */ - gr->storage = VREND_RESOURCE_STORAGE_IOVEC; + gr->storage = VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM; gr->ptr = malloc(args->width); if (!gr->ptr) { FREE(gr); @@ -6225,7 +6225,7 @@ void vrend_renderer_resource_destroy(struct vrend_resource *res) if (res->tbo_tex_id) glDeleteTextures(1, &res->tbo_tex_id); break; - case VREND_RESOURCE_STORAGE_IOVEC: + case VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM: free(res->ptr); break; default: @@ -6475,20 +6475,17 @@ static int vrend_renderer_transfer_write_iov(struct vrend_context *ctx, { void *data; - if (res->storage == VREND_RESOURCE_STORAGE_IOVEC) { - const bool need_write = (res->iov == NULL || - res->iov != iov || - info->offset != (size_t) info->box->x); - if (need_write) { - vrend_read_from_iovec(iov, num_iovs, info->offset, - res->ptr + info->box->x, info->box->width); - - if (res->iov) { - vrend_write_to_iovec(res->iov, res->num_iovs, info->box->x, - res->ptr + info->box->x, info->box->width); - } - } + if (res->storage == VREND_RESOURCE_STORAGE_GUEST || + (res->storage == VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM && res->iov)) { + return vrend_copy_iovec(iov, num_iovs, info->offset, + res->iov, res->num_iovs, info->box->x, + info->box->width, res->ptr); + } + if (res->storage == VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM) { + assert(!res->iov); + vrend_read_from_iovec(iov, num_iovs, info->offset, + res->ptr + info->box->x, info->box->width); return 0; } @@ -7000,20 +6997,17 @@ static int vrend_renderer_transfer_send_iov(struct vrend_resource *res, struct iovec *iov, int num_iovs, const struct vrend_transfer_info *info) { - if (res->storage == VREND_RESOURCE_STORAGE_IOVEC) { - const bool need_send = (res->iov == NULL || - res->iov != iov || - info->offset != (size_t) info->box->x); - if (need_send) { - if (res->iov) { - vrend_read_from_iovec(res->iov, res->num_iovs, info->box->x, - res->ptr + info->box->x, info->box->width); - } - - vrend_write_to_iovec(iov, num_iovs, info->offset, - res->ptr + info->box->x, info->box->width); - } + if (res->storage == VREND_RESOURCE_STORAGE_GUEST || + (res->storage == VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM && res->iov)) { + return vrend_copy_iovec(res->iov, res->num_iovs, info->box->x, + iov, num_iovs, info->offset, + info->box->width, res->ptr); + } + if (res->storage == VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM) { + assert(!res->iov); + vrend_write_to_iovec(iov, num_iovs, info->offset, + res->ptr + info->box->x, info->box->width); return 0; } @@ -8198,7 +8192,7 @@ int vrend_create_query(struct vrend_context *ctx, uint32_t handle, struct vrend_resource *res; uint32_t ret_handle; res = vrend_renderer_ctx_res_lookup(ctx, res_handle); - if (!res || res->storage != VREND_RESOURCE_STORAGE_IOVEC) { + if (!res || res->storage != VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle); return EINVAL; } diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h index 24700c8..4ff7892 100644 --- a/src/vrend_renderer.h +++ b/src/vrend_renderer.h @@ -52,7 +52,11 @@ struct vrend_context; enum vrend_resource_storage_type { VREND_RESOURCE_STORAGE_TEXTURE, VREND_RESOURCE_STORAGE_BUFFER, - VREND_RESOURCE_STORAGE_IOVEC, + /* The resource contents are stored in shared guest memory. */ + VREND_RESOURCE_STORAGE_GUEST, + /* The resource contents are stored in shared guest memory if it's + * attached, otherwise in host system memory. */ + VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM, }; struct vrend_resource { @@ -71,7 +75,11 @@ struct vrend_resource { GLuint handle; void *priv; + /* Pointer to system memory storage for this resource. Only valid for + * VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM buffer storage. + */ char *ptr; + /* IOV pointing to shared guest memory storage for this resource. */ struct iovec *iov; uint32_t num_iovs; uint64_t mipmap_offsets[VR_MAX_TEXTURE_2D_LEVELS];