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 <stevensd@chromium.org>
Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org>
macos/master
David Stevens 5 years ago committed by David Stevens
parent 0e817f334b
commit 3f5ec0c82c
  1. 3
      src/virgl_gbm.c
  2. 2
      src/virgl_hw.h
  3. 200
      src/vrend_renderer.c
  4. 1
      src/vrend_renderer.h

@ -370,6 +370,9 @@ uint32_t virgl_gbm_convert_flags(uint32_t virgl_bind_flags)
flags |= GBM_BO_USE_SCANOUT; flags |= GBM_BO_USE_SCANOUT;
if (virgl_bind_flags & VIRGL_BIND_CURSOR) if (virgl_bind_flags & VIRGL_BIND_CURSOR)
flags |= GBM_BO_USE_CURSOR; flags |= GBM_BO_USE_CURSOR;
if (virgl_bind_flags & VIRGL_BIND_LINEAR)
flags |= GBM_BO_USE_LINEAR;
return flags; return flags;
} }

@ -288,6 +288,8 @@ enum virgl_formats {
#define VIRGL_BIND_PREFER_EMULATED_BGRA (1 << 21) #define VIRGL_BIND_PREFER_EMULATED_BGRA (1 << 21)
#define VIRGL_BIND_LINEAR (1 << 22)
struct virgl_caps_bool_set1 { struct virgl_caps_bool_set1 {
unsigned indep_blend_enable:1; unsigned indep_blend_enable:1;
unsigned indep_blend_func:1; unsigned indep_blend_func:1;

@ -6099,8 +6099,11 @@ static int check_resource_valid(struct vrend_renderer_resource_create_args *args
if (!((args->bind & VIRGL_BIND_SAMPLER_VIEW) || if (!((args->bind & VIRGL_BIND_SAMPLER_VIEW) ||
(args->bind & VIRGL_BIND_DEPTH_STENCIL) || (args->bind & VIRGL_BIND_DEPTH_STENCIL) ||
(args->bind & VIRGL_BIND_RENDER_TARGET) || (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; return -1;
}
if (args->target == PIPE_TEXTURE_2D || if (args->target == PIPE_TEXTURE_2D ||
args->target == PIPE_TEXTURE_RECT || args->target == PIPE_TEXTURE_RECT ||
@ -6170,15 +6173,8 @@ static void *vrend_allocate_using_gbm(struct vrend_resource *gr)
if (!bo) if (!bo)
return NULL; 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; gr->gbm_bo = bo;
return image; return bo;
#else #else
(void)gr; (void)gr;
return NULL; return NULL;
@ -6197,8 +6193,19 @@ static int vrend_renderer_resource_allocate_texture(struct vrend_resource *gr,
if (pr->width0 == 0) if (pr->width0 == 0)
return EINVAL; return EINVAL;
if (!image_oes) if (!image_oes && vrend_allocate_using_gbm(gr)) {
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) && bool format_can_texture_storage = has_feature(feat_texture_storage) &&
(tex_conv_table[format].flags & VIRGL_TEXTURE_CAN_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); 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); glGenTextures(1, &gr->id);
glBindTexture(gr->target, 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); glEGLImageTargetTexture2DOES(gr->target, (GLeglImageOES) image_oes);
} else { } else {
vrend_printf( "missing GL_OES_EGL_image_external extension\n"); vrend_printf( "missing GL_OES_EGL_image_external extension\n");
FREE(gr);
glBindTexture(gr->target, 0); glBindTexture(gr->target, 0);
return EINVAL; FREE(gr);
} return EINVAL;
} else if (pr->nr_samples > 0) { }
if (format_can_texture_storage) { } else {
if (gr->target == GL_TEXTURE_2D_MULTISAMPLE) { internalformat = tex_conv_table[format].internalformat;
glTexStorage2DMultisample(gr->target, pr->nr_samples, glformat = tex_conv_table[format].glformat;
internalformat, pr->width0, pr->height0, gltype = tex_conv_table[format].gltype;
GL_TRUE);
} else { if (internalformat == 0) {
glTexStorage3DMultisample(gr->target, pr->nr_samples, vrend_printf("unknown format is %d\n", pr->format);
internalformat, pr->width0, pr->height0, pr->array_size, glBindTexture(gr->target, 0);
GL_TRUE); FREE(gt);
} return EINVAL;
} else { }
if (gr->target == GL_TEXTURE_2D_MULTISAMPLE) {
glTexImage2DMultisample(gr->target, pr->nr_samples, if (pr->nr_samples > 0) {
internalformat, pr->width0, pr->height0, if (format_can_texture_storage) {
GL_TRUE); 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 { } else {
glTexImage3DMultisample(gr->target, pr->nr_samples, if (gr->target == GL_TEXTURE_2D_MULTISAMPLE) {
internalformat, pr->width0, pr->height0, pr->array_size, glTexImage2DMultisample(gr->target, pr->nr_samples,
GL_TRUE); 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) {
} else if (gr->target == GL_TEXTURE_CUBE_MAP) { int i;
int i; if (format_can_texture_storage)
if (format_can_texture_storage) glTexStorage2D(GL_TEXTURE_CUBE_MAP, pr->last_level + 1, internalformat, pr->width0, pr->height0);
glTexStorage2D(GL_TEXTURE_CUBE_MAP, pr->last_level + 1, internalformat, pr->width0, pr->height0); else {
else { for (i = 0; i < 6; i++) {
for (i = 0; i < 6; i++) { GLenum ctarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
GLenum ctarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; for (level = 0; level <= pr->last_level; level++) {
for (level = 0; level <= pr->last_level; level++) { unsigned mwidth = u_minify(pr->width0, level);
unsigned mwidth = u_minify(pr->width0, level); unsigned mheight = u_minify(pr->height0, level);
unsigned mheight = u_minify(pr->height0, level);
glTexImage2D(ctarget, level, internalformat, mwidth, mheight, 0, glformat,
glTexImage2D(ctarget, level, internalformat, mwidth, mheight, 0, glformat, gltype, NULL);
gltype, NULL); }
} }
} }
} } else if (gr->target == GL_TEXTURE_3D ||
} else if (gr->target == GL_TEXTURE_3D || gr->target == GL_TEXTURE_2D_ARRAY ||
gr->target == GL_TEXTURE_2D_ARRAY || gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) {
gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) { if (format_can_texture_storage) {
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++) {
unsigned depth_param = (gr->target == GL_TEXTURE_2D_ARRAY || gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) ? unsigned depth_param = (gr->target == GL_TEXTURE_2D_ARRAY || gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) ?
pr->array_size : u_minify(pr->depth0, level); pr->array_size : pr->depth0;
unsigned mwidth = u_minify(pr->width0, level); glTexStorage3D(gr->target, pr->last_level + 1, internalformat, pr->width0, pr->height0, depth_param);
unsigned mheight = u_minify(pr->height0, level); } else {
glTexImage3D(gr->target, level, internalformat, mwidth, mheight, for (level = 0; level <= pr->last_level; level++) {
depth_param, 0, glformat, gltype, NULL); 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) {
} else if (gr->target == GL_TEXTURE_1D && vrend_state.use_gles) { report_gles_missing_func(NULL, "glTexImage1D");
report_gles_missing_func(NULL, "glTexImage1D"); } else if (gr->target == GL_TEXTURE_1D) {
} else if (gr->target == GL_TEXTURE_1D) { if (format_can_texture_storage) {
if (format_can_texture_storage) { glTexStorage1D(gr->target, pr->last_level + 1, internalformat, pr->width0);
glTexStorage1D(gr->target, pr->last_level + 1, internalformat, pr->width0); } else {
} else { for (level = 0; level <= pr->last_level; level++) {
for (level = 0; level <= pr->last_level; level++) { unsigned mwidth = u_minify(pr->width0, level);
unsigned mwidth = u_minify(pr->width0, level); glTexImage1D(gr->target, level, internalformat, mwidth, 0,
glTexImage1D(gr->target, level, internalformat, mwidth, 0, glformat, gltype, NULL);
glformat, gltype, NULL); }
} }
} } else {
} else { if (format_can_texture_storage)
if (format_can_texture_storage) glTexStorage2D(gr->target, pr->last_level + 1, internalformat, pr->width0,
glTexStorage2D(gr->target, pr->last_level + 1, internalformat, pr->width0, gr->target == GL_TEXTURE_1D_ARRAY ? pr->array_size : pr->height0);
gr->target == GL_TEXTURE_1D_ARRAY ? pr->array_size : pr->height0); else {
else { for (level = 0; level <= pr->last_level; level++) {
for (level = 0; level <= pr->last_level; level++) { unsigned mwidth = u_minify(pr->width0, level);
unsigned mwidth = u_minify(pr->width0, level); unsigned mheight = u_minify(pr->height0, level);
unsigned mheight = u_minify(pr->height0, level); glTexImage2D(gr->target, level, internalformat, mwidth,
glTexImage2D(gr->target, level, internalformat, mwidth, gr->target == GL_TEXTURE_1D_ARRAY ? pr->array_size : mheight,
gr->target == GL_TEXTURE_1D_ARRAY ? pr->array_size : mheight, 0, glformat, gltype, NULL);
0, glformat, gltype, NULL); }
} }
} }
} }

@ -58,6 +58,7 @@ enum vrend_resource_storage_type {
/* The resource contents are stored in shared guest memory if it's /* The resource contents are stored in shared guest memory if it's
* attached, otherwise in host system memory. */ * attached, otherwise in host system memory. */
VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM, VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM,
VREND_RESOURCE_STORAGE_GBM_ONLY,
}; };
struct vrend_resource { struct vrend_resource {

Loading…
Cancel
Save