From 1b745e0c1ff45e014aa21c3d8edf93227bec99bf Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 13 Oct 2014 11:40:06 -0700 Subject: glamor: Adapt glamor_program API to handle render acceleration This extends the existing API to support options needed for render accleration, including an additional fragment, 'combine', (which provides a place to perform the source IN mask operation before the final OP dest state) and an additional 'defines' parameter which provides a way to add target-dependent values without using a uniform. Signed-off-by: Keith Packard Reviewed-by: Eric Anholt --- glamor/glamor_copy.c | 6 +- glamor/glamor_dash.c | 2 +- glamor/glamor_points.c | 3 +- glamor/glamor_program.c | 276 +++++++++++++++++++++++++++++++++++++++++++--- glamor/glamor_program.h | 62 ++++++++++- glamor/glamor_text.c | 2 +- glamor/glamor_transform.c | 23 +++- glamor/glamor_transform.h | 3 + 8 files changed, 347 insertions(+), 30 deletions(-) diff --git a/glamor/glamor_copy.c b/glamor/glamor_copy.c index 921e80e3d..028acf239 100644 --- a/glamor/glamor_copy.c +++ b/glamor/glamor_copy.c @@ -53,7 +53,7 @@ static const glamor_facet glamor_facet_copyarea = { .vs_exec = (GLAMOR_POS(gl_Position, primitive.xy) " fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"), .fs_exec = " gl_FragColor = texture2D(sampler, fill_pos);\n", - .locations = glamor_program_location_fill, + .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos, .use = use_copyarea, }; @@ -140,7 +140,7 @@ static const glamor_facet glamor_facet_copyplane = { " gl_FragColor = fg;\n" " else\n" " gl_FragColor = bg;\n"), - .locations = glamor_program_location_fill|glamor_program_location_fg|glamor_program_location_bg|glamor_program_location_bitplane, + .locations = glamor_program_location_fillsamp|glamor_program_location_fillpos|glamor_program_location_fg|glamor_program_location_bg|glamor_program_location_bitplane, .use = use_copyplane, }; @@ -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 4281ff0a8..101228e40 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 df7e5a23f..3ba4a6927 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 8aab53f4f..d0912878d 100644 --- a/glamor/glamor_program.c +++ b/glamor/glamor_program.c @@ -47,7 +47,7 @@ static const glamor_facet glamor_fill_tile = { .name = "tile", .vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n", .fs_exec = " gl_FragColor = texture2D(sampler, fill_pos);\n", - .locations = glamor_program_location_fill, + .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos, .use = use_tile, }; @@ -66,7 +66,7 @@ static const glamor_facet glamor_fill_stipple = { " if (a == 0.0)\n" " discard;\n" " gl_FragColor = fg;\n"), - .locations = glamor_program_location_fg | glamor_program_location_fill, + .locations = glamor_program_location_fg | glamor_program_location_fillsamp | glamor_program_location_fillpos, .use = use_stipple, }; @@ -87,7 +87,7 @@ static const glamor_facet glamor_fill_opaque_stipple = { " gl_FragColor = bg;\n" " else\n" " gl_FragColor = fg;\n"), - .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fill, + .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fillsamp | glamor_program_location_fillpos, .use = use_opaque_stipple }; @@ -114,12 +114,15 @@ static glamor_location_var location_vars[] = { .fs_vars = "uniform vec4 bg;\n" }, { - .location = glamor_program_location_fill, + .location = glamor_program_location_fillsamp, + .fs_vars = "uniform sampler2D sampler;\n" + }, + { + .location = glamor_program_location_fillpos, .vs_vars = ("uniform vec2 fill_offset;\n" "uniform vec2 fill_size_inv;\n" "varying vec2 fill_pos;\n"), - .fs_vars = ("uniform sampler2D sampler;\n" - "uniform vec2 fill_size_inv;\n" + .fs_vars = ("uniform vec2 fill_size_inv;\n" "varying vec2 fill_pos;\n") }, { @@ -183,6 +186,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 +199,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 +242,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 +290,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 +301,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); @@ -335,8 +348,8 @@ glamor_build_program(ScreenPtr screen, prog->matrix_uniform = glamor_get_uniform(prog, glamor_program_location_none, "v_matrix"); prog->fg_uniform = glamor_get_uniform(prog, glamor_program_location_fg, "fg"); prog->bg_uniform = glamor_get_uniform(prog, glamor_program_location_bg, "bg"); - prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fill, "fill_offset"); - prog->fill_size_inv_uniform = glamor_get_uniform(prog, glamor_program_location_fill, "fill_size_inv"); + prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_offset"); + prog->fill_size_inv_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_size_inv"); prog->font_uniform = glamor_get_uniform(prog, glamor_program_location_font, "font"); prog->bitplane_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitplane"); prog->bitmul_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitmul"); @@ -396,7 +409,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 +418,238 @@ 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); +} + +const glamor_facet glamor_source_picture = { + .name = "render_picture", + .vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n", + .fs_exec = " vec4 source = texture2D(sampler, fill_pos);\n", + .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos, + .use_render = use_source_picture, +}; + +static Bool +use_source_1x1_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog) +{ + glamor_set_blend(op, prog->alpha, dst); + + return glamor_set_texture_pixmap((PixmapPtr) src->pDrawable); +} + +const glamor_facet glamor_source_1x1_picture = { + .name = "render_picture", + .fs_exec = " vec4 source = texture2D(sampler, vec2(0.5));\n", + .locations = glamor_program_location_fillsamp, + .use_render = use_source_1x1_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, + [glamor_program_source_1x1_picture] = &glamor_source_1x1_picture, +}; + +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" +}; + +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; + + 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; + + 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) { + + /* Can't do transforms, alphamaps or sourcing from non-pixmaps yet */ + if (src->transform || src->alphaMap || src->pDrawable->type != DRAWABLE_PIXMAP) + return NULL; + + if (src->pDrawable->width == 1 && src->pDrawable->height == 1 && src->repeat) + source_type = glamor_program_source_1x1_picture; + else + 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; + } + } + + 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; + } + return prog; +} + +Bool +glamor_use_program_render(glamor_program *prog, + CARD8 op, + PicturePtr src, + PicturePtr dst) +{ + glUseProgram(prog->prog); + + if (prog->prim_use_render && !prog->prim_use_render(op, src, dst, prog)) + return FALSE; + + if (prog->fill_use_render && !prog->fill_use_render(op, src, dst, prog)) + return FALSE; + return TRUE; +} diff --git a/glamor/glamor_program.h b/glamor/glamor_program.h index fa3877c5d..ad1e9fd93 100644 --- a/glamor/glamor_program.h +++ b/glamor/glamor_program.h @@ -27,23 +27,36 @@ typedef enum { glamor_program_location_none = 0, glamor_program_location_fg = 1, glamor_program_location_bg = 2, - glamor_program_location_fill = 4, - glamor_program_location_font = 8, - glamor_program_location_bitplane = 16, - glamor_program_location_dash = 32, + glamor_program_location_fillsamp = 4, + glamor_program_location_fillpos = 8, + glamor_program_location_font = 16, + glamor_program_location_bitplane = 32, + glamor_program_location_dash = 64, + glamor_program_location_atlas = 128, } glamor_program_location; typedef enum { glamor_program_flag_none = 0, } glamor_program_flag; +typedef enum { + glamor_program_alpha_normal, + glamor_program_alpha_ca_first, + glamor_program_alpha_ca_second, + glamor_program_alpha_count +} glamor_program_alpha; + typedef struct _glamor_program glamor_program; typedef Bool (*glamor_use) (PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg); +typedef Bool (*glamor_use_render) (CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog); + typedef struct { const char *name; const int version; + char *vs_defines; + char *fs_defines; const char *vs_vars; const char *vs_exec; const char *fs_vars; @@ -52,6 +65,7 @@ typedef struct { const glamor_program_flag flags; const char *source_name; glamor_use use; + glamor_use_render use_render; } glamor_facet; struct _glamor_program { @@ -71,6 +85,9 @@ struct _glamor_program { glamor_program_flag flags; glamor_use prim_use; glamor_use fill_use; + glamor_program_alpha alpha; + glamor_use_render prim_use_render; + glamor_use_render fill_use_render; }; typedef struct { @@ -83,7 +100,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); Bool glamor_use_program(PixmapPtr pixmap, @@ -97,4 +116,37 @@ glamor_use_program_fill(PixmapPtr pixmap, glamor_program_fill *program_fill, const glamor_facet *prim); +typedef enum { + glamor_program_source_solid, + glamor_program_source_picture, + glamor_program_source_1x1_picture, + glamor_program_source_count, +} glamor_program_source; + +typedef struct { + glamor_program progs[glamor_program_source_count][glamor_program_alpha_count]; +} glamor_program_render; + +static inline Bool +glamor_is_component_alpha(PicturePtr mask) { + if (mask && mask->componentAlpha && PICT_FORMAT_RGB(mask->format)) + return TRUE; + return FALSE; +} + +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); + +Bool +glamor_use_program_render(glamor_program *prog, + CARD8 op, + PicturePtr src, + PicturePtr dst); + #endif /* _GLAMOR_PROGRAM_H_ */ diff --git a/glamor/glamor_text.c b/glamor/glamor_text.c index 8d8c97072..81a22a5af 100644 --- a/glamor/glamor_text.c +++ b/glamor/glamor_text.c @@ -417,7 +417,7 @@ glamor_image_text(DrawablePtr drawable, GCPtr gc, fill_facet = &glamor_facet_image_fill; } - if (!glamor_build_program(screen, prog, prim_facet, fill_facet)) + if (!glamor_build_program(screen, prog, prim_facet, fill_facet, NULL, NULL)) goto bail; } diff --git a/glamor/glamor_transform.c b/glamor/glamor_transform.c index e94bca856..f476a99b7 100644 --- a/glamor/glamor_transform.c +++ b/glamor/glamor_transform.c @@ -155,11 +155,7 @@ glamor_set_solid(PixmapPtr pixmap, } Bool -glamor_set_texture(PixmapPtr texture, - int off_x, - int off_y, - GLint offset_uniform, - GLint size_inv_uniform) +glamor_set_texture_pixmap(PixmapPtr texture) { glamor_pixmap_private *texture_priv; @@ -174,6 +170,23 @@ glamor_set_texture(PixmapPtr texture, glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture_priv->fbo->tex); + /* we're not setting the sampler uniform here as we always use + * GL_TEXTURE0, and the default value for uniforms is zero. So, + * save a bit of CPU time by taking advantage of that. + */ + return TRUE; +} + +Bool +glamor_set_texture(PixmapPtr texture, + int off_x, + int off_y, + GLint offset_uniform, + GLint size_inv_uniform) +{ + if (!glamor_set_texture_pixmap(texture)) + return FALSE; + glUniform2f(offset_uniform, off_x, off_y); glUniform2f(size_inv_uniform, 1.0f/texture->drawable.width, 1.0f/texture->drawable.height); return TRUE; diff --git a/glamor/glamor_transform.h b/glamor/glamor_transform.h index 1d8eed477..dca6a26ab 100644 --- a/glamor/glamor_transform.h +++ b/glamor/glamor_transform.h @@ -38,6 +38,9 @@ glamor_set_color(PixmapPtr pixmap, CARD32 pixel, GLint uniform); +Bool +glamor_set_texture_pixmap(PixmapPtr texture); + Bool glamor_set_texture(PixmapPtr texture, int off_x, -- cgit v1.2.3