[Mesa-dev] [PATCH 25/31] radeonsi: unify the si_compile_* functions for prologs and epilogs

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


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

---
 src/gallium/drivers/radeonsi/si_shader.c | 239 ++++++++-----------------------
 1 file changed, 61 insertions(+), 178 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c
index a3b1189..58f8c15 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -7151,60 +7151,98 @@ int si_compile_tgsi_shader(struct si_screen *sscreen,
 	}
 
 	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
+ * \param prolog	whether the part being requested is a prolog
  * \param tm		LLVM target machine
  * \param debug		debug callback
- * \param compile	the callback responsible for compilation
+ * \param build		the callback responsible for building the main function
  * \return		non-NULL on success
  */
 static struct si_shader_part *
 si_get_shader_part(struct si_screen *sscreen,
 		   struct si_shader_part **list,
+		   enum pipe_shader_type type,
+		   bool prolog,
 		   union si_shader_part_key *key,
 		   LLVMTargetMachineRef tm,
 		   struct pipe_debug_callback *debug,
-		   bool (*compile)(struct si_screen *,
-				   LLVMTargetMachineRef,
-				   struct pipe_debug_callback *,
-				   struct si_shader_part *))
+		   void (*build)(struct si_shader_context *,
+				 union si_shader_part_key *),
+		   const char *name)
 {
 	struct si_shader_part *result;
 
 	pipe_mutex_lock(sscreen->shader_parts_mutex);
 
 	/* Find existing. */
 	for (result = *list; result; result = result->next) {
 		if (memcmp(&result->key, key, sizeof(*key)) == 0) {
 			pipe_mutex_unlock(sscreen->shader_parts_mutex);
 			return result;
 		}
 	}
 
 	/* Compile a new one. */
 	result = CALLOC_STRUCT(si_shader_part);
 	result->key = *key;
-	if (!compile(sscreen, tm, debug, result)) {
+
+	struct si_shader shader = {};
+	struct si_shader_context ctx;
+	struct gallivm_state *gallivm = &ctx.gallivm;
+
+	si_init_shader_ctx(&ctx, sscreen, &shader, tm);
+	ctx.type = type;
+
+	switch (type) {
+	case PIPE_SHADER_VERTEX:
+		break;
+	case PIPE_SHADER_TESS_CTRL:
+		assert(!prolog);
+		shader.key.tcs.epilog = key->tcs_epilog.states;
+		break;
+	case PIPE_SHADER_FRAGMENT:
+		if (prolog)
+			shader.key.ps.prolog = key->ps_prolog.states;
+		else
+			shader.key.ps.epilog = key->ps_epilog.states;
+		break;
+	default:
+		unreachable("bad shader part");
+	}
+
+	build(&ctx, key);
+
+	/* Compile. */
+	si_llvm_finalize_module(&ctx,
+		r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_FRAGMENT));
+
+	if (si_compile_llvm(sscreen, &result->binary, &result->config, tm,
+			    gallivm->module, debug, ctx.type, name)) {
 		FREE(result);
-		pipe_mutex_unlock(sscreen->shader_parts_mutex);
-		return NULL;
+		result = NULL;
+		goto out;
 	}
 
 	result->next = *list;
 	*list = result;
+
+out:
+	si_llvm_dispose(&ctx);
 	pipe_mutex_unlock(sscreen->shader_parts_mutex);
 	return result;
 }
 
 /**
  * Build the vertex shader prolog function.
  *
  * The inputs are the same as VS (a lot of SGPRs and 4 VGPR system values).
  * All inputs are returned unmodified. The vertex load indices are
  * stored after them, which will be used by the API VS for fetching inputs.
@@ -7294,52 +7332,20 @@ static void si_build_vs_prolog_function(struct si_shader_context *ctx,
 
 		index = LLVMBuildBitCast(gallivm->builder, index, ctx->f32, "");
 		ret = LLVMBuildInsertValue(gallivm->builder, ret, index,
 					   num_params++, "");
 	}
 
 	si_llvm_build_ret(ctx, ret);
 }
 
 /**
- * Create a vertex shader prolog.
- */
-static bool si_compile_vs_prolog(struct si_screen *sscreen,
-				 LLVMTargetMachineRef tm,
-				 struct pipe_debug_callback *debug,
-				 struct si_shader_part *out)
-{
-	union si_shader_part_key *key = &out->key;
-	struct si_shader shader = {};
-	struct si_shader_context ctx;
-	struct gallivm_state *gallivm = &ctx.gallivm;
-	bool status = true;
-
-	si_init_shader_ctx(&ctx, sscreen, &shader, tm);
-	ctx.type = PIPE_SHADER_VERTEX;
-
-	si_build_vs_prolog_function(&ctx, key);
-
-	/* Compile. */
-	si_llvm_finalize_module(&ctx,
-		r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_VERTEX));
-
-	if (si_compile_llvm(sscreen, &out->binary, &out->config, tm,
-			    gallivm->module, debug, ctx.type,
-			    "Vertex Shader Prolog"))
-		status = false;
-
-	si_llvm_dispose(&ctx);
-	return status;
-}
-
-/**
  * 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.
  * Otherwise, do nothing.
  */
 static void si_build_vs_epilog_function(struct si_shader_context *ctx,
 					union si_shader_part_key *key)
@@ -7380,67 +7386,37 @@ static void si_build_vs_epilog_function(struct si_shader_context *ctx,
 
 		lp_build_intrinsic(base->gallivm->builder, "llvm.SI.export",
 				   LLVMVoidTypeInContext(base->gallivm->context),
 				   args, 9, 0);
 	}
 
 	LLVMBuildRetVoid(gallivm->builder);
 }
 
 /**
- * Compile the vertex shader epilog. This is also used by the tessellation
- * evaluation shader compiled as VS.
- */
-static bool si_compile_vs_epilog(struct si_screen *sscreen,
-				 LLVMTargetMachineRef tm,
-				 struct pipe_debug_callback *debug,
-				 struct si_shader_part *out)
-{
-	union si_shader_part_key *key = &out->key;
-	struct si_shader_context ctx;
-	struct gallivm_state *gallivm = &ctx.gallivm;
-	bool status = true;
-
-	si_init_shader_ctx(&ctx, sscreen, NULL, tm);
-	ctx.type = PIPE_SHADER_VERTEX;
-
-	si_build_vs_epilog_function(&ctx, key);
-
-	/* Compile. */
-	si_llvm_finalize_module(&ctx,
-		r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_VERTEX));
-
-	if (si_compile_llvm(sscreen, &out->binary, &out->config, tm,
-			    gallivm->module, debug, ctx.type,
-			    "Vertex Shader Epilog"))
-		status = false;
-
-	si_llvm_dispose(&ctx);
-	return status;
-}
-
-/**
  * Create & compile a vertex shader epilog. This a helper used by VS and TES.
  */
 static bool si_get_vs_epilog(struct si_screen *sscreen,
 			     LLVMTargetMachineRef tm,
 		             struct si_shader *shader,
 		             struct pipe_debug_callback *debug,
 			     struct si_vs_epilog_bits *states)
 {
 	union si_shader_part_key epilog_key;
 
 	si_get_vs_epilog_key(shader, states, &epilog_key);
 
 	shader->epilog = si_get_shader_part(sscreen, &sscreen->vs_epilogs,
+					    PIPE_SHADER_VERTEX, true,
 					    &epilog_key, tm, debug,
-					    si_compile_vs_epilog);
+					    si_build_vs_epilog_function,
+					    "Vertex Shader Epilog");
 	return shader->epilog != NULL;
 }
 
 /**
  * Select and compile (or reuse) vertex shader parts (prolog & epilog).
  */
 static bool si_shader_select_vs_parts(struct si_screen *sscreen,
 				      LLVMTargetMachineRef tm,
 				      struct si_shader *shader,
 				      struct pipe_debug_callback *debug)
@@ -7448,22 +7424,24 @@ static bool si_shader_select_vs_parts(struct si_screen *sscreen,
 	struct tgsi_shader_info *info = &shader->selector->info;
 	union si_shader_part_key prolog_key;
 
 	/* Get the prolog. */
 	si_get_vs_prolog_key(shader, &prolog_key);
 
 	/* The prolog is a no-op if there are no inputs. */
 	if (info->num_inputs) {
 		shader->prolog =
 			si_get_shader_part(sscreen, &sscreen->vs_prologs,
+					   PIPE_SHADER_VERTEX, true,
 					   &prolog_key, tm, debug,
-					   si_compile_vs_prolog);
+					   si_build_vs_prolog_function,
+					   "Vertex Shader Prolog");
 		if (!shader->prolog)
 			return false;
 	}
 
 	/* Get the epilog. */
 	if (!shader->key.vs.as_es && !shader->key.vs.as_ls &&
 	    !si_get_vs_epilog(sscreen, tm, shader, debug,
 			      &shader->key.vs.epilog))
 		return false;
 
@@ -7525,70 +7503,38 @@ static void si_build_tcs_epilog_function(struct si_shader_context *ctx,
 
 	si_write_tess_factors(bld_base,
 			      LLVMGetParam(func, last_sgpr + 1),
 			      LLVMGetParam(func, last_sgpr + 2),
 			      LLVMGetParam(func, last_sgpr + 3));
 
 	LLVMBuildRetVoid(gallivm->builder);
 }
 
 /**
- * Compile the TCS epilog. This writes tesselation factors to memory based on
- * the output primitive type of the tesselator (determined by TES).
- */
-static bool si_compile_tcs_epilog(struct si_screen *sscreen,
-				  LLVMTargetMachineRef tm,
-				  struct pipe_debug_callback *debug,
-				  struct si_shader_part *out)
-{
-	union si_shader_part_key *key = &out->key;
-	struct si_shader shader = {};
-	struct si_shader_context ctx;
-	struct gallivm_state *gallivm = &ctx.gallivm;
-	bool status = true;
-
-	si_init_shader_ctx(&ctx, sscreen, &shader, tm);
-	ctx.type = PIPE_SHADER_TESS_CTRL;
-	shader.key.tcs.epilog = key->tcs_epilog.states;
-
-	si_build_tcs_epilog_function(&ctx, key);
-
-	/* Compile. */
-	si_llvm_finalize_module(&ctx,
-		r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_TESS_CTRL));
-
-	if (si_compile_llvm(sscreen, &out->binary, &out->config, tm,
-			    gallivm->module, debug, ctx.type,
-			    "Tessellation Control Shader Epilog"))
-		status = false;
-
-	si_llvm_dispose(&ctx);
-	return status;
-}
-
-/**
  * Select and compile (or reuse) TCS parts (epilog).
  */
 static bool si_shader_select_tcs_parts(struct si_screen *sscreen,
 				       LLVMTargetMachineRef tm,
 				       struct si_shader *shader,
 				       struct pipe_debug_callback *debug)
 {
 	union si_shader_part_key epilog_key;
 
 	/* Get the epilog. */
 	memset(&epilog_key, 0, sizeof(epilog_key));
 	epilog_key.tcs_epilog.states = shader->key.tcs.epilog;
 
 	shader->epilog = si_get_shader_part(sscreen, &sscreen->tcs_epilogs,
+					    PIPE_SHADER_TESS_CTRL, false,
 					    &epilog_key, tm, debug,
-					    si_compile_tcs_epilog);
+					    si_build_tcs_epilog_function,
+					    "Tessellation Control Shader Epilog");
 	return shader->epilog != NULL;
 }
 
 /**
  * Build the pixel shader prolog function. This handles:
  * - two-side color selection and interpolation
  * - overriding interpolation parameters for the API PS
  * - polygon stippling
  *
  * All preloaded SGPRs and VGPRs are passed through unmodified unless they are
@@ -7825,53 +7771,20 @@ static void si_build_ps_prolog_function(struct si_shader_context *ctx,
 	/* Tell LLVM to insert WQM instruction sequence when needed. */
 	if (key->ps_prolog.wqm) {
 		LLVMAddTargetDependentFunctionAttr(func,
 						   "amdgpu-ps-wqm-outputs", "");
 	}
 
 	si_llvm_build_ret(ctx, ret);
 }
 
 /**
- * Compile the pixel shader prolog.
- */
-static bool si_compile_ps_prolog(struct si_screen *sscreen,
-				 LLVMTargetMachineRef tm,
-				 struct pipe_debug_callback *debug,
-				 struct si_shader_part *out)
-{
-	union si_shader_part_key *key = &out->key;
-	struct si_shader shader = {};
-	struct si_shader_context ctx;
-	struct gallivm_state *gallivm = &ctx.gallivm;
-	bool status = true;
-
-	si_init_shader_ctx(&ctx, sscreen, &shader, tm);
-	ctx.type = PIPE_SHADER_FRAGMENT;
-	shader.key.ps.prolog = key->ps_prolog.states;
-
-	si_build_ps_prolog_function(&ctx, key);
-
-	/* Compile. */
-	si_llvm_finalize_module(&ctx,
-		r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_FRAGMENT));
-
-	if (si_compile_llvm(sscreen, &out->binary, &out->config, tm,
-			    gallivm->module, debug, ctx.type,
-			    "Fragment Shader Prolog"))
-		status = false;
-
-	si_llvm_dispose(&ctx);
-	return status;
-}
-
-/**
  * Build the pixel shader epilog function. This handles everything that must be
  * emulated for pixel shader exports. (alpha-test, format conversions, etc)
  */
 static void si_build_ps_epilog_function(struct si_shader_context *ctx,
 					union si_shader_part_key *key)
 {
 	struct gallivm_state *gallivm = &ctx->gallivm;
 	struct lp_build_tgsi_context *bld_base = &ctx->soa.bld_base;
 	LLVMTypeRef params[16+8*4+3];
 	LLVMValueRef depth = NULL, stencil = NULL, samplemask = NULL;
@@ -7958,85 +7871,55 @@ static void si_build_ps_epilog_function(struct si_shader_context *ctx,
 	else if (last_color_export == -1)
 		si_export_null(bld_base);
 
 	if (exp.num)
 		si_emit_ps_exports(ctx, &exp);
 
 	/* Compile. */
 	LLVMBuildRetVoid(gallivm->builder);
 }
 
-
-/**
- * Compile the pixel shader epilog to a binary for concatenation.
- */
-static bool si_compile_ps_epilog(struct si_screen *sscreen,
-				 LLVMTargetMachineRef tm,
-				 struct pipe_debug_callback *debug,
-				 struct si_shader_part *out)
-{
-	union si_shader_part_key *key = &out->key;
-	struct si_shader shader = {};
-	struct si_shader_context ctx;
-	struct gallivm_state *gallivm = &ctx.gallivm;
-	bool status = true;
-
-	si_init_shader_ctx(&ctx, sscreen, &shader, tm);
-	ctx.type = PIPE_SHADER_FRAGMENT;
-	shader.key.ps.epilog = key->ps_epilog.states;
-
-	si_build_ps_epilog_function(&ctx, key);
-
-	/* Compile. */
-	si_llvm_finalize_module(&ctx,
-		r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_FRAGMENT));
-
-	if (si_compile_llvm(sscreen, &out->binary, &out->config, tm,
-			    gallivm->module, debug, ctx.type,
-			    "Fragment Shader Epilog"))
-		status = false;
-
-	si_llvm_dispose(&ctx);
-	return status;
-}
-
 /**
  * Select and compile (or reuse) pixel shader parts (prolog & epilog).
  */
 static bool si_shader_select_ps_parts(struct si_screen *sscreen,
 				      LLVMTargetMachineRef tm,
 				      struct si_shader *shader,
 				      struct pipe_debug_callback *debug)
 {
 	union si_shader_part_key prolog_key;
 	union si_shader_part_key epilog_key;
 
 	/* Get the prolog. */
 	si_get_ps_prolog_key(shader, &prolog_key, true);
 
 	/* The prolog is a no-op if these aren't set. */
 	if (si_need_ps_prolog(&prolog_key)) {
 		shader->prolog =
 			si_get_shader_part(sscreen, &sscreen->ps_prologs,
+					   PIPE_SHADER_FRAGMENT, true,
 					   &prolog_key, tm, debug,
-					   si_compile_ps_prolog);
+					   si_build_ps_prolog_function,
+					   "Fragment Shader Prolog");
 		if (!shader->prolog)
 			return false;
 	}
 
 	/* Get the epilog. */
 	si_get_ps_epilog_key(shader, &epilog_key);
 
 	shader->epilog =
 		si_get_shader_part(sscreen, &sscreen->ps_epilogs,
+				   PIPE_SHADER_FRAGMENT, false,
 				   &epilog_key, tm, debug,
-				   si_compile_ps_epilog);
+				   si_build_ps_epilog_function,
+				   "Fragment Shader Epilog");
 	if (!shader->epilog)
 		return false;
 
 	/* Enable POS_FIXED_PT if polygon stippling is enabled. */
 	if (shader->key.ps.prolog.poly_stipple) {
 		shader->config.spi_ps_input_ena |= S_0286CC_POS_FIXED_PT_ENA(1);
 		assert(G_0286CC_POS_FIXED_PT_ENA(shader->config.spi_ps_input_addr));
 	}
 
 	/* Set up the enable bits for per-sample shading if needed. */
-- 
2.7.4



More information about the mesa-dev mailing list