diff options
Diffstat (limited to 'src/gallium')
-rw-r--r-- | src/gallium/drivers/i915/i915_state_emit.c | 85 |
1 files changed, 54 insertions, 31 deletions
diff --git a/src/gallium/drivers/i915/i915_state_emit.c b/src/gallium/drivers/i915/i915_state_emit.c index 257a8347bbe..39fb13aec7e 100644 --- a/src/gallium/drivers/i915/i915_state_emit.c +++ b/src/gallium/drivers/i915/i915_state_emit.c @@ -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]); } } |