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

Nicolai Hähnle nhaehnle at gmail.com
Wed Apr 12 09:20:03 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 by setting a bit to tell the VS whether the
draw is indexed or not, so that gl_BaseVertex can be adjusted accordingly
when used.

Fixes a bug in
KHR-GL45.shader_draw_parameters_tests.ShaderMultiDrawArraysParameters.*
---
 src/gallium/drivers/radeonsi/si_shader.c     | 17 +++++++++++++++--
 src/gallium/drivers/radeonsi/si_shader.h     |  2 ++
 src/gallium/drivers/radeonsi/si_state_draw.c |  8 ++++++--
 3 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c
index 02447dd..f1daebe 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -1394,23 +1394,36 @@ static void declare_system_value(struct si_shader_context *ctx,
 						  SI_PARAM_BASE_VERTEX), "");
 		break;
 
 	case TGSI_SEMANTIC_VERTEXID_NOBASE:
 		/* Unused. Clarify the meaning in indexed vs. non-indexed
 		 * draws if this is ever used again. */
 		assert(false);
 		break;
 
 	case TGSI_SEMANTIC_BASEVERTEX:
-		value = LLVMGetParam(ctx->main_fn,
-				     SI_PARAM_BASE_VERTEX);
+	{
+		/* For non-indexed draws, the base vertex set by the driver
+		 * (for direct draws) or the CP (for indirect draws) is the
+		 * first vertex ID, but GLSL expects 0 to be returned.
+		 */
+		LLVMValueRef vs_state = LLVMGetParam(ctx->main_fn, SI_PARAM_VS_STATE_BITS);
+		LLVMValueRef indexed;
+
+		indexed = LLVMBuildLShr(gallivm->builder, vs_state, ctx->i32_1, "");
+		indexed = LLVMBuildTrunc(gallivm->builder, indexed, ctx->i1, "");
+
+		value = LLVMBuildSelect(gallivm->builder, indexed,
+					LLVMGetParam(ctx->main_fn, SI_PARAM_BASE_VERTEX),
+					ctx->i32_0, "");
 		break;
+	}
 
 	case TGSI_SEMANTIC_BASEINSTANCE:
 		value = LLVMGetParam(ctx->main_fn,
 				     SI_PARAM_START_INSTANCE);
 		break;
 
 	case TGSI_SEMANTIC_DRAWID:
 		value = LLVMGetParam(ctx->main_fn,
 				     SI_PARAM_DRAWID);
 		break;
diff --git a/src/gallium/drivers/radeonsi/si_shader.h b/src/gallium/drivers/radeonsi/si_shader.h
index fdb0dd4..f145eab 100644
--- a/src/gallium/drivers/radeonsi/si_shader.h
+++ b/src/gallium/drivers/radeonsi/si_shader.h
@@ -213,20 +213,22 @@ enum {
 	SI_PARAM_BLOCK_ID,
 	SI_PARAM_THREAD_ID,
 
 	SI_NUM_PARAMS = SI_PARAM_POS_FIXED_PT + 9, /* +8 for COLOR[0..1] */
 };
 
 /* Fields of driver-defined VS state SGPR. */
 /* Clamp vertex color output (only used in VS as VS). */
 #define S_VS_STATE_CLAMP_VERTEX_COLOR(x)	(((unsigned)(x) & 0x1) << 0)
 #define C_VS_STATE_CLAMP_VERTEX_COLOR		0xFFFFFFFE
+#define S_VS_STATE_INDEXED(x)			(((unsigned)(x) & 0x1) << 1)
+#define C_VS_STATE_INDEXED			0xFFFFFFFD
 #define S_VS_STATE_LS_OUT_PATCH_SIZE(x)		(((unsigned)(x) & 0x1FFF) << 8)
 #define C_VS_STATE_LS_OUT_PATCH_SIZE		0xFFE000FF
 #define S_VS_STATE_LS_OUT_VERTEX_SIZE(x)	(((unsigned)(x) & 0xFF) << 24)
 #define C_VS_STATE_LS_OUT_VERTEX_SIZE		0x00FFFFFF
 
 /* SI-specific system values. */
 enum {
 	TGSI_SEMANTIC_DEFAULT_TESSOUTER_SI = TGSI_SEMANTIC_COUNT,
 	TGSI_SEMANTIC_DEFAULT_TESSINNER_SI,
 };
diff --git a/src/gallium/drivers/radeonsi/si_state_draw.c b/src/gallium/drivers/radeonsi/si_state_draw.c
index 0d70ea9..aa528ce 100644
--- a/src/gallium/drivers/radeonsi/si_state_draw.c
+++ b/src/gallium/drivers/radeonsi/si_state_draw.c
@@ -487,22 +487,26 @@ static void si_emit_rasterizer_prim_state(struct si_context *sctx)
 	 * reset the stipple pattern at each packet (line strips, line loops).
 	 */
 	radeon_set_context_reg(cs, R_028A0C_PA_SC_LINE_STIPPLE,
 		rs->pa_sc_line_stipple |
 		S_028A0C_AUTO_RESET_CNTL(rast_prim == PIPE_PRIM_LINES ? 1 : 2));
 
 	sctx->last_rast_prim = rast_prim;
 	sctx->last_sc_line_stipple = rs->pa_sc_line_stipple;
 }
 
-static void si_emit_vs_state(struct si_context *sctx)
+static void si_emit_vs_state(struct si_context *sctx,
+			     const struct pipe_draw_info *info)
 {
+	sctx->current_vs_state &= C_VS_STATE_INDEXED;
+	sctx->current_vs_state |= S_VS_STATE_INDEXED(!!info->indexed);
+
 	if (sctx->current_vs_state != sctx->last_vs_state) {
 		struct radeon_winsys_cs *cs = sctx->b.gfx.cs;
 
 		radeon_set_sh_reg(cs,
 			sctx->shader_userdata.sh_base[PIPE_SHADER_VERTEX] +
 			SI_SGPR_VS_STATE_BITS * 4,
 			sctx->current_vs_state);
 
 		sctx->last_vs_state = sctx->current_vs_state;
 	}
@@ -1298,21 +1302,21 @@ void si_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
 			continue;
 
 		si_pm4_emit(sctx, state);
 		sctx->emitted.array[i] = state;
 	}
 	sctx->dirty_states = 0;
 
 	si_emit_rasterizer_prim_state(sctx);
 	if (sctx->tes_shader.cso)
 		si_emit_derived_tess_state(sctx, info, &num_patches);
-	si_emit_vs_state(sctx);
+	si_emit_vs_state(sctx, info);
 	si_emit_draw_registers(sctx, info, num_patches);
 
 	si_ce_pre_draw_synchronization(sctx);
 	si_emit_draw_packets(sctx, info, ib);
 	si_ce_post_draw_synchronization(sctx);
 
 	if (sctx->trace_buf)
 		si_trace_emit(sctx);
 
 	/* Workaround for a VGT hang when streamout is enabled.
-- 
2.9.3



More information about the mesa-dev mailing list