From 5c2129d4347ddf44e299f014335beeb239360fca Mon Sep 17 00:00:00 2001 From: Gurchetan Singh Date: Tue, 1 Oct 2019 18:03:11 -0700 Subject: [PATCH] virgl: fix stride + layer_stride inconsistency With blob resources, stride doesn't necesarily have to equal width * bpp. The use case for this a minigbm blob resource with blob mem BLOB_MEM_HOST3D_GUEST imported into guest Mesa. In addition, for BLOB_MEM_HOST we can repurpose the transfer ioctls to also flush caches if need be, so this seems a good time to fix this issue. Reviewed-by: Tomeu Vizoso Part-of: --- src/gallium/drivers/virgl/virgl_encode.c | 12 +++++++-- src/gallium/winsys/virgl/drm/virgl_drm_winsys.c | 34 ++++++++++++++++++++++--- src/gallium/winsys/virgl/drm/virgl_drm_winsys.h | 1 + 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/gallium/drivers/virgl/virgl_encode.c b/src/gallium/drivers/virgl/virgl_encode.c index 2d1b91a..ee75deb 100644 --- a/src/gallium/drivers/virgl/virgl_encode.c +++ b/src/gallium/drivers/virgl/virgl_encode.c @@ -1429,10 +1429,18 @@ void virgl_encode_transfer(struct virgl_screen *vs, struct virgl_cmd_buf *buf, struct virgl_transfer *trans, uint32_t direction) { uint32_t command; + struct virgl_resource *vres = virgl_resource(trans->base.resource); + enum virgl_transfer3d_encode_stride stride_type = + virgl_transfer3d_host_inferred_stride; + + if (trans->base.box.depth == 1 && trans->base.level == 0 && + trans->base.resource->target == PIPE_TEXTURE_2D && + vres->blob_mem == VIRGL_BLOB_MEM_HOST3D_GUEST) + stride_type = virgl_transfer3d_explicit_stride; + command = VIRGL_CMD0(VIRGL_CCMD_TRANSFER3D, 0, VIRGL_TRANSFER3D_SIZE); virgl_encoder_write_dword(buf, command); - virgl_encoder_transfer3d_common(vs, buf, trans, - virgl_transfer3d_host_inferred_stride); + virgl_encoder_transfer3d_common(vs, buf, trans, stride_type); virgl_encoder_write_dword(buf, trans->offset); virgl_encoder_write_dword(buf, direction); } diff --git a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c index a5a672e..6f4b24e 100644 --- a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c +++ b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c @@ -265,6 +265,7 @@ virgl_drm_winsys_resource_create(struct virgl_winsys *qws, res->res_handle = createcmd.res_handle; res->bo_handle = createcmd.bo_handle; res->size = size; + res->target = target; pipe_reference_init(&res->reference, 1); p_atomic_set(&res->external, false); p_atomic_set(&res->num_cs_references, 0); @@ -280,6 +281,27 @@ virgl_drm_winsys_resource_create(struct virgl_winsys *qws, return res; } +/* + * Previously, with DRM_IOCTL_VIRTGPU_RESOURCE_CREATE, all host resources had + * a guest memory shadow resource with size = stride * bpp. Virglrenderer + * would guess the stride implicitly when performing transfer operations, if + * the stride wasn't specified. Interestingly, vtest would specify the stride. + * + * Guessing the stride breaks down with YUV images, which may be imported into + * Mesa as 3R8 images. It also doesn't work if an external allocator + * (i.e, minigbm) decides to use a stride not equal to stride * bpp. With blob + * resources, the size = stride * bpp restriction no longer holds, so use + * explicit strides passed into Mesa. + */ +static inline bool use_explicit_stride(struct virgl_hw_res *res, uint32_t level, + uint32_t depth) +{ + return (params[param_resource_blob].value && + res->blob_mem == VIRTGPU_BLOB_MEM_HOST3D_GUEST && + res->target == PIPE_TEXTURE_2D && + level == 0 && depth == 1); +} + static int virgl_bo_transfer_put(struct virgl_winsys *vws, struct virgl_hw_res *res, @@ -302,8 +324,10 @@ virgl_bo_transfer_put(struct virgl_winsys *vws, tohostcmd.box.d = box->depth; tohostcmd.offset = buf_offset; tohostcmd.level = level; - // tohostcmd.stride = stride; - // tohostcmd.layer_stride = stride; + + if (use_explicit_stride(res, level, box->depth)) + tohostcmd.stride = stride; + return drmIoctl(vdws->fd, DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST, &tohostcmd); } @@ -323,14 +347,16 @@ virgl_bo_transfer_get(struct virgl_winsys *vws, fromhostcmd.bo_handle = res->bo_handle; fromhostcmd.level = level; fromhostcmd.offset = buf_offset; - // fromhostcmd.stride = stride; - // fromhostcmd.layer_stride = layer_stride; fromhostcmd.box.x = box->x; fromhostcmd.box.y = box->y; fromhostcmd.box.z = box->z; fromhostcmd.box.w = box->width; fromhostcmd.box.h = box->height; fromhostcmd.box.d = box->depth; + + if (use_explicit_stride(res, level, box->depth)) + fromhostcmd.stride = stride; + return drmIoctl(vdws->fd, DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST, &fromhostcmd); } diff --git a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h index 0f8ecab..1d7f03d 100644 --- a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h +++ b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h @@ -36,6 +36,7 @@ struct hash_table; struct virgl_hw_res { struct pipe_reference reference; + enum pipe_texture_target target; uint32_t res_handle; uint32_t bo_handle; int num_cs_references; -- 2.7.4