[virglrenderer-devel] [PATCH v2 2/2] vrend: Work around multi-sample glBlitFramebuffer limitations on GLES
Gert Wollny
gert.wollny at collabora.com
Tue Jun 12 10:55:41 UTC 2018
On GLES a multi-sample FBO region can only be blit to an non multi-sample
region if the source and the target rectangle are the same. The fallback
using GL and shaders doesn't work if a stencil buffer is involved, because
writing to a stencil buffer from a shader is usually not supported (i.e.
the extension ARB_shader_stencil_export is not available).
Implement a workaround for this case and also the case when the depth
buffer is involved by first blitting the complete multi-sample FBO to an
intermediate, non multi-sample FBO, and apply the region blit to the
actual target FBO afterwards.
Fixes:
dEQP-GLES3.functional.fbo.invalidate.sub.unbind_blit_msaa_color
dEQP-GLES3.functional.fbo.invalidate.sub.unbind_blit_msaa_depth
dEQP-GLES3.functional.fbo.invalidate.sub.unbind_blit_msaa_stencil
dEQP-GLES3.functional.fbo.invalidate.whole.unbind_blit_msaa_color
dEQP-GLES3.functional.fbo.invalidate.whole.unbind_blit_msaa_depth
dEQP-GLES3.functional.fbo.invalidate.whole.unbind_blit_msaa_stencil
v2: * Replace allocation via the formerly extracted resource allocation
funtion with allocating the texture via the newly extracted methods
to copy the texture parameters and allocate the texture.
* in the intermediate blit use the minified size that corresonds
to the layer to be copied
Signed-off-by: Gert Wollny <gert.wollny at collabora.com>
---
src/vrend_renderer.c | 72 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 68 insertions(+), 4 deletions(-)
diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c
index 9a7412b..30d112e 100644
--- a/src/vrend_renderer.c
+++ b/src/vrend_renderer.c
@@ -6092,6 +6092,9 @@ static void vrend_renderer_blit_int(struct vrend_context *ctx,
GLenum filter;
int n_layers = 1, i;
bool use_gl = false;
+ bool make_intermediate_copy = false;
+ GLuint intermediate_fbo = 0;
+ struct vrend_resource *intermediate_copy = 0;
filter = convert_mag_filter(info->filter);
@@ -6178,6 +6181,51 @@ static void vrend_renderer_blit_int(struct vrend_context *ctx,
} else
glDisable(GL_SCISSOR_TEST);
+ /* An GLES GL_INVALID_OPERATION is generated if one wants to blit from a
+ * multi-sample fbo to a non multi-sample fbo and the source and destination
+ * rectangles are not defined with the same (X0, Y0) and (X1, Y1) bounds.
+ *
+ * Since stencil data can only be written in a fragment shader when
+ * ARB_shader_stencil_export is available, the workaround using GL as given
+ * above is usually not available. Instead, to work around the blit
+ * limitations on GLES first copy the full frame to a non-multisample
+ * surface and then copy the according area to the final target surface.
+ */
+ if (vrend_state.use_gles &&
+ (info->mask & PIPE_MASK_ZS) &&
+ ((src_res->base.nr_samples > 1) &&
+ (src_res->base.nr_samples != dst_res->base.nr_samples)) &&
+ ((info->src.box.x != info->dst.box.x) ||
+ (src_y1 != dst_y1) ||
+ (info->src.box.width != info->dst.box.width) ||
+ (src_y2 != dst_y2))) {
+
+ make_intermediate_copy = true;
+
+ /* Create a texture that is the same like the src_res texture, but
+ * without multi-sample */
+ struct vrend_renderer_resource_create_args args;
+ memset(&args, 0, sizeof(struct vrend_renderer_resource_create_args));
+ args.width = src_res->base.width0;
+ args.height = src_res->base.height0;
+ args.depth = src_res->base.depth0;
+ args.format = src_res->base.format;
+ args.target = src_res->base.target;
+ args.last_level = src_res->base.last_level;
+ args.array_size = src_res->base.array_size;
+ intermediate_copy = (struct vrend_resource *)CALLOC_STRUCT(vrend_texture);
+ vrend_renderer_resource_copy_args(&args, intermediate_copy);
+ vrend_renderer_resource_allocate_texture(intermediate_copy);
+
+ glGenFramebuffers(1, &intermediate_fbo);
+ } else {
+ /* If no intermediate copy is needed make the variables point to the
+ * original source to simplify the code below.
+ */
+ intermediate_fbo = ctx->sub->blit_fb_ids[0];
+ intermediate_copy = src_res;
+ }
+
glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->sub->blit_fb_ids[0]);
if (info->mask & PIPE_MASK_RGBA)
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT,
@@ -6196,16 +6244,28 @@ static void vrend_renderer_blit_int(struct vrend_context *ctx,
n_layers = info->dst.box.depth;
for (i = 0; i < n_layers; i++) {
glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->sub->blit_fb_ids[0]);
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT,
- GL_TEXTURE_2D, 0, 0);
vrend_fb_bind_texture(src_res, 0, info->src.level, info->src.box.z + i);
- glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->sub->blit_fb_ids[1]);
+ if (make_intermediate_copy) {
+ int level_width = u_minify(src_res->base.width0, info->src.level);
+ int level_height = u_minify(src_res->base.width0, info->src.level);
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, intermediate_fbo);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, 0, 0);
+ vrend_fb_bind_texture(intermediate_copy, 0, info->src.level, info->src.box.z + i);
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediate_fbo);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]);
+ glBlitFramebuffer(0, 0, level_width, level_height,
+ 0, 0, level_width, level_height,
+ glmask, filter);
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->sub->blit_fb_ids[1]);
vrend_fb_bind_texture(dst_res, 0, info->dst.level, info->dst.box.z + i);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
- glBindFramebuffer(GL_READ_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, intermediate_fbo);
glBlitFramebuffer(info->src.box.x,
src_y1,
@@ -6218,6 +6278,10 @@ static void vrend_renderer_blit_int(struct vrend_context *ctx,
glmask, filter);
}
+ if (make_intermediate_copy) {
+ vrend_renderer_resource_destroy(intermediate_copy, false);
+ glDeleteFramebuffers(1, &intermediate_fbo);
+ }
}
void vrend_renderer_blit(struct vrend_context *ctx,
--
2.17.1
More information about the virglrenderer-devel
mailing list