[Mesa-dev] [PATCH 1/2] radeonsi: Use amdgcn intrinsics for fs interpolation

Tom Stellard thomas.stellard at amd.com
Wed Nov 16 02:14:55 UTC 2016


---
 src/gallium/drivers/radeonsi/si_shader.c | 197 ++++++++++++++++++++++---------
 1 file changed, 143 insertions(+), 54 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c
index 0410a32..306e12f 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -1204,6 +1204,81 @@ static int lookup_interp_param_index(unsigned interpolate, unsigned location)
 	}
 }
 
+static LLVMValueRef build_fs_interp(
+	struct lp_build_tgsi_context *bld_base,
+	LLVMValueRef llvm_chan,
+	LLVMValueRef attr_number,
+	LLVMValueRef params,
+	LLVMValueRef i,
+	LLVMValueRef j) {
+
+	struct si_shader_context *ctx = si_shader_context(bld_base);
+	struct gallivm_state *gallivm = bld_base->base.gallivm;
+	LLVMValueRef args[5];
+	LLVMValueRef p1;
+	if (HAVE_LLVM < 0x0400) {
+		LLVMValueRef ij[2];
+		ij[0] = LLVMBuildBitCast(gallivm->builder, i, ctx->i32, "");
+		ij[1] = LLVMBuildBitCast(gallivm->builder, j, ctx->i32, "");
+
+		args[0] = llvm_chan;
+		args[1] = attr_number;
+		args[2] = params;
+		args[3] = lp_build_gather_values(gallivm, ij, 2);
+		return lp_build_intrinsic(gallivm->builder, "llvm.fs.interp",
+					  ctx->f32, args, 4,
+					  LP_FUNC_ATTR_READNONE);
+
+	}
+
+	args[0] = i;
+	args[1] = llvm_chan;
+	args[2] = attr_number;
+	args[3] = params;
+
+	p1 = lp_build_intrinsic(gallivm->builder, "llvm.amdgcn.interp.p1",
+				ctx->f32, args, 4, LP_FUNC_ATTR_READNONE);
+
+	args[0] = p1;
+	args[1] = j;
+	args[2] = llvm_chan;
+	args[3] = attr_number;
+	args[4] = params;
+
+	return lp_build_intrinsic(gallivm->builder, "llvm.amdgcn.interp.p2",
+				  ctx->f32, args, 5, LP_FUNC_ATTR_READNONE);
+}
+
+static LLVMValueRef build_fs_interp_mov(
+	struct lp_build_tgsi_context *bld_base,
+	LLVMValueRef parameter,
+	LLVMValueRef llvm_chan,
+	LLVMValueRef attr_number,
+	LLVMValueRef params) {
+
+	struct si_shader_context *ctx = si_shader_context(bld_base);
+	struct gallivm_state *gallivm = bld_base->base.gallivm;
+	LLVMValueRef args[4];
+	if (HAVE_LLVM < 0x0400) {
+		args[0] = llvm_chan;
+		args[1] = attr_number;
+		args[2] = params;
+
+		return lp_build_intrinsic(gallivm->builder,
+					  "llvm.SI.fs.constant",
+					  ctx->f32, args, 3,
+					  LP_FUNC_ATTR_READNONE);
+	}
+
+	args[0] = parameter;
+	args[1] = llvm_chan;
+	args[2] = attr_number;
+	args[3] = params;
+
+	return lp_build_intrinsic(gallivm->builder, "llvm.amdgcn.interp.mov",
+				  ctx->f32, args, 4, LP_FUNC_ATTR_READNONE);
+}
+
 /**
  * Interpolate a fragment shader input.
  *
@@ -1229,16 +1304,15 @@ static void interp_fs_input(struct si_shader_context *ctx,
 			    LLVMValueRef face,
 			    LLVMValueRef result[4])
 {
-	struct lp_build_context *base = &ctx->soa.bld_base.base;
-	struct lp_build_context *uint =	&ctx->soa.bld_base.uint_bld;
+	struct lp_build_tgsi_context *bld_base = &ctx->soa.bld_base;
+	struct lp_build_context *base = &bld_base->base;
+	struct lp_build_context *uint =	&bld_base->uint_bld;
 	struct gallivm_state *gallivm = base->gallivm;
-	const char *intr_name;
 	LLVMValueRef attr_number;
+	LLVMValueRef i, j;
 
 	unsigned chan;
 
-	attr_number = lp_build_const_int32(gallivm, input_index);
-
 	/* fs.constant returns the param from the middle vertex, so it's not
 	 * really useful for flat shading. It's meant to be used for custom
 	 * interpolation (but the intrinsic can't fetch from the other two
@@ -1248,12 +1322,26 @@ static void interp_fs_input(struct si_shader_context *ctx,
 	 * to do the right thing. The only reason we use fs.constant is that
 	 * fs.interp cannot be used on integers, because they can be equal
 	 * to NaN.
+	 *
+	 * When interp is true we will use fs.constant or for newer llvm,
+         * amdgcn.interp.mov.
 	 */
-	intr_name = interp_param ? "llvm.SI.fs.interp" : "llvm.SI.fs.constant";
+	bool interp = interp_param != NULL;
+
+	attr_number = lp_build_const_int32(gallivm, input_index);
+
+	if (interp) {
+		interp_param = LLVMBuildBitCast(gallivm->builder, interp_param,
+						LLVMVectorType(ctx->f32, 2), "");
+
+		i = LLVMBuildExtractElement(gallivm->builder, interp_param,
+						uint->zero, "");
+		j = LLVMBuildExtractElement(gallivm->builder, interp_param,
+						uint->one, "");
+	}
 
 	if (semantic_name == TGSI_SEMANTIC_COLOR &&
 	    ctx->shader->key.ps.prolog.color_two_side) {
-		LLVMValueRef args[4];
 		LLVMValueRef is_face_positive;
 		LLVMValueRef back_attr_number;
 
@@ -1269,22 +1357,25 @@ static void interp_fs_input(struct si_shader_context *ctx,
 		is_face_positive = LLVMBuildICmp(gallivm->builder, LLVMIntNE,
 						 face, uint->zero, "");
 
-		args[2] = prim_mask;
-		args[3] = interp_param;
 		for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
 			LLVMValueRef llvm_chan = lp_build_const_int32(gallivm, chan);
 			LLVMValueRef front, back;
 
-			args[0] = llvm_chan;
-			args[1] = attr_number;
-			front = lp_build_intrinsic(gallivm->builder, intr_name,
-						ctx->f32, args, args[3] ? 4 : 3,
-						LP_FUNC_ATTR_READNONE);
-
-			args[1] = back_attr_number;
-			back = lp_build_intrinsic(gallivm->builder, intr_name,
-					       ctx->f32, args, args[3] ? 4 : 3,
-					       LP_FUNC_ATTR_READNONE);
+			if (interp) {
+				front = build_fs_interp(bld_base, llvm_chan,
+							attr_number, prim_mask,
+							i, j);
+				back = build_fs_interp(bld_base, llvm_chan,
+							back_attr_number, prim_mask,
+							i, j);
+			} else {
+				front = build_fs_interp_mov(bld_base,
+					lp_build_const_int32(gallivm, 2), /* P0 */
+					llvm_chan, attr_number, prim_mask);
+				back = build_fs_interp_mov(bld_base,
+					lp_build_const_int32(gallivm, 2), /* P0 */
+					llvm_chan, back_attr_number, prim_mask);
+			}
 
 			result[chan] = LLVMBuildSelect(gallivm->builder,
 						is_face_positive,
@@ -1293,30 +1384,29 @@ static void interp_fs_input(struct si_shader_context *ctx,
 						"");
 		}
 	} else if (semantic_name == TGSI_SEMANTIC_FOG) {
-		LLVMValueRef args[4];
-
-		args[0] = uint->zero;
-		args[1] = attr_number;
-		args[2] = prim_mask;
-		args[3] = interp_param;
-		result[0] = lp_build_intrinsic(gallivm->builder, intr_name,
-					ctx->f32, args, args[3] ? 4 : 3,
-					LP_FUNC_ATTR_READNONE);
+		if (interp) {
+			result[0] = build_fs_interp(bld_base, uint->zero,
+						attr_number, prim_mask, i, j);
+		} else {
+			result[0] = build_fs_interp_mov(bld_base, uint->zero,
+				lp_build_const_int32(gallivm, 2), /* P0 */
+				attr_number, prim_mask);
+		}
 		result[1] =
 		result[2] = lp_build_const_float(gallivm, 0.0f);
 		result[3] = lp_build_const_float(gallivm, 1.0f);
 	} else {
 		for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
-			LLVMValueRef args[4];
 			LLVMValueRef llvm_chan = lp_build_const_int32(gallivm, chan);
 
-			args[0] = llvm_chan;
-			args[1] = attr_number;
-			args[2] = prim_mask;
-			args[3] = interp_param;
-			result[chan] = lp_build_intrinsic(gallivm->builder, intr_name,
-						ctx->f32, args, args[3] ? 4 : 3,
-						LP_FUNC_ATTR_READNONE);
+			if (interp) {
+				result[chan] = build_fs_interp(bld_base,
+					llvm_chan, attr_number, prim_mask, i, j);
+			} else {
+				result[chan] = build_fs_interp_mov(bld_base,
+					lp_build_const_int32(gallivm, 2), /* P0 */
+					llvm_chan, attr_number, prim_mask);
+			}
 		}
 	}
 }
@@ -4969,9 +5059,9 @@ static void build_interp_intrinsic(const struct lp_build_tgsi_action *action,
 	struct si_shader_context *ctx = si_shader_context(bld_base);
 	struct si_shader *shader = ctx->shader;
 	struct gallivm_state *gallivm = bld_base->base.gallivm;
+	struct lp_build_context *uint = &bld_base->uint_bld;
 	LLVMValueRef interp_param;
 	const struct tgsi_full_instruction *inst = emit_data->inst;
-	const char *intr_name;
 	int input_index = inst->Src[0].Register.Index;
 	int chan;
 	int i;
@@ -5032,32 +5122,33 @@ static void build_interp_intrinsic(const struct lp_build_tgsi_action *action,
 
 			temp2 = LLVMBuildFMul(gallivm->builder, ddy_el, emit_data->args[1], "");
 
-			temp2 = LLVMBuildFAdd(gallivm->builder, temp2, temp1, "");
-
-			ij_out[i] = LLVMBuildBitCast(gallivm->builder,
-						     temp2, ctx->i32, "");
+			ij_out[i] = LLVMBuildFAdd(gallivm->builder, temp2, temp1, "");
 		}
 		interp_param = lp_build_gather_values(bld_base->base.gallivm, ij_out, 2);
 	}
 
-	intr_name = interp_param ? "llvm.SI.fs.interp" : "llvm.SI.fs.constant";
 	for (chan = 0; chan < 4; chan++) {
-		LLVMValueRef args[4];
 		LLVMValueRef llvm_chan;
 		unsigned schan;
 
 		schan = tgsi_util_get_full_src_register_swizzle(&inst->Src[0], chan);
 		llvm_chan = lp_build_const_int32(gallivm, schan);
 
-		args[0] = llvm_chan;
-		args[1] = attr_number;
-		args[2] = params;
-		args[3] = interp_param;
-
-		emit_data->output[chan] =
-			lp_build_intrinsic(gallivm->builder, intr_name,
-					   ctx->f32, args, args[3] ? 4 : 3,
-					   LP_FUNC_ATTR_READNONE);
+		if (interp_param) {
+			interp_param = LLVMBuildBitCast(gallivm->builder,
+				interp_param, LLVMVectorType(ctx->f32, 2), "");
+			LLVMValueRef i = LLVMBuildExtractElement(
+				gallivm->builder, interp_param, uint->zero, "");
+			LLVMValueRef j = LLVMBuildExtractElement(
+				gallivm->builder, interp_param, uint->one, "");
+			emit_data->output[chan] = build_fs_interp(bld_base,
+				llvm_chan, attr_number, params,
+				i, j);
+		} else {
+			emit_data->output[chan] = build_fs_interp_mov(bld_base,
+				lp_build_const_int32(gallivm, 2), /* P0 */
+				llvm_chan, attr_number, params);
+		}
 	}
 }
 
@@ -7899,8 +7990,6 @@ static void si_build_ps_prolog_function(struct si_shader_context *ctx,
 			interp[1] = LLVMBuildExtractValue(gallivm->builder, ret,
 							  interp_vgpr + 1, "");
 			interp_ij = lp_build_gather_values(gallivm, interp, 2);
-			interp_ij = LLVMBuildBitCast(gallivm->builder, interp_ij,
-						     ctx->v2i32, "");
 		}
 
 		/* Use the absolute location of the input. */
-- 
2.7.4



More information about the mesa-dev mailing list