diff --git a/src/virgl_hw.h b/src/virgl_hw.h index 62c1095..d27c153 100644 --- a/src/virgl_hw.h +++ b/src/virgl_hw.h @@ -442,6 +442,7 @@ enum virgl_formats { #define VIRGL_CAP_V2_STRING_MARKER (1 << 4) #define VIRGL_CAP_V2_DIFFERENT_GPU (1 << 5) #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/virgl_protocol.h b/src/virgl_protocol.h index dc1bafa..9f45480 100644 --- a/src/virgl_protocol.h +++ b/src/virgl_protocol.h @@ -608,12 +608,16 @@ 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 -#define VIRGL_COPY_TRANSFER3D_SYNCHRONIZED 14 +#define VIRGL_COPY_TRANSFER3D_FLAGS 14 +#define VIRGL_COPY_TRANSFER3D_FLAGS_SYNCHRONIZED (1 << 0) +/* 1 << 1 means transfer from host. + 0 << 1 means transfer to host.*/ +#define VIRGL_COPY_TRANSFER3D_FLAGS_READ_FROM_HOST (1 << 1) /* set tweak flags */ #define VIRGL_SET_TWEAKS_SIZE 2 diff --git a/src/vrend_decode.c b/src/vrend_decode.c index a55d542..6f5bd86 100644 --- a/src/vrend_decode.c +++ b/src/vrend_decode.c @@ -1420,19 +1420,39 @@ static int vrend_decode_copy_transfer3d(struct vrend_context *ctx, const uint32_ uint32_t dst_handle; uint32_t src_handle; + memset(&info, 0, sizeof(info)); + info.box = &box; + if (length != VIRGL_COPY_TRANSFER3D_SIZE) return EINVAL; - memset(&info, 0, sizeof(info)); - info.box = &box; - vrend_decode_transfer_common(buf, &dst_handle, &info); - info.offset = get_buf_entry(buf, VIRGL_COPY_TRANSFER3D_SRC_RES_OFFSET); - info.synchronized = (get_buf_entry(buf, VIRGL_COPY_TRANSFER3D_SYNCHRONIZED) != 0); + // synchronized is set either to 1 or 0. This means that we can use other bits + // to identify the direction of copy transfer + uint32_t flags = get_buf_entry(buf, VIRGL_COPY_TRANSFER3D_FLAGS); + bool read_from_host = flags & (1 << 1); + bool synchronized = flags & (1 << 0); - src_handle = get_buf_entry(buf, VIRGL_COPY_TRANSFER3D_SRC_RES_HANDLE); + if (!read_from_host) { + // this means that guest would like to make transfer to host + // it can also mean that guest is using legacy copy transfer path + vrend_decode_transfer_common(buf, &dst_handle, &info); + info.offset = get_buf_entry(buf, VIRGL_COPY_TRANSFER3D_SRC_RES_OFFSET); + info.synchronized = (synchronized != 0); - return vrend_renderer_copy_transfer3d(ctx, dst_handle, src_handle, - &info); + src_handle = get_buf_entry(buf, VIRGL_COPY_TRANSFER3D_SRC_RES_HANDLE); + + return vrend_renderer_copy_transfer3d(ctx, dst_handle, src_handle, + &info); + } else { + vrend_decode_transfer_common(buf, &src_handle, &info); + info.offset = get_buf_entry(buf, VIRGL_COPY_TRANSFER3D_SRC_RES_OFFSET); + info.synchronized = (synchronized != 0); + + dst_handle = get_buf_entry(buf, VIRGL_COPY_TRANSFER3D_SRC_RES_HANDLE); + + return vrend_renderer_copy_transfer3d_from_host(ctx, dst_handle, src_handle, + &info); + } } static int vrend_decode_pipe_resource_create(struct vrend_context *ctx, const uint32_t *buf, uint32_t length) diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index ffb1abc..02794fe 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -8574,6 +8574,45 @@ int vrend_renderer_copy_transfer3d(struct vrend_context *ctx, src_res->num_iovs, info); } +int vrend_renderer_copy_transfer3d_from_host(struct vrend_context *ctx, + uint32_t dst_handle, + uint32_t src_handle, + const struct vrend_transfer_info *info) +{ + struct vrend_resource *src_res, *dst_res; + + src_res = vrend_renderer_ctx_res_lookup(ctx, src_handle); + dst_res = vrend_renderer_ctx_res_lookup(ctx, dst_handle); + + if (!src_res) { + vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, src_handle); + return EINVAL; + } + + if (!dst_res) { + vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, dst_handle); + return EINVAL; + } + + if (!dst_res->iov) { + vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, dst_handle); + return EINVAL; + } + + if (!check_transfer_bounds(src_res, info)) { + vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_CMD_BUFFER, dst_handle); + return EINVAL; + } + + if (!check_iov_bounds(src_res, info, dst_res->iov, dst_res->num_iovs)) { + vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_CMD_BUFFER, dst_handle); + return EINVAL; + } + + return vrend_renderer_transfer_send_iov(ctx, src_res, dst_res->iov, + dst_res->num_iovs, info); +} + void vrend_set_stencil_ref(struct vrend_context *ctx, struct pipe_stencil_ref *ref) { @@ -10888,6 +10927,14 @@ static void vrend_renderer_fill_caps_v2(int gl_ver, int gles_ver, union virgl_c if (vrend_winsys_different_gpu()) caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_DIFFERENT_GPU; + // we use capability bits (not a version of protocol), because + // we disable this on client side if virglrenderer is used under + // vtest. vtest can't support this, because size of resource + // is used to create shmem. On drm path, we can use this, because + // size of drm resource (bo) is not passed to virglrenderer and + // we can pass "1" as size on drm path, but not on vtest. + caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_COPY_TRANSFER_BOTH_DIRECTIONS; + if (has_feature(feat_anisotropic_filter)) { float max_aniso; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &max_aniso); diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h index e6f84cc..ca9c353 100644 --- a/src/vrend_renderer.h +++ b/src/vrend_renderer.h @@ -256,6 +256,11 @@ int vrend_renderer_copy_transfer3d(struct vrend_context *ctx, uint32_t src_handle, const struct vrend_transfer_info *info); +int vrend_renderer_copy_transfer3d_from_host(struct vrend_context *ctx, + uint32_t dst_handle, + uint32_t src_handle, + const struct vrend_transfer_info *info); + void vrend_set_viewport_states(struct vrend_context *ctx, uint32_t start_slot, uint32_t num_viewports, const struct pipe_viewport_state *state);