diff options
author | Brian Paul <[email protected]> | 2011-09-15 11:31:55 -0600 |
---|---|---|
committer | Brian Paul <[email protected]> | 2011-09-15 11:31:55 -0600 |
commit | a7109a31999f78a1184346f423a8df15be18d570 (patch) | |
tree | cc571c922a2c97753fdb6a0d20cdbdc4a07af23d /src/gallium | |
parent | ba6f1f2c29c148e33acc9d2b411c19c7c9a9d04f (diff) |
softpipe: fix blending for luminance/intensity surfaces
If we're drawing to a luminance, luminance/alpha or intensity surface
we have to adjust (rebase) the fragment/quad colors before writing them
to the tile cache. The tile cache always stores RGBA colors but if
we're caching a L/A surface (for example) we need to be sure that R=G=B
so that subsequent reads from the surface cache appear to return L/A
We previously had a special case for RGB (no alpha) surfaces. This
change generalizes that for the other base formats.
Fixes https://bugs.freedesktop.org/show_bug.cgi?id=40408, but sRGB
formats are still failing. That'll be addressed in a later patch.
Diffstat (limited to 'src/gallium')
-rw-r--r-- | src/gallium/drivers/softpipe/sp_quad_blend.c | 161 |
1 files changed, 96 insertions, 65 deletions
diff --git a/src/gallium/drivers/softpipe/sp_quad_blend.c b/src/gallium/drivers/softpipe/sp_quad_blend.c index 65f17d2f55b..c1a9b6f3c5d 100644 --- a/src/gallium/drivers/softpipe/sp_quad_blend.c +++ b/src/gallium/drivers/softpipe/sp_quad_blend.c @@ -41,12 +41,22 @@ #include "sp_quad_pipe.h" +enum format +{ + RGBA, + RGB, + LUMINANCE, + LUMINANCE_ALPHA, + INTENSITY +}; + + /** Subclass of quad_stage */ struct blend_quad_stage { struct quad_stage base; - boolean has_dst_alpha[PIPE_MAX_COLOR_BUFS]; boolean clamp[PIPE_MAX_COLOR_BUFS]; /**< clamp colors to [0,1]? */ + enum format base_format[PIPE_MAX_COLOR_BUFS]; }; @@ -245,15 +255,13 @@ logicop_quad(struct quad_stage *qs, * \param dest the destination/framebuffer quad colors * \param const_blend_color the constant blend color * \param blend_index which set of blending terms to use - * \param has_dst_alpha does the dest color buffer have an alpha channel? */ static void blend_quad(struct quad_stage *qs, float (*quadColor)[4], float (*dest)[4], const float const_blend_color[4], - unsigned blend_index, - boolean has_dst_alpha) + unsigned blend_index) { static const float zero[4] = { 0, 0, 0, 0 }; static const float one[4] = { 1, 1, 1, 1 }; @@ -289,20 +297,15 @@ blend_quad(struct quad_stage *qs, VEC4_MUL(source[2], quadColor[2], dest[2]); /* B */ break; case PIPE_BLENDFACTOR_DST_ALPHA: - if (has_dst_alpha) { + { const float *alpha = dest[3]; VEC4_MUL(source[0], quadColor[0], alpha); /* R */ VEC4_MUL(source[1], quadColor[1], alpha); /* G */ VEC4_MUL(source[2], quadColor[2], alpha); /* B */ } - else { - VEC4_COPY(source[0], quadColor[0]); /* R */ - VEC4_COPY(source[1], quadColor[1]); /* G */ - VEC4_COPY(source[2], quadColor[2]); /* B */ - } break; case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: - if (has_dst_alpha) { + { const float *alpha = quadColor[3]; float diff[4], temp[4]; VEC4_SUB(diff, one, dest[3]); @@ -311,11 +314,6 @@ blend_quad(struct quad_stage *qs, VEC4_MUL(source[1], quadColor[1], temp); /* G */ VEC4_MUL(source[2], quadColor[2], temp); /* B */ } - else { - VEC4_COPY(source[0], zero); /* R */ - VEC4_COPY(source[1], zero); /* G */ - VEC4_COPY(source[2], zero); /* B */ - } break; case PIPE_BLENDFACTOR_CONST_COLOR: { @@ -369,18 +367,13 @@ blend_quad(struct quad_stage *qs, } break; case PIPE_BLENDFACTOR_INV_DST_ALPHA: - if (has_dst_alpha) { + { float inv_alpha[4]; VEC4_SUB(inv_alpha, one, dest[3]); VEC4_MUL(source[0], quadColor[0], inv_alpha); /* R */ VEC4_MUL(source[1], quadColor[1], inv_alpha); /* G */ VEC4_MUL(source[2], quadColor[2], inv_alpha); /* B */ } - else { - VEC4_COPY(source[0], zero); /* R */ - VEC4_COPY(source[1], zero); /* G */ - VEC4_COPY(source[2], zero); /* B */ - } break; case PIPE_BLENDFACTOR_INV_DST_COLOR: { @@ -444,10 +437,7 @@ blend_quad(struct quad_stage *qs, case PIPE_BLENDFACTOR_DST_COLOR: /* fall-through */ case PIPE_BLENDFACTOR_DST_ALPHA: - if (has_dst_alpha) - VEC4_MUL(source[3], quadColor[3], dest[3]); /* A */ - else - VEC4_COPY(source[3], quadColor[3]); /* A */ + VEC4_MUL(source[3], quadColor[3], dest[3]); /* A */ break; case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: /* multiply alpha by 1.0 */ @@ -477,14 +467,11 @@ blend_quad(struct quad_stage *qs, case PIPE_BLENDFACTOR_INV_DST_COLOR: /* fall-through */ case PIPE_BLENDFACTOR_INV_DST_ALPHA: - if (has_dst_alpha) { + { float inv_alpha[4]; VEC4_SUB(inv_alpha, one, dest[3]); VEC4_MUL(source[3], quadColor[3], inv_alpha); /* A */ } - else { - VEC4_COPY(source[3], zero); /* A */ - } break; case PIPE_BLENDFACTOR_INV_CONST_COLOR: /* fall-through */ @@ -525,14 +512,9 @@ blend_quad(struct quad_stage *qs, VEC4_MUL(blend_dest[2], blend_dest[2], quadColor[3]); /* B * A */ break; case PIPE_BLENDFACTOR_DST_ALPHA: - if (has_dst_alpha) { - VEC4_MUL(blend_dest[0], blend_dest[0], blend_dest[3]); /* R * A */ - VEC4_MUL(blend_dest[1], blend_dest[1], blend_dest[3]); /* G * A */ - VEC4_MUL(blend_dest[2], blend_dest[2], blend_dest[3]); /* B * A */ - } - else { - /* blend_dest = blend_dest * 1 NO-OP, leave blend_dest as-is */ - } + VEC4_MUL(blend_dest[0], blend_dest[0], blend_dest[3]); /* R * A */ + VEC4_MUL(blend_dest[1], blend_dest[1], blend_dest[3]); /* G * A */ + VEC4_MUL(blend_dest[2], blend_dest[2], blend_dest[3]); /* B * A */ break; case PIPE_BLENDFACTOR_DST_COLOR: VEC4_MUL(blend_dest[0], blend_dest[0], blend_dest[0]); /* R */ @@ -540,7 +522,7 @@ blend_quad(struct quad_stage *qs, VEC4_MUL(blend_dest[2], blend_dest[2], blend_dest[2]); /* B */ break; case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: - if (has_dst_alpha) { + { const float *alpha = quadColor[3]; float diff[4], temp[4]; VEC4_SUB(diff, one, blend_dest[3]); @@ -549,11 +531,6 @@ blend_quad(struct quad_stage *qs, VEC4_MUL(blend_dest[1], quadColor[1], temp); /* G */ VEC4_MUL(blend_dest[2], quadColor[2], temp); /* B */ } - else { - VEC4_COPY(blend_dest[0], zero); /* R */ - VEC4_COPY(blend_dest[1], zero); /* G */ - VEC4_COPY(blend_dest[2], zero); /* B */ - } break; case PIPE_BLENDFACTOR_CONST_COLOR: { @@ -606,19 +583,14 @@ blend_quad(struct quad_stage *qs, } break; case PIPE_BLENDFACTOR_INV_DST_ALPHA: - if (has_dst_alpha) { + { float inv_comp[4]; VEC4_SUB(inv_comp, one, blend_dest[3]); /* A */ VEC4_MUL(blend_dest[0], inv_comp, blend_dest[0]); /* R */ VEC4_MUL(blend_dest[1], inv_comp, blend_dest[1]); /* G */ VEC4_MUL(blend_dest[2], inv_comp, blend_dest[2]); /* B */ } - else { - VEC4_COPY(blend_dest[0], zero); /* R */ - VEC4_COPY(blend_dest[1], zero); /* G */ - VEC4_COPY(blend_dest[2], zero); /* B */ - } - break; + break; case PIPE_BLENDFACTOR_INV_DST_COLOR: { float inv_comp[4]; @@ -677,12 +649,7 @@ blend_quad(struct quad_stage *qs, case PIPE_BLENDFACTOR_DST_COLOR: /* fall-through */ case PIPE_BLENDFACTOR_DST_ALPHA: - if (has_dst_alpha) { - VEC4_MUL(blend_dest[3], blend_dest[3], blend_dest[3]); /* A */ - } - else { - /* blend_dest = blend_dest * 1 NO-OP, leave blend_dest as-is */ - } + VEC4_MUL(blend_dest[3], blend_dest[3], blend_dest[3]); /* A */ break; case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: /* blend_dest = blend_dest * 1 NO-OP, leave blend_dest as-is */ @@ -711,14 +678,11 @@ blend_quad(struct quad_stage *qs, case PIPE_BLENDFACTOR_INV_DST_COLOR: /* fall-through */ case PIPE_BLENDFACTOR_INV_DST_ALPHA: - if (has_dst_alpha) { + { float inv_comp[4]; VEC4_SUB(inv_comp, one, blend_dest[3]); /* A */ VEC4_MUL(blend_dest[3], inv_comp, blend_dest[3]); /* A */ } - else { - VEC4_COPY(blend_dest[3], zero); /* A */ - } break; case PIPE_BLENDFACTOR_INV_CONST_COLOR: /* fall-through */ @@ -829,6 +793,54 @@ clamp_colors(float (*quadColor)[4]) } +/** + * If we're drawing to a luminance, luminance/alpha or intensity surface + * we have to adjust (rebase) the fragment/quad colors before writing them + * to the tile cache. The tile cache always stores RGBA colors but if + * we're caching a L/A surface (for example) we need to be sure that R=G=B + * so that subsequent reads from the surface cache appear to return L/A + * values. + * The piglit fbo-blending-formats test will exercise this. + */ +static void +rebase_colors(enum format base_format, float (*quadColor)[4]) +{ + unsigned i; + + switch (base_format) { + case RGB: + for (i = 0; i < 4; i++) { + /* A = 1 */ + quadColor[3][i] = 1.0F; + } + break; + case LUMINANCE: + for (i = 0; i < 4; i++) { + /* B = G = R */ + quadColor[2][i] = quadColor[1][i] = quadColor[0][i]; + /* A = 1 */ + quadColor[3][i] = 1.0F; + } + break; + case LUMINANCE_ALPHA: + for (i = 0; i < 4; i++) { + /* B = G = R */ + quadColor[2][i] = quadColor[1][i] = quadColor[0][i]; + } + break; + case INTENSITY: + for (i = 0; i < 4; i++) { + /* A = B = G = R */ + quadColor[3][i] = quadColor[2][i] = quadColor[1][i] = quadColor[0][i]; + } + break; + default: + ; /* nothing */ + } +} + + + static void blend_fallback(struct quad_stage *qs, struct quad_header *quads[], @@ -900,10 +912,11 @@ blend_fallback(struct quad_stage *qs, logicop_quad( qs, quadColor, dest ); } else if (blend->rt[blend_buf].blend_enable) { - blend_quad( qs, quadColor, dest, blend_color, - blend_buf, bqs->has_dst_alpha[cbuf] ); + blend_quad(qs, quadColor, dest, blend_color, blend_buf); } + rebase_colors(bqs->base_format[cbuf], quadColor); + if (blend->rt[blend_buf].colormask != 0xf) colormask_quad( blend->rt[cbuf].colormask, quadColor, dest); @@ -928,6 +941,7 @@ blend_single_add_src_alpha_inv_src_alpha(struct quad_stage *qs, struct quad_header *quads[], unsigned nr) { + const struct blend_quad_stage *bqs = blend_quad_stage(qs); static const float one[4] = { 1, 1, 1, 1 }; float one_minus_alpha[QUAD_SIZE]; float dest[4][QUAD_SIZE]; @@ -971,6 +985,8 @@ blend_single_add_src_alpha_inv_src_alpha(struct quad_stage *qs, VEC4_ADD_SAT(quadColor[2], source[2], dest[2]); /* B */ VEC4_ADD_SAT(quadColor[3], source[3], dest[3]); /* A */ + rebase_colors(bqs->base_format[0], quadColor); + for (j = 0; j < QUAD_SIZE; j++) { if (quad->inout.mask & (1 << j)) { int x = itx + (j & 1); @@ -1024,6 +1040,8 @@ blend_single_add_one_one(struct quad_stage *qs, VEC4_ADD_SAT(quadColor[2], quadColor[2], dest[2]); /* B */ VEC4_ADD_SAT(quadColor[3], quadColor[3], dest[3]); /* A */ + rebase_colors(bqs->base_format[0], quadColor); + for (j = 0; j < QUAD_SIZE; j++) { if (quad->inout.mask & (1 << j)) { int x = itx + (j & 1); @@ -1048,6 +1066,7 @@ single_output_color(struct quad_stage *qs, struct quad_header *quads[], unsigned nr) { + const struct blend_quad_stage *bqs = blend_quad_stage(qs); uint i, j, q; struct softpipe_cached_tile *tile @@ -1060,7 +1079,9 @@ single_output_color(struct quad_stage *qs, float (*quadColor)[4] = quad->output.color[0]; const int itx = (quad->input.x0 & (TILE_SIZE-1)); const int ity = (quad->input.y0 & (TILE_SIZE-1)); - + + rebase_colors(bqs->base_format[0], quadColor); + for (j = 0; j < QUAD_SIZE; j++) { if (quad->inout.mask & (1 << j)) { int x = itx + (j & 1); @@ -1127,9 +1148,19 @@ choose_blend_quad(struct quad_stage *qs, const enum pipe_format format = softpipe->framebuffer.cbufs[i]->format; const struct util_format_description *desc = util_format_description(format); - bqs->has_dst_alpha[i] = util_format_has_alpha(format); /* assuming all or no color channels are normalized: */ bqs->clamp[i] = desc->channel[0].normalized; + + if (util_format_is_intensity(format)) + bqs->base_format[i] = INTENSITY; + else if (util_format_is_luminance(format)) + bqs->base_format[i] = LUMINANCE; + else if (util_format_is_luminance_alpha(format)) + bqs->base_format[i] = LUMINANCE_ALPHA; + else if (util_format_is_rgb_no_alpha(format)) + bqs->base_format[i] = RGB; + else + bqs->base_format[i] = RGBA; } qs->run(qs, quads, nr); |