From: Brian Paul Date: Wed, 14 Sep 2011 14:15:14 +0000 (-0600) Subject: softpipe: implement blend color clamping X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ec22b75be1c57f991f48bf6cc1d4b910911e8bf2;p=mesa.git softpipe: implement blend color clamping Per the GL spec, clamp incoming colors prior to blending depending on whether the destination buffer stores normalized (non-float) values. Note that the constant blend color needs to be clamped too (we always get the unclamped color from Mesa). Fixes https://bugs.freedesktop.org/show_bug.cgi?id=40412 --- diff --git a/src/gallium/drivers/softpipe/sp_context.h b/src/gallium/drivers/softpipe/sp_context.h index 410b0a65792..d51ce9fe333 100644 --- a/src/gallium/drivers/softpipe/sp_context.h +++ b/src/gallium/drivers/softpipe/sp_context.h @@ -75,6 +75,7 @@ struct softpipe_context { /** Other rendering state */ struct pipe_blend_color blend_color; + struct pipe_blend_color blend_color_clamped; struct pipe_stencil_ref stencil_ref; struct pipe_clip_state clip; struct pipe_resource *constants[PIPE_SHADER_TYPES][PIPE_MAX_CONSTANT_BUFFERS]; diff --git a/src/gallium/drivers/softpipe/sp_quad_blend.c b/src/gallium/drivers/softpipe/sp_quad_blend.c index c881194768a..65f17d2f55b 100644 --- a/src/gallium/drivers/softpipe/sp_quad_blend.c +++ b/src/gallium/drivers/softpipe/sp_quad_blend.c @@ -41,6 +41,23 @@ #include "sp_quad_pipe.h" +/** 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]? */ +}; + + +/** cast wrapper */ +static INLINE struct blend_quad_stage * +blend_quad_stage(struct quad_stage *stage) +{ + return (struct blend_quad_stage *) stage; +} + + #define VEC4_COPY(DST, SRC) \ do { \ DST[0] = SRC[0]; \ @@ -226,6 +243,7 @@ logicop_quad(struct quad_stage *qs, * Do blending for a 2x2 quad for one color buffer. * \param quadColor the incoming quad colors * \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? */ @@ -233,6 +251,7 @@ 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) { @@ -301,18 +320,18 @@ blend_quad(struct quad_stage *qs, case PIPE_BLENDFACTOR_CONST_COLOR: { float comp[4]; - VEC4_SCALAR(comp, softpipe->blend_color.color[0]); /* R */ + VEC4_SCALAR(comp, const_blend_color[0]); /* R */ VEC4_MUL(source[0], quadColor[0], comp); /* R */ - VEC4_SCALAR(comp, softpipe->blend_color.color[1]); /* G */ + VEC4_SCALAR(comp, const_blend_color[1]); /* G */ VEC4_MUL(source[1], quadColor[1], comp); /* G */ - VEC4_SCALAR(comp, softpipe->blend_color.color[2]); /* B */ + VEC4_SCALAR(comp, const_blend_color[2]); /* B */ VEC4_MUL(source[2], quadColor[2], comp); /* B */ } break; case PIPE_BLENDFACTOR_CONST_ALPHA: { float alpha[4]; - VEC4_SCALAR(alpha, softpipe->blend_color.color[3]); + VEC4_SCALAR(alpha, const_blend_color[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 */ @@ -378,20 +397,20 @@ blend_quad(struct quad_stage *qs, { float inv_comp[4]; /* R */ - VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[0]); + VEC4_SCALAR(inv_comp, 1.0f - const_blend_color[0]); VEC4_MUL(source[0], quadColor[0], inv_comp); /* G */ - VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[1]); + VEC4_SCALAR(inv_comp, 1.0f - const_blend_color[1]); VEC4_MUL(source[1], quadColor[1], inv_comp); /* B */ - VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[2]); + VEC4_SCALAR(inv_comp, 1.0f - const_blend_color[2]); VEC4_MUL(source[2], quadColor[2], inv_comp); } break; case PIPE_BLENDFACTOR_INV_CONST_ALPHA: { float inv_alpha[4]; - VEC4_SCALAR(inv_alpha, 1.0f - softpipe->blend_color.color[3]); + VEC4_SCALAR(inv_alpha, 1.0f - const_blend_color[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 */ @@ -439,7 +458,7 @@ blend_quad(struct quad_stage *qs, case PIPE_BLENDFACTOR_CONST_ALPHA: { float comp[4]; - VEC4_SCALAR(comp, softpipe->blend_color.color[3]); /* A */ + VEC4_SCALAR(comp, const_blend_color[3]); /* A */ VEC4_MUL(source[3], quadColor[3], comp); /* A */ } break; @@ -473,7 +492,7 @@ blend_quad(struct quad_stage *qs, { float inv_comp[4]; /* A */ - VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[3]); + VEC4_SCALAR(inv_comp, 1.0f - const_blend_color[3]); VEC4_MUL(source[3], quadColor[3], inv_comp); } break; @@ -539,18 +558,18 @@ blend_quad(struct quad_stage *qs, case PIPE_BLENDFACTOR_CONST_COLOR: { float comp[4]; - VEC4_SCALAR(comp, softpipe->blend_color.color[0]); /* R */ + VEC4_SCALAR(comp, const_blend_color[0]); /* R */ VEC4_MUL(blend_dest[0], blend_dest[0], comp); /* R */ - VEC4_SCALAR(comp, softpipe->blend_color.color[1]); /* G */ + VEC4_SCALAR(comp, const_blend_color[1]); /* G */ VEC4_MUL(blend_dest[1], blend_dest[1], comp); /* G */ - VEC4_SCALAR(comp, softpipe->blend_color.color[2]); /* B */ + VEC4_SCALAR(comp, const_blend_color[2]); /* B */ VEC4_MUL(blend_dest[2], blend_dest[2], comp); /* B */ } break; case PIPE_BLENDFACTOR_CONST_ALPHA: { float comp[4]; - VEC4_SCALAR(comp, softpipe->blend_color.color[3]); /* A */ + VEC4_SCALAR(comp, const_blend_color[3]); /* A */ VEC4_MUL(blend_dest[0], blend_dest[0], comp); /* R */ VEC4_MUL(blend_dest[1], blend_dest[1], comp); /* G */ VEC4_MUL(blend_dest[2], blend_dest[2], comp); /* B */ @@ -615,20 +634,20 @@ blend_quad(struct quad_stage *qs, { float inv_comp[4]; /* R */ - VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[0]); + VEC4_SCALAR(inv_comp, 1.0f - const_blend_color[0]); VEC4_MUL(blend_dest[0], blend_dest[0], inv_comp); /* G */ - VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[1]); + VEC4_SCALAR(inv_comp, 1.0f - const_blend_color[1]); VEC4_MUL(blend_dest[1], blend_dest[1], inv_comp); /* B */ - VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[2]); + VEC4_SCALAR(inv_comp, 1.0f - const_blend_color[2]); VEC4_MUL(blend_dest[2], blend_dest[2], inv_comp); } break; case PIPE_BLENDFACTOR_INV_CONST_ALPHA: { float inv_comp[4]; - VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[3]); + VEC4_SCALAR(inv_comp, 1.0f - const_blend_color[3]); VEC4_MUL(blend_dest[0], blend_dest[0], inv_comp); VEC4_MUL(blend_dest[1], blend_dest[1], inv_comp); VEC4_MUL(blend_dest[2], blend_dest[2], inv_comp); @@ -673,7 +692,7 @@ blend_quad(struct quad_stage *qs, case PIPE_BLENDFACTOR_CONST_ALPHA: { float comp[4]; - VEC4_SCALAR(comp, softpipe->blend_color.color[3]); /* A */ + VEC4_SCALAR(comp, const_blend_color[3]); /* A */ VEC4_MUL(blend_dest[3], blend_dest[3], comp); /* A */ } break; @@ -706,7 +725,7 @@ blend_quad(struct quad_stage *qs, case PIPE_BLENDFACTOR_INV_CONST_ALPHA: { float inv_comp[4]; - VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[3]); + VEC4_SCALAR(inv_comp, 1.0f - const_blend_color[3]); VEC4_MUL(blend_dest[3], blend_dest[3], inv_comp); } break; @@ -794,11 +813,28 @@ colormask_quad(unsigned colormask, } +/** + * Clamp all colors in a quad to [0, 1] + */ +static void +clamp_colors(float (*quadColor)[4]) +{ + unsigned i, j; + + for (j = 0; j < QUAD_SIZE; j++) { + for (i = 0; i < 4; i++) { + quadColor[i][j] = CLAMP(quadColor[i][j], 0.0F, 1.0F); + } + } +} + + static void blend_fallback(struct quad_stage *qs, struct quad_header *quads[], unsigned nr) { + const struct blend_quad_stage *bqs = blend_quad_stage(qs); struct softpipe_context *softpipe = qs->softpipe; const struct pipe_blend_state *blend = softpipe->blend; unsigned cbuf; @@ -815,10 +851,15 @@ blend_fallback(struct quad_stage *qs, = sp_get_cached_tile(softpipe->cbuf_cache[cbuf], quads[0]->input.x0, quads[0]->input.y0); - boolean has_dst_alpha - = util_format_has_alpha(softpipe->framebuffer.cbufs[cbuf]->format); + const boolean clamp = bqs->clamp[cbuf]; + const float *blend_color; uint q, i, j; + if (clamp) + blend_color = softpipe->blend_color_clamped.color; + else + blend_color = softpipe->blend_color.color; + for (q = 0; q < nr; q++) { struct quad_header *quad = quads[q]; float (*quadColor)[4]; @@ -837,6 +878,13 @@ blend_fallback(struct quad_stage *qs, quadColor = quad->output.color[cbuf]; } + /* If fixed-point dest color buffer, need to clamp the incoming + * fragment colors now. + */ + if (clamp) { + clamp_colors(quadColor); + } + /* get/swizzle dest colors */ for (j = 0; j < QUAD_SIZE; j++) { @@ -852,7 +900,8 @@ 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_buf, has_dst_alpha ); + blend_quad( qs, quadColor, dest, blend_color, + blend_buf, bqs->has_dst_alpha[cbuf] ); } if (blend->rt[blend_buf].colormask != 0xf) @@ -939,6 +988,7 @@ blend_single_add_one_one(struct quad_stage *qs, struct quad_header *quads[], unsigned nr) { + const struct blend_quad_stage *bqs = blend_quad_stage(qs); float dest[4][QUAD_SIZE]; uint i, j, q; @@ -962,6 +1012,13 @@ blend_single_add_one_one(struct quad_stage *qs, } } + /* If fixed-point dest color buffer, need to clamp the incoming + * fragment colors now. + */ + if (bqs->clamp[0]) { + clamp_colors(quadColor); + } + VEC4_ADD_SAT(quadColor[0], quadColor[0], dest[0]); /* R */ VEC4_ADD_SAT(quadColor[1], quadColor[1], dest[1]); /* G */ VEC4_ADD_SAT(quadColor[2], quadColor[2], dest[2]); /* B */ @@ -980,6 +1037,12 @@ blend_single_add_one_one(struct quad_stage *qs, } +/** + * Just copy the quad color to the framebuffer tile (respecting the writemask), + * for one color buffer. + * Clamping will be done, if needed (depending on the color buffer's + * datatype) when we write/pack the colors later. + */ static void single_output_color(struct quad_stage *qs, struct quad_header *quads[], @@ -1023,8 +1086,10 @@ choose_blend_quad(struct quad_stage *qs, struct quad_header *quads[], unsigned nr) { + struct blend_quad_stage *bqs = blend_quad_stage(qs); struct softpipe_context *softpipe = qs->softpipe; const struct pipe_blend_state *blend = softpipe->blend; + unsigned i; qs->run = blend_fallback; @@ -1055,6 +1120,18 @@ choose_blend_quad(struct quad_stage *qs, } } + /* For each color buffer, determine if the buffer has destination alpha and + * whether color clamping is needed. + */ + for (i = 0; i < softpipe->framebuffer.nr_cbufs; i++) { + 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; + } + qs->run(qs, quads, nr); } @@ -1073,12 +1150,15 @@ static void blend_destroy(struct quad_stage *qs) struct quad_stage *sp_quad_blend_stage( struct softpipe_context *softpipe ) { - struct quad_stage *stage = CALLOC_STRUCT(quad_stage); + struct blend_quad_stage *stage = CALLOC_STRUCT(blend_quad_stage); + + if (!stage) + return NULL; - stage->softpipe = softpipe; - stage->begin = blend_begin; - stage->run = choose_blend_quad; - stage->destroy = blend_destroy; + stage->base.softpipe = softpipe; + stage->base.begin = blend_begin; + stage->base.run = choose_blend_quad; + stage->base.destroy = blend_destroy; - return stage; + return &stage->base; } diff --git a/src/gallium/drivers/softpipe/sp_state_blend.c b/src/gallium/drivers/softpipe/sp_state_blend.c index 12863824b8e..1fbc5f34560 100644 --- a/src/gallium/drivers/softpipe/sp_state_blend.c +++ b/src/gallium/drivers/softpipe/sp_state_blend.c @@ -28,6 +28,7 @@ /* Authors: Keith Whitwell */ +#include "util/u_math.h" #include "util/u_memory.h" #include "draw/draw_context.h" #include "sp_context.h" @@ -69,11 +70,17 @@ softpipe_set_blend_color(struct pipe_context *pipe, const struct pipe_blend_color *blend_color) { struct softpipe_context *softpipe = softpipe_context(pipe); + unsigned i; draw_flush(softpipe->draw); softpipe->blend_color = *blend_color; + /* save clamped color too */ + for (i = 0; i < 4; i++) + softpipe->blend_color_clamped.color[i] = + CLAMP(blend_color->color[i], 0.0f, 1.0f); + softpipe->dirty |= SP_NEW_BLEND; }