[PATCH] glamor: initial attempt at component alpha in single pass

Dave Airlie airlied at gmail.com
Tue Jan 12 17:25:34 PST 2016


From: Dave Airlie <airlied at redhat.com>

It's been on the list to add dual source blending support to avoid
the two pass componentAlpha code, radeon has done this for a while
in EXA, so let's add support to bring glamor up to using it.

This adds dual blend to both render and composite glyphs paths.

Initial results show close to doubling of speed of x11perf -rgb10text.

Signed-off-by: Dave Airlie <airlied at redhat.com>
---
 glamor/glamor.c                  |  2 ++
 glamor/glamor_composite_glyphs.c |  2 +-
 glamor/glamor_priv.h             |  8 +++++
 glamor/glamor_program.c          | 28 ++++++++++++++--
 glamor/glamor_program.h          |  1 +
 glamor/glamor_render.c           | 71 ++++++++++++++++++++++++++++++++++------
 6 files changed, 98 insertions(+), 14 deletions(-)

diff --git a/glamor/glamor.c b/glamor/glamor.c
index 116d10c..523f0cb 100644
--- a/glamor/glamor.c
+++ b/glamor/glamor.c
@@ -571,6 +571,8 @@ glamor_init(ScreenPtr screen, unsigned int flags)
         glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP ||
         epoxy_gl_version() >= 30 ||
         epoxy_has_gl_extension("GL_NV_pack_subimage");
+    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 8692904..fb31340 100644
--- a/glamor/glamor_composite_glyphs.c
+++ b/glamor/glamor_composite_glyphs.c
@@ -186,7 +186,7 @@ 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;\nout vec4 color0;\nout 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 a190e67..6a84548 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,
 };
 
@@ -201,6 +208,7 @@ typedef struct glamor_screen_private {
     Bool has_unpack_subimage;
     Bool has_rw_pbo;
     Bool use_quads;
+    Bool has_dual_blend;
     int max_fbo_size;
 
     struct xorg_list
diff --git a/glamor/glamor_program.c b/glamor/glamor_program.c
index 416c54a..f3e1202 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);
 
@@ -438,6 +442,10 @@ static struct blendinfo composite_op_info[] = {
     [PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
 };
 
+static struct blendinfo composite_op_db_info[] = {
+    [PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC1_ALPHA},
+};
+
 static void
 glamor_set_blend(CARD8 op, glamor_program_alpha alpha, PicturePtr dst)
 {
@@ -459,6 +467,8 @@ glamor_set_blend(CARD8 op, glamor_program_alpha alpha, PicturePtr dst)
         return;
 
     op_info = &composite_op_info[op];
+    if (alpha == glamor_program_alpha_dual_blend)
+        op_info = &composite_op_db_info[op];
 
     src_blend = op_info->source_blend;
     dst_blend = op_info->dest_blend;
@@ -479,6 +489,10 @@ glamor_set_blend(CARD8 op, glamor_program_alpha alpha, PicturePtr dst)
             dst_blend = GL_SRC_COLOR;
         else if (dst_blend == GL_ONE_MINUS_SRC_ALPHA)
             dst_blend = GL_ONE_MINUS_SRC_COLOR;
+        else if (dst_blend == GL_SRC1_ALPHA)
+            dst_blend = GL_SRC1_COLOR;
+        else if (dst_blend == GL_ONE_MINUS_SRC1_ALPHA)
+            dst_blend = GL_ONE_MINUS_SRC1_COLOR;
     }
 
     glEnable(GL_BLEND);
@@ -547,7 +561,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 +583,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 +601,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;
@@ -596,7 +613,12 @@ glamor_setup_program_render(CARD8                 op,
         /* 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 {
+            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 9e561cd..ab6e46f 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 d8574ec..da3af4f 100644
--- a/glamor/glamor_render.c
+++ b/glamor/glamor_render.c
@@ -59,6 +59,10 @@ static struct blendinfo composite_op_info[] = {
     [PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
 };
 
+static struct blendinfo ca_composite_op_info[] = {
+    [PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC1_COLOR},
+};
+
 #define RepeatFix			10
 static GLuint
 glamor_create_composite_fs(struct shader_key *key)
@@ -208,10 +212,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 +262,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 +276,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 +354,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;
@@ -391,7 +418,15 @@ glamor_set_composite_op(ScreenPtr screen,
         glamor_fallback("unsupported render op %d \n", op);
         return GL_FALSE;
     }
-    op_info = &composite_op_info[op];
+
+    if (mask && mask->componentAlpha) {
+        if (op != PictOpOver) {
+            glamor_fallback("unsupported render op %d \n", op);
+            return GL_FALSE;
+        }
+        op_info = &ca_composite_op_info[op];
+    } else
+        op_info = &composite_op_info[op];
 
     source_blend = op_info->source_blend;
     dest_blend = op_info->dest_blend;
@@ -413,6 +448,10 @@ glamor_set_composite_op(ScreenPtr screen,
             dest_blend = GL_SRC_COLOR;
         else if (dest_blend == GL_ONE_MINUS_SRC_ALPHA)
             dest_blend = GL_ONE_MINUS_SRC_COLOR;
+        else if (dest_blend == GL_SRC1_ALPHA)
+            dest_blend = GL_SRC1_COLOR;
+        else if (dest_blend == GL_ONE_MINUS_SRC1_ALPHA)
+            dest_blend = GL_ONE_MINUS_SRC1_COLOR;
     }
 
     op_info_result->source_blend = source_blend;
@@ -698,6 +737,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;
     }
@@ -793,6 +836,7 @@ glamor_composite_choose_shader(CARD8 op,
                                PictFormatShort *psaved_source_format)
 {
     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;
@@ -861,6 +905,8 @@ glamor_composite_choose_shader(CARD8 op,
         else {
             if (op == PictOpClear)
                 key.mask = SHADER_MASK_NONE;
+            else if (op == PictOpOver && glamor_priv->has_dual_blend)
+                key.in = SHADER_IN_CA_DUAL_BLEND;
             else if (op == PictOpSrc || op == PictOpAdd
                      || op == PictOpIn || op == PictOpOut
                      || op == PictOpOverReverse)
@@ -1100,7 +1146,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);
@@ -1127,7 +1173,7 @@ glamor_composite_with_shader(CARD8 op,
         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,
@@ -1248,7 +1294,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);
@@ -1353,6 +1399,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;
@@ -1370,7 +1417,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);
@@ -1437,9 +1484,13 @@ glamor_composite_clipped_region(CARD8 op,
      */
 
     if (mask && mask->componentAlpha) {
-        if (op == PictOpOver) {
-            two_pass_ca = TRUE;
-            op = PictOpOutReverse;
+        if (!glamor_priv->has_dual_blend) {
+            if (op == PictOpOver) {
+                ca_state = CA_TWO_PASS;
+                op = PictOpOutReverse;
+            }
+        } else {
+            ca_state = CA_DUAL_BLEND;
         }
     }
 
@@ -1500,7 +1551,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;
-- 
2.4.3



More information about the xorg-devel mailing list