[Mesa-dev] [PATCH 2/2] r600g: add support for primitive id without geom shader

Dave Airlie airlied at gmail.com
Mon Jan 26 19:46:33 PST 2015


From: Dave Airlie <airlied at redhat.com>

GLSL 1.50 specifies a fragment shader may have a primitive id
input without a geometry shader present.

On r600 hw there is a special GS scenario for this, you have
to enable GS_SCENARIO_A and pass the primitive id through
the vertex shader which operates in GS_A mode.

This is a first pass attempt at this, and passes the piglit
tests that test for this.

TODO: r600/700 support.
make nicer.

Signed-off-by: Dave Airlie <airlied at redhat.com>
---
 src/gallium/drivers/r600/evergreen_state.c   |  6 +++++
 src/gallium/drivers/r600/r600_hw_context.c   |  2 +-
 src/gallium/drivers/r600/r600_shader.c       | 33 ++++++++++++++++++++++++++++
 src/gallium/drivers/r600/r600_shader.h       |  4 ++++
 src/gallium/drivers/r600/r600_state_common.c |  5 +++++
 5 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/src/gallium/drivers/r600/evergreen_state.c b/src/gallium/drivers/r600/evergreen_state.c
index 36b86aa..bc1fa48 100644
--- a/src/gallium/drivers/r600/evergreen_state.c
+++ b/src/gallium/drivers/r600/evergreen_state.c
@@ -2111,6 +2111,12 @@ static void evergreen_emit_shader_stages(struct r600_context *rctx, struct r600_
 
 	uint32_t v = 0, v2 = 0, primid = 0;
 
+	if (rctx->vs_shader->current->shader.vs_as_gs_a) {
+		fprintf(stderr, "got fs prim id with no geom\n");
+		v2 = S_028A40_MODE(V_028A40_GS_SCENARIO_A);
+		primid = 1;
+	}
+
 	if (state->geom_enable) {
 		uint32_t cut_val;
 
diff --git a/src/gallium/drivers/r600/r600_hw_context.c b/src/gallium/drivers/r600/r600_hw_context.c
index ccc5a8b..cd57eed 100644
--- a/src/gallium/drivers/r600/r600_hw_context.c
+++ b/src/gallium/drivers/r600/r600_hw_context.c
@@ -315,9 +315,9 @@ void r600_begin_new_cs(struct r600_context *ctx)
 	ctx->stencil_ref.atom.dirty = true;
 	ctx->vertex_fetch_shader.atom.dirty = true;
 	ctx->export_shader.atom.dirty = true;
+	ctx->shader_stages.atom.dirty = true;
 	if (ctx->gs_shader) {
 		ctx->geometry_shader.atom.dirty = true;
-		ctx->shader_stages.atom.dirty = true;
 		ctx->gs_rings.atom.dirty = true;
 	}
 	ctx->vertex_shader.atom.dirty = true;
diff --git a/src/gallium/drivers/r600/r600_shader.c b/src/gallium/drivers/r600/r600_shader.c
index 471df91..8841b08 100644
--- a/src/gallium/drivers/r600/r600_shader.c
+++ b/src/gallium/drivers/r600/r600_shader.c
@@ -596,6 +596,20 @@ static int select_twoside_color(struct r600_shader_ctx *ctx, int front, int back
 	return 0;
 }
 
+static int vs_add_primid_output(struct r600_shader_ctx *ctx)
+{
+	int i;
+	i = ctx->shader->noutput++;
+	ctx->shader->output[i].name = TGSI_SEMANTIC_PRIMID;
+	ctx->shader->output[i].sid = 0;
+	ctx->shader->output[i].gpr = 0;
+	ctx->shader->output[i].interpolate = TGSI_INTERPOLATE_CONSTANT;
+	ctx->shader->output[i].write_mask = 0x4;
+	ctx->shader->output[i].spi_sid = ctx->shader->ps_prim_id_input;
+
+	return 0;
+}
+
 static int tgsi_declaration(struct r600_shader_ctx *ctx)
 {
 	struct tgsi_full_declaration *d = &ctx->parse.FullToken.FullDeclaration;
@@ -626,6 +640,11 @@ static int tgsi_declaration(struct r600_shader_ctx *ctx)
 			case TGSI_SEMANTIC_POSITION:
 				ctx->fragcoord_input = i;
 				break;
+			case TGSI_SEMANTIC_PRIMID:
+				/* set this for now */
+				ctx->shader->gs_prim_id_input = true;
+				ctx->shader->ps_prim_id_input = i;
+				break;
 			}
 			if (ctx->bc->chip_class >= EVERGREEN) {
 				if ((r = evergreen_interp_input(ctx, i)))
@@ -1800,6 +1819,9 @@ static int r600_shader_from_tgsi(struct r600_context *rctx,
 	ctx.shader = shader;
 	ctx.native_integers = true;
 
+	shader->vs_as_gs_a = key.vs_as_gs_a;
+	if (key.vs_as_gs_a)
+		shader->ps_prim_id_input = key.vs_prim_id_out;
 	shader->vs_as_es = key.vs_as_es;
 
 	r600_bytecode_init(ctx.bc, rscreen->b.chip_class, rscreen->b.family,
@@ -1938,6 +1960,10 @@ static int r600_shader_from_tgsi(struct r600_context *rctx,
 	ctx.nliterals = 0;
 	ctx.literals = NULL;
 	shader->fs_write_all = FALSE;
+
+	if (shader->vs_as_gs_a)
+		vs_add_primid_output(&ctx);
+
 	while (!tgsi_parse_end_of_tokens(&ctx.parse)) {
 		tgsi_parse_token(&ctx.parse);
 		switch (ctx.parse.FullToken.Token.Type) {
@@ -2335,7 +2361,14 @@ static int r600_shader_from_tgsi(struct r600_context *rctx,
 					output[j].swizzle_z = 4; /* 0 */
 					output[j].swizzle_w = 5; /* 1 */
 					break;
+				case TGSI_SEMANTIC_PRIMID:
+					output[j].swizzle_x = 2;
+					output[j].swizzle_y = 4; /* 0 */
+					output[j].swizzle_z = 4; /* 0 */
+					output[j].swizzle_w = 4; /* 0 */
+					break;
 				}
+
 				break;
 			case TGSI_PROCESSOR_FRAGMENT:
 				if (shader->output[i].name == TGSI_SEMANTIC_COLOR) {
diff --git a/src/gallium/drivers/r600/r600_shader.h b/src/gallium/drivers/r600/r600_shader.h
index ab67013..b2559e9 100644
--- a/src/gallium/drivers/r600/r600_shader.h
+++ b/src/gallium/drivers/r600/r600_shader.h
@@ -84,6 +84,8 @@ struct r600_shader {
 	unsigned		max_arrays;
 	unsigned		num_arrays;
 	unsigned		vs_as_es;
+	unsigned		vs_as_gs_a;
+	unsigned                ps_prim_id_input;
 	struct r600_shader_array * arrays;
 };
 
@@ -92,6 +94,8 @@ struct r600_shader_key {
 	unsigned alpha_to_one:1;
 	unsigned nr_cbufs:4;
 	unsigned vs_as_es:1;
+	unsigned vs_as_gs_a:1;
+	unsigned vs_prim_id_out:8;
 };
 
 struct r600_shader_array {
diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c
index 1030620..b498d00 100644
--- a/src/gallium/drivers/r600/r600_state_common.c
+++ b/src/gallium/drivers/r600/r600_state_common.c
@@ -707,6 +707,10 @@ static INLINE struct r600_shader_key r600_shader_selector_key(struct pipe_contex
 			key.nr_cbufs = 2;
 	} else if (sel->type == PIPE_SHADER_VERTEX) {
 		key.vs_as_es = (rctx->gs_shader != NULL);
+		if (rctx->ps_shader->current->shader.gs_prim_id_input && !rctx->gs_shader) {
+			key.vs_as_gs_a = true;
+			key.vs_prim_id_out = rctx->ps_shader->current->shader.input[rctx->ps_shader->current->shader.ps_prim_id_input].spi_sid;
+		}
 	}
 	return key;
 }
@@ -1265,6 +1269,7 @@ static bool r600_update_derived_state(struct r600_context *rctx)
 				r600_update_ps_state(ctx, rctx->ps_shader->current);
 		}
 
+		rctx->shader_stages.atom.dirty = true;
 		update_shader_atom(ctx, &rctx->pixel_shader, rctx->ps_shader->current);
 	}
 
-- 
1.9.3



More information about the mesa-dev mailing list