i915g: Fix the blending for the A8 destination buffer case.
authorStéphane Marchesin <marcheu@chromium.org>
Mon, 16 Jan 2012 07:32:59 +0000 (23:32 -0800)
committerStéphane Marchesin <marcheu@chromium.org>
Mon, 16 Jan 2012 07:39:49 +0000 (23:39 -0800)
The i915 GPU can't do A8 dst, so we abuse GREEN8 buffers for that
purpose. However, things get hairy as we start to do blending,
because then GL_DST_*_ALPHA should be replaced with GL_DST_*_COLOR.
This is what we do here.

Fixes piglt fbo-alpha.

src/gallium/drivers/i915/i915_clear.c
src/gallium/drivers/i915/i915_context.h
src/gallium/drivers/i915/i915_state_emit.c
src/gallium/drivers/i915/i915_state_static.c

index 7341156310da648781d94fda4501e5bce3e59b6b..d6e6f567b89dc6ca65f5c7a1404d057fafe87daa 100644 (file)
@@ -74,7 +74,7 @@ i915_clear_emit(struct pipe_context *pipe, unsigned buffers,
       }
 
       /* correctly swizzle clear value */
-      if (i915->current.need_target_fixup)
+      if (i915->current.target_fixup_format)
          util_pack_color(color->f, cbuf->format, &u_color);
       else
          util_pack_color(color->f, PIPE_FORMAT_B8G8R8A8_UNORM, &u_color);
index fb511853e720837471fc240896fe452b6adfdaca..e39c7cc137f457fa3cb223ab3e11dbdb36bb36e4 100644 (file)
@@ -167,7 +167,7 @@ struct i915_state
    unsigned dst_buf_vars;
    uint32_t draw_offset;
    uint32_t draw_size;
-   unsigned need_target_fixup;
+   uint32_t target_fixup_format;
    uint32_t fixup_swizzle;
 
    unsigned id;                        /* track lost context events */
index 426c683502ac5322d7b495ca2bdd24bf3cb0736e..9d487cfcdc12dcbbb437ea8cadc4212efdef9be3 100644 (file)
@@ -151,8 +151,25 @@ emit_immediate(struct i915_context *i915)
    }
 
    for (i = 1; i < I915_MAX_IMMEDIATE; i++) {
-      if (dirty & (1 << i))
-         OUT_BATCH(i915->current.immediate[i]);
+      if (dirty & (1 << i)) {
+         /* Fixup blend function for A8 dst buffers.
+          * When we blend to an A8 buffer, the GPU thinks it's a G8 buffer,
+          * and therefore we need to use the color factor for alphas. */
+         if ((i == I915_IMMEDIATE_S6) &&
+             (i915->current.target_fixup_format == PIPE_FORMAT_A8_UNORM)) {
+            uint32_t imm = i915->current.immediate[i];
+            uint32_t srcRGB = (imm >> S6_CBUF_SRC_BLEND_FACT_SHIFT) & BLENDFACT_MASK;
+            if (srcRGB == BLENDFACT_DST_ALPHA)
+               srcRGB = BLENDFACT_DST_COLR;
+            else if (srcRGB == BLENDFACT_INV_DST_ALPHA)
+               srcRGB = BLENDFACT_INV_DST_COLR;
+            imm &= ~SRC_BLND_FACT(BLENDFACT_MASK);
+            imm |= SRC_BLND_FACT(srcRGB);
+            OUT_BATCH(imm);
+         } else {
+            OUT_BATCH(i915->current.immediate[i]);
+         }
+      }
    }
 }
 
@@ -346,7 +363,7 @@ emit_constants(struct i915_context *i915)
 static void
 validate_program(struct i915_context *i915, unsigned *batch_space)
 {
-   uint additional_size = i915->current.need_target_fixup;
+   uint additional_size = i915->current.target_fixup_format ? 1 : 0;
 
    /* we need more batch space if we want to emulate rgba framebuffers */
    *batch_space = i915->fs->program_len + 3 * additional_size;
@@ -355,7 +372,7 @@ validate_program(struct i915_context *i915, unsigned *batch_space)
 static void
 emit_program(struct i915_context *i915)
 {
-   uint target_fixup = i915->current.need_target_fixup;
+   uint need_target_fixup = i915->current.target_fixup_format ? 1 : 0;
    uint i;
 
    /* we should always have, at least, a pass-through program */
@@ -364,7 +381,7 @@ emit_program(struct i915_context *i915)
    {
       /* first word has the size, we have to adjust that */
       uint size = (i915->fs->program[0]);
-      size += target_fixup * 3;
+      size += need_target_fixup * 3;
       OUT_BATCH(size);
    }
 
@@ -373,7 +390,7 @@ emit_program(struct i915_context *i915)
       OUT_BATCH(i915->fs->program[i]);
 
    /* we emit an additional mov with swizzle to fake RGBA framebuffers */
-   if (target_fixup) {
+   if (need_target_fixup) {
       /* mov out_color, out_color.zyxw */
       OUT_BATCH(A0_MOV |
                 (REG_TYPE_OC << A0_DEST_TYPE_SHIFT) |
index 9370f3dc2d32d4291bbfee0204e4bd6ff1429de7..9587dec4b9025128be575ffda3b9293db57a4c1f 100644 (file)
@@ -177,7 +177,7 @@ static const struct
    { PIPE_FORMAT_NONE,           0x00000000},
 };
 
-static uint need_target_fixup(struct pipe_surface* p, uint32_t *fixup)
+static uint32_t need_target_fixup(struct pipe_surface* p, uint32_t *fixup)
 {
    enum pipe_format f;
    /* if we don't have a surface bound yet, we don't need to fixup the shader */
@@ -188,7 +188,7 @@ static uint need_target_fixup(struct pipe_surface* p, uint32_t *fixup)
    for(int i=0; fixup_formats[i].format != PIPE_FORMAT_NONE; i++)
       if (fixup_formats[i].format == f) {
          *fixup = fixup_formats[i].hw_swizzle;
-         return 1;
+         return f;
       }
 
    *fixup = 0;
@@ -240,9 +240,9 @@ static void update_dst_buf_vars(struct i915_context *i915)
    }
 
    need_fixup = need_target_fixup(cbuf_surface, &fixup);
-   if (i915->current.need_target_fixup != need_fixup ||
+   if (i915->current.target_fixup_format != need_fixup ||
          i915->current.fixup_swizzle != fixup) {
-      i915->current.need_target_fixup = need_fixup;
+      i915->current.target_fixup_format = need_fixup;
       i915->current.fixup_swizzle = fixup;
       i915->hardware_dirty |= I915_HW_PROGRAM;
    }