diff --git a/src/gallium/drivers/i915/i915_clear.c b/src/gallium/drivers/i915/i915_clear.c index 814fc90b214..e89c4e2f0f6 100644 --- a/src/gallium/drivers/i915/i915_clear.c +++ b/src/gallium/drivers/i915/i915_clear.c @@ -73,7 +73,7 @@ i915_clear_emit(struct pipe_context *pipe, unsigned buffers, } /* correctly swizzle clear value */ - if (i915->current.target_fixup_format) + if (i915->current.fixup_swizzle) util_pack_color(color->f, cbuf->format, &u_color); else util_pack_color(color->f, PIPE_FORMAT_B8G8R8A8_UNORM, &u_color); diff --git a/src/gallium/drivers/i915/i915_context.h b/src/gallium/drivers/i915/i915_context.h index 65de266399d..a5f893bbd63 100644 --- a/src/gallium/drivers/i915/i915_context.h +++ b/src/gallium/drivers/i915/i915_context.h @@ -170,7 +170,8 @@ struct i915_state unsigned dst_buf_vars; uint32_t draw_offset; uint32_t draw_size; - uint32_t target_fixup_format; + + /* Reswizzle for OC writes in PIXEL_SHADER_PROGRAM, or 0 if unnecessary. */ uint32_t fixup_swizzle; unsigned id; /* track lost context events */ @@ -214,6 +215,11 @@ struct i915_sampler_state { struct i915_surface { struct pipe_surface templ; uint32_t buf_info; /* _3DSTATE_BUF_INFO_CMD flags */ + + /* PIXEL_SHADER_PROGRAM swizzle for OC buffer to handle the cbuf format (or 0 if none). */ + uint32_t oc_swizzle; + /* cbuf swizzle from dst r/g/b/a channels in memory to channels of gallium API. */ + uint8_t color_swizzle[4]; }; struct i915_velems_state { diff --git a/src/gallium/drivers/i915/i915_state_emit.c b/src/gallium/drivers/i915/i915_state_emit.c index 9f0f9e33ca3..3e0da67cff5 100644 --- a/src/gallium/drivers/i915/i915_state_emit.c +++ b/src/gallium/drivers/i915/i915_state_emit.c @@ -179,7 +179,8 @@ static void emit_immediate_s6(struct i915_context *i915, uint imm) * and therefore we need to use the color factor for alphas. */ uint srcRGB; - if (i915->current.target_fixup_format == PIPE_FORMAT_A8_UNORM) { + if (i915->framebuffer.cbufs[0] && + i915->framebuffer.cbufs[0]->format == PIPE_FORMAT_A8_UNORM) { srcRGB = (imm >> S6_CBUF_SRC_BLEND_FACT_SHIFT) & BLENDFACT_MASK; if (srcRGB == BLENDFACT_DST_ALPHA) srcRGB = BLENDFACT_DST_COLR; @@ -425,7 +426,7 @@ validate_program(struct i915_context *i915, unsigned *batch_space) { uint additional_size = 0; - additional_size += i915->current.target_fixup_format ? 3 : 0; + additional_size += i915->current.fixup_swizzle ? 3 : 0; /* we need more batch space if we want to emulate rgba framebuffers */ *batch_space = i915->fs->decl_len + i915->fs->program_len + additional_size; @@ -464,7 +465,7 @@ emit_program(struct i915_context *i915) } /* we emit an additional mov with swizzle to fake RGBA framebuffers */ - if (i915->current.target_fixup_format) { + if (i915->current.fixup_swizzle) { /* mov out_color, out_color.zyxw */ OUT_BATCH(A0_MOV | (REG_TYPE_OC << A0_DEST_TYPE_SHIFT) | diff --git a/src/gallium/drivers/i915/i915_state_static.c b/src/gallium/drivers/i915/i915_state_static.c index 3f6923c15ab..2d0a7416072 100644 --- a/src/gallium/drivers/i915/i915_state_static.c +++ b/src/gallium/drivers/i915/i915_state_static.c @@ -82,6 +82,7 @@ static void update_framebuffer(struct i915_context *i915) unsigned x, y; int layer; uint32_t draw_offset, draw_size; + uint32_t oc_swizzle = 0; if (cbuf_surface) { struct i915_surface *surf = i915_surface(cbuf_surface); @@ -95,6 +96,8 @@ static void update_framebuffer(struct i915_context *i915) x = tex->image_offset[cbuf_surface->u.tex.level][layer].nblocksx; y = tex->image_offset[cbuf_surface->u.tex.level][layer].nblocksy; + + oc_swizzle = surf->oc_swizzle; } else { i915->current.cbuf_bo = NULL; x = y = 0; @@ -134,6 +137,11 @@ static void update_framebuffer(struct i915_context *i915) i915->hardware_dirty |= I915_HW_STATIC; + if (i915->current.fixup_swizzle != oc_swizzle) { + i915->current.fixup_swizzle = oc_swizzle; + i915->hardware_dirty |= I915_HW_PROGRAM; + } + /* flush the cache in case we sample from the old renderbuffers */ i915_set_flush_dirty(i915, I915_FLUSH_CACHE); } @@ -144,45 +152,12 @@ struct i915_tracked_state i915_hw_framebuffer = { I915_NEW_FRAMEBUFFER }; -static uint32_t need_target_fixup(struct pipe_surface* p, uint32_t *fixup) -{ - const struct - { - enum pipe_format format; - uint hw_swizzle; - } fixup_formats[] = { - { PIPE_FORMAT_R8G8B8A8_UNORM, 0x21030000 /* BGRA */}, - { PIPE_FORMAT_R8G8B8X8_UNORM, 0x21030000 /* BGRX */}, - { PIPE_FORMAT_L8_UNORM, 0x00030000 /* RRRA */}, - { PIPE_FORMAT_I8_UNORM, 0x00030000 /* RRRA */}, - { PIPE_FORMAT_A8_UNORM, 0x33330000 /* AAAA */}, - { PIPE_FORMAT_NONE, 0x00000000}, - }; - - enum pipe_format f; - /* if we don't have a surface bound yet, we don't need to fixup the shader */ - if (!p) - return 0; - - f = p->format; - 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 f; - } - - *fixup = 0; - return 0; -} - static void update_dst_buf_vars(struct i915_context *i915) { struct pipe_surface *cbuf_surface = i915->framebuffer.cbufs[0]; struct pipe_surface *depth_surface = i915->framebuffer.zsbuf; uint32_t dst_buf_vars, cformat, zformat; uint32_t early_z = 0; - uint32_t fixup = 0; - int need_fixup; if (cbuf_surface) cformat = cbuf_surface->format; @@ -219,14 +194,6 @@ static void update_dst_buf_vars(struct i915_context *i915) i915->hardware_dirty |= I915_HW_STATIC; } - need_fixup = need_target_fixup(cbuf_surface, &fixup); - if (i915->current.target_fixup_format != need_fixup || - i915->current.fixup_swizzle != fixup) { - i915->current.target_fixup_format = need_fixup; - i915->current.fixup_swizzle = fixup; - /* we also send a new program to make sure the fixup for RGBA surfaces happens */ - i915->hardware_dirty |= I915_HW_PROGRAM; - } } struct i915_tracked_state i915_hw_dst_buf_vars = { diff --git a/src/gallium/drivers/i915/i915_surface.c b/src/gallium/drivers/i915/i915_surface.c index 3c717bccec3..e43284fa36f 100644 --- a/src/gallium/drivers/i915/i915_surface.c +++ b/src/gallium/drivers/i915/i915_surface.c @@ -349,6 +349,31 @@ i915_clear_depth_stencil_blitter(struct pipe_context *pipe, * Screen surface functions */ +static void i915_set_color_surface_swizzle(struct i915_surface *surf) +{ + const struct { + enum pipe_format format; + uint8_t color_swizzle[4]; + uint32_t oc_swizzle; + } fixup_formats[] = { + { PIPE_FORMAT_R8G8B8A8_UNORM, {2, 1, 0, 3 }, 0x21030000 /* BGRA */}, + { PIPE_FORMAT_R8G8B8X8_UNORM, {2, 1, 0, 3 }, 0x21030000 /* BGRX */}, + { PIPE_FORMAT_L8_UNORM, {0, 0, 0, 0 }, 0x00030000 /* RRRA */}, + { PIPE_FORMAT_I8_UNORM, {0, 0, 0, 0 }, 0x00030000 /* RRRA */}, + { PIPE_FORMAT_A8_UNORM, {3, 3, 3, 3 }, 0x33330000 /* AAAA */}, + }; + + for (int i = 0; i < ARRAY_SIZE(fixup_formats); i++) { + if (fixup_formats[i].format == surf->templ.format) { + memcpy(surf->color_swizzle, fixup_formats[i].color_swizzle, sizeof(surf->color_swizzle)); + surf->oc_swizzle = fixup_formats[i].oc_swizzle; + return; + } + } + + for (int i = 0; i < 4; i++) + surf->color_swizzle[i] = i; +} static struct pipe_surface * i915_create_surface_custom(struct pipe_context *ctx, @@ -385,6 +410,8 @@ i915_create_surface_custom(struct pipe_context *ctx, surf->buf_info = BUF_3D_ID_DEPTH; } else { surf->buf_info = BUF_3D_ID_COLOR_BACK; + + i915_set_color_surface_swizzle(surf); } surf->buf_info |= BUF_3D_PITCH(tex->stride); /* pitch in bytes */