Mesa (master): r600g: atomize blend state

Marek Olšák mareko at kemper.freedesktop.org
Tue Oct 9 22:29:52 UTC 2012


Module: Mesa
Branch: master
Commit: faaba52aedf9807ced2ddfccc4133589a7bacd5f
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=faaba52aedf9807ced2ddfccc4133589a7bacd5f

Author: Marek Olšák <maraeo at gmail.com>
Date:   Fri Oct  5 02:45:29 2012 +0200

r600g: atomize blend state

This is not so trivial, because we disable blending if the dual src
blending is turned on and the number of color outputs is less than 2.
I decided to create 2 command buffers in the blend state object and just
switch between them when needed, because there are other states unrelated
to blending (like the color mask) and those shouldn't be changed
(the old code had it wrong).

Reviewed-by: Jerome Glisse <jglisse at redhat.com>

---

 src/gallium/drivers/r600/evergreen_hw_context.c |   20 ----
 src/gallium/drivers/r600/evergreen_state.c      |   87 ++++++++--------
 src/gallium/drivers/r600/r600_blit.c            |    2 +-
 src/gallium/drivers/r600/r600_hw_context.c      |   19 +---
 src/gallium/drivers/r600/r600_hw_context_priv.h |    1 -
 src/gallium/drivers/r600/r600_pipe.c            |    7 --
 src/gallium/drivers/r600/r600_pipe.h            |   41 ++++++--
 src/gallium/drivers/r600/r600_state.c           |  121 ++++++++++++-----------
 src/gallium/drivers/r600/r600_state_common.c    |   60 ++++++++----
 9 files changed, 182 insertions(+), 176 deletions(-)

diff --git a/src/gallium/drivers/r600/evergreen_hw_context.c b/src/gallium/drivers/r600/evergreen_hw_context.c
index 666b18c..547f4f5 100644
--- a/src/gallium/drivers/r600/evergreen_hw_context.c
+++ b/src/gallium/drivers/r600/evergreen_hw_context.c
@@ -95,17 +95,8 @@ static const struct r600_reg evergreen_context_reg_list[] = {
 	{R_0286E0_SPI_BARYC_CNTL, 0, 0},
 	{R_0286E4_SPI_PS_IN_CONTROL_2, 0, 0},
 	{R_0286E8_SPI_COMPUTE_INPUT_CNTL, 0, 0},
-	{R_028780_CB_BLEND0_CONTROL, 0, 0},
-	{R_028784_CB_BLEND1_CONTROL, 0, 0},
-	{R_028788_CB_BLEND2_CONTROL, 0, 0},
-	{R_02878C_CB_BLEND3_CONTROL, 0, 0},
-	{R_028790_CB_BLEND4_CONTROL, 0, 0},
-	{R_028794_CB_BLEND5_CONTROL, 0, 0},
-	{R_028798_CB_BLEND6_CONTROL, 0, 0},
-	{R_02879C_CB_BLEND7_CONTROL, 0, 0},
 	{R_028800_DB_DEPTH_CONTROL, 0, 0},
 	{R_02880C_DB_SHADER_CONTROL, 0, 0},
-	{R_028808_CB_COLOR_CONTROL, 0, 0},
 	{R_028814_PA_SU_SC_MODE_CNTL, 0, 0},
 	{R_028840_SQ_PGM_START_PS, REG_FLAG_NEED_BO, 0},
 	{R_028844_SQ_PGM_RESOURCES_PS, 0, 0},
@@ -120,7 +111,6 @@ static const struct r600_reg evergreen_context_reg_list[] = {
 	{R_028A48_PA_SC_MODE_CNTL_0, 0, 0},
 	{R_028ABC_DB_HTILE_SURFACE, 0, 0},
 	{R_028B54_VGT_SHADER_STAGES_EN, 0, 0},
-	{R_028B70_DB_ALPHA_TO_MASK, 0, 0},
 	{R_028B78_PA_SU_POLY_OFFSET_DB_FMT_CNTL, 0, 0},
 	{R_028B7C_PA_SU_POLY_OFFSET_CLAMP, 0, 0},
 	{R_028B80_PA_SU_POLY_OFFSET_FRONT_SCALE, 0, 0},
@@ -191,16 +181,7 @@ static const struct r600_reg cayman_context_reg_list[] = {
 	{R_0286E0_SPI_BARYC_CNTL, 0, 0},
 	{R_0286E4_SPI_PS_IN_CONTROL_2, 0, 0},
 	{R_0286E8_SPI_COMPUTE_INPUT_CNTL, 0, 0},
-	{R_028780_CB_BLEND0_CONTROL, 0, 0},
-	{R_028784_CB_BLEND1_CONTROL, 0, 0},
-	{R_028788_CB_BLEND2_CONTROL, 0, 0},
-	{R_02878C_CB_BLEND3_CONTROL, 0, 0},
-	{R_028790_CB_BLEND4_CONTROL, 0, 0},
-	{R_028794_CB_BLEND5_CONTROL, 0, 0},
-	{R_028798_CB_BLEND6_CONTROL, 0, 0},
-	{R_02879C_CB_BLEND7_CONTROL, 0, 0},
 	{R_028800_DB_DEPTH_CONTROL, 0, 0},
-	{R_028808_CB_COLOR_CONTROL, 0, 0},
 	{R_02880C_DB_SHADER_CONTROL, 0, 0},
 	{R_028814_PA_SU_SC_MODE_CNTL, 0, 0},
 	{R_028838_SQ_DYN_GPR_RESOURCE_LIMIT_1, 0, 0},
@@ -226,7 +207,6 @@ static const struct r600_reg cayman_context_reg_list[] = {
 	{R_028A48_PA_SC_MODE_CNTL_0, 0, 0},
 	{R_028ABC_DB_HTILE_SURFACE, 0, 0},
 	{R_028B54_VGT_SHADER_STAGES_EN, 0, 0},
-	{R_028B70_DB_ALPHA_TO_MASK, 0, 0},
 	{R_028B78_PA_SU_POLY_OFFSET_DB_FMT_CNTL, 0, 0},
 	{R_028B7C_PA_SU_POLY_OFFSET_CLAMP, 0, 0},
 	{R_028B80_PA_SU_POLY_OFFSET_FRONT_SCALE, 0, 0},
diff --git a/src/gallium/drivers/r600/evergreen_state.c b/src/gallium/drivers/r600/evergreen_state.c
index a3b76d9..9aef66b 100644
--- a/src/gallium/drivers/r600/evergreen_state.c
+++ b/src/gallium/drivers/r600/evergreen_state.c
@@ -683,22 +683,16 @@ boolean evergreen_is_format_supported(struct pipe_screen *screen,
 static void *evergreen_create_blend_state_mode(struct pipe_context *ctx,
 					       const struct pipe_blend_state *state, int mode)
 {
-	struct r600_context *rctx = (struct r600_context *)ctx;
-	struct r600_pipe_blend *blend = CALLOC_STRUCT(r600_pipe_blend);
-	struct r600_pipe_state *rstate;
-	uint32_t color_control = 0, target_mask;
-	/* XXX there is more then 8 framebuffer */
-	unsigned blend_cntl[8];
+	uint32_t color_control = 0, target_mask = 0;
+	struct r600_blend_state *blend = CALLOC_STRUCT(r600_blend_state);
 
-	if (blend == NULL) {
+	if (!blend) {
 		return NULL;
 	}
 
-	rstate = &blend->rstate;
-
-	rstate->id = R600_PIPE_STATE_BLEND;
+	r600_init_command_buffer(&blend->buffer, 20);
+	r600_init_command_buffer(&blend->buffer_no_blend, 20);
 
-	target_mask = 0;
 	if (state->logicop_enable) {
 		color_control |= (state->logicop_func << 16) | (state->logicop_func << 20);
 	} else {
@@ -714,17 +708,32 @@ static void *evergreen_create_blend_state_mode(struct pipe_context *ctx,
 			target_mask |= (state->rt[0].colormask << (4 * i));
 		}
 	}
+
+	/* only have dual source on MRT0 */
+	blend->dual_src_blend = util_blend_state_is_dual(state, 0);
 	blend->cb_target_mask = target_mask;
+	blend->alpha_to_one = state->alpha_to_one;
 
 	if (target_mask)
 		color_control |= S_028808_MODE(mode);
 	else
 		color_control |= S_028808_MODE(V_028808_CB_DISABLE);
 
-	r600_pipe_state_add_reg(rstate, R_028808_CB_COLOR_CONTROL,
-				color_control);
-	/* only have dual source on MRT0 */
-	blend->dual_src_blend = util_blend_state_is_dual(state, 0);
+
+	r600_store_context_reg(&blend->buffer, R_028808_CB_COLOR_CONTROL, color_control);
+	r600_store_context_reg(&blend->buffer, R_028B70_DB_ALPHA_TO_MASK,
+			       S_028B70_ALPHA_TO_MASK_ENABLE(state->alpha_to_coverage) |
+			       S_028B70_ALPHA_TO_MASK_OFFSET0(2) |
+			       S_028B70_ALPHA_TO_MASK_OFFSET1(2) |
+			       S_028B70_ALPHA_TO_MASK_OFFSET2(2) |
+			       S_028B70_ALPHA_TO_MASK_OFFSET3(2));
+	r600_store_context_reg_seq(&blend->buffer, R_028780_CB_BLEND0_CONTROL, 8);
+
+	/* Copy over the dwords set so far into buffer_no_blend.
+	 * Only the CB_BLENDi_CONTROL registers must be set after this. */
+	memcpy(blend->buffer_no_blend.buf, blend->buffer.buf, blend->buffer.num_dw * 4);
+	blend->buffer_no_blend.num_dw = blend->buffer.num_dw;
+
 	for (int i = 0; i < 8; i++) {
 		/* state->rt entries > 0 only written if independent blending */
 		const int j = state->independent_blend_enable ? i : 0;
@@ -735,36 +744,29 @@ static void *evergreen_create_blend_state_mode(struct pipe_context *ctx,
 		unsigned eqA = state->rt[j].alpha_func;
 		unsigned srcA = state->rt[j].alpha_src_factor;
 		unsigned dstA = state->rt[j].alpha_dst_factor;
+		uint32_t bc = 0;
 
-		blend_cntl[i] = 0;
-		if (!state->rt[j].blend_enable)
+		r600_store_value(&blend->buffer_no_blend, 0);
+
+		if (!state->rt[j].blend_enable) {
+			r600_store_value(&blend->buffer, 0);
 			continue;
+		}
 
-		blend_cntl[i] |= S_028780_BLEND_CONTROL_ENABLE(1);
-		blend_cntl[i] |= S_028780_COLOR_COMB_FCN(r600_translate_blend_function(eqRGB));
-		blend_cntl[i] |= S_028780_COLOR_SRCBLEND(r600_translate_blend_factor(srcRGB));
-		blend_cntl[i] |= S_028780_COLOR_DESTBLEND(r600_translate_blend_factor(dstRGB));
+		bc |= S_028780_BLEND_CONTROL_ENABLE(1);
+		bc |= S_028780_COLOR_COMB_FCN(r600_translate_blend_function(eqRGB));
+		bc |= S_028780_COLOR_SRCBLEND(r600_translate_blend_factor(srcRGB));
+		bc |= S_028780_COLOR_DESTBLEND(r600_translate_blend_factor(dstRGB));
 
 		if (srcA != srcRGB || dstA != dstRGB || eqA != eqRGB) {
-			blend_cntl[i] |= S_028780_SEPARATE_ALPHA_BLEND(1);
-			blend_cntl[i] |= S_028780_ALPHA_COMB_FCN(r600_translate_blend_function(eqA));
-			blend_cntl[i] |= S_028780_ALPHA_SRCBLEND(r600_translate_blend_factor(srcA));
-			blend_cntl[i] |= S_028780_ALPHA_DESTBLEND(r600_translate_blend_factor(dstA));
+			bc |= S_028780_SEPARATE_ALPHA_BLEND(1);
+			bc |= S_028780_ALPHA_COMB_FCN(r600_translate_blend_function(eqA));
+			bc |= S_028780_ALPHA_SRCBLEND(r600_translate_blend_factor(srcA));
+			bc |= S_028780_ALPHA_DESTBLEND(r600_translate_blend_factor(dstA));
 		}
+		r600_store_value(&blend->buffer, bc);
 	}
-	for (int i = 0; i < 8; i++) {
-		r600_pipe_state_add_reg(rstate, R_028780_CB_BLEND0_CONTROL + i * 4, blend_cntl[i]);
-	}
-
-	r600_pipe_state_add_reg(rstate, R_028B70_DB_ALPHA_TO_MASK,
-				S_028B70_ALPHA_TO_MASK_ENABLE(state->alpha_to_coverage) |
-				S_028B70_ALPHA_TO_MASK_OFFSET0(2) |
-				S_028B70_ALPHA_TO_MASK_OFFSET1(2) |
-				S_028B70_ALPHA_TO_MASK_OFFSET2(2) |
-				S_028B70_ALPHA_TO_MASK_OFFSET3(2));
-
-	blend->alpha_to_one = state->alpha_to_one;
-	return rstate;
+	return blend;
 }
 
 static void *evergreen_create_blend_state(struct pipe_context *ctx,
@@ -2351,6 +2353,7 @@ void evergreen_init_state_functions(struct r600_context *rctx)
 
 	r600_init_atom(rctx, &rctx->alphatest_state.atom, id++, r600_emit_alphatest_state, 6);
 	r600_init_atom(rctx, &rctx->blend_color.atom, id++, r600_emit_blend_color, 6);
+	r600_init_atom(rctx, &rctx->blend_state.atom, id++, r600_emit_cso_state, 0);
 	r600_init_atom(rctx, &rctx->cb_misc_state.atom, id++, evergreen_emit_cb_misc_state, 4);
 	r600_init_atom(rctx, &rctx->clip_misc_state.atom, id++, r600_emit_clip_misc_state, 6);
 	r600_init_atom(rctx, &rctx->clip_state.atom, id++, evergreen_emit_clip_state, 26);
@@ -3335,25 +3338,21 @@ void evergreen_fetch_shader(struct pipe_context *ctx,
 void *evergreen_create_resolve_blend(struct r600_context *rctx)
 {
 	struct pipe_blend_state blend;
-	struct r600_pipe_state *rstate;
 
 	memset(&blend, 0, sizeof(blend));
 	blend.independent_blend_enable = true;
 	blend.rt[0].colormask = 0xf;
-	rstate = evergreen_create_blend_state_mode(&rctx->context, &blend, V_028808_CB_RESOLVE);
-	return rstate;
+	return evergreen_create_blend_state_mode(&rctx->context, &blend, V_028808_CB_RESOLVE);
 }
 
 void *evergreen_create_decompress_blend(struct r600_context *rctx)
 {
 	struct pipe_blend_state blend;
-	struct r600_pipe_state *rstate;
 
 	memset(&blend, 0, sizeof(blend));
 	blend.independent_blend_enable = true;
 	blend.rt[0].colormask = 0xf;
-	rstate = evergreen_create_blend_state_mode(&rctx->context, &blend, V_028808_CB_DECOMPRESS);
-	return rstate;
+	return evergreen_create_blend_state_mode(&rctx->context, &blend, V_028808_CB_DECOMPRESS);
 }
 
 void *evergreen_create_db_flush_dsa(struct r600_context *rctx)
diff --git a/src/gallium/drivers/r600/r600_blit.c b/src/gallium/drivers/r600/r600_blit.c
index 062f6d9..a88cb5e 100644
--- a/src/gallium/drivers/r600/r600_blit.c
+++ b/src/gallium/drivers/r600/r600_blit.c
@@ -68,7 +68,7 @@ static void r600_blitter_begin(struct pipe_context *ctx, enum r600_blitter_op op
 		util_blitter_save_viewport(rctx->blitter, &rctx->viewport.state);
 		util_blitter_save_scissor(rctx->blitter, &rctx->scissor);
 		util_blitter_save_fragment_shader(rctx->blitter, rctx->ps_shader);
-		util_blitter_save_blend(rctx->blitter, rctx->states[R600_PIPE_STATE_BLEND]);
+		util_blitter_save_blend(rctx->blitter, rctx->blend_state.cso);
 		util_blitter_save_depth_stencil_alpha(rctx->blitter, rctx->states[R600_PIPE_STATE_DSA]);
 		util_blitter_save_stencil_ref(rctx->blitter, &rctx->stencil_ref.pipe_state);
                 util_blitter_save_sample_mask(rctx->blitter, rctx->sample_mask.sample_mask);
diff --git a/src/gallium/drivers/r600/r600_hw_context.c b/src/gallium/drivers/r600/r600_hw_context.c
index c457f35..b3f0fba 100644
--- a/src/gallium/drivers/r600/r600_hw_context.c
+++ b/src/gallium/drivers/r600/r600_hw_context.c
@@ -177,12 +177,6 @@ int r600_context_add_block(struct r600_context *ctx, const struct r600_reg *reg,
 			continue;
 		}
 
-		/* ignore regs not on R600 on R600 */
-		if ((reg[i].flags & REG_FLAG_NOT_R600) && ctx->family == CHIP_R600) {
-			n = 1;
-			continue;
-		}
-
 		/* register that need relocation are in their own group */
 		/* find number of consecutive registers */
 		n = 0;
@@ -227,20 +221,10 @@ static const struct r600_reg r600_config_reg_list[] = {
 static const struct r600_reg r600_context_reg_list[] = {
 	{R_028A4C_PA_SC_MODE_CNTL, 0, 0},
 	{GROUP_FORCE_NEW_BLOCK, 0, 0},
-	{R_028780_CB_BLEND0_CONTROL, REG_FLAG_NOT_R600, 0},
-	{R_028784_CB_BLEND1_CONTROL, REG_FLAG_NOT_R600, 0},
-	{R_028788_CB_BLEND2_CONTROL, REG_FLAG_NOT_R600, 0},
-	{R_02878C_CB_BLEND3_CONTROL, REG_FLAG_NOT_R600, 0},
-	{R_028790_CB_BLEND4_CONTROL, REG_FLAG_NOT_R600, 0},
-	{R_028794_CB_BLEND5_CONTROL, REG_FLAG_NOT_R600, 0},
-	{R_028798_CB_BLEND6_CONTROL, REG_FLAG_NOT_R600, 0},
-	{R_02879C_CB_BLEND7_CONTROL, REG_FLAG_NOT_R600, 0},
 	{R_028800_DB_DEPTH_CONTROL, 0, 0},
-	{R_028804_CB_BLEND_CONTROL, 0, 0},
 	{R_02880C_DB_SHADER_CONTROL, 0, 0},
 	{GROUP_FORCE_NEW_BLOCK, 0, 0},
 	{R_028D24_DB_HTILE_SURFACE, 0, 0},
-	{R_028D44_DB_ALPHA_TO_MASK, 0, 0},
 	{R_028250_PA_SC_VPORT_SCISSOR_0_TL, 0, 0},
 	{R_028254_PA_SC_VPORT_SCISSOR_0_BR, 0, 0},
 	{R_0286D4_SPI_INTERP_CONTROL_0, 0, 0},
@@ -891,6 +875,9 @@ void r600_begin_new_cs(struct r600_context *ctx)
 	ctx->stencil_ref.atom.dirty = true;
 	ctx->viewport.atom.dirty = true;
 
+	if (ctx->blend_state.cso)
+		ctx->blend_state.atom.dirty = true;
+
 	if (ctx->chip_class <= R700) {
 		ctx->seamless_cube_map.atom.dirty = true;
 	}
diff --git a/src/gallium/drivers/r600/r600_hw_context_priv.h b/src/gallium/drivers/r600/r600_hw_context_priv.h
index 85fd74d..c59a9ab 100644
--- a/src/gallium/drivers/r600/r600_hw_context_priv.h
+++ b/src/gallium/drivers/r600/r600_hw_context_priv.h
@@ -35,7 +35,6 @@
 /* these flags are used in register flags and added into block flags */
 #define REG_FLAG_NEED_BO 1
 #define REG_FLAG_DIRTY_ALWAYS 2
-#define REG_FLAG_NOT_R600 8
 #define REG_FLAG_ENABLE_ALWAYS 16
 #define REG_FLAG_FLUSH_CHANGE 64
 
diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c
index 70cfe14..35fa9d4 100644
--- a/src/gallium/drivers/r600/r600_pipe.c
+++ b/src/gallium/drivers/r600/r600_pipe.c
@@ -159,9 +159,6 @@ static void r600_destroy_context(struct pipe_context *context)
 	pipe_resource_reference((struct pipe_resource**)&rctx->dummy_cmask, NULL);
 	pipe_resource_reference((struct pipe_resource**)&rctx->dummy_fmask, NULL);
 
-	if (rctx->no_blend) {
-		rctx->context.delete_blend_state(&rctx->context, rctx->no_blend);
-	}
 	if (rctx->dummy_pixel_shader) {
 		rctx->context.delete_fs_state(&rctx->context, rctx->dummy_pixel_shader);
 	}
@@ -204,7 +201,6 @@ static struct pipe_context *r600_create_context(struct pipe_screen *screen, void
 {
 	struct r600_context *rctx = CALLOC_STRUCT(r600_context);
 	struct r600_screen* rscreen = (struct r600_screen *)screen;
-	struct pipe_blend_state no_blend = {};
 
 	if (rctx == NULL)
 		return NULL;
@@ -311,9 +307,6 @@ static struct pipe_context *r600_create_context(struct pipe_screen *screen, void
 						     TGSI_INTERPOLATE_CONSTANT);
 	rctx->context.bind_fs_state(&rctx->context, rctx->dummy_pixel_shader);
 
-	no_blend.rt[0].colormask = 0xF;
-	rctx->no_blend = rctx->context.create_blend_state(&rctx->context, &no_blend);
-
 	return &rctx->context;
 
 fail:
diff --git a/src/gallium/drivers/r600/r600_pipe.h b/src/gallium/drivers/r600/r600_pipe.h
index c6e0241..449c785 100644
--- a/src/gallium/drivers/r600/r600_pipe.h
+++ b/src/gallium/drivers/r600/r600_pipe.h
@@ -35,7 +35,7 @@
 #include "r600_resource.h"
 #include "evergreen_compute.h"
 
-#define R600_NUM_ATOMS 29
+#define R600_NUM_ATOMS 30
 
 #define R600_MAX_CONST_BUFFERS 2
 #define R600_MAX_CONST_BUFFER_SIZE 4096
@@ -161,7 +161,6 @@ struct r600_viewport_state {
 };
 
 enum r600_pipe_state_id {
-	R600_PIPE_STATE_BLEND = 0,
 	R600_PIPE_STATE_SCISSOR,
 	R600_PIPE_STATE_RASTERIZER,
 	R600_PIPE_STATE_DSA,
@@ -223,10 +222,12 @@ struct r600_pipe_rasterizer {
 	bool				multisample_enable;
 };
 
-struct r600_pipe_blend {
-	struct r600_pipe_state		rstate;
+struct r600_blend_state {
+	struct r600_command_buffer	buffer;
+	struct r600_command_buffer	buffer_no_blend;
 	unsigned			cb_target_mask;
 	unsigned			cb_color_control;
+	unsigned			cb_color_control_no_blend;
 	bool				dual_src_blend;
 	bool				alpha_to_one;
 };
@@ -359,6 +360,14 @@ struct r600_vertexbuf_state
 	uint32_t			dirty_mask;
 };
 
+/* CSO (constant state object, in other words, immutable state). */
+struct r600_cso_state
+{
+	struct r600_atom atom;
+	void *cso; /* e.g. r600_blend_state */
+	struct r600_command_buffer *cb;
+};
+
 struct r600_context {
 	struct pipe_context		context;
 	struct blitter_context		*blitter;
@@ -409,6 +418,7 @@ struct r600_context {
 	struct r600_command_buffer      start_compute_cs_cmd;
 	/* Register states. */
 	struct r600_alphatest_state	alphatest_state;
+	struct r600_cso_state		blend_state;
 	struct r600_blend_color		blend_color;
 	struct r600_cb_misc_state	cb_misc_state;
 	struct r600_clip_misc_state	clip_misc_state;
@@ -431,13 +441,7 @@ struct r600_context {
 	struct r600_vertexbuf_state	cs_vertex_buffer_state;
 	/******************************/
 
-	/* current external blend state (from state tracker) */
-	struct r600_pipe_blend		*blend;
-	/* state with disabled blending - used internally with blend_override */
-	struct r600_pipe_blend		*no_blend;
-
-	/* 1 - override current blend state with no_blend, 0 - use external state */
-	unsigned	blend_override;
+	bool			force_blend_disable;
 
 	struct radeon_winsys_cs	*cs;
 
@@ -518,6 +522,20 @@ static INLINE void r600_emit_atom(struct r600_context *rctx, struct r600_atom *a
 	atom->dirty = false;
 }
 
+static INLINE void r600_set_cso_state(struct r600_cso_state *state, void *cso)
+{
+	state->cso = cso;
+	state->atom.dirty = cso != NULL;
+}
+
+static INLINE void r600_set_cso_state_with_cb(struct r600_cso_state *state, void *cso,
+					      struct r600_command_buffer *cb)
+{
+	state->cb = cb;
+	state->atom.num_dw = cb->num_dw;
+	r600_set_cso_state(state, cso);
+}
+
 /* evergreen_state.c */
 struct pipe_sampler_view *
 evergreen_create_sampler_view_custom(struct pipe_context *ctx,
@@ -644,6 +662,7 @@ void r600_translate_index_buffer(struct r600_context *r600,
 
 /* r600_state_common.c */
 void r600_init_common_state_functions(struct r600_context *rctx);
+void r600_emit_cso_state(struct r600_context *rctx, struct r600_atom *atom);
 void r600_emit_alphatest_state(struct r600_context *rctx, struct r600_atom *atom);
 void r600_emit_blend_color(struct r600_context *rctx, struct r600_atom *atom);
 void r600_emit_vgt_state(struct r600_context *rctx, struct r600_atom *atom);
diff --git a/src/gallium/drivers/r600/r600_state.c b/src/gallium/drivers/r600/r600_state.c
index 9a6b9f1..98b4581 100644
--- a/src/gallium/drivers/r600/r600_state.c
+++ b/src/gallium/drivers/r600/r600_state.c
@@ -692,21 +692,49 @@ void r600_polygon_offset_update(struct r600_context *rctx)
 	}
 }
 
+static uint32_t r600_get_blend_control(const struct pipe_blend_state *state, unsigned i)
+{
+	int j = state->independent_blend_enable ? i : 0;
+
+	unsigned eqRGB = state->rt[j].rgb_func;
+	unsigned srcRGB = state->rt[j].rgb_src_factor;
+	unsigned dstRGB = state->rt[j].rgb_dst_factor;
+
+	unsigned eqA = state->rt[j].alpha_func;
+	unsigned srcA = state->rt[j].alpha_src_factor;
+	unsigned dstA = state->rt[j].alpha_dst_factor;
+	uint32_t bc = 0;
+
+	if (!state->rt[j].blend_enable)
+		return 0;
+
+	bc |= S_028804_COLOR_COMB_FCN(r600_translate_blend_function(eqRGB));
+	bc |= S_028804_COLOR_SRCBLEND(r600_translate_blend_factor(srcRGB));
+	bc |= S_028804_COLOR_DESTBLEND(r600_translate_blend_factor(dstRGB));
+
+	if (srcA != srcRGB || dstA != dstRGB || eqA != eqRGB) {
+		bc |= S_028804_SEPARATE_ALPHA_BLEND(1);
+		bc |= S_028804_ALPHA_COMB_FCN(r600_translate_blend_function(eqA));
+		bc |= S_028804_ALPHA_SRCBLEND(r600_translate_blend_factor(srcA));
+		bc |= S_028804_ALPHA_DESTBLEND(r600_translate_blend_factor(dstA));
+	}
+	return bc;
+}
+
 static void *r600_create_blend_state_mode(struct pipe_context *ctx,
 					  const struct pipe_blend_state *state,
 					  int mode)
 {
 	struct r600_context *rctx = (struct r600_context *)ctx;
-	struct r600_pipe_blend *blend = CALLOC_STRUCT(r600_pipe_blend);
-	struct r600_pipe_state *rstate;
 	uint32_t color_control = 0, target_mask = 0;
+	struct r600_blend_state *blend = CALLOC_STRUCT(r600_blend_state);
 
-	if (blend == NULL) {
+	if (!blend) {
 		return NULL;
 	}
-	rstate = &blend->rstate;
 
-	rstate->id = R600_PIPE_STATE_BLEND;
+	r600_init_command_buffer(&blend->buffer, 20);
+	r600_init_command_buffer(&blend->buffer_no_blend, 20);
 
 	/* R600 does not support per-MRT blends */
 	if (rctx->family > CHIP_R600)
@@ -739,56 +767,42 @@ static void *r600_create_blend_state_mode(struct pipe_context *ctx,
 	else
 		color_control |= S_028808_SPECIAL_OP(V_028808_DISABLE);
 
-	blend->cb_target_mask = target_mask;
-	blend->cb_color_control = color_control;
 	/* only MRT0 has dual src blend */
 	blend->dual_src_blend = util_blend_state_is_dual(state, 0);
-	for (int i = 0; i < 8; i++) {
-		/* state->rt entries > 0 only written if independent blending */
-		const int j = state->independent_blend_enable ? i : 0;
-
-		unsigned eqRGB = state->rt[j].rgb_func;
-		unsigned srcRGB = state->rt[j].rgb_src_factor;
-		unsigned dstRGB = state->rt[j].rgb_dst_factor;
-
-		unsigned eqA = state->rt[j].alpha_func;
-		unsigned srcA = state->rt[j].alpha_src_factor;
-		unsigned dstA = state->rt[j].alpha_dst_factor;
-		uint32_t bc = 0;
-
-		if (!state->rt[j].blend_enable)
-			continue;
-
-		bc |= S_028804_COLOR_COMB_FCN(r600_translate_blend_function(eqRGB));
-		bc |= S_028804_COLOR_SRCBLEND(r600_translate_blend_factor(srcRGB));
-		bc |= S_028804_COLOR_DESTBLEND(r600_translate_blend_factor(dstRGB));
-
-		if (srcA != srcRGB || dstA != dstRGB || eqA != eqRGB) {
-			bc |= S_028804_SEPARATE_ALPHA_BLEND(1);
-			bc |= S_028804_ALPHA_COMB_FCN(r600_translate_blend_function(eqA));
-			bc |= S_028804_ALPHA_SRCBLEND(r600_translate_blend_factor(srcA));
-			bc |= S_028804_ALPHA_DESTBLEND(r600_translate_blend_factor(dstA));
-		}
+	blend->cb_target_mask = target_mask;
+	blend->cb_color_control = color_control;
+	blend->cb_color_control_no_blend = color_control & C_028808_TARGET_BLEND_ENABLE;
+	blend->alpha_to_one = state->alpha_to_one;
+
+	r600_store_context_reg(&blend->buffer, R_028D44_DB_ALPHA_TO_MASK,
+			       S_028D44_ALPHA_TO_MASK_ENABLE(state->alpha_to_coverage) |
+			       S_028D44_ALPHA_TO_MASK_OFFSET0(2) |
+			       S_028D44_ALPHA_TO_MASK_OFFSET1(2) |
+			       S_028D44_ALPHA_TO_MASK_OFFSET2(2) |
+			       S_028D44_ALPHA_TO_MASK_OFFSET3(2));
 
-		/* R600 does not support per-MRT blends */
-		if (rctx->family > CHIP_R600)
-			r600_pipe_state_add_reg(rstate, R_028780_CB_BLEND0_CONTROL + i * 4, bc);
-		if (i == 0)
-			r600_pipe_state_add_reg(rstate, R_028804_CB_BLEND_CONTROL, bc);
+	/* Copy over the registers set so far into buffer_no_blend. */
+	memcpy(blend->buffer_no_blend.buf, blend->buffer.buf, blend->buffer.num_dw * 4);
+	blend->buffer_no_blend.num_dw = blend->buffer.num_dw;
+
+	/* Only add blend registers if blending is enabled. */
+	if (!G_028808_TARGET_BLEND_ENABLE(color_control)) {
+		return blend;
 	}
 
-	r600_pipe_state_add_reg(rstate, R_028D44_DB_ALPHA_TO_MASK,
-				S_028D44_ALPHA_TO_MASK_ENABLE(state->alpha_to_coverage) |
-				S_028D44_ALPHA_TO_MASK_OFFSET0(2) |
-				S_028D44_ALPHA_TO_MASK_OFFSET1(2) |
-				S_028D44_ALPHA_TO_MASK_OFFSET2(2) |
-				S_028D44_ALPHA_TO_MASK_OFFSET3(2));
+	/* The first R600 does not support per-MRT blends */
+	r600_store_context_reg(&blend->buffer, R_028804_CB_BLEND_CONTROL,
+			       r600_get_blend_control(state, 0));
 
-	blend->alpha_to_one = state->alpha_to_one;
-	return rstate;
+	if (rctx->family > CHIP_R600) {
+		r600_store_context_reg_seq(&blend->buffer, R_028780_CB_BLEND0_CONTROL, 8);
+		for (int i = 0; i < 8; i++) {
+			r600_store_value(&blend->buffer, r600_get_blend_control(state, i));
+		}
+	}
+	return blend;
 }
 
-
 static void *r600_create_blend_state(struct pipe_context *ctx,
 				     const struct pipe_blend_state *state)
 {
@@ -2151,6 +2165,7 @@ void r600_init_state_functions(struct r600_context *rctx)
 
 	r600_init_atom(rctx, &rctx->alphatest_state.atom, id++, r600_emit_alphatest_state, 6);
 	r600_init_atom(rctx, &rctx->blend_color.atom, id++, r600_emit_blend_color, 6);
+	r600_init_atom(rctx, &rctx->blend_state.atom, id++, r600_emit_cso_state, 0);
 	r600_init_atom(rctx, &rctx->cb_misc_state.atom, id++, r600_emit_cb_misc_state, 7);
 	r600_init_atom(rctx, &rctx->clip_misc_state.atom, id++, r600_emit_clip_misc_state, 6);
 	r600_init_atom(rctx, &rctx->clip_state.atom, id++, r600_emit_clip_state, 26);
@@ -2731,7 +2746,6 @@ void r600_fetch_shader(struct pipe_context *ctx,
 void *r600_create_resolve_blend(struct r600_context *rctx)
 {
 	struct pipe_blend_state blend;
-	struct r600_pipe_state *rstate;
 	unsigned i;
 
 	memset(&blend, 0, sizeof(blend));
@@ -2746,32 +2760,27 @@ void *r600_create_resolve_blend(struct r600_context *rctx)
 		blend.rt[i].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
 		blend.rt[i].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
 	}
-	rstate = r600_create_blend_state_mode(&rctx->context, &blend, V_028808_SPECIAL_RESOLVE_BOX);
-	return rstate;
+	return r600_create_blend_state_mode(&rctx->context, &blend, V_028808_SPECIAL_RESOLVE_BOX);
 }
 
 void *r700_create_resolve_blend(struct r600_context *rctx)
 {
 	struct pipe_blend_state blend;
-	struct r600_pipe_state *rstate;
 
 	memset(&blend, 0, sizeof(blend));
 	blend.independent_blend_enable = true;
 	blend.rt[0].colormask = 0xf;
-	rstate = r600_create_blend_state_mode(&rctx->context, &blend, V_028808_SPECIAL_RESOLVE_BOX);
-	return rstate;
+	return r600_create_blend_state_mode(&rctx->context, &blend, V_028808_SPECIAL_RESOLVE_BOX);
 }
 
 void *r600_create_decompress_blend(struct r600_context *rctx)
 {
 	struct pipe_blend_state blend;
-	struct r600_pipe_state *rstate;
 
 	memset(&blend, 0, sizeof(blend));
 	blend.independent_blend_enable = true;
 	blend.rt[0].colormask = 0xf;
-	rstate = r600_create_blend_state_mode(&rctx->context, &blend, V_028808_SPECIAL_EXPAND_SAMPLES);
-	return rstate;
+	return r600_create_blend_state_mode(&rctx->context, &blend, V_028808_SPECIAL_EXPAND_SAMPLES);
 }
 
 void *r600_create_db_flush_dsa(struct r600_context *rctx)
diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c
index 4e336b1..5ba0430 100644
--- a/src/gallium/drivers/r600/r600_state_common.c
+++ b/src/gallium/drivers/r600/r600_state_common.c
@@ -60,6 +60,11 @@ void r600_init_atom(struct r600_context *rctx,
 	atom->dirty = false;
 }
 
+void r600_emit_cso_state(struct r600_context *rctx, struct r600_atom *atom)
+{
+	r600_emit_command_buffer(rctx->cs, ((struct r600_cso_state*)atom)->cb);
+}
+
 void r600_emit_alphatest_state(struct r600_context *rctx, struct r600_atom *atom)
 {
 	struct radeon_winsys_cs *cs = rctx->cs;
@@ -113,22 +118,31 @@ static unsigned r600_conv_pipe_prim(unsigned prim)
 /* common state between evergreen and r600 */
 
 static void r600_bind_blend_state_internal(struct r600_context *rctx,
-		struct r600_pipe_blend *blend)
+		struct r600_blend_state *blend, bool blend_disable)
 {
-	struct r600_pipe_state *rstate;
+	unsigned color_control;
 	bool update_cb = false;
 
-	rstate = &blend->rstate;
-	rctx->states[rstate->id] = rstate;
-	r600_context_pipe_state_set(rctx, rstate);
+	rctx->alpha_to_one = blend->alpha_to_one;
+	rctx->dual_src_blend = blend->dual_src_blend;
+
+	if (!blend_disable) {
+		r600_set_cso_state_with_cb(&rctx->blend_state, blend, &blend->buffer);
+		color_control = blend->cb_color_control;
+	} else {
+		/* Blending is disabled. */
+		r600_set_cso_state_with_cb(&rctx->blend_state, blend, &blend->buffer_no_blend);
+		color_control = blend->cb_color_control_no_blend;
+	}
 
+	/* Update derived states. */
 	if (rctx->cb_misc_state.blend_colormask != blend->cb_target_mask) {
 		rctx->cb_misc_state.blend_colormask = blend->cb_target_mask;
 		update_cb = true;
 	}
 	if (rctx->chip_class <= R700 &&
-	    rctx->cb_misc_state.cb_color_control != blend->cb_color_control) {
-		rctx->cb_misc_state.cb_color_control = blend->cb_color_control;
+	    rctx->cb_misc_state.cb_color_control != color_control) {
+		rctx->cb_misc_state.cb_color_control = color_control;
 		update_cb = true;
 	}
 	if (rctx->cb_misc_state.dual_src_blend != blend->dual_src_blend) {
@@ -143,17 +157,12 @@ static void r600_bind_blend_state_internal(struct r600_context *rctx,
 static void r600_bind_blend_state(struct pipe_context *ctx, void *state)
 {
 	struct r600_context *rctx = (struct r600_context *)ctx;
-	struct r600_pipe_blend *blend = (struct r600_pipe_blend *)state;
+	struct r600_blend_state *blend = (struct r600_blend_state *)state;
 
 	if (blend == NULL)
 		return;
 
-	rctx->blend = blend;
-	rctx->alpha_to_one = blend->alpha_to_one;
-	rctx->dual_src_blend = blend->dual_src_blend;
-
-	if (!rctx->blend_override)
-		r600_bind_blend_state_internal(rctx, blend);
+	r600_bind_blend_state_internal(rctx, blend, rctx->force_blend_disable);
 }
 
 static void r600_set_blend_color(struct pipe_context *ctx,
@@ -459,6 +468,15 @@ static void r600_delete_sampler_state(struct pipe_context *ctx, void *state)
 	free(state);
 }
 
+static void r600_delete_blend_state(struct pipe_context *ctx, void *state)
+{
+	struct r600_blend_state *blend = (struct r600_blend_state*)state;
+
+	r600_release_command_buffer(&blend->buffer);
+	r600_release_command_buffer(&blend->buffer_no_blend);
+	FREE(blend);
+}
+
 static void r600_delete_state(struct pipe_context *ctx, void *state)
 {
 	struct r600_context *rctx = (struct r600_context *)ctx;
@@ -1076,7 +1094,8 @@ static void r600_set_sample_mask(struct pipe_context *pipe, unsigned sample_mask
 static void r600_update_derived_state(struct r600_context *rctx)
 {
 	struct pipe_context * ctx = (struct pipe_context*)rctx;
-	unsigned ps_dirty = 0, blend_override;
+	unsigned ps_dirty = 0;
+	bool blend_disable;
 
 	if (!rctx->blitter->running) {
 		unsigned i;
@@ -1110,13 +1129,14 @@ static void r600_update_derived_state(struct r600_context *rctx)
 	if (ps_dirty)
 		r600_context_pipe_state_set(rctx, &rctx->ps_shader->current->rstate);
 
-	blend_override = (rctx->dual_src_blend &&
+	blend_disable = (rctx->dual_src_blend &&
 			rctx->ps_shader->current->nr_ps_color_outputs < 2);
 
-	if (blend_override != rctx->blend_override) {
-		rctx->blend_override = blend_override;
+	if (blend_disable != rctx->force_blend_disable) {
+		rctx->force_blend_disable = blend_disable;
 		r600_bind_blend_state_internal(rctx,
-				blend_override ? rctx->no_blend : rctx->blend);
+					       rctx->blend_state.cso,
+					       blend_disable);
 	}
 
 	if (rctx->chip_class >= EVERGREEN) {
@@ -1553,7 +1573,7 @@ void r600_init_common_state_functions(struct r600_context *rctx)
 	rctx->context.bind_vertex_elements_state = r600_bind_vertex_elements;
 	rctx->context.bind_vertex_sampler_states = r600_bind_vs_sampler_states;
 	rctx->context.bind_vs_state = r600_bind_vs_state;
-	rctx->context.delete_blend_state = r600_delete_state;
+	rctx->context.delete_blend_state = r600_delete_blend_state;
 	rctx->context.delete_depth_stencil_alpha_state = r600_delete_state;
 	rctx->context.delete_fs_state = r600_delete_ps_state;
 	rctx->context.delete_rasterizer_state = r600_delete_rs_state;




More information about the mesa-commit mailing list