diff --git a/glamor/glamor.c b/glamor/glamor.c index 0b5ebef1d..d4f3be2dd 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -576,6 +576,8 @@ glamor_init(ScreenPtr screen, unsigned int flags) epoxy_has_gl_extension("GL_NV_pack_subimage"); glamor_priv->has_vertex_array_object = epoxy_has_gl_extension("GL_ARB_vertex_array_object"); + glamor_priv->has_dual_blend = + epoxy_has_gl_extension("GL_ARB_blend_func_extended"); glamor_setup_debug_output(screen); diff --git a/glamor/glamor_composite_glyphs.c b/glamor/glamor_composite_glyphs.c index 8692904eb..2e4dfe223 100644 --- a/glamor/glamor_composite_glyphs.c +++ b/glamor/glamor_composite_glyphs.c @@ -186,7 +186,9 @@ static const glamor_facet glamor_facet_composite_glyphs_130 = { .vs_exec = (" vec2 pos = primitive.zw * vec2(gl_VertexID&1, (gl_VertexID&2)>>1);\n" GLAMOR_POS(gl_Position, (primitive.xy + pos)) " glyph_pos = (source + pos) * ATLAS_DIM_INV;\n"), - .fs_vars = ("varying vec2 glyph_pos;\n"), + .fs_vars = ("varying vec2 glyph_pos;\n" + "out vec4 color0;\n" + "out vec4 color1;\n"), .fs_exec = (" vec4 mask = texture2D(atlas, glyph_pos);\n"), .source_name = "source", .locations = glamor_program_location_atlas, diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h index 8ed53e7fb..e49aee5ab 100644 --- a/glamor/glamor_priv.h +++ b/glamor/glamor_priv.h @@ -86,6 +86,12 @@ typedef struct glamor_composite_shader { }; } glamor_composite_shader; +enum ca_state { + CA_NONE, + CA_TWO_PASS, + CA_DUAL_BLEND, +}; + enum shader_source { SHADER_SOURCE_SOLID, SHADER_SOURCE_TEXTURE, @@ -106,6 +112,7 @@ enum shader_in { SHADER_IN_NORMAL, SHADER_IN_CA_SOURCE, SHADER_IN_CA_ALPHA, + SHADER_IN_CA_DUAL_BLEND, SHADER_IN_COUNT, }; @@ -202,6 +209,7 @@ typedef struct glamor_screen_private { Bool has_rw_pbo; Bool use_quads; Bool has_vertex_array_object; + Bool has_dual_blend; int max_fbo_size; struct xorg_list diff --git a/glamor/glamor_program.c b/glamor/glamor_program.c index 416c54a71..ddab16f05 100644 --- a/glamor/glamor_program.c +++ b/glamor/glamor_program.c @@ -344,6 +344,10 @@ glamor_build_program(ScreenPtr screen, #endif glBindAttribLocation(prog->prog, GLAMOR_VERTEX_SOURCE, prim->source_name); } + if (prog->alpha == glamor_program_alpha_dual_blend) { + glBindFragDataLocationIndexed(prog->prog, 0, 0, "color0"); + glBindFragDataLocationIndexed(prog->prog, 0, 1, "color1"); + } glamor_link_glsl_prog(screen, prog->prog, "%s_%s", prim->name, fill->name); @@ -474,11 +478,24 @@ glamor_set_blend(CARD8 op, glamor_program_alpha alpha, PicturePtr dst) } /* Set up the source alpha value for blending in component alpha mode. */ - if (alpha != glamor_program_alpha_normal && op_info->source_alpha) { - if (dst_blend == GL_SRC_ALPHA) + if (alpha == glamor_program_alpha_dual_blend) { + switch (dst_blend) { + case GL_SRC_ALPHA: + dst_blend = GL_SRC1_COLOR; + break; + case GL_ONE_MINUS_SRC_ALPHA: + dst_blend = GL_ONE_MINUS_SRC1_COLOR; + break; + } + } else if (alpha != glamor_program_alpha_normal) { + switch (dst_blend) { + case GL_SRC_ALPHA: dst_blend = GL_SRC_COLOR; - else if (dst_blend == GL_ONE_MINUS_SRC_ALPHA) + break; + case GL_ONE_MINUS_SRC_ALPHA: dst_blend = GL_ONE_MINUS_SRC_COLOR; + break; + } } glEnable(GL_BLEND); @@ -547,7 +564,9 @@ static const glamor_facet *glamor_facet_source[glamor_program_source_count] = { static const char *glamor_combine[] = { [glamor_program_alpha_normal] = " gl_FragColor = source * mask.a;\n", [glamor_program_alpha_ca_first] = " gl_FragColor = source.a * mask;\n", - [glamor_program_alpha_ca_second] = " gl_FragColor = source * mask;\n" + [glamor_program_alpha_ca_second] = " gl_FragColor = source * mask;\n", + [glamor_program_alpha_dual_blend] = " color0 = source * mask;\n" + " color1 = source.a * mask;\n" }; static Bool @@ -567,9 +586,9 @@ glamor_setup_one_program_render(ScreenPtr screen, if (!fill) return FALSE; + prog->alpha = alpha; if (!glamor_build_program(screen, prog, prim, fill, glamor_combine[alpha], defines)) return FALSE; - prog->alpha = alpha; } return TRUE; @@ -585,6 +604,7 @@ glamor_setup_program_render(CARD8 op, const char *defines) { ScreenPtr screen = dst->pDrawable->pScreen; + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); glamor_program_alpha alpha; glamor_program_source source_type; glamor_program *prog; @@ -593,10 +613,15 @@ glamor_setup_program_render(CARD8 op, return NULL; if (glamor_is_component_alpha(mask)) { - /* This only works for PictOpOver */ - if (op != PictOpOver) - return NULL; - alpha = glamor_program_alpha_ca_first; + if (glamor_priv->has_dual_blend) { + alpha = glamor_program_alpha_dual_blend; + } else { + /* This only works for PictOpOver */ + if (op != PictOpOver) + return NULL; + + alpha = glamor_program_alpha_ca_first; + } } else alpha = glamor_program_alpha_normal; diff --git a/glamor/glamor_program.h b/glamor/glamor_program.h index 9e561cd92..ab6e46f7b 100644 --- a/glamor/glamor_program.h +++ b/glamor/glamor_program.h @@ -43,6 +43,7 @@ typedef enum { glamor_program_alpha_normal, glamor_program_alpha_ca_first, glamor_program_alpha_ca_second, + glamor_program_alpha_dual_blend, glamor_program_alpha_count } glamor_program_alpha; diff --git a/glamor/glamor_render.c b/glamor/glamor_render.c index 1b226aa28..e563e4099 100644 --- a/glamor/glamor_render.c +++ b/glamor/glamor_render.c @@ -208,10 +208,24 @@ glamor_create_composite_fs(struct shader_key *key) "{\n" " gl_FragColor = get_source().a * get_mask();\n" "}\n"; + const char *in_ca_dual_blend = + GLAMOR_DEFAULT_PRECISION + "out vec4 color0;\n" + "out vec4 color1;\n" + "void main()\n" + "{\n" + " color0 = get_source() * get_mask();\n" + " color1 = get_source().a * get_mask();\n" + "}\n"; + const char *header_ca_dual_blend = + "#version 130\n"; + char *source; const char *source_fetch; const char *mask_fetch = ""; const char *in; + const char *header; + const char *header_norm = ""; GLuint prog; switch (key->source) { @@ -244,6 +258,7 @@ glamor_create_composite_fs(struct shader_key *key) FatalError("Bad composite shader mask"); } + header = header_norm; switch (key->in) { case SHADER_IN_SOURCE_ONLY: in = in_source_only; @@ -257,11 +272,15 @@ glamor_create_composite_fs(struct shader_key *key) case SHADER_IN_CA_ALPHA: in = in_ca_alpha; break; + case SHADER_IN_CA_DUAL_BLEND: + in = in_ca_dual_blend; + header = header_ca_dual_blend; + break; default: FatalError("Bad composite IN type"); } - XNFasprintf(&source, "%s%s%s%s%s%s", repeat_define, relocate_texture, + XNFasprintf(&source, "%s%s%s%s%s%s%s", header, repeat_define, relocate_texture, rel_sampler, source_fetch, mask_fetch, in); prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, source); @@ -331,6 +350,10 @@ glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key, glBindAttribLocation(prog, GLAMOR_VERTEX_SOURCE, "v_texcoord0"); glBindAttribLocation(prog, GLAMOR_VERTEX_MASK, "v_texcoord1"); + if (key->in == SHADER_IN_CA_DUAL_BLEND) { + glBindFragDataLocationIndexed(prog, 0, 0, "color0"); + glBindFragDataLocationIndexed(prog, 0, 1, "color1"); + } glamor_link_glsl_prog(screen, prog, "composite"); shader->prog = prog; @@ -382,7 +405,8 @@ glamor_lookup_composite_shader(ScreenPtr screen, struct static Bool glamor_set_composite_op(ScreenPtr screen, CARD8 op, struct blendinfo *op_info_result, - PicturePtr dest, PicturePtr mask) + PicturePtr dest, PicturePtr mask, + enum ca_state ca_state) { GLenum source_blend, dest_blend; struct blendinfo *op_info; @@ -391,6 +415,7 @@ glamor_set_composite_op(ScreenPtr screen, glamor_fallback("unsupported render op %d \n", op); return GL_FALSE; } + op_info = &composite_op_info[op]; source_blend = op_info->source_blend; @@ -407,12 +432,25 @@ glamor_set_composite_op(ScreenPtr screen, } /* Set up the source alpha value for blending in component alpha mode. */ - if (mask && mask->componentAlpha - && PICT_FORMAT_RGB(mask->format) != 0 && op_info->source_alpha) { - if (dest_blend == GL_SRC_ALPHA) + if (ca_state == CA_DUAL_BLEND) { + switch (dest_blend) { + case GL_SRC_ALPHA: + dest_blend = GL_SRC1_COLOR; + break; + case GL_ONE_MINUS_SRC_ALPHA: + dest_blend = GL_ONE_MINUS_SRC1_COLOR; + break; + } + } else if (mask && mask->componentAlpha + && PICT_FORMAT_RGB(mask->format) != 0 && op_info->source_alpha) { + switch (dest_blend) { + case GL_SRC_ALPHA: dest_blend = GL_SRC_COLOR; - else if (dest_blend == GL_ONE_MINUS_SRC_ALPHA) + break; + case GL_ONE_MINUS_SRC_ALPHA: dest_blend = GL_ONE_MINUS_SRC_COLOR; + break; + } } op_info_result->source_blend = source_blend; @@ -623,6 +661,10 @@ combine_pict_format(PictFormatShort * des, const PictFormatShort src, src_type = PICT_TYPE_A; mask_type = PICT_FORMAT_TYPE(mask); break; + case SHADER_IN_CA_DUAL_BLEND: + src_type = PICT_FORMAT_TYPE(src); + mask_type = PICT_FORMAT_TYPE(mask); + break; default: return FALSE; } @@ -715,9 +757,11 @@ glamor_composite_choose_shader(CARD8 op, struct shader_key *s_key, glamor_composite_shader ** shader, struct blendinfo *op_info, - PictFormatShort *psaved_source_format) + PictFormatShort *psaved_source_format, + enum ca_state ca_state) { ScreenPtr screen = dest->pDrawable->pScreen; + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); enum glamor_pixmap_status source_status = GLAMOR_NONE; enum glamor_pixmap_status mask_status = GLAMOR_NONE; PictFormatShort saved_source_format = 0; @@ -786,6 +830,8 @@ glamor_composite_choose_shader(CARD8 op, else { if (op == PictOpClear) key.mask = SHADER_MASK_NONE; + else if (glamor_priv->has_dual_blend) + key.in = SHADER_IN_CA_DUAL_BLEND; else if (op == PictOpSrc || op == PictOpAdd || op == PictOpIn || op == PictOpOut || op == PictOpOverReverse) @@ -933,7 +979,7 @@ glamor_composite_choose_shader(CARD8 op, goto fail; } - if (!glamor_set_composite_op(screen, op, op_info, dest, mask)) + if (!glamor_set_composite_op(screen, op, op_info, dest, mask, ca_state)) goto fail; *shader = glamor_lookup_composite_shader(screen, &key); @@ -1025,7 +1071,7 @@ glamor_composite_with_shader(CARD8 op, glamor_pixmap_private *mask_pixmap_priv, glamor_pixmap_private *dest_pixmap_priv, int nrect, glamor_composite_rect_t *rects, - Bool two_pass_ca) + enum ca_state ca_state) { ScreenPtr screen = dest->pDrawable->pScreen; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); @@ -1048,17 +1094,17 @@ glamor_composite_with_shader(CARD8 op, source_pixmap_priv, mask_pixmap_priv, dest_pixmap_priv, &key, &shader, &op_info, - &saved_source_format)) { + &saved_source_format, ca_state)) { glamor_fallback("glamor_composite_choose_shader failed\n"); return ret; } - if (two_pass_ca) { + if (ca_state == CA_TWO_PASS) { if (!glamor_composite_choose_shader(PictOpAdd, source, mask, dest, source_pixmap, mask_pixmap, dest_pixmap, source_pixmap_priv, mask_pixmap_priv, dest_pixmap_priv, &key_ca, &shader_ca, &op_info_ca, - &saved_source_format)) { + &saved_source_format, ca_state)) { glamor_fallback("glamor_composite_choose_shader failed\n"); return ret; } @@ -1173,7 +1219,7 @@ glamor_composite_with_shader(CARD8 op, glamor_put_vbo_space(screen); glamor_flush_composite_rects(screen); nrect -= rect_processed; - if (two_pass_ca) { + if (ca_state == CA_TWO_PASS) { glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv, &key_ca, shader_ca, &op_info_ca); glamor_flush_composite_rects(screen); @@ -1278,6 +1324,7 @@ glamor_composite_clipped_region(CARD8 op, glamor_pixmap_private *source_pixmap_priv = glamor_get_pixmap_private(source_pixmap); glamor_pixmap_private *mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap); glamor_pixmap_private *dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap); + glamor_screen_private *glamor_priv = glamor_get_screen_private(dest_pixmap->drawable.pScreen); ScreenPtr screen = dest->pDrawable->pScreen; PicturePtr temp_src = source, temp_mask = mask; PixmapPtr temp_src_pixmap = source_pixmap; @@ -1295,7 +1342,7 @@ glamor_composite_clipped_region(CARD8 op, int height; BoxPtr box; int nbox; - Bool two_pass_ca = FALSE; + enum ca_state ca_state = CA_NONE; extent = RegionExtents(region); box = RegionRects(region); @@ -1357,14 +1404,15 @@ glamor_composite_clipped_region(CARD8 op, x_temp_mask = -extent->x1 + x_dest + dest->pDrawable->x; y_temp_mask = -extent->y1 + y_dest + dest->pDrawable->y; } - /* Do two-pass PictOpOver componentAlpha, until we enable - * dual source color blending. - */ if (mask && mask->componentAlpha) { - if (op == PictOpOver) { - two_pass_ca = TRUE; - op = PictOpOutReverse; + if (glamor_priv->has_dual_blend) { + ca_state = CA_DUAL_BLEND; + } else { + if (op == PictOpOver) { + ca_state = CA_TWO_PASS; + op = PictOpOutReverse; + } } } @@ -1416,7 +1464,7 @@ glamor_composite_clipped_region(CARD8 op, temp_src_pixmap, temp_mask_pixmap, dest_pixmap, temp_src_priv, temp_mask_priv, dest_pixmap_priv, - box_cnt, prect, two_pass_ca); + box_cnt, prect, ca_state); if (!ok) break; nbox -= box_cnt; @@ -1477,7 +1525,7 @@ glamor_composite(CARD8 op, if (op >= ARRAY_SIZE(composite_op_info)) goto fail; - if (mask && mask->componentAlpha) { + if (mask && mask->componentAlpha && !glamor_priv->has_dual_blend) { if (op == PictOpAtop || op == PictOpAtopReverse || op == PictOpXor || op >= PictOpSaturate) {