From 3f5ec0c82c8c6281b8beead8cf223bb7e6f82357 Mon Sep 17 00:00:00 2001 From: David Stevens Date: Tue, 3 Sep 2019 14:36:15 +0900 Subject: [PATCH] virgl/gbm: improve gbm resource creation This change makes a set of changes to increase the range of gbm-based resources that can be allocated: - Add VIRGL_BIND_LINEAR to support linear gbm allocations. - Relax the bind flag argument check if VIRGL_BIND_SHARED or VIRGL_BIND_LINEAR is set. - For resources allocated from gbm, only try to create an image if one of the render target or sampler view bind flags is set. - Don't try to calculate the internal image format for external images. This change also fixes a use-after-free that could occur if external image creation failed. Signed-off-by: David Stevens Reviewed-by: Gurchetan Singh --- src/virgl_gbm.c | 3 + src/virgl_hw.h | 2 + src/vrend_renderer.c | 200 +++++++++++++++++++++++-------------------- src/vrend_renderer.h | 1 + 4 files changed, 111 insertions(+), 95 deletions(-) diff --git a/src/virgl_gbm.c b/src/virgl_gbm.c index 4f926e8..68d1c01 100644 --- a/src/virgl_gbm.c +++ b/src/virgl_gbm.c @@ -370,6 +370,9 @@ uint32_t virgl_gbm_convert_flags(uint32_t virgl_bind_flags) flags |= GBM_BO_USE_SCANOUT; if (virgl_bind_flags & VIRGL_BIND_CURSOR) flags |= GBM_BO_USE_CURSOR; + if (virgl_bind_flags & VIRGL_BIND_LINEAR) + flags |= GBM_BO_USE_LINEAR; + return flags; } diff --git a/src/virgl_hw.h b/src/virgl_hw.h index d966093..145780b 100644 --- a/src/virgl_hw.h +++ b/src/virgl_hw.h @@ -288,6 +288,8 @@ enum virgl_formats { #define VIRGL_BIND_PREFER_EMULATED_BGRA (1 << 21) +#define VIRGL_BIND_LINEAR (1 << 22) + struct virgl_caps_bool_set1 { unsigned indep_blend_enable:1; unsigned indep_blend_func:1; diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index 785f15a..e42a3ed 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -6099,8 +6099,11 @@ static int check_resource_valid(struct vrend_renderer_resource_create_args *args if (!((args->bind & VIRGL_BIND_SAMPLER_VIEW) || (args->bind & VIRGL_BIND_DEPTH_STENCIL) || (args->bind & VIRGL_BIND_RENDER_TARGET) || - (args->bind & VIRGL_BIND_CURSOR))) + (args->bind & VIRGL_BIND_CURSOR) || + (args->bind & VIRGL_BIND_SHARED) || + (args->bind & VIRGL_BIND_LINEAR))) { return -1; + } if (args->target == PIPE_TEXTURE_2D || args->target == PIPE_TEXTURE_RECT || @@ -6170,15 +6173,8 @@ static void *vrend_allocate_using_gbm(struct vrend_resource *gr) if (!bo) return NULL; - void *image = virgl_egl_image_from_dmabuf(egl, bo); - if (!image) { - gbm_bo_destroy(bo); - return NULL; - } - - gr->egl_image = image; gr->gbm_bo = bo; - return image; + return bo; #else (void)gr; return NULL; @@ -6197,8 +6193,19 @@ static int vrend_renderer_resource_allocate_texture(struct vrend_resource *gr, if (pr->width0 == 0) return EINVAL; - if (!image_oes) - image_oes = vrend_allocate_using_gbm(gr); + if (!image_oes && vrend_allocate_using_gbm(gr)) { + if ((gr->base.bind & (VIRGL_BIND_RENDER_TARGET | VIRGL_BIND_SAMPLER_VIEW)) == 0) { + gr->storage = VREND_RESOURCE_STORAGE_GBM_ONLY; + return 0; + } + image_oes = virgl_egl_image_from_dmabuf(egl, gr->gbm_bo); + if (!image_oes) { + gbm_bo_destroy(gr->gbm_bo); + gr->gbm_bo = NULL; + } else { + gr->egl_image = image_oes; + } + } bool format_can_texture_storage = has_feature(feat_texture_storage) && (tex_conv_table[format].flags & VIRGL_TEXTURE_CAN_TEXTURE_STORAGE); @@ -6242,16 +6249,6 @@ static int vrend_renderer_resource_allocate_texture(struct vrend_resource *gr, debug_texture(__func__, gr); - internalformat = tex_conv_table[format].internalformat; - glformat = tex_conv_table[format].glformat; - gltype = tex_conv_table[format].gltype; - - if (internalformat == 0) { - vrend_printf("unknown format is %d\n", pr->format); - FREE(gt); - return EINVAL; - } - glGenTextures(1, &gr->id); glBindTexture(gr->target, gr->id); @@ -6260,88 +6257,101 @@ static int vrend_renderer_resource_allocate_texture(struct vrend_resource *gr, glEGLImageTargetTexture2DOES(gr->target, (GLeglImageOES) image_oes); } else { vrend_printf( "missing GL_OES_EGL_image_external extension\n"); - FREE(gr); glBindTexture(gr->target, 0); - return EINVAL; - } - } else if (pr->nr_samples > 0) { - if (format_can_texture_storage) { - if (gr->target == GL_TEXTURE_2D_MULTISAMPLE) { - glTexStorage2DMultisample(gr->target, pr->nr_samples, - internalformat, pr->width0, pr->height0, - GL_TRUE); - } else { - glTexStorage3DMultisample(gr->target, pr->nr_samples, - internalformat, pr->width0, pr->height0, pr->array_size, - GL_TRUE); - } - } else { - if (gr->target == GL_TEXTURE_2D_MULTISAMPLE) { - glTexImage2DMultisample(gr->target, pr->nr_samples, - internalformat, pr->width0, pr->height0, - GL_TRUE); + FREE(gr); + return EINVAL; + } + } else { + internalformat = tex_conv_table[format].internalformat; + glformat = tex_conv_table[format].glformat; + gltype = tex_conv_table[format].gltype; + + if (internalformat == 0) { + vrend_printf("unknown format is %d\n", pr->format); + glBindTexture(gr->target, 0); + FREE(gt); + return EINVAL; + } + + if (pr->nr_samples > 0) { + if (format_can_texture_storage) { + if (gr->target == GL_TEXTURE_2D_MULTISAMPLE) { + glTexStorage2DMultisample(gr->target, pr->nr_samples, + internalformat, pr->width0, pr->height0, + GL_TRUE); + } else { + glTexStorage3DMultisample(gr->target, pr->nr_samples, + internalformat, pr->width0, pr->height0, pr->array_size, + GL_TRUE); + } } else { - glTexImage3DMultisample(gr->target, pr->nr_samples, - internalformat, pr->width0, pr->height0, pr->array_size, - GL_TRUE); + if (gr->target == GL_TEXTURE_2D_MULTISAMPLE) { + glTexImage2DMultisample(gr->target, pr->nr_samples, + internalformat, pr->width0, pr->height0, + GL_TRUE); + } else { + glTexImage3DMultisample(gr->target, pr->nr_samples, + internalformat, pr->width0, pr->height0, pr->array_size, + GL_TRUE); + } } - } - } else if (gr->target == GL_TEXTURE_CUBE_MAP) { - int i; - if (format_can_texture_storage) - glTexStorage2D(GL_TEXTURE_CUBE_MAP, pr->last_level + 1, internalformat, pr->width0, pr->height0); - else { - for (i = 0; i < 6; i++) { - GLenum ctarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; - for (level = 0; level <= pr->last_level; level++) { - unsigned mwidth = u_minify(pr->width0, level); - unsigned mheight = u_minify(pr->height0, level); - - glTexImage2D(ctarget, level, internalformat, mwidth, mheight, 0, glformat, - gltype, NULL); + } else if (gr->target == GL_TEXTURE_CUBE_MAP) { + int i; + if (format_can_texture_storage) + glTexStorage2D(GL_TEXTURE_CUBE_MAP, pr->last_level + 1, internalformat, pr->width0, pr->height0); + else { + for (i = 0; i < 6; i++) { + GLenum ctarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; + for (level = 0; level <= pr->last_level; level++) { + unsigned mwidth = u_minify(pr->width0, level); + unsigned mheight = u_minify(pr->height0, level); + + glTexImage2D(ctarget, level, internalformat, mwidth, mheight, 0, glformat, + gltype, NULL); + } } } - } - } else if (gr->target == GL_TEXTURE_3D || - gr->target == GL_TEXTURE_2D_ARRAY || - gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) { - if (format_can_texture_storage) { - unsigned depth_param = (gr->target == GL_TEXTURE_2D_ARRAY || gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) ? - pr->array_size : pr->depth0; - glTexStorage3D(gr->target, pr->last_level + 1, internalformat, pr->width0, pr->height0, depth_param); - } else { - for (level = 0; level <= pr->last_level; level++) { + } else if (gr->target == GL_TEXTURE_3D || + gr->target == GL_TEXTURE_2D_ARRAY || + gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) { + if (format_can_texture_storage) { unsigned depth_param = (gr->target == GL_TEXTURE_2D_ARRAY || gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) ? - pr->array_size : u_minify(pr->depth0, level); - unsigned mwidth = u_minify(pr->width0, level); - unsigned mheight = u_minify(pr->height0, level); - glTexImage3D(gr->target, level, internalformat, mwidth, mheight, - depth_param, 0, glformat, gltype, NULL); + pr->array_size : pr->depth0; + glTexStorage3D(gr->target, pr->last_level + 1, internalformat, pr->width0, pr->height0, depth_param); + } else { + for (level = 0; level <= pr->last_level; level++) { + unsigned depth_param = (gr->target == GL_TEXTURE_2D_ARRAY || gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) ? + pr->array_size : u_minify(pr->depth0, level); + unsigned mwidth = u_minify(pr->width0, level); + unsigned mheight = u_minify(pr->height0, level); + glTexImage3D(gr->target, level, internalformat, mwidth, mheight, + depth_param, 0, glformat, gltype, NULL); + } } - } - } else if (gr->target == GL_TEXTURE_1D && vrend_state.use_gles) { - report_gles_missing_func(NULL, "glTexImage1D"); - } else if (gr->target == GL_TEXTURE_1D) { - if (format_can_texture_storage) { - glTexStorage1D(gr->target, pr->last_level + 1, internalformat, pr->width0); - } else { - for (level = 0; level <= pr->last_level; level++) { - unsigned mwidth = u_minify(pr->width0, level); - glTexImage1D(gr->target, level, internalformat, mwidth, 0, - glformat, gltype, NULL); + } else if (gr->target == GL_TEXTURE_1D && vrend_state.use_gles) { + report_gles_missing_func(NULL, "glTexImage1D"); + } else if (gr->target == GL_TEXTURE_1D) { + if (format_can_texture_storage) { + glTexStorage1D(gr->target, pr->last_level + 1, internalformat, pr->width0); + } else { + for (level = 0; level <= pr->last_level; level++) { + unsigned mwidth = u_minify(pr->width0, level); + glTexImage1D(gr->target, level, internalformat, mwidth, 0, + glformat, gltype, NULL); + } } - } - } else { - if (format_can_texture_storage) - glTexStorage2D(gr->target, pr->last_level + 1, internalformat, pr->width0, - gr->target == GL_TEXTURE_1D_ARRAY ? pr->array_size : pr->height0); - else { - for (level = 0; level <= pr->last_level; level++) { - unsigned mwidth = u_minify(pr->width0, level); - unsigned mheight = u_minify(pr->height0, level); - glTexImage2D(gr->target, level, internalformat, mwidth, - gr->target == GL_TEXTURE_1D_ARRAY ? pr->array_size : mheight, - 0, glformat, gltype, NULL); + } else { + if (format_can_texture_storage) + glTexStorage2D(gr->target, pr->last_level + 1, internalformat, pr->width0, + gr->target == GL_TEXTURE_1D_ARRAY ? pr->array_size : pr->height0); + else { + for (level = 0; level <= pr->last_level; level++) { + unsigned mwidth = u_minify(pr->width0, level); + unsigned mheight = u_minify(pr->height0, level); + glTexImage2D(gr->target, level, internalformat, mwidth, + gr->target == GL_TEXTURE_1D_ARRAY ? pr->array_size : mheight, + 0, glformat, gltype, NULL); + } } } } diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h index e89c05d..f7c94c8 100644 --- a/src/vrend_renderer.h +++ b/src/vrend_renderer.h @@ -58,6 +58,7 @@ enum vrend_resource_storage_type { /* The resource contents are stored in shared guest memory if it's * attached, otherwise in host system memory. */ VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM, + VREND_RESOURCE_STORAGE_GBM_ONLY, }; struct vrend_resource {