diff --git a/src/virgl_hw.h b/src/virgl_hw.h index 58dafd9..70bef95 100644 --- a/src/virgl_hw.h +++ b/src/virgl_hw.h @@ -407,6 +407,7 @@ enum virgl_formats { /* These are used by the capability_bits_v2 field in virgl_caps_v2. */ #define VIRGL_CAP_V2_BLEND_EQUATION (1 << 0) +#define VIRGL_CAP_V2_UNTYPED_RESOURCE (1 << 1) /* 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 a230898..f6c7164 100644 --- a/src/virgl_protocol.h +++ b/src/virgl_protocol.h @@ -102,6 +102,7 @@ enum virgl_context_cmd { VIRGL_CCMD_SET_TWEAKS, VIRGL_CCMD_CLEAR_TEXTURE, VIRGL_CCMD_PIPE_RESOURCE_CREATE, + VIRGL_CCMD_PIPE_RESOURCE_SET_TYPE, VIRGL_MAX_COMMANDS }; @@ -636,4 +637,17 @@ enum vrend_tweak_type { #define VIRGL_PIPE_RES_CREATE_FLAGS 10 #define VIRGL_PIPE_RES_CREATE_BLOB_ID 11 +/* VIRGL_CCMD_PIPE_RESOURCE_SET_TYPE */ +#define VIRGL_PIPE_RES_SET_TYPE_SIZE(nplanes) (8 + (nplanes) * 2) +#define VIRGL_PIPE_RES_SET_TYPE_RES_HANDLE 1 +#define VIRGL_PIPE_RES_SET_TYPE_FORMAT 2 +#define VIRGL_PIPE_RES_SET_TYPE_BIND 3 +#define VIRGL_PIPE_RES_SET_TYPE_WIDTH 4 +#define VIRGL_PIPE_RES_SET_TYPE_HEIGHT 5 +#define VIRGL_PIPE_RES_SET_TYPE_USAGE 6 +#define VIRGL_PIPE_RES_SET_TYPE_MODIFIER_LO 7 +#define VIRGL_PIPE_RES_SET_TYPE_MODIFIER_HI 8 +#define VIRGL_PIPE_RES_SET_TYPE_PLANE_STRIDE(plane) (9 + (plane) * 2) +#define VIRGL_PIPE_RES_SET_TYPE_PLANE_OFFSET(plane) (10 + (plane) * 2) + #endif diff --git a/src/vrend_debug.c b/src/vrend_debug.c index 9339830..e48bfac 100644 --- a/src/vrend_debug.c +++ b/src/vrend_debug.c @@ -78,6 +78,7 @@ static const char *command_names[VIRGL_MAX_COMMANDS] = { "TWEAK", "CLEAR_TEXTURE" "PIPE_RESOURCE_CREATE", + "PIPE_RESOURCE_SET_TYPE", }; static const char *object_type_names[VIRGL_MAX_OBJECTS] = { diff --git a/src/vrend_decode.c b/src/vrend_decode.c index 3008f60..8739f2c 100644 --- a/src/vrend_decode.c +++ b/src/vrend_decode.c @@ -1431,6 +1431,34 @@ static int vrend_decode_pipe_resource_create(struct vrend_context *ctx, const ui return vrend_renderer_pipe_resource_create(ctx, blob_id, &args); } +static int vrend_decode_pipe_resource_set_type(struct vrend_context *ctx, const uint32_t *buf, uint32_t length) +{ + struct vrend_renderer_resource_set_type_args args = { 0 }; + uint32_t res_id; + + if (length >= VIRGL_PIPE_RES_SET_TYPE_SIZE(0)) + args.plane_count = (length - VIRGL_PIPE_RES_SET_TYPE_SIZE(0)) / 2; + + if (length != VIRGL_PIPE_RES_SET_TYPE_SIZE(args.plane_count) || + !args.plane_count || args.plane_count > VIRGL_GBM_MAX_PLANES) + return EINVAL; + + res_id = get_buf_entry(buf, VIRGL_PIPE_RES_SET_TYPE_RES_HANDLE); + args.format = get_buf_entry(buf, VIRGL_PIPE_RES_SET_TYPE_FORMAT); + args.bind = get_buf_entry(buf, VIRGL_PIPE_RES_SET_TYPE_BIND); + args.width = get_buf_entry(buf, VIRGL_PIPE_RES_SET_TYPE_WIDTH); + args.height = get_buf_entry(buf, VIRGL_PIPE_RES_SET_TYPE_HEIGHT); + args.usage = get_buf_entry(buf, VIRGL_PIPE_RES_SET_TYPE_USAGE); + args.modifier = get_buf_entry(buf, VIRGL_PIPE_RES_SET_TYPE_MODIFIER_LO); + args.modifier |= (uint64_t)get_buf_entry(buf, VIRGL_PIPE_RES_SET_TYPE_MODIFIER_HI) << 32; + for (uint32_t i = 0; i < args.plane_count; i++) { + args.plane_strides[i] = get_buf_entry(buf, VIRGL_PIPE_RES_SET_TYPE_PLANE_STRIDE(i)); + args.plane_offsets[i] = get_buf_entry(buf, VIRGL_PIPE_RES_SET_TYPE_PLANE_OFFSET(i)); + } + + return vrend_renderer_pipe_resource_set_type(ctx, res_id, &args); +} + static void vrend_decode_ctx_init_base(struct vrend_decode_ctx *dctx, uint32_t ctx_id); @@ -1568,7 +1596,8 @@ static const vrend_decode_callback decode_table[VIRGL_MAX_COMMANDS] = { [VIRGL_CCMD_COPY_TRANSFER3D] = vrend_decode_copy_transfer3d, [VIRGL_CCMD_END_TRANSFERS] = vrend_decode_dummy, [VIRGL_CCMD_SET_TWEAKS] = vrend_decode_set_tweaks, - [VIRGL_CCMD_PIPE_RESOURCE_CREATE] = vrend_decode_pipe_resource_create + [VIRGL_CCMD_PIPE_RESOURCE_CREATE] = vrend_decode_pipe_resource_create, + [VIRGL_CCMD_PIPE_RESOURCE_SET_TYPE] = vrend_decode_pipe_resource_set_type, }; static int vrend_decode_ctx_submit_cmd(struct virgl_context *ctx, diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index f4c509b..a8d2e33 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -706,8 +706,9 @@ struct vrend_context { * * It is however possible that we encounter untyped virgl_resources that * have no pipe_resources. To work with untyped virgl_resources, we park - * them in untyped_resources first when they are attached. TODO: create - * vrend_resources after we get the type information. + * them in untyped_resources first when they are attached. We move them + * into res_hash only after we get the type information and create the + * vrend_resources in vrend_decode_pipe_resource_set_type. */ struct list_head untyped_resources; struct virgl_resource *untyped_resource_cache; @@ -10272,6 +10273,11 @@ static void vrend_renderer_fill_caps_v2(int gl_ver, int gles_ver, union virgl_c if (has_feature(feat_blend_equation_advanced)) caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_BLEND_EQUATION; + +#ifdef HAVE_EPOXY_EGL_H + if (egl) + caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_UNTYPED_RESOURCE; +#endif } void vrend_renderer_fill_caps(uint32_t set, uint32_t version, @@ -10466,6 +10472,7 @@ void vrend_renderer_attach_res_ctx(struct vrend_context *ctx, } ctx->untyped_resource_cache = res; + /* defer to vrend_renderer_pipe_resource_set_type */ return; } @@ -10740,6 +10747,122 @@ struct pipe_resource *vrend_get_blob_pipe(struct vrend_context *ctx, uint64_t bl return NULL; } +int +vrend_renderer_pipe_resource_set_type(struct vrend_context *ctx, + uint32_t res_id, + const struct vrend_renderer_resource_set_type_args *args) +{ + struct virgl_resource *res = NULL; + + /* look up the untyped resource */ + if (ctx->untyped_resource_cache && + ctx->untyped_resource_cache->res_id == res_id) { + res = ctx->untyped_resource_cache; + ctx->untyped_resource_cache = NULL; + } else { + /* cache miss */ + struct vrend_untyped_resource *iter; + LIST_FOR_EACH_ENTRY(iter, &ctx->untyped_resources, head) { + if (iter->resource->res_id == res_id) { + res = iter->resource; + list_del(&iter->head); + free(iter); + break; + } + } + } + + /* either a bad res_id or the resource is already typed */ + if (!res) { + if (vrend_renderer_ctx_res_lookup(ctx, res_id)) + return 0; + + vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_id); + return EINVAL; + } + + /* resource is still untyped */ + if (!res->pipe_resource) { +#ifdef HAVE_EPOXY_EGL_H + const struct vrend_renderer_resource_create_args create_args = { + .target = PIPE_TEXTURE_2D, + .format = args->format, + .bind = args->bind, + .width = args->width, + .height = args->height, + .depth = 1, + .array_size = 1, + .last_level = 0, + .nr_samples = 0, + .flags = 0, + }; + int plane_fds[VIRGL_GBM_MAX_PLANES]; + struct vrend_resource *gr; + uint32_t virgl_format; + uint32_t drm_format; + int ret; + + if (res->fd_type != VIRGL_RESOURCE_FD_DMABUF) + return EINVAL; + + for (uint32_t i = 0; i < args->plane_count; i++) + plane_fds[i] = res->fd; + + gr = vrend_resource_create(&create_args); + if (!gr) + return ENOMEM; + + virgl_format = vrend_resource_fixup_emulated_bgra(gr, true); + drm_format = 0; + if (virgl_gbm_convert_format(&virgl_format, &drm_format)) { + vrend_printf("%s: unsupported format %d\n", __func__, virgl_format); + FREE(gr); + return EINVAL; + } + + gr->egl_image = virgl_egl_image_from_dmabuf(egl, + args->width, + args->height, + drm_format, + args->modifier, + args->plane_count, + plane_fds, + args->plane_strides, + args->plane_offsets); + if (!gr->egl_image) { + vrend_printf("%s: failed to create egl image\n", __func__); + FREE(gr); + return EINVAL; + } + + gr->storage_bits |= VREND_STORAGE_EGL_IMAGE; + + ret = vrend_resource_alloc_texture(gr, virgl_format, gr->egl_image); + if (ret) { + virgl_egl_image_destroy(egl, gr->egl_image); + FREE(gr); + return ret; + } + + /* "promote" the fd to pipe_resource */ + close(res->fd); + res->fd = -1; + res->fd_type = VIRGL_RESOURCE_FD_INVALID; + res->pipe_resource = &gr->base; +#else /* HAVE_EPOXY_EGL_H */ + (void)args; + vrend_printf("%s: no EGL support \n", __func__); + return EINVAL; +#endif /* HAVE_EPOXY_EGL_H */ + } + + vrend_ctx_resource_insert(ctx->res_hash, + res->res_id, + (struct vrend_resource *)res->pipe_resource); + + return 0; +} + uint32_t vrend_renderer_resource_get_map_info(struct pipe_resource *pres) { struct vrend_resource *res = (struct vrend_resource *)pres; diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h index 0bd7daf..87feb80 100644 --- a/src/vrend_renderer.h +++ b/src/vrend_renderer.h @@ -186,6 +186,19 @@ struct vrend_renderer_resource_create_args { uint32_t flags; }; +/* set the type info of an untyped blob resource */ +struct vrend_renderer_resource_set_type_args { + uint32_t format; + uint32_t bind; + uint32_t width; + uint32_t height; + uint32_t usage; + uint64_t modifier; + uint32_t plane_count; + uint32_t plane_strides[VIRGL_GBM_MAX_PLANES]; + uint32_t plane_offsets[VIRGL_GBM_MAX_PLANES]; +}; + struct pipe_resource * vrend_renderer_resource_create(const struct vrend_renderer_resource_create_args *args, void *image_eos); @@ -491,6 +504,11 @@ vrend_renderer_pipe_resource_create(struct vrend_context *ctx, uint32_t blob_id, struct pipe_resource *vrend_get_blob_pipe(struct vrend_context *ctx, uint64_t blob_id); +int +vrend_renderer_pipe_resource_set_type(struct vrend_context *ctx, + uint32_t res_id, + const struct vrend_renderer_resource_set_type_args *args); + uint32_t vrend_renderer_resource_get_map_info(struct pipe_resource *pres); int vrend_renderer_resource_map(struct pipe_resource *pres, void **map, uint64_t *out_size);