[Mesa-dev] [PATCH 2/3] radeonsi: enable vertex color clamping for tess and GS

Marek Olšák maraeo at gmail.com
Wed Jun 27 20:10:24 UTC 2018


From: Marek Olšák <marek.olsak at amd.com>

---
 src/gallium/drivers/radeonsi/si_descriptors.c | 10 +-
 src/gallium/drivers/radeonsi/si_shader.c      | 97 +++++++++++++------
 src/gallium/drivers/radeonsi/si_shader.h      |  2 +-
 src/gallium/drivers/radeonsi/si_state_draw.c  | 11 +++
 4 files changed, 87 insertions(+), 33 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_descriptors.c b/src/gallium/drivers/radeonsi/si_descriptors.c
index e8c028061d1..323cdbbf7af 100644
--- a/src/gallium/drivers/radeonsi/si_descriptors.c
+++ b/src/gallium/drivers/radeonsi/si_descriptors.c
@@ -1995,26 +1995,28 @@ static void si_shader_pointers_begin_new_cs(struct si_context *sctx)
  * This assigns a mapping from PIPE_SHADER_* to SPI_SHADER_USER_DATA_*.
  */
 static void si_set_user_data_base(struct si_context *sctx,
 				  unsigned shader, uint32_t new_base)
 {
 	uint32_t *base = &sctx->shader_pointers.sh_base[shader];
 
 	if (*base != new_base) {
 		*base = new_base;
 
-		if (new_base) {
+		if (new_base)
 			si_mark_shader_pointers_dirty(sctx, shader);
 
-			if (shader == PIPE_SHADER_VERTEX)
-				sctx->last_vs_state = ~0;
-		}
+		/* Any change in enabled shader stages requires re-emitting
+		 * the VS state SGPR, because it contains the clamp_vertex_color
+		 * state, which can be done VS, TES, and GS.
+		 */
+		sctx->last_vs_state = ~0;
 	}
 }
 
 /* This must be called when these shaders are changed from non-NULL to NULL
  * and vice versa:
  * - geometry shader
  * - tessellation control shader
  * - tessellation evaluation shader
  */
 void si_shader_change_notify(struct si_context *sctx)
diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c
index 9bee8440027..32db089ed2c 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -3669,52 +3669,50 @@ static void si_llvm_emit_vs_epilogue(struct ac_shader_abi *abi,
 	assert(info->num_outputs <= max_outputs);
 
 	outputs = MALLOC((info->num_outputs + 1) * sizeof(outputs[0]));
 
 	/* Vertex color clamping.
 	 *
 	 * This uses a state constant loaded in a user data SGPR and
 	 * an IF statement is added that clamps all colors if the constant
 	 * is true.
 	 */
-	if (ctx->type == PIPE_SHADER_VERTEX) {
-		struct lp_build_if_state if_ctx;
-		LLVMValueRef cond = NULL;
-		LLVMValueRef addr, val;
-
-		for (i = 0; i < info->num_outputs; i++) {
-			if (info->output_semantic_name[i] != TGSI_SEMANTIC_COLOR &&
-			    info->output_semantic_name[i] != TGSI_SEMANTIC_BCOLOR)
-				continue;
+	struct lp_build_if_state if_ctx;
+	LLVMValueRef cond = NULL;
+	LLVMValueRef addr, val;
 
-			/* We've found a color. */
-			if (!cond) {
-				/* The state is in the first bit of the user SGPR. */
-				cond = LLVMGetParam(ctx->main_fn,
-						    ctx->param_vs_state_bits);
-				cond = LLVMBuildTrunc(ctx->ac.builder, cond,
-						      ctx->i1, "");
-				lp_build_if(&if_ctx, &ctx->gallivm, cond);
-			}
+	for (i = 0; i < info->num_outputs; i++) {
+		if (info->output_semantic_name[i] != TGSI_SEMANTIC_COLOR &&
+		    info->output_semantic_name[i] != TGSI_SEMANTIC_BCOLOR)
+			continue;
 
-			for (j = 0; j < 4; j++) {
-				addr = addrs[4 * i + j];
-				val = LLVMBuildLoad(ctx->ac.builder, addr, "");
-				val = ac_build_clamp(&ctx->ac, val);
-				LLVMBuildStore(ctx->ac.builder, val, addr);
-			}
+		/* We've found a color. */
+		if (!cond) {
+			/* The state is in the first bit of the user SGPR. */
+			cond = LLVMGetParam(ctx->main_fn,
+					    ctx->param_vs_state_bits);
+			cond = LLVMBuildTrunc(ctx->ac.builder, cond,
+					      ctx->i1, "");
+			lp_build_if(&if_ctx, &ctx->gallivm, cond);
 		}
 
-		if (cond)
-			lp_build_endif(&if_ctx);
+		for (j = 0; j < 4; j++) {
+			addr = addrs[4 * i + j];
+			val = LLVMBuildLoad(ctx->ac.builder, addr, "");
+			val = ac_build_clamp(&ctx->ac, val);
+			LLVMBuildStore(ctx->ac.builder, val, addr);
+		}
 	}
 
+	if (cond)
+		lp_build_endif(&if_ctx);
+
 	for (i = 0; i < info->num_outputs; i++) {
 		outputs[i].semantic_name = info->output_semantic_name[i];
 		outputs[i].semantic_index = info->output_semantic_index[i];
 
 		for (j = 0; j < 4; j++) {
 			outputs[i].values[j] =
 				LLVMBuildLoad(ctx->ac.builder,
 					      addrs[4 * i + j],
 					      "");
 			outputs[i].vertex_stream[j] =
@@ -4738,21 +4736,21 @@ static void create_function(struct si_shader_context *ctx)
 		declare_vs_specific_input_sgprs(ctx, &fninfo);
 		ctx->param_vertex_buffers = add_arg(&fninfo, ARG_SGPR,
 			ac_array_in_const32_addr_space(ctx->v4i32));
 
 		if (shader->key.as_es) {
 			ctx->param_es2gs_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
 		} else if (shader->key.as_ls) {
 			/* no extra parameters */
 		} else {
 			if (shader->is_gs_copy_shader) {
-				fninfo.num_params = ctx->param_rw_buffers + 1;
+				fninfo.num_params = ctx->param_vs_state_bits + 1;
 				fninfo.num_sgpr_params = fninfo.num_params;
 			}
 
 			/* The locations of the other parameters are assigned dynamically. */
 			declare_streamout_params(ctx, &shader->selector->so,
 						 &fninfo);
 		}
 
 		/* VGPRs */
 		declare_vs_input_vgprs(ctx, &fninfo, &num_prolog_vgprs);
@@ -5819,22 +5817,65 @@ si_generate_gs_copy_shader(struct si_screen *sscreen,
 			}
 		}
 
 		/* Streamout and exports. */
 		if (gs_selector->so.num_outputs) {
 			si_llvm_emit_streamout(&ctx, outputs,
 					       gsinfo->num_outputs,
 					       stream);
 		}
 
-		if (stream == 0)
+		if (stream == 0) {
+			/* Vertex color clamping.
+			 *
+			 * This uses a state constant loaded in a user data SGPR and
+			 * an IF statement is added that clamps all colors if the constant
+			 * is true.
+			 */
+			struct lp_build_if_state if_ctx;
+			LLVMValueRef v[2], cond = NULL;
+			LLVMBasicBlockRef blocks[2];
+
+			for (unsigned i = 0; i < gsinfo->num_outputs; i++) {
+				if (gsinfo->output_semantic_name[i] != TGSI_SEMANTIC_COLOR &&
+				    gsinfo->output_semantic_name[i] != TGSI_SEMANTIC_BCOLOR)
+					continue;
+
+				/* We've found a color. */
+				if (!cond) {
+					/* The state is in the first bit of the user SGPR. */
+					cond = LLVMGetParam(ctx.main_fn,
+							    ctx.param_vs_state_bits);
+					cond = LLVMBuildTrunc(ctx.ac.builder, cond,
+							      ctx.i1, "");
+					lp_build_if(&if_ctx, &ctx.gallivm, cond);
+					/* Remember blocks for Phi. */
+					blocks[0] = if_ctx.true_block;
+					blocks[1] = if_ctx.entry_block;
+				}
+
+				for (unsigned j = 0; j < 4; j++) {
+					/* Insert clamp into the true block. */
+					v[0] = ac_build_clamp(&ctx.ac, outputs[i].values[j]);
+					v[1] = outputs[i].values[j];
+
+					/* Insert Phi into the endif block. */
+					LLVMPositionBuilderAtEnd(ctx.ac.builder, if_ctx.merge_block);
+					outputs[i].values[j] = ac_build_phi(&ctx.ac, ctx.f32, 2, v, blocks);
+					LLVMPositionBuilderAtEnd(ctx.ac.builder, if_ctx.true_block);
+				}
+			}
+			if (cond)
+				lp_build_endif(&if_ctx);
+
 			si_llvm_export_vs(&ctx, outputs, gsinfo->num_outputs);
+		}
 
 		LLVMBuildBr(builder, end_bb);
 	}
 
 	LLVMPositionBuilderAtEnd(builder, end_bb);
 
 	LLVMBuildRetVoid(ctx.ac.builder);
 
 	ctx.type = PIPE_SHADER_GEOMETRY; /* override for shader dumping */
 	si_llvm_optimize_module(&ctx);
diff --git a/src/gallium/drivers/radeonsi/si_shader.h b/src/gallium/drivers/radeonsi/si_shader.h
index bba4d4f9018..0dc27f29afd 100644
--- a/src/gallium/drivers/radeonsi/si_shader.h
+++ b/src/gallium/drivers/radeonsi/si_shader.h
@@ -221,21 +221,21 @@ enum {
 
 	/* GS limits */
 	GFX6_GS_NUM_USER_SGPR = SI_NUM_RESOURCE_SGPRS,
 #if HAVE_32BIT_POINTERS
 	GFX9_VSGS_NUM_USER_SGPR = SI_VS_NUM_USER_SGPR,
 	GFX9_TESGS_NUM_USER_SGPR = SI_TES_NUM_USER_SGPR,
 #else
 	GFX9_VSGS_NUM_USER_SGPR = GFX9_MERGED_NUM_USER_SGPR,
 	GFX9_TESGS_NUM_USER_SGPR = GFX9_MERGED_NUM_USER_SGPR,
 #endif
-	SI_GSCOPY_NUM_USER_SGPR = SI_SGPR_RW_BUFFERS + (HAVE_32BIT_POINTERS ? 1 : 2),
+	SI_GSCOPY_NUM_USER_SGPR = SI_NUM_VS_STATE_RESOURCE_SGPRS,
 
 	/* PS only */
 	SI_SGPR_ALPHA_REF	= SI_NUM_RESOURCE_SGPRS,
 	SI_PS_NUM_USER_SGPR,
 };
 
 /* LLVM function parameter indices */
 enum {
 	SI_NUM_RESOURCE_PARAMS = 4,
 
diff --git a/src/gallium/drivers/radeonsi/si_state_draw.c b/src/gallium/drivers/radeonsi/si_state_draw.c
index 2291b4a00ad..f35f73a37ce 100644
--- a/src/gallium/drivers/radeonsi/si_state_draw.c
+++ b/src/gallium/drivers/radeonsi/si_state_draw.c
@@ -564,25 +564,36 @@ static void si_emit_vs_state(struct si_context *sctx,
 
 	if (sctx->num_vs_blit_sgprs) {
 		/* Re-emit the state after we leave u_blitter. */
 		sctx->last_vs_state = ~0;
 		return;
 	}
 
 	if (sctx->current_vs_state != sctx->last_vs_state) {
 		struct radeon_cmdbuf *cs = sctx->gfx_cs;
 
+		/* For the API vertex shader (VS_STATE_INDEXED). */
 		radeon_set_sh_reg(cs,
 			sctx->shader_pointers.sh_base[PIPE_SHADER_VERTEX] +
 			SI_SGPR_VS_STATE_BITS * 4,
 			sctx->current_vs_state);
 
+		/* For vertex color clamping, which is done in the last stage
+		 * before the rasterizer. */
+		if (sctx->gs_shader.cso || sctx->tes_shader.cso) {
+			/* GS copy shader or TES if GS is missing. */
+			radeon_set_sh_reg(cs,
+				R_00B130_SPI_SHADER_USER_DATA_VS_0 +
+				SI_SGPR_VS_STATE_BITS * 4,
+				sctx->current_vs_state);
+		}
+
 		sctx->last_vs_state = sctx->current_vs_state;
 	}
 }
 
 static inline bool si_prim_restart_index_changed(struct si_context *sctx,
 						 const struct pipe_draw_info *info)
 {
 	return info->primitive_restart &&
 	       (info->restart_index != sctx->last_restart_index ||
 		sctx->last_restart_index == SI_RESTART_INDEX_UNKNOWN);
-- 
2.17.1



More information about the mesa-dev mailing list