diff --git a/src/gallium/drivers/virgl/virgl_resource.c b/src/gallium/drivers/virgl/virgl_resource.c index 469ef75953f..501d69f57af 100644 --- a/src/gallium/drivers/virgl/virgl_resource.c +++ b/src/gallium/drivers/virgl/virgl_resource.c @@ -582,6 +582,49 @@ static struct pipe_resource *virgl_resource_from_handle(struct pipe_screen *scre return NULL; } + /* assign blob resource a type in case it was created untyped */ + if (res->blob_mem && plane == 0 && + (vs->caps.caps.v2.capability_bits_v2 & VIRGL_CAP_V2_UNTYPED_RESOURCE)) { + uint32_t plane_strides[VIRGL_MAX_PLANE_COUNT]; + uint32_t plane_offsets[VIRGL_MAX_PLANE_COUNT]; + uint32_t plane_count = 0; + struct pipe_resource *iter = &res->u.b; + + do { + struct virgl_resource *plane = virgl_resource(iter); + + /* must be a plain 2D texture sharing the same hw_res */ + if (plane->u.b.target != PIPE_TEXTURE_2D || + plane->u.b.depth0 != 1 || + plane->u.b.array_size != 1 || + plane->u.b.last_level != 0 || + plane->u.b.nr_samples > 1 || + plane->hw_res != res->hw_res || + plane_count >= VIRGL_MAX_PLANE_COUNT) { + vs->vws->resource_reference(vs->vws, &res->hw_res, NULL); + FREE(res); + return NULL; + } + + plane_strides[plane_count] = plane->metadata.stride[0]; + plane_offsets[plane_count] = plane->metadata.plane_offset; + plane_count++; + iter = iter->next; + } while (iter); + + vs->vws->resource_set_type(vs->vws, + res->hw_res, + pipe_to_virgl_format(res->u.b.format), + pipe_to_virgl_bind(vs, res->u.b.bind), + res->u.b.width0, + res->u.b.height0, + usage, + res->metadata.modifier, + plane_count, + plane_strides, + plane_offsets); + } + virgl_texture_init(res); return &res->u.b; diff --git a/src/gallium/drivers/virgl/virgl_winsys.h b/src/gallium/drivers/virgl/virgl_winsys.h index 29f2ed8d930..0754e0d608e 100644 --- a/src/gallium/drivers/virgl/virgl_winsys.h +++ b/src/gallium/drivers/virgl/virgl_winsys.h @@ -33,6 +33,7 @@ struct virgl_hw_res; #define VIRGL_MAX_TBUF_DWORDS 1024 #define VIRGL_MAX_CMDBUF_DWORDS ((64 * 1024) + VIRGL_MAX_TBUF_DWORDS) +#define VIRGL_MAX_PLANE_COUNT 3 struct virgl_drm_caps { union virgl_caps caps; @@ -87,6 +88,15 @@ struct virgl_winsys { uint32_t *plane_offset, uint64_t *modifier, uint32_t *blob_mem); + void (*resource_set_type)(struct virgl_winsys *vws, + struct virgl_hw_res *res, + uint32_t format, uint32_t bind, + uint32_t width, uint32_t height, + uint32_t usage, uint64_t modifier, + uint32_t plane_count, + const uint32_t *plane_strides, + const uint32_t *plane_offsets); + boolean (*resource_get_handle)(struct virgl_winsys *vws, struct virgl_hw_res *res, uint32_t stride, diff --git a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c index 2be575fb21d..bf79ba7ddf7 100644 --- a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c +++ b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.c @@ -210,6 +210,7 @@ virgl_drm_winsys_resource_create_blob(struct virgl_winsys *qws, res->bo_handle = drm_rc_blob.bo_handle; res->size = size; res->flags = flags; + res->maybe_untyped = false; pipe_reference_init(&res->reference, 1); p_atomic_set(&res->external, false); p_atomic_set(&res->num_cs_references, 0); @@ -267,6 +268,7 @@ virgl_drm_winsys_resource_create(struct virgl_winsys *qws, res->bo_handle = createcmd.bo_handle; res->size = size; res->target = target; + res->maybe_untyped = false; pipe_reference_init(&res->reference, 1); p_atomic_set(&res->external, false); p_atomic_set(&res->num_cs_references, 0); @@ -425,6 +427,10 @@ virgl_drm_winsys_resource_create_handle(struct virgl_winsys *qws, struct virgl_hw_res *res = NULL; uint32_t handle = whandle->handle; + if (whandle->plane >= VIRGL_MAX_PLANE_COUNT) { + return NULL; + } + if (whandle->offset != 0 && whandle->type == WINSYS_HANDLE_TYPE_SHARED) { _debug_printf("attempt to import unsupported winsys offset %u\n", whandle->offset); @@ -496,6 +502,7 @@ virgl_drm_winsys_resource_create_handle(struct virgl_winsys *qws, *blob_mem = info_arg.blob_mem; res->size = info_arg.size; + res->maybe_untyped = info_arg.blob_mem ? true : false; pipe_reference_init(&res->reference, 1); p_atomic_set(&res->external, true); res->num_cs_references = 0; @@ -509,6 +516,58 @@ done: return res; } +static void +virgl_drm_winsys_resource_set_type(struct virgl_winsys *qws, + struct virgl_hw_res *res, + uint32_t format, uint32_t bind, + uint32_t width, uint32_t height, + uint32_t usage, uint64_t modifier, + uint32_t plane_count, + const uint32_t *plane_strides, + const uint32_t *plane_offsets) +{ + struct virgl_drm_winsys *qdws = virgl_drm_winsys(qws); + uint32_t cmd[VIRGL_PIPE_RES_SET_TYPE_SIZE(VIRGL_MAX_PLANE_COUNT)]; + struct drm_virtgpu_execbuffer eb; + int ret; + + mtx_lock(&qdws->bo_handles_mutex); + + if (!res->maybe_untyped) { + mtx_unlock(&qdws->bo_handles_mutex); + return; + } + res->maybe_untyped = false; + + assert(plane_count && plane_count <= VIRGL_MAX_PLANE_COUNT); + + cmd[0] = VIRGL_CMD0(VIRGL_CCMD_PIPE_RESOURCE_SET_TYPE, 0, VIRGL_PIPE_RES_SET_TYPE_SIZE(plane_count)); + cmd[VIRGL_PIPE_RES_SET_TYPE_RES_HANDLE] = res->res_handle, + cmd[VIRGL_PIPE_RES_SET_TYPE_FORMAT] = format; + cmd[VIRGL_PIPE_RES_SET_TYPE_BIND] = bind; + cmd[VIRGL_PIPE_RES_SET_TYPE_WIDTH] = width; + cmd[VIRGL_PIPE_RES_SET_TYPE_HEIGHT] = height; + cmd[VIRGL_PIPE_RES_SET_TYPE_USAGE] = usage; + cmd[VIRGL_PIPE_RES_SET_TYPE_MODIFIER_LO] = (uint32_t)modifier; + cmd[VIRGL_PIPE_RES_SET_TYPE_MODIFIER_HI] = (uint32_t)(modifier >> 32); + for (uint32_t i = 0; i < plane_count; i++) { + cmd[VIRGL_PIPE_RES_SET_TYPE_PLANE_STRIDE(i)] = plane_strides[i]; + cmd[VIRGL_PIPE_RES_SET_TYPE_PLANE_OFFSET(i)] = plane_offsets[i]; + } + + memset(&eb, 0, sizeof(eb)); + eb.command = (uintptr_t)cmd; + eb.size = (1 + VIRGL_PIPE_RES_SET_TYPE_SIZE(plane_count)) * 4; + eb.num_bo_handles = 1; + eb.bo_handles = (uintptr_t)&res->bo_handle; + + ret = drmIoctl(qdws->fd, DRM_IOCTL_VIRTGPU_EXECBUFFER, &eb); + if (ret == -1) + _debug_printf("failed to set resource type: %s", errno); + + mtx_unlock(&qdws->bo_handles_mutex); +} + static boolean virgl_drm_winsys_resource_get_handle(struct virgl_winsys *qws, struct virgl_hw_res *res, uint32_t stride, @@ -1091,6 +1150,7 @@ virgl_drm_winsys_create(int drmFD) qdws->base.resource_create = virgl_drm_winsys_resource_cache_create; qdws->base.resource_reference = virgl_drm_resource_reference; qdws->base.resource_create_from_handle = virgl_drm_winsys_resource_create_handle; + qdws->base.resource_set_type = virgl_drm_winsys_resource_set_type; qdws->base.resource_get_handle = virgl_drm_winsys_resource_get_handle; qdws->base.resource_map = virgl_drm_resource_map; qdws->base.resource_wait = virgl_drm_resource_wait; diff --git a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h index 1d7f03de264..28fb9715aaf 100644 --- a/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h +++ b/src/gallium/winsys/virgl/drm/virgl_drm_winsys.h @@ -48,6 +48,9 @@ struct virgl_hw_res { uint32_t flags; uint32_t flink_name; + /* false when the resource is known to be typed */ + bool maybe_untyped; + /* true when the resource is imported or exported */ int external;