aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBrian Paul <[email protected]>2011-09-15 11:31:55 -0600
committerBrian Paul <[email protected]>2011-09-15 11:31:55 -0600
commita7109a31999f78a1184346f423a8df15be18d570 (patch)
treecc571c922a2c97753fdb6a0d20cdbdc4a07af23d /src
parentba6f1f2c29c148e33acc9d2b411c19c7c9a9d04f (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')
-rw-r--r--src/gallium/drivers/softpipe/sp_quad_blend.c161
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);