From 2abe2e6d41c3460d6306dcd547fe58740c68f0ca Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 3 Sep 2012 16:48:42 +0300 Subject: [PATCH] compositor: paint opaque regions with RGBX shader weston_surface_draw() is restructured so that it will always use the RGBX shader for opaque regions, if the surface is assigned the RGBA shader. Previously for opaque regions, we simply assumed, that the texture alpha would be 1.0. If it was not (which really is an application bug), the region would be misrendered. The RGBX shader forces the texture alpha to 1.0. Xwayland surfaces may have bad alpha data in the opaque client area. If blending was enabled, the bad alpha would be used with the RGBA shader. This patch fixes rendering opaque xwayland windows with full-surface alpha applied. Test case: xterm, with full-surface alpha one step below 1.0. Before, black text was fully transparent, now it is correctly only slightly transparent. Signed-off-by: Pekka Paalanen --- src/compositor.c | 74 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index 5e9a0c25..918b455b 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1317,6 +1317,32 @@ repaint_region(struct weston_surface *es, pixman_region32_t *region, ec->vtxcnt.size = 0; } +static void +weston_compositor_use_shader(struct weston_compositor *compositor, + struct weston_shader *shader) +{ + if (compositor->current_shader == shader) + return; + + glUseProgram(shader->program); + compositor->current_shader = shader; +} + +static void +weston_shader_uniforms(struct weston_shader *shader, + struct weston_surface *surface, + struct weston_output *output) +{ + int i; + + glUniformMatrix4fv(shader->proj_uniform, + 1, GL_FALSE, output->matrix.d); + glUniform4fv(shader->color_uniform, 1, surface->color); + glUniform1f(shader->alpha_uniform, surface->alpha); + + for (i = 0; i < surface->num_textures; i++) + glUniform1i(shader->tex_uniforms[i], i); +} WL_EXPORT void weston_surface_draw(struct weston_surface *es, struct weston_output *output, @@ -1331,8 +1357,6 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output, int i; pixman_region32_init(&repaint); - pixman_region32_init(&surface_blend); - pixman_region32_intersect(&repaint, &es->transform.boundingbox, damage); pixman_region32_subtract(&repaint, &repaint, &es->clip); @@ -1345,22 +1369,8 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output, glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - /* blended region is whole surface minus opaque region: */ - pixman_region32_init_rect(&surface_blend, 0, 0, - es->geometry.width, es->geometry.height); - if (es->alpha >= 1.0) - pixman_region32_subtract(&surface_blend, &surface_blend, - &es->opaque); - - if (ec->current_shader != es->shader) { - glUseProgram(es->shader->program); - ec->current_shader = es->shader; - } - - glUniformMatrix4fv(es->shader->proj_uniform, - 1, GL_FALSE, output->matrix.d); - glUniform4fv(es->shader->color_uniform, 1, es->color); - glUniform1f(es->shader->alpha_uniform, es->alpha); + weston_compositor_use_shader(ec, es->shader); + weston_shader_uniforms(es->shader, es, output); if (es->transform.enabled || output->zoom.active) filter = GL_LINEAR; @@ -1368,26 +1378,46 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output, filter = GL_NEAREST; for (i = 0; i < es->num_textures; i++) { - glUniform1i(es->shader->tex_uniforms[i], i); glActiveTexture(GL_TEXTURE0 + i); glBindTexture(es->target, es->textures[i]); glTexParameteri(es->target, GL_TEXTURE_MIN_FILTER, filter); glTexParameteri(es->target, GL_TEXTURE_MAG_FILTER, filter); } - if (pixman_region32_not_empty(&es->opaque) && es->alpha >= 1.0) { - glDisable(GL_BLEND); + /* blended region is whole surface minus opaque region: */ + pixman_region32_init_rect(&surface_blend, 0, 0, + es->geometry.width, es->geometry.height); + pixman_region32_subtract(&surface_blend, &surface_blend, &es->opaque); + + if (pixman_region32_not_empty(&es->opaque)) { + if (es->shader == &ec->texture_shader_rgba) { + /* Special case for RGBA textures with possibly + * bad data in alpha channel: use the shader + * that forces texture alpha = 1.0. + * Xwayland surfaces need this. + */ + weston_compositor_use_shader(ec, &ec->texture_shader_rgbx); + weston_shader_uniforms(&ec->texture_shader_rgbx, es, output); + } + + if (es->alpha < 1.0) + glEnable(GL_BLEND); + else + glDisable(GL_BLEND); + repaint_region(es, &repaint, &es->opaque); } if (pixman_region32_not_empty(&surface_blend)) { + weston_compositor_use_shader(ec, es->shader); glEnable(GL_BLEND); repaint_region(es, &repaint, &surface_blend); } + pixman_region32_fini(&surface_blend); + out: pixman_region32_fini(&repaint); - pixman_region32_fini(&surface_blend); } WL_EXPORT void