[Mesa-dev] [PATCH 29/31] radeonsi: make the GS copy shader owned by the GS selector

Nicolai Hähnle nhaehnle at gmail.com
Mon Oct 31 22:11:16 UTC 2016


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

The copy shader only depends on the selector. This change avoids creating
separate code paths for monolithic vs. non-monolithic geometry shaders.
---
 src/gallium/drivers/radeonsi/si_pipe.h          |  2 +-
 src/gallium/drivers/radeonsi/si_shader.c        | 18 ++++--------------
 src/gallium/drivers/radeonsi/si_shader.h        |  9 ++++++++-
 src/gallium/drivers/radeonsi/si_state_shaders.c | 22 ++++++++++++++++++----
 4 files changed, 31 insertions(+), 20 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h
index 0240a3c..e7617bc 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -443,21 +443,21 @@ static inline struct tgsi_shader_info *si_get_vs_info(struct si_context *sctx)
 		return &sctx->tes_shader.cso->info;
 	else if (sctx->vs_shader.cso)
 		return &sctx->vs_shader.cso->info;
 	else
 		return NULL;
 }
 
 static inline struct si_shader* si_get_vs_state(struct si_context *sctx)
 {
 	if (sctx->gs_shader.current)
-		return sctx->gs_shader.current->gs_copy_shader;
+		return sctx->gs_shader.cso->gs_copy_shader;
 	else if (sctx->tes_shader.current)
 		return sctx->tes_shader.current;
 	else
 		return sctx->vs_shader.current;
 }
 
 static inline bool si_vs_exports_prim_id(struct si_shader *shader)
 {
 	if (shader->selector->type == PIPE_SHADER_VERTEX)
 		return shader->key.vs.epilog.export_prim_id;
diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c
index e755399..38f65f3 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -5944,21 +5944,21 @@ static const char *si_get_shader_name(struct si_shader *shader,
 		else
 			return "Vertex Shader as VS";
 	case PIPE_SHADER_TESS_CTRL:
 		return "Tessellation Control Shader";
 	case PIPE_SHADER_TESS_EVAL:
 		if (shader->key.tes.as_es)
 			return "Tessellation Evaluation Shader as ES";
 		else
 			return "Tessellation Evaluation Shader as VS";
 	case PIPE_SHADER_GEOMETRY:
-		if (shader->gs_copy_shader == NULL)
+		if (shader->is_gs_copy_shader)
 			return "GS Copy Shader as VS";
 		else
 			return "Geometry Shader";
 	case PIPE_SHADER_FRAGMENT:
 		return "Pixel Shader";
 	case PIPE_SHADER_COMPUTE:
 		return "Compute Shader";
 	default:
 		return "Unknown Shader";
 	}
@@ -6073,21 +6073,21 @@ int si_compile_llvm(struct si_screen *sscreen,
 
 static void si_llvm_build_ret(struct si_shader_context *ctx, LLVMValueRef ret)
 {
 	if (LLVMGetTypeKind(LLVMTypeOf(ret)) == LLVMVoidTypeKind)
 		LLVMBuildRetVoid(ctx->gallivm.builder);
 	else
 		LLVMBuildRet(ctx->gallivm.builder, ret);
 }
 
 /* Generate code for the hardware VS shader stage to go with a geometry shader */
-static struct si_shader *
+struct si_shader *
 si_generate_gs_copy_shader(struct si_screen *sscreen,
 			   LLVMTargetMachineRef tm,
 			   struct si_shader_selector *gs_selector,
 			   struct pipe_debug_callback *debug)
 {
 	struct si_shader_context ctx;
 	struct si_shader *shader;
 	struct gallivm_state *gallivm = &ctx.gallivm;
 	struct lp_build_tgsi_context *bld_base = &ctx.soa.bld_base;
 	struct lp_build_context *uint = &bld_base->uint_bld;
@@ -6096,20 +6096,22 @@ si_generate_gs_copy_shader(struct si_screen *sscreen,
 	LLVMValueRef args[9];
 	int i, r;
 
 	outputs = MALLOC(gsinfo->num_outputs * sizeof(outputs[0]));
 
 	shader = CALLOC_STRUCT(si_shader);
 	if (!shader)
 		return NULL;
 
 	shader->selector = gs_selector;
+	shader->is_gs_copy_shader = true;
+
 	si_init_shader_ctx(&ctx, sscreen, shader, tm);
 	ctx.type = PIPE_SHADER_VERTEX;
 	ctx.is_gs_copy_shader = true;
 
 	create_meta_data(&ctx);
 	create_function(&ctx);
 	preload_ring_buffers(&ctx);
 
 	args[0] = ctx.gsvs_ring[0];
 	args[1] = lp_build_mul_imm(uint,
@@ -7143,27 +7145,20 @@ int si_compile_tgsi_shader(struct si_screen *sscreen,
 			shader->info.num_input_vgprs += 1;
 		}
 		if (G_0286CC_ANCILLARY_ENA(shader->config.spi_ps_input_addr))
 			shader->info.num_input_vgprs += 1;
 		if (G_0286CC_SAMPLE_COVERAGE_ENA(shader->config.spi_ps_input_addr))
 			shader->info.num_input_vgprs += 1;
 		if (G_0286CC_POS_FIXED_PT_ENA(shader->config.spi_ps_input_addr))
 			shader->info.num_input_vgprs += 1;
 	}
 
-	if (ctx.type == PIPE_SHADER_GEOMETRY) {
-		shader->gs_copy_shader =
-			si_generate_gs_copy_shader(sscreen, tm, shader->selector, debug);
-		if (!shader->gs_copy_shader)
-			return -1;
-	}
-
 	return 0;
 }
 
 /**
  * Create, compile and return a shader part (prolog or epilog).
  *
  * \param sscreen	screen
  * \param list		list of shader parts of the same category
  * \param type		shader type
  * \param key		shader part key
@@ -8091,25 +8086,20 @@ int si_shader_create(struct si_screen *sscreen, LLVMTargetMachineRef tm,
 	if (r) {
 		fprintf(stderr, "LLVM failed to upload shader\n");
 		return r;
 	}
 
 	return 0;
 }
 
 void si_shader_destroy(struct si_shader *shader)
 {
-	if (shader->gs_copy_shader) {
-		si_shader_destroy(shader->gs_copy_shader);
-		FREE(shader->gs_copy_shader);
-	}
-
 	if (shader->scratch_bo)
 		r600_resource_reference(&shader->scratch_bo, NULL);
 
 	r600_resource_reference(&shader->bo, NULL);
 
 	if (!shader->is_binary_shared)
 		radeon_shader_binary_clean(&shader->binary);
 
 	free(shader->shader_log);
 }
diff --git a/src/gallium/drivers/radeonsi/si_shader.h b/src/gallium/drivers/radeonsi/si_shader.h
index 6c7a05f..91f9cbf 100644
--- a/src/gallium/drivers/radeonsi/si_shader.h
+++ b/src/gallium/drivers/radeonsi/si_shader.h
@@ -250,20 +250,22 @@ struct si_shader_selector {
 
 	pipe_mutex		mutex;
 	struct si_shader	*first_variant; /* immutable after the first variant */
 	struct si_shader	*last_variant; /* mutable */
 
 	/* The compiled TGSI shader expecting a prolog and/or epilog (not
 	 * uploaded to a buffer).
 	 */
 	struct si_shader	*main_shader_part;
 
+	struct si_shader	*gs_copy_shader;
+
 	struct tgsi_token       *tokens;
 	struct pipe_stream_output_info  so;
 	struct tgsi_shader_info		info;
 
 	/* PIPE_SHADER_[VERTEX|FRAGMENT|...] */
 	unsigned	type;
 
 	/* GS parameters. */
 	unsigned	esgs_itemsize;
 	unsigned	gs_input_verts_per_prim;
@@ -437,26 +439,26 @@ struct si_shader_info {
 	ubyte			nr_param_exports;
 };
 
 struct si_shader {
 	struct si_shader_selector	*selector;
 	struct si_shader		*next_variant;
 
 	struct si_shader_part		*prolog;
 	struct si_shader_part		*epilog;
 
-	struct si_shader		*gs_copy_shader;
 	struct si_pm4_state		*pm4;
 	struct r600_resource		*bo;
 	struct r600_resource		*scratch_bo;
 	union si_shader_key		key;
 	bool				is_binary_shared;
+	bool				is_gs_copy_shader;
 
 	/* The following data is all that's needed for binary shaders. */
 	struct radeon_shader_binary	binary;
 	struct si_shader_config		config;
 	struct si_shader_info		info;
 
 	/* Shader key + LLVM IR + disassembly + statistics.
 	 * Generated for debug contexts only.
 	 */
 	char				*shader_log;
@@ -464,20 +466,25 @@ struct si_shader {
 };
 
 struct si_shader_part {
 	struct si_shader_part *next;
 	union si_shader_part_key key;
 	struct radeon_shader_binary binary;
 	struct si_shader_config config;
 };
 
 /* si_shader.c */
+struct si_shader *
+si_generate_gs_copy_shader(struct si_screen *sscreen,
+			   LLVMTargetMachineRef tm,
+			   struct si_shader_selector *gs_selector,
+			   struct pipe_debug_callback *debug);
 int si_compile_tgsi_shader(struct si_screen *sscreen,
 			   LLVMTargetMachineRef tm,
 			   struct si_shader *shader,
 			   bool is_monolithic,
 			   struct pipe_debug_callback *debug);
 int si_shader_create(struct si_screen *sscreen, LLVMTargetMachineRef tm,
 		     struct si_shader *shader,
 		     struct pipe_debug_callback *debug);
 int si_compile_llvm(struct si_screen *sscreen,
 		    struct radeon_shader_binary *binary,
diff --git a/src/gallium/drivers/radeonsi/si_state_shaders.c b/src/gallium/drivers/radeonsi/si_state_shaders.c
index 537c673..bd217f3 100644
--- a/src/gallium/drivers/radeonsi/si_state_shaders.c
+++ b/src/gallium/drivers/radeonsi/si_state_shaders.c
@@ -825,21 +825,20 @@ static void si_shader_init_pm4_state(struct si_screen *sscreen,
 		si_shader_hs(shader);
 		break;
 	case PIPE_SHADER_TESS_EVAL:
 		if (shader->key.tes.as_es)
 			si_shader_es(sscreen, shader);
 		else
 			si_shader_vs(sscreen, shader, NULL);
 		break;
 	case PIPE_SHADER_GEOMETRY:
 		si_shader_gs(shader);
-		si_shader_vs(sscreen, shader->gs_copy_shader, shader->selector);
 		break;
 	case PIPE_SHADER_FRAGMENT:
 		si_shader_ps(shader);
 		break;
 	default:
 		assert(0);
 	}
 }
 
 static unsigned si_get_alpha_test_func(struct si_context *sctx)
@@ -1225,20 +1224,31 @@ void si_init_shader_selector_async(void *job, int thread_index)
 				if (sel->info.colors_written & (1 << i))
 					key.ps.epilog.spi_shader_col_format |=
 						V_028710_SPI_SHADER_FP16_ABGR << (i * 4);
 			break;
 		}
 
 		if (si_shader_select_with_key(sscreen, &state, &key, tm, debug,
 					      false, sel->is_debug_context))
 			fprintf(stderr, "radeonsi: can't create a monolithic shader\n");
 	}
+
+	/* The GS copy shader is always pre-compiled. */
+	if (sel->type == PIPE_SHADER_GEOMETRY) {
+		sel->gs_copy_shader = si_generate_gs_copy_shader(sscreen, tm, sel, debug);
+		if (!sel->gs_copy_shader) {
+			fprintf(stderr, "radeonsi: can't create GS copy shader\n");
+			return;
+		}
+
+		si_shader_vs(sscreen, sel->gs_copy_shader, sel);
+	}
 }
 
 static void *si_create_shader_selector(struct pipe_context *ctx,
 				       const struct pipe_shader_state *state)
 {
 	struct si_screen *sscreen = (struct si_screen *)ctx->screen;
 	struct si_context *sctx = (struct si_context*)ctx;
 	struct si_shader_selector *sel = CALLOC_STRUCT(si_shader_selector);
 	int i;
 
@@ -1507,22 +1517,24 @@ static void si_delete_shader(struct si_context *sctx, struct si_shader *shader)
 		case PIPE_SHADER_TESS_CTRL:
 			si_pm4_delete_state(sctx, hs, shader->pm4);
 			break;
 		case PIPE_SHADER_TESS_EVAL:
 			if (shader->key.tes.as_es)
 				si_pm4_delete_state(sctx, es, shader->pm4);
 			else
 				si_pm4_delete_state(sctx, vs, shader->pm4);
 			break;
 		case PIPE_SHADER_GEOMETRY:
-			si_pm4_delete_state(sctx, gs, shader->pm4);
-			si_pm4_delete_state(sctx, vs, shader->gs_copy_shader->pm4);
+			if (shader->is_gs_copy_shader)
+				si_pm4_delete_state(sctx, vs, shader->pm4);
+			else
+				si_pm4_delete_state(sctx, gs, shader->pm4);
 			break;
 		case PIPE_SHADER_FRAGMENT:
 			si_pm4_delete_state(sctx, ps, shader->pm4);
 			break;
 		}
 	}
 
 	si_shader_destroy(shader);
 	free(shader);
 }
@@ -1548,20 +1560,22 @@ static void si_delete_shader_selector(struct pipe_context *ctx, void *state)
 	}
 
 	while (p) {
 		c = p->next_variant;
 		si_delete_shader(sctx, p);
 		p = c;
 	}
 
 	if (sel->main_shader_part)
 		si_delete_shader(sctx, sel->main_shader_part);
+	if (sel->gs_copy_shader)
+		si_delete_shader(sctx, sel->gs_copy_shader);
 
 	util_queue_fence_destroy(&sel->ready);
 	pipe_mutex_destroy(sel->mutex);
 	free(sel->tokens);
 	free(sel);
 }
 
 static unsigned si_get_ps_input_cntl(struct si_context *sctx,
 				     struct si_shader *vs, unsigned name,
 				     unsigned index, unsigned interpolate)
@@ -2204,21 +2218,21 @@ bool si_update_shaders(struct si_context *sctx)
 		si_pm4_bind_state(sctx, vs, sctx->vs_shader.current->pm4);
 		si_update_so(sctx, sctx->vs_shader.cso);
 	}
 
 	/* Update GS. */
 	if (sctx->gs_shader.cso) {
 		r = si_shader_select(ctx, &sctx->gs_shader);
 		if (r)
 			return false;
 		si_pm4_bind_state(sctx, gs, sctx->gs_shader.current->pm4);
-		si_pm4_bind_state(sctx, vs, sctx->gs_shader.current->gs_copy_shader->pm4);
+		si_pm4_bind_state(sctx, vs, sctx->gs_shader.cso->gs_copy_shader->pm4);
 		si_update_so(sctx, sctx->gs_shader.cso);
 
 		if (!si_update_gs_ring_buffers(sctx))
 			return false;
 
 		si_update_gsvs_ring_bindings(sctx);
 	} else {
 		si_pm4_bind_state(sctx, gs, NULL);
 		si_pm4_bind_state(sctx, es, NULL);
 	}
-- 
2.7.4



More information about the mesa-dev mailing list