i915g: Implement surface format fixup without adding an extra instruction.
authorStéphane Marchesin <marcheu@chromium.org>
Thu, 30 Jun 2011 09:05:50 +0000 (02:05 -0700)
committerStéphane Marchesin <marcheu@chromium.org>
Thu, 30 Jun 2011 09:13:28 +0000 (02:13 -0700)
We also avoid writing output color twice, which might not work when we run out of phases.

src/gallium/drivers/i915/i915_state_emit.c

index 257a8347bbe087834ea4a505e4cbab64ed559088..39fb13aec7ec936e4b6e1e5fb76bb66783365e22 100644 (file)
@@ -130,7 +130,7 @@ validate_immediate(struct i915_context *i915, unsigned *batch_space)
 static void
 emit_immediate(struct i915_context *i915)
 {
-   /* remove unwatned bits and S7 */
+   /* remove unwanted bits and S7 */
    unsigned dirty = (1 << I915_IMMEDIATE_S0 | 1 << I915_IMMEDIATE_S1 |
                      1 << I915_IMMEDIATE_S2 | 1 << I915_IMMEDIATE_S3 |
                      1 << I915_IMMEDIATE_S3 | 1 << I915_IMMEDIATE_S4 |
@@ -346,18 +346,22 @@ emit_constants(struct i915_context *i915)
 static const struct
 {
    enum pipe_format format;
-   uint hw_swizzle;
+   uint hw_shift_R;
+   uint hw_shift_G;
+   uint hw_shift_B;
+   uint hw_shift_A;
 } fixup_formats[] = {
-   { PIPE_FORMAT_R8G8B8A8_UNORM, 0x21030000 /* BGRA */},
-   { PIPE_FORMAT_L8_UNORM,       0x00030000 /* RRRR */},
-   { PIPE_FORMAT_I8_UNORM,       0x00030000 /* RRRR */},
-   { PIPE_FORMAT_A8_UNORM,       0x33330000 /* AAAA */},
-   { PIPE_FORMAT_NONE,           0x00000000},
+   { PIPE_FORMAT_R8G8B8A8_UNORM, 20, 24, 28, 16 /* BGRA */},
+   { PIPE_FORMAT_L8_UNORM,       28, 28, 28, 16 /* RRRA */},
+   { PIPE_FORMAT_I8_UNORM,       28, 28, 28, 16 /* RRRA */},
+   { PIPE_FORMAT_A8_UNORM,       16, 16, 16, 16 /* AAAA */},
+   { PIPE_FORMAT_NONE,           0,   0,  0,  0},
 };
 
 static boolean need_fixup(struct pipe_surface* p)
 {
    enum pipe_format f;
+
    /* if we don't have a surface bound yet, we don't need to fixup the shader */
    if (!p)
       return FALSE;
@@ -370,22 +374,32 @@ static boolean need_fixup(struct pipe_surface* p)
    return FALSE;
 }
 
-static uint fixup_swizzle(enum pipe_format f)
+static uint fixup_swizzle(enum pipe_format f, uint v)
 {
-   for(int i=0; fixup_formats[i].format != PIPE_FORMAT_NONE; i++)
+   int i;
+
+   for(i=0; fixup_formats[i].format != PIPE_FORMAT_NONE; i++)
       if (fixup_formats[i].format == f)
-         return fixup_formats[i].hw_swizzle;
+           break;
+
+   if (fixup_formats[i].format == PIPE_FORMAT_NONE)
+          return v;
 
-   return 0;
+   uint rgba = v & 0xFFFF0000;
+
+   v &= 0xFFFF;
+   v |= ((rgba >> fixup_formats[i].hw_shift_R) & 0xF) << 28;
+   v |= ((rgba >> fixup_formats[i].hw_shift_G) & 0xF) << 24;
+   v |= ((rgba >> fixup_formats[i].hw_shift_B) & 0xF) << 20;
+   v |= ((rgba >> fixup_formats[i].hw_shift_A) & 0xF) << 16;
+
+   return v;
 }
 
 static void
 validate_program(struct i915_context *i915, unsigned *batch_space)
 {
-   struct pipe_surface *cbuf_surface = i915->framebuffer.cbufs[0];
-
-   /* we need more batch space if we want to emulate rgba framebuffers */
-   *batch_space = i915->fs->program_len + (need_fixup(cbuf_surface) ? 3 : 0);
+   *batch_space = i915->fs->program_len;
 }
 
 static void
@@ -393,27 +407,36 @@ emit_program(struct i915_context *i915)
 {
    struct pipe_surface *cbuf_surface = i915->framebuffer.cbufs[0];
    boolean need_format_fixup = need_fixup(cbuf_surface);
-   uint i;
+   int i;
+   int fixup_offset = -1;
 
    /* we should always have, at least, a pass-through program */
    assert(i915->fs->program_len > 0);
-   for (i = 0; i < i915->fs->program_len; i++) {
-         if ((i == 0) && need_format_fixup)
-            OUT_BATCH(i915->fs->program[i] + 3);
-         else
-            OUT_BATCH(i915->fs->program[i]);
-   }
 
-   /* we emit an additional mov with swizzle to fake RGBA framebuffers */
    if (need_format_fixup) {
-      /* mov out_color, out_color.zyxw */
-      OUT_BATCH(A0_MOV |
-                (REG_TYPE_OC << A0_DEST_TYPE_SHIFT) |
-                A0_DEST_CHANNEL_ALL |
-                (REG_TYPE_OC << A0_SRC0_TYPE_SHIFT) |
-                (T_DIFFUSE << A0_SRC0_NR_SHIFT));
-      OUT_BATCH(fixup_swizzle(cbuf_surface->format));
-      OUT_BATCH(0);
+      /* Find where we emit the output color */
+      for (i = i915->fs->program_len - 3; i>0; i-=3) {
+         uint instr = i915->fs->program[i];
+         if ((instr & (REG_NR_MASK << A0_DEST_TYPE_SHIFT)) == 
+             (REG_TYPE_OC << A0_DEST_TYPE_SHIFT) ) {
+            /* Found it! */
+            fixup_offset = i + 1;
+            break;
+        }
+      }
+      if (fixup_offset == -1) {
+         need_format_fixup = FALSE;
+         debug_printf("couldn't find fixup offset\n");
+      }
+   }
+
+   /* emit the program to the hw */
+   for (i = 0; i < i915->fs->program_len; i++) {
+      if (need_format_fixup && (i == fixup_offset) ) {
+         uint v = fixup_swizzle(cbuf_surface->format, i915->fs->program[i]);
+         OUT_BATCH(v);
+      } else
+         OUT_BATCH(i915->fs->program[i]);
    }
 }