Просмотр исходного кода

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.
tags/mesa-8.0-rc1
Brian Paul 14 лет назад
Родитель
Сommit
a7109a3199
1 измененных файлов: 96 добавлений и 65 удалений
  1. 96
    65
      src/gallium/drivers/softpipe/sp_quad_blend.c

+ 96
- 65
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);

Загрузка…
Отмена
Сохранить