Mesa (floating): softpipe: rework blending to work properly

Luca Barbieri lb at kemper.freedesktop.org
Fri Aug 27 17:25:21 UTC 2010


Module: Mesa
Branch: floating
Commit: eff368a72c3097628e70599a00415be131b2f7ad
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=eff368a72c3097628e70599a00415be131b2f7ad

Author: Luca Barbieri <luca at luca-barbieri.com>
Date:   Thu Aug 26 18:22:14 2010 +0200

softpipe: rework blending to work properly

This changes makes softpipe clamp blend source, destination input,
source factor and destination factor if the target is fixed point.

Also, it makes it support an unclamped blend color properly.

Note this is NOT related to vertex/fragment clamping and is
independent of these controls, and only dependent on the type of
_each_ color buffer.

This is supposed to be the behavior specified by OpenGL 4.1 and
ARB_color_buffer_float.

Not sure about other APIs.

---

 src/gallium/drivers/softpipe/sp_context.h       |   12 +-
 src/gallium/drivers/softpipe/sp_quad_blend.c    |  282 +++++++++--------------
 src/gallium/drivers/softpipe/sp_state_blend.c   |    6 +-
 src/gallium/drivers/softpipe/sp_state_surface.c |   28 +++
 4 files changed, 158 insertions(+), 170 deletions(-)

diff --git a/src/gallium/drivers/softpipe/sp_context.h b/src/gallium/drivers/softpipe/sp_context.h
index 9361a3d..adc4628 100644
--- a/src/gallium/drivers/softpipe/sp_context.h
+++ b/src/gallium/drivers/softpipe/sp_context.h
@@ -70,7 +70,7 @@ struct softpipe_context {
    struct sp_so_state *so;
 
    /** Other rendering state */
-   struct pipe_blend_color blend_color;
+   struct pipe_blend_color blend_color[2]; /* [0] is unclamped, [1] is clamped */
    struct pipe_stencil_ref stencil_ref;
    struct pipe_clip_state clip;
    struct pipe_resource *constants[PIPE_SHADER_TYPES][PIPE_MAX_CONSTANT_BUFFERS];
@@ -152,6 +152,16 @@ struct softpipe_context {
       struct quad_stage *first; /**< points to one of the above stages */
    } quad;
 
+   /** Per-colorbuffer derived state: used for blending
+    * (but only depending on fb, not blend state) */
+   struct
+   {
+      boolean has_dest_alpha;
+      boolean clamp_blend_source_factors_and_results;
+      boolean clamp_blend_dest;
+      boolean perform_logicop;
+   } cbuf_derived[PIPE_MAX_COLOR_BUFS];
+
    /** TGSI exec things */
    struct {
       struct sp_sampler_varient *geom_samplers_list[PIPE_MAX_GEOMETRY_SAMPLERS];
diff --git a/src/gallium/drivers/softpipe/sp_quad_blend.c b/src/gallium/drivers/softpipe/sp_quad_blend.c
index 6af1b2d..650c3ba 100644
--- a/src/gallium/drivers/softpipe/sp_quad_blend.c
+++ b/src/gallium/drivers/softpipe/sp_quad_blend.c
@@ -219,26 +219,50 @@ 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 blend_index  which set of blending terms to use
  * \param has_dst_alpha  does the dest color buffer have an alpha channel?
+ * \param clamp_blend_source_factors_and_results should we clamp the blend source, factors and result?
+ * \param clamp_blend_source_factors_and_results should we clamp the blend destination before using it as input?
  */
 static void
 blend_quad(struct quad_stage *qs, 
            float (*quadColor)[4],
-           float (*dest)[4],
+           float (*raw_dest)[4],
            unsigned blend_index,
-           boolean has_dst_alpha)
+           boolean has_dst_alpha,
+           boolean clamp_blend_source_factors_and_results,
+           boolean clamp_blend_dest)
 {
    static const float zero[4] = { 0, 0, 0, 0 };
    static const float one[4] = { 1, 1, 1, 1 };
    struct softpipe_context *softpipe = qs->softpipe;
    float source[4][QUAD_SIZE] = { { 0 } };
+   float clamped_dest[4][QUAD_SIZE] = { { 0 } };
+   float (*dest)[4] = raw_dest;
+
+   if(clamp_blend_source_factors_and_results)
+   {
+      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);
+   }
+
+   /* this is only TRUE for weird cases like SNORM targets, since
+    * otherwise we either must not do this, or it superfluous to do so
+    */
+   if(clamp_blend_dest)
+   {
+      unsigned i, j;
+      for (j = 0; j < QUAD_SIZE; j++)
+         for (i = 0; i < 4; i++)
+            clamped_dest[i][j] = CLAMP(raw_dest[i][j], 0.0f, 1.0f);
+      dest = clamped_dest;
+   }
 
    /*
     * Compute src/first term RGB
@@ -299,18 +323,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, softpipe->blend_color[clamp_blend_source_factors_and_results].color[0]); /* R */
       VEC4_MUL(source[0], quadColor[0], comp); /* R */
-      VEC4_SCALAR(comp, softpipe->blend_color.color[1]); /* G */
+      VEC4_SCALAR(comp, softpipe->blend_color[clamp_blend_source_factors_and_results].color[1]); /* G */
       VEC4_MUL(source[1], quadColor[1], comp); /* G */
-      VEC4_SCALAR(comp, softpipe->blend_color.color[2]); /* B */
+      VEC4_SCALAR(comp, softpipe->blend_color[clamp_blend_source_factors_and_results].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, softpipe->blend_color[clamp_blend_source_factors_and_results].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 */
@@ -376,20 +400,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 - softpipe->blend_color[clamp_blend_source_factors_and_results].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 - softpipe->blend_color[clamp_blend_source_factors_and_results].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 - softpipe->blend_color[clamp_blend_source_factors_and_results].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 - softpipe->blend_color[clamp_blend_source_factors_and_results].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 */
@@ -437,7 +461,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, softpipe->blend_color[clamp_blend_source_factors_and_results].color[3]); /* A */
       VEC4_MUL(source[3], quadColor[3], comp); /* A */
    }
    break;
@@ -471,7 +495,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 - softpipe->blend_color[clamp_blend_source_factors_and_results].color[3]);
       VEC4_MUL(source[3], quadColor[3], inv_comp);
    }
    break;
@@ -531,18 +555,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, softpipe->blend_color[clamp_blend_source_factors_and_results].color[0]); /* R */
       VEC4_MUL(dest[0], dest[0], comp); /* R */
-      VEC4_SCALAR(comp, softpipe->blend_color.color[1]); /* G */
+      VEC4_SCALAR(comp, softpipe->blend_color[clamp_blend_source_factors_and_results].color[1]); /* G */
       VEC4_MUL(dest[1], dest[1], comp); /* G */
-      VEC4_SCALAR(comp, softpipe->blend_color.color[2]); /* B */
+      VEC4_SCALAR(comp, softpipe->blend_color[clamp_blend_source_factors_and_results].color[2]); /* B */
       VEC4_MUL(dest[2], 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, softpipe->blend_color[clamp_blend_source_factors_and_results].color[3]); /* A */
       VEC4_MUL(dest[0], dest[0], comp); /* R */
       VEC4_MUL(dest[1], dest[1], comp); /* G */
       VEC4_MUL(dest[2], dest[2], comp); /* B */
@@ -607,20 +631,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 - softpipe->blend_color[clamp_blend_source_factors_and_results].color[0]);
       VEC4_MUL(dest[0], dest[0], inv_comp);
       /* G */
-      VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[1]);
+      VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color[clamp_blend_source_factors_and_results].color[1]);
       VEC4_MUL(dest[1], dest[1], inv_comp);
       /* B */
-      VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[2]);
+      VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color[clamp_blend_source_factors_and_results].color[2]);
       VEC4_MUL(dest[2], 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 - softpipe->blend_color[clamp_blend_source_factors_and_results].color[3]);
       VEC4_MUL(dest[0], dest[0], inv_comp);
       VEC4_MUL(dest[1], dest[1], inv_comp);
       VEC4_MUL(dest[2], dest[2], inv_comp);
@@ -665,7 +689,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, softpipe->blend_color[clamp_blend_source_factors_and_results].color[3]); /* A */
       VEC4_MUL(dest[3], dest[3], comp); /* A */
    }
    break;
@@ -698,7 +722,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 - softpipe->blend_color[clamp_blend_source_factors_and_results].color[3]);
       VEC4_MUL(dest[3], dest[3], inv_comp);
    }
    break;
@@ -706,24 +730,56 @@ blend_quad(struct quad_stage *qs,
       assert(0 && "invalid alpha dst factor");
    }
 
+   /* NOTE: we cannot rely on the float->ubyte conversion for
+    * the final clamping here, because we cache tiles, and must avoid
+    * reading back unclamped values from a cached tile
+    */
+
    /*
     * Combine RGB terms
     */
    switch (softpipe->blend->rt[blend_index].rgb_func) {
    case PIPE_BLEND_ADD:
-      VEC4_ADD_SAT(quadColor[0], source[0], dest[0]); /* R */
-      VEC4_ADD_SAT(quadColor[1], source[1], dest[1]); /* G */
-      VEC4_ADD_SAT(quadColor[2], source[2], dest[2]); /* B */
+      if(clamp_blend_source_factors_and_results)
+      {
+         VEC4_ADD_SAT(quadColor[0], source[0], dest[0]); /* R */
+         VEC4_ADD_SAT(quadColor[1], source[1], dest[1]); /* G */
+         VEC4_ADD_SAT(quadColor[2], source[2], dest[2]); /* B */
+      }
+      else
+      {
+         VEC4_ADD(quadColor[0], source[0], dest[0]); /* R */
+         VEC4_ADD(quadColor[1], source[1], dest[1]); /* G */
+         VEC4_ADD(quadColor[2], source[2], dest[2]); /* B */
+      }
       break;
    case PIPE_BLEND_SUBTRACT:
-      VEC4_SUB_SAT(quadColor[0], source[0], dest[0]); /* R */
-      VEC4_SUB_SAT(quadColor[1], source[1], dest[1]); /* G */
-      VEC4_SUB_SAT(quadColor[2], source[2], dest[2]); /* B */
+      if(clamp_blend_source_factors_and_results)
+      {
+         VEC4_SUB_SAT(quadColor[0], source[0], dest[0]); /* R */
+         VEC4_SUB_SAT(quadColor[1], source[1], dest[1]); /* G */
+         VEC4_SUB_SAT(quadColor[2], source[2], dest[2]); /* B */
+      }
+      else
+      {
+         VEC4_SUB(quadColor[0], source[0], dest[0]); /* R */
+         VEC4_SUB(quadColor[1], source[1], dest[1]); /* G */
+         VEC4_SUB(quadColor[2], source[2], dest[2]); /* B */
+      }
       break;
    case PIPE_BLEND_REVERSE_SUBTRACT:
-      VEC4_SUB_SAT(quadColor[0], dest[0], source[0]); /* R */
-      VEC4_SUB_SAT(quadColor[1], dest[1], source[1]); /* G */
-      VEC4_SUB_SAT(quadColor[2], dest[2], source[2]); /* B */
+      if(clamp_blend_source_factors_and_results)
+      {
+         VEC4_SUB_SAT(quadColor[0], dest[0], source[0]); /* R */
+         VEC4_SUB_SAT(quadColor[1], dest[1], source[1]); /* G */
+         VEC4_SUB_SAT(quadColor[2], dest[2], source[2]); /* B */
+      }
+      else
+      {
+         VEC4_SUB(quadColor[0], dest[0], source[0]); /* R */
+         VEC4_SUB(quadColor[1], dest[1], source[1]); /* G */
+         VEC4_SUB(quadColor[2], dest[2], source[2]); /* B */
+      }
       break;
    case PIPE_BLEND_MIN:
       VEC4_MIN(quadColor[0], source[0], dest[0]); /* R */
@@ -744,13 +800,22 @@ blend_quad(struct quad_stage *qs,
     */
    switch (softpipe->blend->rt[blend_index].alpha_func) {
    case PIPE_BLEND_ADD:
-      VEC4_ADD_SAT(quadColor[3], source[3], dest[3]); /* A */
+      if(clamp_blend_source_factors_and_results)
+         VEC4_ADD_SAT(quadColor[3], source[3], dest[3]); /* A */
+      else
+         VEC4_ADD(quadColor[3], source[3], dest[3]); /* A */
       break;
    case PIPE_BLEND_SUBTRACT:
-      VEC4_SUB_SAT(quadColor[3], source[3], dest[3]); /* A */
+      if(clamp_blend_source_factors_and_results)
+         VEC4_SUB_SAT(quadColor[3], source[3], dest[3]); /* A */
+      else
+         VEC4_SUB(quadColor[3], source[3], dest[3]); /* A */
       break;
    case PIPE_BLEND_REVERSE_SUBTRACT:
-      VEC4_SUB_SAT(quadColor[3], dest[3], source[3]); /* A */
+      if(clamp_blend_source_factors_and_results)
+         VEC4_SUB_SAT(quadColor[3], dest[3], source[3]); /* A */
+      else
+         VEC4_SUB(quadColor[3], dest[3], source[3]); /* A */
       break;
    case PIPE_BLEND_MIN:
       VEC4_MIN(quadColor[3], source[3], dest[3]); /* A */
@@ -804,8 +869,6 @@ 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);
       uint q, i, j;
 
       for (q = 0; q < nr; q++) {
@@ -824,12 +887,16 @@ blend_fallback(struct quad_stage *qs,
             }
          }
 
-
          if (blend->logicop_enable) {
-            logicop_quad( qs, quadColor, dest );
+            /* yes, this must disable blend even if we don't actually perform it */
+            if(softpipe->cbuf_derived[cbuf].perform_logicop)
+               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_buf,
+                  softpipe->cbuf_derived[cbuf].has_dest_alpha,
+                  softpipe->cbuf_derived[cbuf].clamp_blend_source_factors_and_results,
+                  softpipe->cbuf_derived[cbuf].clamp_blend_dest );
          }
 
          if (blend->rt[blend_buf].colormask != 0xf)
@@ -850,115 +917,8 @@ blend_fallback(struct quad_stage *qs,
    }
 }
 
-
-static void
-blend_single_add_src_alpha_inv_src_alpha(struct quad_stage *qs, 
-                                         struct quad_header *quads[],
-                                         unsigned nr)
-{
-   static const float one[4] = { 1, 1, 1, 1 };
-   float one_minus_alpha[QUAD_SIZE];
-   float dest[4][QUAD_SIZE];
-   float source[4][QUAD_SIZE];
-   uint i, j, q;
-
-   struct softpipe_cached_tile *tile
-      = sp_get_cached_tile(qs->softpipe->cbuf_cache[0],
-                           quads[0]->input.x0, 
-                           quads[0]->input.y0);
-
-   for (q = 0; q < nr; q++) {
-      struct quad_header *quad = quads[q];
-      float (*quadColor)[4] = quad->output.color[0];
-      const float *alpha = quadColor[3];
-      const int itx = (quad->input.x0 & (TILE_SIZE-1));
-      const int ity = (quad->input.y0 & (TILE_SIZE-1));
-      
-      /* get/swizzle dest colors */
-      for (j = 0; j < QUAD_SIZE; j++) {
-         int x = itx + (j & 1);
-         int y = ity + (j >> 1);
-         for (i = 0; i < 4; i++) {
-            dest[i][j] = tile->data.color[y][x][i];
-         }
-      }
-
-      VEC4_MUL(source[0], quadColor[0], alpha); /* R */
-      VEC4_MUL(source[1], quadColor[1], alpha); /* G */
-      VEC4_MUL(source[2], quadColor[2], alpha); /* B */
-      VEC4_MUL(source[3], quadColor[3], alpha); /* A */
-
-      VEC4_SUB(one_minus_alpha, one, alpha);
-      VEC4_MUL(dest[0], dest[0], one_minus_alpha); /* R */
-      VEC4_MUL(dest[1], dest[1], one_minus_alpha); /* G */
-      VEC4_MUL(dest[2], dest[2], one_minus_alpha); /* B */
-      VEC4_MUL(dest[3], dest[3], one_minus_alpha); /* B */
-
-      VEC4_ADD_SAT(quadColor[0], source[0], dest[0]); /* R */
-      VEC4_ADD_SAT(quadColor[1], source[1], dest[1]); /* G */
-      VEC4_ADD_SAT(quadColor[2], source[2], dest[2]); /* B */
-      VEC4_ADD_SAT(quadColor[3], source[3], dest[3]); /* A */
-
-      for (j = 0; j < QUAD_SIZE; j++) {
-         if (quad->inout.mask & (1 << j)) {
-            int x = itx + (j & 1);
-            int y = ity + (j >> 1);
-            for (i = 0; i < 4; i++) { /* loop over color chans */
-               tile->data.color[y][x][i] = quadColor[i][j];
-            }
-         }
-      }
-   }
-}
-
 static void
-blend_single_add_one_one(struct quad_stage *qs, 
-                         struct quad_header *quads[],
-                         unsigned nr)
-{
-   float dest[4][QUAD_SIZE];
-   uint i, j, q;
-
-   struct softpipe_cached_tile *tile
-      = sp_get_cached_tile(qs->softpipe->cbuf_cache[0],
-                           quads[0]->input.x0, 
-                           quads[0]->input.y0);
-
-   for (q = 0; q < nr; q++) {
-      struct quad_header *quad = quads[q];
-      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));
-      
-      /* get/swizzle dest colors */
-      for (j = 0; j < QUAD_SIZE; j++) {
-         int x = itx + (j & 1);
-         int y = ity + (j >> 1);
-         for (i = 0; i < 4; i++) {
-            dest[i][j] = tile->data.color[y][x][i];
-         }
-      }
-     
-      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 */
-      VEC4_ADD_SAT(quadColor[3], quadColor[3], dest[3]); /* A */
-
-      for (j = 0; j < QUAD_SIZE; j++) {
-         if (quad->inout.mask & (1 << j)) {
-            int x = itx + (j & 1);
-            int y = ity + (j >> 1);
-            for (i = 0; i < 4; i++) { /* loop over color chans */
-               tile->data.color[y][x][i] = quadColor[i][j];
-            }
-         }
-      }
-   }
-}
-
-
-static void
-single_output_color(struct quad_stage *qs, 
+single_output_color(struct quad_stage *qs,
                     struct quad_header *quads[],
                     unsigned nr)
 {
@@ -1004,32 +964,18 @@ choose_blend_quad(struct quad_stage *qs,
    const struct pipe_blend_state *blend = softpipe->blend;
 
    qs->run = blend_fallback;
-   
+
    if (softpipe->framebuffer.nr_cbufs == 0) {
       qs->run = blend_noop;
    }
    else if (!softpipe->blend->logicop_enable &&
             softpipe->blend->rt[0].colormask == 0xf &&
-            softpipe->framebuffer.nr_cbufs == 1)
+            softpipe->framebuffer.nr_cbufs == 1
+            )
    {
-      if (!blend->rt[0].blend_enable) {
+      if (!blend->rt[0].blend_enable)
+         /* if blending is disabled, being fixed-point does not cause any clamping */
          qs->run = single_output_color;
-      }
-      else if (blend->rt[0].rgb_src_factor == blend->rt[0].alpha_src_factor &&
-               blend->rt[0].rgb_dst_factor == blend->rt[0].alpha_dst_factor &&
-               blend->rt[0].rgb_func == blend->rt[0].alpha_func)
-      {
-         if (blend->rt[0].alpha_func == PIPE_BLEND_ADD) {
-            if (blend->rt[0].rgb_src_factor == PIPE_BLENDFACTOR_ONE &&
-                blend->rt[0].rgb_dst_factor == PIPE_BLENDFACTOR_ONE) {
-               qs->run = blend_single_add_one_one;
-            }
-            else if (blend->rt[0].rgb_src_factor == PIPE_BLENDFACTOR_SRC_ALPHA &&
-                blend->rt[0].rgb_dst_factor == PIPE_BLENDFACTOR_INV_SRC_ALPHA)
-               qs->run = blend_single_add_src_alpha_inv_src_alpha;
-
-         }
-      }
    }
 
    qs->run(qs, quads, nr);
diff --git a/src/gallium/drivers/softpipe/sp_state_blend.c b/src/gallium/drivers/softpipe/sp_state_blend.c
index 2a203f4..fe295d5 100644
--- a/src/gallium/drivers/softpipe/sp_state_blend.c
+++ b/src/gallium/drivers/softpipe/sp_state_blend.c
@@ -29,6 +29,7 @@
  */
 
 #include "util/u_memory.h"
+#include "util/u_math.h"
 #include "draw/draw_context.h"
 #include "sp_context.h"
 #include "sp_state.h"
@@ -64,10 +65,13 @@ void 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;
+   softpipe->blend_color[0] = *blend_color;
+   for(i = 0; i < 4; ++i)
+      softpipe->blend_color[1].color[i] = CLAMP(softpipe->blend_color[0].color[i], 0.0f, 1.0f);
 
    softpipe->dirty |= SP_NEW_BLEND;
 }
diff --git a/src/gallium/drivers/softpipe/sp_state_surface.c b/src/gallium/drivers/softpipe/sp_state_surface.c
index 2db6fae..f294590 100644
--- a/src/gallium/drivers/softpipe/sp_state_surface.c
+++ b/src/gallium/drivers/softpipe/sp_state_surface.c
@@ -100,5 +100,33 @@ softpipe_set_framebuffer_state(struct pipe_context *pipe,
    sp->framebuffer.width = fb->width;
    sp->framebuffer.height = fb->height;
 
+   /* find out how to do blending for this framebuffer, in case we want to do so */
+   for (i = 0; i < fb->nr_cbufs; i++)
+   {
+      const struct util_format_description* desc = util_format_description(fb->cbufs[i]->format);
+      unsigned chan;
+
+      sp->cbuf_derived[i].has_dest_alpha = util_format_has_alpha(fb->cbufs[i]->format);
+      sp->cbuf_derived[i].clamp_blend_source_factors_and_results = FALSE;
+      sp->cbuf_derived[i].clamp_blend_dest = FALSE;
+      sp->cbuf_derived[i].perform_logicop = TRUE;
+
+      for(chan = 0; chan < desc->nr_channels; ++chan)
+      {
+         if(desc->channel[chan].type == UTIL_FORMAT_TYPE_FLOAT)
+            sp->cbuf_derived[i].perform_logicop = FALSE;
+         else
+         {
+            sp->cbuf_derived[i].clamp_blend_source_factors_and_results = TRUE;
+            /* we can skip this for unsigned normalized, since they are
+             * already in the [0, 1] range
+             */
+            if(desc->channel[chan].type != UTIL_FORMAT_TYPE_UNSIGNED
+                  || !desc->channel[chan].normalized)
+               sp->cbuf_derived[i].clamp_blend_dest = TRUE;
+         }
+      }
+   }
+
    sp->dirty |= SP_NEW_FRAMEBUFFER;
 }




More information about the mesa-commit mailing list