glamor: Add support for CA rendering in a single pass.

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.

v2: Fix breakage of all of CA acceleration for systems without
    GL_ARB_blend_func_extended.  Add CA support for all the ops we
    support in non-CA mode when blend_func_extended is present.  Clean
    up some comments and formatting.  (changes by anholt)

Signed-off-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
Dave Airlie 2016-01-12 18:13:46 +10:00 committed by Eric Anholt
parent cab14a9a08
commit e7308b6c77
6 changed files with 118 additions and 32 deletions

View File

@ -576,6 +576,8 @@ glamor_init(ScreenPtr screen, unsigned int flags)
epoxy_has_gl_extension("GL_NV_pack_subimage"); epoxy_has_gl_extension("GL_NV_pack_subimage");
glamor_priv->has_vertex_array_object = glamor_priv->has_vertex_array_object =
epoxy_has_gl_extension("GL_ARB_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); glamor_setup_debug_output(screen);

View File

@ -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" .vs_exec = (" vec2 pos = primitive.zw * vec2(gl_VertexID&1, (gl_VertexID&2)>>1);\n"
GLAMOR_POS(gl_Position, (primitive.xy + pos)) GLAMOR_POS(gl_Position, (primitive.xy + pos))
" glyph_pos = (source + pos) * ATLAS_DIM_INV;\n"), " 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"), .fs_exec = (" vec4 mask = texture2D(atlas, glyph_pos);\n"),
.source_name = "source", .source_name = "source",
.locations = glamor_program_location_atlas, .locations = glamor_program_location_atlas,

View File

@ -86,6 +86,12 @@ typedef struct glamor_composite_shader {
}; };
} glamor_composite_shader; } glamor_composite_shader;
enum ca_state {
CA_NONE,
CA_TWO_PASS,
CA_DUAL_BLEND,
};
enum shader_source { enum shader_source {
SHADER_SOURCE_SOLID, SHADER_SOURCE_SOLID,
SHADER_SOURCE_TEXTURE, SHADER_SOURCE_TEXTURE,
@ -106,6 +112,7 @@ enum shader_in {
SHADER_IN_NORMAL, SHADER_IN_NORMAL,
SHADER_IN_CA_SOURCE, SHADER_IN_CA_SOURCE,
SHADER_IN_CA_ALPHA, SHADER_IN_CA_ALPHA,
SHADER_IN_CA_DUAL_BLEND,
SHADER_IN_COUNT, SHADER_IN_COUNT,
}; };
@ -202,6 +209,7 @@ typedef struct glamor_screen_private {
Bool has_rw_pbo; Bool has_rw_pbo;
Bool use_quads; Bool use_quads;
Bool has_vertex_array_object; Bool has_vertex_array_object;
Bool has_dual_blend;
int max_fbo_size; int max_fbo_size;
struct xorg_list struct xorg_list

View File

@ -344,6 +344,10 @@ glamor_build_program(ScreenPtr screen,
#endif #endif
glBindAttribLocation(prog->prog, GLAMOR_VERTEX_SOURCE, prim->source_name); 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); 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. */ /* Set up the source alpha value for blending in component alpha mode. */
if (alpha != glamor_program_alpha_normal && op_info->source_alpha) { if (alpha == glamor_program_alpha_dual_blend) {
if (dst_blend == GL_SRC_ALPHA) 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; 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; dst_blend = GL_ONE_MINUS_SRC_COLOR;
break;
}
} }
glEnable(GL_BLEND); glEnable(GL_BLEND);
@ -547,7 +564,9 @@ static const glamor_facet *glamor_facet_source[glamor_program_source_count] = {
static const char *glamor_combine[] = { static const char *glamor_combine[] = {
[glamor_program_alpha_normal] = " gl_FragColor = source * mask.a;\n", [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_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 static Bool
@ -567,9 +586,9 @@ glamor_setup_one_program_render(ScreenPtr screen,
if (!fill) if (!fill)
return FALSE; return FALSE;
prog->alpha = alpha;
if (!glamor_build_program(screen, prog, prim, fill, glamor_combine[alpha], defines)) if (!glamor_build_program(screen, prog, prim, fill, glamor_combine[alpha], defines))
return FALSE; return FALSE;
prog->alpha = alpha;
} }
return TRUE; return TRUE;
@ -585,6 +604,7 @@ glamor_setup_program_render(CARD8 op,
const char *defines) const char *defines)
{ {
ScreenPtr screen = dst->pDrawable->pScreen; ScreenPtr screen = dst->pDrawable->pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_program_alpha alpha; glamor_program_alpha alpha;
glamor_program_source source_type; glamor_program_source source_type;
glamor_program *prog; glamor_program *prog;
@ -593,10 +613,15 @@ glamor_setup_program_render(CARD8 op,
return NULL; return NULL;
if (glamor_is_component_alpha(mask)) { if (glamor_is_component_alpha(mask)) {
/* This only works for PictOpOver */ if (glamor_priv->has_dual_blend) {
if (op != PictOpOver) alpha = glamor_program_alpha_dual_blend;
return NULL; } else {
alpha = glamor_program_alpha_ca_first; /* This only works for PictOpOver */
if (op != PictOpOver)
return NULL;
alpha = glamor_program_alpha_ca_first;
}
} else } else
alpha = glamor_program_alpha_normal; alpha = glamor_program_alpha_normal;

View File

@ -43,6 +43,7 @@ typedef enum {
glamor_program_alpha_normal, glamor_program_alpha_normal,
glamor_program_alpha_ca_first, glamor_program_alpha_ca_first,
glamor_program_alpha_ca_second, glamor_program_alpha_ca_second,
glamor_program_alpha_dual_blend,
glamor_program_alpha_count glamor_program_alpha_count
} glamor_program_alpha; } glamor_program_alpha;

View File

@ -208,10 +208,24 @@ glamor_create_composite_fs(struct shader_key *key)
"{\n" "{\n"
" gl_FragColor = get_source().a * get_mask();\n" " gl_FragColor = get_source().a * get_mask();\n"
"}\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; char *source;
const char *source_fetch; const char *source_fetch;
const char *mask_fetch = ""; const char *mask_fetch = "";
const char *in; const char *in;
const char *header;
const char *header_norm = "";
GLuint prog; GLuint prog;
switch (key->source) { switch (key->source) {
@ -244,6 +258,7 @@ glamor_create_composite_fs(struct shader_key *key)
FatalError("Bad composite shader mask"); FatalError("Bad composite shader mask");
} }
header = header_norm;
switch (key->in) { switch (key->in) {
case SHADER_IN_SOURCE_ONLY: case SHADER_IN_SOURCE_ONLY:
in = in_source_only; in = in_source_only;
@ -257,11 +272,15 @@ glamor_create_composite_fs(struct shader_key *key)
case SHADER_IN_CA_ALPHA: case SHADER_IN_CA_ALPHA:
in = in_ca_alpha; in = in_ca_alpha;
break; break;
case SHADER_IN_CA_DUAL_BLEND:
in = in_ca_dual_blend;
header = header_ca_dual_blend;
break;
default: default:
FatalError("Bad composite IN type"); 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); rel_sampler, source_fetch, mask_fetch, in);
prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, source); 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_SOURCE, "v_texcoord0");
glBindAttribLocation(prog, GLAMOR_VERTEX_MASK, "v_texcoord1"); 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"); glamor_link_glsl_prog(screen, prog, "composite");
shader->prog = prog; shader->prog = prog;
@ -382,7 +405,8 @@ glamor_lookup_composite_shader(ScreenPtr screen, struct
static Bool static Bool
glamor_set_composite_op(ScreenPtr screen, glamor_set_composite_op(ScreenPtr screen,
CARD8 op, struct blendinfo *op_info_result, 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; GLenum source_blend, dest_blend;
struct blendinfo *op_info; struct blendinfo *op_info;
@ -391,6 +415,7 @@ glamor_set_composite_op(ScreenPtr screen,
glamor_fallback("unsupported render op %d \n", op); glamor_fallback("unsupported render op %d \n", op);
return GL_FALSE; return GL_FALSE;
} }
op_info = &composite_op_info[op]; op_info = &composite_op_info[op];
source_blend = op_info->source_blend; 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. */ /* Set up the source alpha value for blending in component alpha mode. */
if (mask && mask->componentAlpha if (ca_state == CA_DUAL_BLEND) {
&& PICT_FORMAT_RGB(mask->format) != 0 && op_info->source_alpha) { switch (dest_blend) {
if (dest_blend == GL_SRC_ALPHA) 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; 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; dest_blend = GL_ONE_MINUS_SRC_COLOR;
break;
}
} }
op_info_result->source_blend = source_blend; op_info_result->source_blend = source_blend;
@ -623,6 +661,10 @@ combine_pict_format(PictFormatShort * des, const PictFormatShort src,
src_type = PICT_TYPE_A; src_type = PICT_TYPE_A;
mask_type = PICT_FORMAT_TYPE(mask); mask_type = PICT_FORMAT_TYPE(mask);
break; break;
case SHADER_IN_CA_DUAL_BLEND:
src_type = PICT_FORMAT_TYPE(src);
mask_type = PICT_FORMAT_TYPE(mask);
break;
default: default:
return FALSE; return FALSE;
} }
@ -715,9 +757,11 @@ glamor_composite_choose_shader(CARD8 op,
struct shader_key *s_key, struct shader_key *s_key,
glamor_composite_shader ** shader, glamor_composite_shader ** shader,
struct blendinfo *op_info, struct blendinfo *op_info,
PictFormatShort *psaved_source_format) PictFormatShort *psaved_source_format,
enum ca_state ca_state)
{ {
ScreenPtr screen = dest->pDrawable->pScreen; 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 source_status = GLAMOR_NONE;
enum glamor_pixmap_status mask_status = GLAMOR_NONE; enum glamor_pixmap_status mask_status = GLAMOR_NONE;
PictFormatShort saved_source_format = 0; PictFormatShort saved_source_format = 0;
@ -786,6 +830,8 @@ glamor_composite_choose_shader(CARD8 op,
else { else {
if (op == PictOpClear) if (op == PictOpClear)
key.mask = SHADER_MASK_NONE; 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 else if (op == PictOpSrc || op == PictOpAdd
|| op == PictOpIn || op == PictOpOut || op == PictOpIn || op == PictOpOut
|| op == PictOpOverReverse) || op == PictOpOverReverse)
@ -933,7 +979,7 @@ glamor_composite_choose_shader(CARD8 op,
goto fail; 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; goto fail;
*shader = glamor_lookup_composite_shader(screen, &key); *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 *mask_pixmap_priv,
glamor_pixmap_private *dest_pixmap_priv, glamor_pixmap_private *dest_pixmap_priv,
int nrect, glamor_composite_rect_t *rects, int nrect, glamor_composite_rect_t *rects,
Bool two_pass_ca) enum ca_state ca_state)
{ {
ScreenPtr screen = dest->pDrawable->pScreen; ScreenPtr screen = dest->pDrawable->pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 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, source_pixmap_priv, mask_pixmap_priv,
dest_pixmap_priv, dest_pixmap_priv,
&key, &shader, &op_info, &key, &shader, &op_info,
&saved_source_format)) { &saved_source_format, ca_state)) {
glamor_fallback("glamor_composite_choose_shader failed\n"); glamor_fallback("glamor_composite_choose_shader failed\n");
return ret; return ret;
} }
if (two_pass_ca) { if (ca_state == CA_TWO_PASS) {
if (!glamor_composite_choose_shader(PictOpAdd, source, mask, dest, if (!glamor_composite_choose_shader(PictOpAdd, source, mask, dest,
source_pixmap, mask_pixmap, dest_pixmap, source_pixmap, mask_pixmap, dest_pixmap,
source_pixmap_priv, source_pixmap_priv,
mask_pixmap_priv, dest_pixmap_priv, mask_pixmap_priv, dest_pixmap_priv,
&key_ca, &shader_ca, &op_info_ca, &key_ca, &shader_ca, &op_info_ca,
&saved_source_format)) { &saved_source_format, ca_state)) {
glamor_fallback("glamor_composite_choose_shader failed\n"); glamor_fallback("glamor_composite_choose_shader failed\n");
return ret; return ret;
} }
@ -1173,7 +1219,7 @@ glamor_composite_with_shader(CARD8 op,
glamor_put_vbo_space(screen); glamor_put_vbo_space(screen);
glamor_flush_composite_rects(screen); glamor_flush_composite_rects(screen);
nrect -= rect_processed; nrect -= rect_processed;
if (two_pass_ca) { if (ca_state == CA_TWO_PASS) {
glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv, glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv,
&key_ca, shader_ca, &op_info_ca); &key_ca, shader_ca, &op_info_ca);
glamor_flush_composite_rects(screen); 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 *source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
glamor_pixmap_private *mask_pixmap_priv = glamor_get_pixmap_private(mask_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_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; ScreenPtr screen = dest->pDrawable->pScreen;
PicturePtr temp_src = source, temp_mask = mask; PicturePtr temp_src = source, temp_mask = mask;
PixmapPtr temp_src_pixmap = source_pixmap; PixmapPtr temp_src_pixmap = source_pixmap;
@ -1295,7 +1342,7 @@ glamor_composite_clipped_region(CARD8 op,
int height; int height;
BoxPtr box; BoxPtr box;
int nbox; int nbox;
Bool two_pass_ca = FALSE; enum ca_state ca_state = CA_NONE;
extent = RegionExtents(region); extent = RegionExtents(region);
box = RegionRects(region); box = RegionRects(region);
@ -1357,14 +1404,15 @@ glamor_composite_clipped_region(CARD8 op,
x_temp_mask = -extent->x1 + x_dest + dest->pDrawable->x; x_temp_mask = -extent->x1 + x_dest + dest->pDrawable->x;
y_temp_mask = -extent->y1 + y_dest + dest->pDrawable->y; 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 (mask && mask->componentAlpha) {
if (op == PictOpOver) { if (glamor_priv->has_dual_blend) {
two_pass_ca = TRUE; ca_state = CA_DUAL_BLEND;
op = PictOpOutReverse; } 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_pixmap, temp_mask_pixmap, dest_pixmap,
temp_src_priv, temp_mask_priv, temp_src_priv, temp_mask_priv,
dest_pixmap_priv, dest_pixmap_priv,
box_cnt, prect, two_pass_ca); box_cnt, prect, ca_state);
if (!ok) if (!ok)
break; break;
nbox -= box_cnt; nbox -= box_cnt;
@ -1477,7 +1525,7 @@ glamor_composite(CARD8 op,
if (op >= ARRAY_SIZE(composite_op_info)) if (op >= ARRAY_SIZE(composite_op_info))
goto fail; goto fail;
if (mask && mask->componentAlpha) { if (mask && mask->componentAlpha && !glamor_priv->has_dual_blend) {
if (op == PictOpAtop if (op == PictOpAtop
|| op == PictOpAtopReverse || op == PictOpAtopReverse
|| op == PictOpXor || op >= PictOpSaturate) { || op == PictOpXor || op >= PictOpSaturate) {