From 108ef814a4350409916f48c06b88e6a7e3f16f5e Mon Sep 17 00:00:00 2001 From: Gert Wollny Date: Tue, 14 May 2019 10:59:20 +0200 Subject: [PATCH] formats: Check and enable implementation specific readback formats on GLES With 6a3cd2bd vrend: send list of readback-formats to guest stricter format checks were introduced on GLES. This may lead to format conversions in guest and host that can be avoided for additional implementation specific readback formats. So when we build the format list also check whether a bound texture format can also be read back from the fbo and report the standard and additional formats also to the guest. v2: Make things simpler and more correct (Erik) i.e.: - default to false in the check for readback formats - rename test function to indicate that we test color formats only - don't pass the gl_version, instead use the epoxy functions to get the platform info v3: - check for DS readback support (Thanks to Erik for pointing out that this is not available in unextended GLES) - drop some superfluous braces (Erik) v4: - move DS checks to separate commit (Erik) v5: - split patch to move preparations that don't change functionality to preceeding patches - reduce the amount of error checking (Erik) - only check readback for formats that can actually be used as render targets - remove some temporary variables (Erik) Signed-off-by: Gert Wollny Reviewed-by: Erik Faye-Lund --- src/vrend_formats.c | 36 ++++++++++++++++++++++++++++++++++-- src/vrend_renderer.c | 32 ++++++++++++++------------------ src/vrend_renderer.h | 1 + 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/src/vrend_formats.c b/src/vrend_formats.c index 1f7b008..7ed514b 100644 --- a/src/vrend_formats.c +++ b/src/vrend_formats.c @@ -294,10 +294,37 @@ static struct vrend_format_table gles_bit10_formats[] = { { VIRGL_FORMAT_B10G10R10A2_UNORM, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, NO_SWIZZLE }, }; +static bool color_format_can_readback(struct vrend_format_table *virgl_format, int gles_ver) +{ + GLint imp = 0; + + if (virgl_format->format == VIRGL_FORMAT_R8G8B8A8_UNORM) + return true; + + if (gles_ver >= 30 && + (virgl_format->format == VIRGL_FORMAT_R32G32B32A32_SINT || + virgl_format->format == VIRGL_FORMAT_R32G32B32A32_UINT)) + return true; + + if ((virgl_format->format == VIRGL_FORMAT_R32G32B32A32_FLOAT) && + (gles_ver >= 32 || epoxy_has_gl_extension("GL_EXT_color_buffer_float"))) + return true; + + /* Check implementation specific readback formats */ + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &imp); + if (imp == (GLint)virgl_format->gltype) { + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &imp); + if (imp == (GLint)virgl_format->glformat) + return true; + } + return false; +} static void vrend_add_formats(struct vrend_format_table *table, int num_entries) { int i; + const bool is_desktop_gl = epoxy_is_desktop_gl(); + const int gles_ver = is_desktop_gl ? 0 : epoxy_gl_version(); for (i = 0; i < num_entries; i++) { GLenum status; @@ -402,8 +429,13 @@ static void vrend_add_formats(struct vrend_format_table *table, int num_entries) status = glCheckFramebufferStatus(GL_FRAMEBUFFER); binding = VIRGL_BIND_SAMPLER_VIEW; - if (status == GL_FRAMEBUFFER_COMPLETE) - binding |= (is_depth ? VIRGL_BIND_DEPTH_STENCIL : VIRGL_BIND_RENDER_TARGET); + if (status == GL_FRAMEBUFFER_COMPLETE) { + binding |= is_depth ? VIRGL_BIND_DEPTH_STENCIL : VIRGL_BIND_RENDER_TARGET; + + if (is_desktop_gl || + color_format_can_readback(&table[i], gles_ver)) + flags |= VIRGL_TEXTURE_CAN_READBACK; + } glDeleteTextures(1, &tex_id); glDeleteFramebuffers(1, &fb_id); diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index 5b0be73..50ae303 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -648,6 +648,12 @@ static inline bool vrend_format_can_sample(enum virgl_formats format) { return tex_conv_table[format].bindings & VIRGL_BIND_SAMPLER_VIEW; } + +static inline bool vrend_format_can_readback(enum virgl_formats format) +{ + return tex_conv_table[format].flags & VIRGL_TEXTURE_CAN_READBACK; +} + static inline bool vrend_format_can_render(enum virgl_formats format) { return tex_conv_table[format].bindings & VIRGL_BIND_RENDER_TARGET; @@ -9027,24 +9033,14 @@ static void vrend_renderer_fill_caps_v2(int gl_ver, int gles_ver, union virgl_c if (has_feature(feat_indirect_params)) caps->v2.capability_bits |= VIRGL_CAP_INDIRECT_PARAMS; - if (gl_ver > 0) { - for (int i = 0; i < VIRGL_FORMAT_MAX; i++) { - if (tex_conv_table[i].internalformat != 0) { - enum virgl_formats fmt = (enum virgl_formats)i; - if (vrend_format_can_sample(fmt)) - set_format_bit(&caps->v2.supported_readback_formats, fmt); - } - } - } else { - assert(gles_ver > 0); - set_format_bit(&caps->v2.supported_readback_formats, VIRGL_FORMAT_R8G8B8A8_UNORM); - - if (gles_ver >= 30) { - set_format_bit(&caps->v2.supported_readback_formats, VIRGL_FORMAT_R32G32B32A32_SINT); - set_format_bit(&caps->v2.supported_readback_formats, VIRGL_FORMAT_R32G32B32A32_UINT); - - if (gles_ver >= 32 || epoxy_has_gl_extension("GL_EXT_color_buffer_float")) - set_format_bit(&caps->v2.supported_readback_formats, VIRGL_FORMAT_R32G32B32A32_FLOAT); + for (int i = 0; i < VIRGL_FORMAT_MAX; i++) { + if (tex_conv_table[i].internalformat != 0) { + enum virgl_formats fmt = (enum virgl_formats)i; + if (vrend_format_can_readback(fmt)) { + VREND_DEBUG(dbg_features, NULL, "Support readback of %s\n", + util_format_name(fmt)); + set_format_bit(&caps->v2.supported_readback_formats, fmt); + } } } diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h index 6a82f0d..24700c8 100644 --- a/src/vrend_renderer.h +++ b/src/vrend_renderer.h @@ -79,6 +79,7 @@ struct vrend_resource { #define VIRGL_TEXTURE_NEED_SWIZZLE (1 << 0) #define VIRGL_TEXTURE_CAN_TEXTURE_STORAGE (1 << 1) +#define VIRGL_TEXTURE_CAN_READBACK (1 << 2) struct vrend_format_table { enum virgl_formats format;