diff --git a/libweston/renderer-gl/fragment.glsl b/libweston/renderer-gl/fragment.glsl index f56d1bc1..daa9cf67 100644 --- a/libweston/renderer-gl/fragment.glsl +++ b/libweston/renderer-gl/fragment.glsl @@ -53,6 +53,7 @@ precision mediump float; * snippet. */ compile_const int c_variant = DEF_VARIANT; +compile_const bool c_input_is_premult = DEF_INPUT_IS_PREMULT; compile_const bool c_green_tint = DEF_GREEN_TINT; vec4 @@ -79,7 +80,6 @@ yuva2rgba(vec4 yuva) color_out.g = Y - 0.39176229 * su - 0.81296764 * sv; color_out.b = Y + 2.01723214 * su; - color_out.rgb *= yuva.w; color_out.a = yuva.w; return color_out; @@ -146,11 +146,18 @@ main() { vec4 color; - /* Electrical (non-linear) RGBA values, pre-multiplied */ + /* Electrical (non-linear) RGBA values, may be premult or not */ color = sample_input_texture(); - /* View alpha (opacity) */ - color *= alpha; + /* Ensure premultiplied alpha, apply view alpha (opacity) */ + if (c_input_is_premult) { + color *= alpha; + } else { + color.a *= alpha; + color.rgb *= color.a; + } + + /* color is guaranteed premult here */ if (c_green_tint) color = vec4(0.0, 0.3, 0.0, 0.2) + color * 0.8; diff --git a/libweston/renderer-gl/gl-renderer-internal.h b/libweston/renderer-gl/gl-renderer-internal.h index cf2476db..0beb1dc6 100644 --- a/libweston/renderer-gl/gl-renderer-internal.h +++ b/libweston/renderer-gl/gl-renderer-internal.h @@ -62,13 +62,14 @@ enum gl_shader_texture_variant { struct gl_shader_requirements { unsigned variant:4; /* enum gl_shader_texture_variant */ + bool input_is_premult:1; bool green_tint:1; /* * The total size of all bitfields plus pad_bits_ must fill up exactly * how many bytes the compiler allocates for them together. */ - unsigned pad_bits_:27; + unsigned pad_bits_:26; }; static_assert(sizeof(struct gl_shader_requirements) == 4 /* total bitfield size in bytes */, @@ -202,6 +203,9 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec); GLenum gl_shader_texture_variant_get_target(enum gl_shader_texture_variant v); +bool +gl_shader_texture_variant_can_be_premult(enum gl_shader_texture_variant v); + void gl_shader_destroy(struct gl_renderer *gr, struct gl_shader *shader); diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index f4ee6891..5f9b8c2d 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -738,6 +738,7 @@ triangle_fan_debug(struct gl_renderer *gr, alt = (struct gl_shader_config) { .req = { .variant = SHADER_VARIANT_SOLID, + .input_is_premult = true, }, .projection = sconf->projection, .view_alpha = 1.0f, @@ -925,6 +926,7 @@ maybe_censor_override(struct gl_shader_config *sconf, const struct gl_shader_config alt = { .req = { .variant = SHADER_VARIANT_SOLID, + .input_is_premult = true, }, .projection = sconf->projection, .view_alpha = sconf->view_alpha, @@ -960,6 +962,8 @@ gl_shader_config_set_input_textures(struct gl_shader_config *sconf, int i; sconf->req.variant = gs->shader_variant; + sconf->req.input_is_premult = + gl_shader_texture_variant_can_be_premult(gs->shader_variant); for (i = 0; i < 4; i++) sconf->unicolor[i] = gs->color[i]; @@ -1264,6 +1268,7 @@ draw_output_borders(struct weston_output *output, struct gl_shader_config sconf = { .req = { .variant = SHADER_VARIANT_RGBA, + .input_is_premult = true, }, .view_alpha = 1.0f, }; @@ -1488,6 +1493,7 @@ blit_shadow_to_output(struct weston_output *output, const struct gl_shader_config sconf = { .req = { .variant = SHADER_VARIANT_RGBA, + .input_is_premult = true, }, .projection = { .d = { /* transpose */ diff --git a/libweston/renderer-gl/gl-shaders.c b/libweston/renderer-gl/gl-shaders.c index 4a47ca98..0b1c8cfb 100644 --- a/libweston/renderer-gl/gl-shaders.c +++ b/libweston/renderer-gl/gl-shaders.c @@ -147,8 +147,9 @@ create_shader_description_string(const struct gl_shader_requirements *req) int size; char *str; - size = asprintf(&str, "%s %cgreen", + size = asprintf(&str, "%s %cinput_is_premult %cgreen", gl_shader_texture_variant_to_string(req->variant), + req->input_is_premult ? '+' : '-', req->green_tint ? '+' : '-'); if (size < 0) return NULL; @@ -163,8 +164,10 @@ create_shader_config_string(const struct gl_shader_requirements *req) size = asprintf(&str, "#define DEF_GREEN_TINT %s\n" + "#define DEF_INPUT_IS_PREMULT %s\n" "#define DEF_VARIANT %s\n", req->green_tint ? "true" : "false", + req->input_is_premult ? "true" : "false", gl_shader_texture_variant_to_string(req->variant)); if (size < 0) return NULL; @@ -349,6 +352,7 @@ gl_renderer_create_fallback_shader(struct gl_renderer *gr) { static const struct gl_shader_requirements fallback_requirements = { .variant = SHADER_VARIANT_SOLID, + .input_is_premult = true, }; struct gl_shader *shader; @@ -415,6 +419,25 @@ gl_renderer_garbage_collect_programs(struct gl_renderer *gr) } } +bool +gl_shader_texture_variant_can_be_premult(enum gl_shader_texture_variant v) +{ + switch (v) { + case SHADER_VARIANT_SOLID: + case SHADER_VARIANT_RGBA: + case SHADER_VARIANT_EXTERNAL: + return true; + case SHADER_VARIANT_NONE: + case SHADER_VARIANT_RGBX: + case SHADER_VARIANT_Y_U_V: + case SHADER_VARIANT_Y_UV: + case SHADER_VARIANT_Y_XUXV: + case SHADER_VARIANT_XYUV: + return false; + } + return true; +} + GLenum gl_shader_texture_variant_get_target(enum gl_shader_texture_variant v) {