[Mesa-dev] [PATCH] radeonsi: fix gl_BaseVertex value in non-indexed draws

Nicolai Hähnle nhaehnle at gmail.com
Fri Apr 7 22:41:12 UTC 2017


From: Nicolai Hähnle <nicolai.haehnle at amd.com>

gl_BaseVertex is supposed to be 0 in non-indexed draws. Unfortunately, the
way they're implemented, the VGT always generates indices starting at 0,
and the VS prolog adds the start index.

There's a VGT_INDX_OFFSET register which causes the VGT to start at a
driver-defined index. However, this register cannot be written from
indirect draws.

So fix this unlikely case in the VS prolog.

Fixes a bug in
KHR-GL45.shader_draw_parameters_tests.ShaderMultiDrawArraysParameters.*
---
 src/gallium/drivers/radeonsi/si_pipe.h          |  1 +
 src/gallium/drivers/radeonsi/si_shader.c        | 17 +++++++++++++++++
 src/gallium/drivers/radeonsi/si_shader.h        |  1 +
 src/gallium/drivers/radeonsi/si_state_draw.c    |  5 +++++
 src/gallium/drivers/radeonsi/si_state_shaders.c |  2 ++
 5 files changed, 26 insertions(+)

diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h
index daf2932..ecf0f41 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -343,20 +343,21 @@ struct si_context {
 	int			last_sh_base_reg;
 	int			last_primitive_restart_en;
 	int			last_restart_index;
 	int			last_gs_out_prim;
 	int			last_prim;
 	int			last_multi_vgt_param;
 	int			last_rast_prim;
 	unsigned		last_sc_line_stipple;
 	enum pipe_prim_type	current_rast_prim; /* primitive type after TES, GS */
 	bool			gs_tri_strip_adj_fix;
+	bool			current_indexed;
 
 	/* Scratch buffer */
 	struct r600_atom	scratch_state;
 	struct r600_resource	*scratch_buffer;
 	unsigned		scratch_waves;
 	unsigned		spi_tmpring_size;
 
 	struct r600_resource	*compute_scratch_buffer;
 
 	/* Emitted derived tessellation state. */
diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c
index f5f86f9..e76ee05 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -7871,20 +7871,37 @@ static void si_build_vs_prolog_function(struct si_shader_context *ctx,
 			index = LLVMBuildAdd(gallivm->builder,
 					     LLVMGetParam(func, ctx->param_vertex_id),
 					     LLVMGetParam(func, SI_SGPR_BASE_VERTEX), "");
 		}
 
 		index = LLVMBuildBitCast(gallivm->builder, index, ctx->f32, "");
 		ret = LLVMBuildInsertValue(gallivm->builder, ret, index,
 					   num_params++, "");
 	}
 
+	/* For DrawArrays(Indirect) and variants, the basevertex loaded into
+	 * the SGPR is the 'first' parameter of the draw call. However, the
+	 * value returned as gl_BaseVertex to the VS should be 0.
+	 */
+	if (key->vs_prolog.states.clear_basevertex) {
+		LLVMValueRef index;
+
+		index = LLVMBuildAdd(gallivm->builder,
+				     LLVMGetParam(func, ctx->param_vertex_id),
+				     LLVMGetParam(func, SI_SGPR_BASE_VERTEX), "");
+		index = LLVMBuildBitCast(gallivm->builder, index, ctx->f32, "");
+		ret = LLVMBuildInsertValue(gallivm->builder, ret, index,
+					   ctx->param_vertex_id, "");
+		ret = LLVMBuildInsertValue(gallivm->builder, ret, ctx->i32_0,
+					   SI_SGPR_BASE_VERTEX, "");
+	}
+
 	si_llvm_build_ret(ctx, ret);
 }
 
 /**
  * Build the vertex shader epilog function. This is also used by the tessellation
  * evaluation shader compiled as VS.
  *
  * The input is PrimitiveID.
  *
  * If PrimitiveID is required by the pixel shader, export it.
diff --git a/src/gallium/drivers/radeonsi/si_shader.h b/src/gallium/drivers/radeonsi/si_shader.h
index 17ffc5d..a3fcb42 100644
--- a/src/gallium/drivers/radeonsi/si_shader.h
+++ b/src/gallium/drivers/radeonsi/si_shader.h
@@ -334,20 +334,21 @@ struct si_shader_selector {
  *                      |     |     |    |    |
  * Only VS & PS:     VS | --  | --  | -- | -- | PS
  * With GS:          ES | --  | --  | GS | VS | PS
  * With Tessel.:     LS | HS  | VS  | -- | -- | PS
  * With both:        LS | HS  | ES  | GS | VS | PS
  */
 
 /* Common VS bits between the shader key and the prolog key. */
 struct si_vs_prolog_bits {
 	unsigned	instance_divisors[SI_MAX_ATTRIBS];
+	unsigned	clear_basevertex:1;
 };
 
 /* Common VS bits between the shader key and the epilog key. */
 struct si_vs_epilog_bits {
 	unsigned	export_prim_id:1; /* when PS needs it and GS is disabled */
 };
 
 /* Common TCS bits between the shader key and the epilog key. */
 struct si_tcs_epilog_bits {
 	unsigned	prim_mode:3;
diff --git a/src/gallium/drivers/radeonsi/si_state_draw.c b/src/gallium/drivers/radeonsi/si_state_draw.c
index 2c4e371..4549dd2 100644
--- a/src/gallium/drivers/radeonsi/si_state_draw.c
+++ b/src/gallium/drivers/radeonsi/si_state_draw.c
@@ -1145,20 +1145,25 @@ void si_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
 	else if (sctx->tes_shader.cso)
 		rast_prim = sctx->tes_shader.cso->info.properties[TGSI_PROPERTY_TES_PRIM_MODE];
 	else
 		rast_prim = info->mode;
 
 	if (rast_prim != sctx->current_rast_prim) {
 		sctx->current_rast_prim = rast_prim;
 		sctx->do_update_shaders = true;
 	}
 
+	if (info->indexed != sctx->current_indexed) {
+		sctx->current_indexed = info->indexed;
+		sctx->do_update_shaders = true;
+	}
+
 	if (sctx->gs_shader.cso) {
 		/* Determine whether the GS triangle strip adjacency fix should
 		 * be applied. Rotate every other triangle if
 		 * - triangle strips with adjacency are fed to the GS and
 		 * - primitive restart is disabled (the rotation doesn't help
 		 *   when the restart occurs after an odd number of triangles).
 		 */
 		bool gs_tri_strip_adj_fix =
 			!sctx->tes_shader.cso &&
 			info->mode == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY &&
diff --git a/src/gallium/drivers/radeonsi/si_state_shaders.c b/src/gallium/drivers/radeonsi/si_state_shaders.c
index ff4ff01..f821c9d 100644
--- a/src/gallium/drivers/radeonsi/si_state_shaders.c
+++ b/src/gallium/drivers/radeonsi/si_state_shaders.c
@@ -1043,20 +1043,22 @@ static inline void si_shader_selector_key(struct pipe_context *ctx,
 		if (sctx->tes_shader.cso)
 			key->as_ls = 1;
 		else if (sctx->gs_shader.cso)
 			key->as_es = 1;
 		else {
 			si_shader_selector_key_hw_vs(sctx, sel, key);
 
 			if (sctx->ps_shader.cso && sctx->ps_shader.cso->info.uses_primid)
 				key->part.vs.epilog.export_prim_id = 1;
 		}
+		if (!sctx->current_indexed && sel->info.uses_basevertex)
+			key->part.vs.prolog.clear_basevertex = 1;
 		break;
 	case PIPE_SHADER_TESS_CTRL:
 		key->part.tcs.epilog.prim_mode =
 			sctx->tes_shader.cso->info.properties[TGSI_PROPERTY_TES_PRIM_MODE];
 		key->part.tcs.epilog.tes_reads_tess_factors =
 			sctx->tes_shader.cso->info.reads_tess_factors;
 
 		if (sel == sctx->fixed_func_tcs_shader.cso)
 			key->mono.tcs.inputs_to_copy = sctx->vs_shader.cso->outputs_written;
 		break;
-- 
2.9.3



More information about the mesa-dev mailing list