[PATCH 6/7] glamor: Adapt glamor_program API to handle render acceleration

Eric Anholt eric at anholt.net
Tue May 12 13:48:34 PDT 2015


Summary: Tiny nitpicks, one functional concern.

Keith Packard <keithp at keithp.com> writes:
> This extends the existing API to support options needed for render
> accleratoin, including an additional fragment, 'combine', (which

acceleration

> provides a place to perform the source IN mask operation before the
> final OP dest state) and an addtional 'defines' parameter which

additional

> provides a way to add target-dependent values without using a uniform.
>
> Signed-off-by: Keith Packard <keithp at keithp.com>
> ---
>  glamor/glamor_copy.c    |   2 +-
>  glamor/glamor_dash.c    |   2 +-
>  glamor/glamor_points.c  |   3 +-
>  glamor/glamor_program.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++--
>  glamor/glamor_program.h |  51 ++++++++++-
>  glamor/glamor_text.c    |   2 +-
>  6 files changed, 279 insertions(+), 11 deletions(-)
>
> diff --git a/glamor/glamor_copy.c b/glamor/glamor_copy.c
> index 921e80e..2ffe645 100644
> --- a/glamor/glamor_copy.c
> +++ b/glamor/glamor_copy.c
> @@ -338,7 +338,7 @@ glamor_copy_fbo_fbo_draw(DrawablePtr src,
>  
>      if (!prog->prog) {
>          if (!glamor_build_program(screen, prog,
> -                                  copy_facet, NULL))
> +                                  copy_facet, NULL, NULL, NULL))
>              goto bail_ctx;
>      }
>  
> diff --git a/glamor/glamor_dash.c b/glamor/glamor_dash.c
> index 4281ff0..101228e 100644
> --- a/glamor/glamor_dash.c
> +++ b/glamor/glamor_dash.c
> @@ -170,7 +170,7 @@ glamor_dash_setup(DrawablePtr drawable, GCPtr gc)
>          if (!prog->prog) {
>              if (!glamor_build_program(screen, prog,
>                                        &glamor_facet_double_dash_lines,
> -                                      NULL))
> +                                      NULL, NULL, NULL))
>                  goto bail;
>          }
>  
> diff --git a/glamor/glamor_points.c b/glamor/glamor_points.c
> index df7e5a2..3ba4a69 100644
> --- a/glamor/glamor_points.c
> +++ b/glamor/glamor_points.c
> @@ -60,7 +60,8 @@ glamor_poly_point_gl(DrawablePtr drawable, GCPtr gc, int mode, int npt, DDXPoint
>      if (!prog->prog) {
>          if (!glamor_build_program(screen, prog,
>                                    &glamor_facet_point,
> -                                  &glamor_fill_solid))
> +                                  &glamor_fill_solid,
> +                                  NULL, NULL))
>              goto bail;
>      }
>  
> diff --git a/glamor/glamor_program.c b/glamor/glamor_program.c
> index 8aab53f..857256d 100644
> --- a/glamor/glamor_program.c
> +++ b/glamor/glamor_program.c
> @@ -183,6 +183,7 @@ fs_location_vars(glamor_program_location locations)
>  
>  static const char vs_template[] =
>      "%s"                                /* version */
> +    "%s"                                /* defines */
>      "%s"                                /* prim vs_vars */
>      "%s"                                /* fill vs_vars */
>      "%s"                                /* location vs_vars */
> @@ -195,12 +196,14 @@ static const char vs_template[] =
>  static const char fs_template[] =
>      "%s"                                /* version */
>      GLAMOR_DEFAULT_PRECISION
> +    "%s"                                /* defines */
>      "%s"                                /* prim fs_vars */
>      "%s"                                /* fill fs_vars */
>      "%s"                                /* location fs_vars */
>      "void main() {\n"
>      "%s"                                /* prim fs_exec */
>      "%s"                                /* fill fs_exec */
> +    "%s"                                /* combine */
>      "}\n";
>  
>  static const char *
> @@ -236,7 +239,9 @@ Bool
>  glamor_build_program(ScreenPtr          screen,
>                       glamor_program     *prog,
>                       const glamor_facet *prim,
> -                     const glamor_facet *fill)
> +                     const glamor_facet *fill,
> +                     const char         *combine,
> +                     const char         *defines)
>  {
>      glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
>  
> @@ -282,6 +287,7 @@ glamor_build_program(ScreenPtr          screen,
>      if (asprintf(&vs_prog_string,
>                   vs_template,
>                   str(version_string),
> +                 str(defines),
>                   str(prim->vs_vars),
>                   str(fill->vs_vars),
>                   vs_vars,
> @@ -292,26 +298,30 @@ glamor_build_program(ScreenPtr          screen,
>      if (asprintf(&fs_prog_string,
>                   fs_template,
>                   str(version_string),
> +                 str(defines),
>                   str(prim->fs_vars),
>                   str(fill->fs_vars),
>                   fs_vars,
>                   str(prim->fs_exec),
> -                 str(fill->fs_exec)) < 0)
> +                 str(fill->fs_exec),
> +                 str(combine)) < 0)
>          fs_prog_string = NULL;
>  
>      if (!vs_prog_string || !fs_prog_string)
>          goto fail;
>  
> +    prog->prog = glCreateProgram();
>  #if DBG
> -    ErrorF("\nPrograms for %s %s\nVertex shader:\n\n%s\n\nFragment Shader:\n\n%s",
> -           prim->name, fill->name, vs_prog_string, fs_prog_string);
> +    ErrorF("\n\tProgram %d for %s %s\n\tVertex shader:\n\n\t================\n%s\n\n\tFragment Shader:\n\n%s\t================\n",
> +           prog->prog, prim->name, fill->name, vs_prog_string, fs_prog_string);
>  #endif
>  
> -    prog->prog = glCreateProgram();
>      prog->flags = flags;
>      prog->locations = locations;
>      prog->prim_use = prim->use;
> +    prog->prim_use_render = prim->use_render;
>      prog->fill_use = fill->use;
> +    prog->fill_use_render = fill->use_render;
>  
>      vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_prog_string);
>      fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_prog_string);
> @@ -396,7 +406,7 @@ glamor_use_program_fill(PixmapPtr               pixmap,
>          if (!fill)
>              return NULL;
>  
> -        if (!glamor_build_program(screen, prog, prim, fill))
> +        if (!glamor_build_program(screen, prog, prim, fill, NULL, NULL))
>              return NULL;
>      }
>  
> @@ -405,3 +415,211 @@ glamor_use_program_fill(PixmapPtr               pixmap,
>  
>      return prog;
>  }
> +
> +static struct blendinfo composite_op_info[] = {
> +    [PictOpClear] = {0, 0, GL_ZERO, GL_ZERO},
> +    [PictOpSrc] = {0, 0, GL_ONE, GL_ZERO},
> +    [PictOpDst] = {0, 0, GL_ZERO, GL_ONE},
> +    [PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
> +    [PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
> +    [PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO},
> +    [PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA},
> +    [PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
> +    [PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
> +    [PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
> +    [PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
> +    [PictOpXor] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
> +    [PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
> +};
> +
> +static void
> +glamor_set_blend(CARD8 op, glamor_program_alpha alpha, PicturePtr dst)
> +{
> +    GLenum src_blend, dst_blend;
> +    struct blendinfo *op_info;
> +
> +    switch (alpha) {
> +    case glamor_program_alpha_ca_first:
> +        op = PictOpOutReverse;
> +        break;
> +    case glamor_program_alpha_ca_second:
> +        op = PictOpAdd;
> +        break;
> +    default:
> +        break;
> +    }
> +
> +    if (op == PictOpSrc)
> +        return;
> +    op_info = &composite_op_info[op];
> +
> +    src_blend = op_info->source_blend;
> +    dst_blend = op_info->dest_blend;
> +
> +    /* If there's no dst alpha channel, adjust the blend op so that we'll treat
> +     * it as always 1.
> +     */
> +    if (PICT_FORMAT_A(dst->format) == 0 && op_info->dest_alpha) {
> +        if (src_blend == GL_DST_ALPHA)
> +            src_blend = GL_ONE;
> +        else if (src_blend == GL_ONE_MINUS_DST_ALPHA)
> +            src_blend = GL_ZERO;
> +    }
> +
> +    /* 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)
> +            dst_blend = GL_SRC_COLOR;
> +        else if (dst_blend == GL_ONE_MINUS_SRC_ALPHA)
> +            dst_blend = GL_ONE_MINUS_SRC_COLOR;
> +    }
> +
> +    glEnable(GL_BLEND);
> +    glBlendFunc(src_blend, dst_blend);
> +}
> +
> +static Bool
> +use_source_solid(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
> +{
> +
> +    glamor_set_blend(op, prog->alpha, dst);
> +
> +    glamor_set_color(glamor_get_drawable_pixmap(dst->pDrawable),
> +                     src->pSourcePict->solidFill.color,
> +                     prog->fg_uniform);
> +    return TRUE;
> +}
> +
> +const glamor_facet glamor_source_solid = {
> +    .name = "render_solid",
> +    .fs_exec = "       vec4 source = fg;\n",
> +    .locations = glamor_program_location_fg,
> +    .use_render = use_source_solid,
> +};
> +
> +static Bool
> +use_source_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
> +{
> +    glamor_set_blend(op, prog->alpha, dst);
> +
> +    return glamor_set_texture((PixmapPtr) src->pDrawable,
> +                              0, 0,
> +                              prog->fill_offset_uniform,
> +                              prog->fill_size_inv_uniform);
> +
> +    return TRUE;
> +}
> +
> +const glamor_facet glamor_source_picture = {
> +    .name = "render_picture",
> +    .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) / fill_size;\n",
> +    .fs_exec =  "       vec4 source = texture2D(sampler, fill_pos);\n",
> +    .locations = glamor_program_location_fill,
> +    .use_render = use_source_picture,
> +};
> +
> +const glamor_facet *glamor_facet_source[glamor_program_source_count] = {
> +    [glamor_program_source_solid] = &glamor_source_solid,
> +    [glamor_program_source_picture] = &glamor_source_picture,
> +};
> +

> +static const char *glamor_combine[] = {
> +    "       gl_FragColor = source * mask.a;\n",
> +    "       gl_FragColor = source.a * mask;\n",
> +    "       gl_FragColor = source * mask;\n"
> +};

This would be nice as:
    [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"

> +
> +static Bool
> +glamor_setup_one_program_render(ScreenPtr               screen,
> +                                glamor_program          *prog,
> +                                glamor_program_source   source_type,
> +                                glamor_program_alpha    alpha,
> +                                const glamor_facet      *prim,
> +                                const char              *defines)
> +{
> +    if(prog->failed)
> +        return FALSE;

missing space

> +
> +    if (!prog->prog) {
> +        const glamor_facet      *fill = glamor_facet_source[source_type];
> +
> +        if (!fill)
> +            return FALSE;
> +
> +        if (!glamor_build_program(screen, prog, prim, fill, glamor_combine[alpha], defines))
> +            return FALSE;
> +        prog->alpha = alpha;
> +    }
> +
> +    return TRUE;
> +}
> +
> +glamor_program *
> +glamor_setup_program_render(CARD8                 op,
> +                            PicturePtr            src,
> +                            PicturePtr            mask,
> +                            PicturePtr            dst,
> +                            glamor_program_render *program_render,
> +                            const glamor_facet    *prim,
> +                            const char            *defines)
> +{
> +    ScreenPtr                   screen = dst->pDrawable->pScreen;
> +    glamor_program_alpha        alpha;
> +    glamor_program_source       source_type;
> +    glamor_program              *prog, *ret;
> +
> +    if (op > sizeof (composite_op_info)/sizeof (composite_op_info[0]))

if (op > ARRAY_SIZE(composite_op_info))

> +        return NULL;
> +
> +    if (glamor_is_component_alpha(mask)) {
> +        /* This only works for PictOpOver */
> +        if (op != PictOpOver)
> +            return NULL;
> +        alpha = glamor_program_alpha_ca_first;
> +    } else
> +        alpha = glamor_program_alpha_normal;
> +
> +    if (src->pDrawable)
> +        source_type = glamor_program_source_picture;
> +    else {
> +        SourcePictPtr   sp = src->pSourcePict;
> +        if (!sp)
> +            return NULL;
> +        switch (sp->type) {
> +        case SourcePictTypeSolidFill:
> +            source_type = glamor_program_source_solid;
> +            break;
> +        default:
> +            return NULL;
> +        }
> +    }

I don't think the glamor_program_source_picture path is complete -- what
about src->transform and src->alphaMap?

I'd be just fine with the text path only doing solids, and glyph-masking
a texture being something we fall back to the slow path for.  If so, and
we need to do 1x1 repeating src (I think that's how a lot of text is
drawn still, right?), we might want to drop fill_pos in the facet and
just texture2D(sampler, vec2(0.5)).

> +
> +    ret = &program_render->progs[source_type][alpha];
> +    for (;;) {
> +        prog = &program_render->progs[source_type][alpha];
> +
> +        if (!glamor_setup_one_program_render(screen, prog, source_type, alpha, prim, defines))
> +            return NULL;
> +
> +        if (alpha != glamor_program_alpha_ca_first)
> +            break;
> +        alpha++;
> +    }

This was hard to read, and I think explicit might be nicer:

    prog = &program_render->progs[source_type][alpha];
    if (!glamor_setup_one_program_render(screen, prog, source_type, alpha, prim, defines))
        return NULL;
    if (alpha == glamor_program_alpha_ca_first) {
        /* Make sure we can also build the second program before deciding
         * to use this path.
         */
        if (!glamor_setup_one_program_render(screen,
                                             &program_render->progs[source_type][glamor_program_alpha_ca_second],
                                             source_type, glamor_program_alpha_ca_second, prim,
                                             defines)) {
            return NULL;
        }
    }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 818 bytes
Desc: not available
URL: <http://lists.x.org/archives/xorg-devel/attachments/20150512/8d98f922/attachment.sig>


More information about the xorg-devel mailing list