[Mesa-dev] [PATCH 2/2] radeonsi: support indirect indexing in INTERP_* opcodes

Nicolai Hähnle nhaehnle at gmail.com
Fri Jun 16 20:37:15 UTC 2017


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

The hardware doesn't support it, so we just interpolate all array elements
and then use indirect indexing on the resulting vector.

Clearly, this is not very efficient. There is an argument to be had for
adding if/else, or perhaps even pulling the data out of LDS directly.
Both don't really seem worth the effort, considering that it seems nobody
actually uses this feature.
---
 src/gallium/drivers/radeonsi/si_shader.c | 78 ++++++++++++++++++++++++--------
 1 file changed, 58 insertions(+), 20 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c
index e525a18..370022f 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -3517,49 +3517,70 @@ static void interp_fetch_args(
 	}
 }
 
 static void build_interp_intrinsic(const struct lp_build_tgsi_action *action,
 				struct lp_build_tgsi_context *bld_base,
 				struct lp_build_emit_data *emit_data)
 {
 	struct si_shader_context *ctx = si_shader_context(bld_base);
 	struct si_shader *shader = ctx->shader;
 	struct gallivm_state *gallivm = &ctx->gallivm;
+	const struct tgsi_shader_info *info = &shader->selector->info;
 	LLVMValueRef interp_param;
 	const struct tgsi_full_instruction *inst = emit_data->inst;
-	int input_index = inst->Src[0].Register.Index;
+	const struct tgsi_full_src_register *input = &inst->Src[0];
+	int input_base, input_array_size;
 	int chan;
 	int i;
-	LLVMValueRef attr_number;
 	LLVMValueRef params = LLVMGetParam(ctx->main_fn, SI_PARAM_PRIM_MASK);
+	LLVMValueRef array_idx;
 	int interp_param_idx;
-	unsigned interp = shader->selector->info.input_interpolate[input_index];
+	unsigned interp;
 	unsigned location;
 
-	assert(inst->Src[0].Register.File == TGSI_FILE_INPUT);
+	assert(input->Register.File == TGSI_FILE_INPUT);
+
+	if (input->Register.Indirect) {
+		unsigned array_id = input->Indirect.ArrayID;
+
+		if (array_id) {
+			input_base = info->input_array_first[array_id];
+			input_array_size = info->input_array_last[array_id] - input_base + 1;
+		} else {
+			input_base = inst->Src[0].Register.Index;
+			input_array_size = info->num_inputs - input_base;
+		}
+
+		array_idx = get_indirect_index(ctx, &input->Indirect,
+					       input->Register.Index - input_base);
+	} else {
+		input_base = inst->Src[0].Register.Index;
+		input_array_size = 1;
+		array_idx = ctx->i32_0;
+	}
+
+	interp = shader->selector->info.input_interpolate[input_base];
 
 	if (inst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET ||
 	    inst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE)
 		location = TGSI_INTERPOLATE_LOC_CENTER;
 	else
 		location = TGSI_INTERPOLATE_LOC_CENTROID;
 
 	interp_param_idx = lookup_interp_param_index(interp, location);
 	if (interp_param_idx == -1)
 		return;
 	else if (interp_param_idx)
 		interp_param = LLVMGetParam(ctx->main_fn, interp_param_idx);
 	else
 		interp_param = NULL;
 
-	attr_number = LLVMConstInt(ctx->i32, input_index, 0);
-
 	if (inst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET ||
 	    inst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) {
 		LLVMValueRef ij_out[2];
 		LLVMValueRef ddxy_out = si_llvm_emit_ddxy_interp(bld_base, interp_param);
 
 		/*
 		 * take the I then J parameters, and the DDX/Y for it, and
 		 * calculate the IJ inputs for the interpolator.
 		 * temp1 = ddx * offset/sample.x + I;
 		 * interp_param.I = ddy * offset/sample.y + temp1;
@@ -3584,42 +3605,59 @@ static void build_interp_intrinsic(const struct lp_build_tgsi_action *action,
 
 			temp1 = LLVMBuildFAdd(gallivm->builder, temp1, interp_el, "");
 
 			temp2 = LLVMBuildFMul(gallivm->builder, ddy_el, emit_data->args[1], "");
 
 			ij_out[i] = LLVMBuildFAdd(gallivm->builder, temp2, temp1, "");
 		}
 		interp_param = lp_build_gather_values(gallivm, ij_out, 2);
 	}
 
+	if (interp_param) {
+		interp_param = LLVMBuildBitCast(gallivm->builder,
+			interp_param, LLVMVectorType(ctx->f32, 2), "");
+	}
+
 	for (chan = 0; chan < 4; chan++) {
 		LLVMValueRef llvm_chan;
+		LLVMValueRef gather = LLVMGetUndef(LLVMVectorType(ctx->f32, input_array_size));
 		unsigned schan;
 
 		schan = tgsi_util_get_full_src_register_swizzle(&inst->Src[0], chan);
 		llvm_chan = LLVMConstInt(ctx->i32, schan, 0);
 
-		if (interp_param) {
-			interp_param = LLVMBuildBitCast(gallivm->builder,
-				interp_param, LLVMVectorType(ctx->f32, 2), "");
-			LLVMValueRef i = LLVMBuildExtractElement(
-				gallivm->builder, interp_param, ctx->i32_0, "");
-			LLVMValueRef j = LLVMBuildExtractElement(
-				gallivm->builder, interp_param, ctx->i32_1, "");
-			emit_data->output[chan] = ac_build_fs_interp(&ctx->ac,
-				llvm_chan, attr_number, params,
-				i, j);
-		} else {
-			emit_data->output[chan] = ac_build_fs_interp_mov(&ctx->ac,
-				LLVMConstInt(ctx->i32, 2, 0), /* P0 */
-				llvm_chan, attr_number, params);
+		for (unsigned i = 0; i < input_array_size; ++i) {
+			LLVMValueRef attr_number = LLVMConstInt(ctx->i32, input_base + i, false);
+			LLVMValueRef v;
+
+			if (interp_param) {
+				interp_param = LLVMBuildBitCast(gallivm->builder,
+					interp_param, LLVMVectorType(ctx->f32, 2), "");
+				LLVMValueRef i = LLVMBuildExtractElement(
+					gallivm->builder, interp_param, ctx->i32_0, "");
+				LLVMValueRef j = LLVMBuildExtractElement(
+					gallivm->builder, interp_param, ctx->i32_1, "");
+				v = ac_build_fs_interp(&ctx->ac,
+					llvm_chan, attr_number, params,
+					i, j);
+			} else {
+				v = ac_build_fs_interp_mov(&ctx->ac,
+					LLVMConstInt(ctx->i32, 2, 0), /* P0 */
+					llvm_chan, attr_number, params);
+			}
+
+			gather = LLVMBuildInsertElement(gallivm->builder,
+				gather, v, LLVMConstInt(ctx->i32, i, false), "");
 		}
+
+		emit_data->output[chan] = LLVMBuildExtractElement(
+			gallivm->builder, gather, array_idx, "");
 	}
 }
 
 static LLVMValueRef si_emit_ballot(struct si_shader_context *ctx,
 				   LLVMValueRef value)
 {
 	struct gallivm_state *gallivm = &ctx->gallivm;
 	LLVMValueRef args[3] = {
 		value,
 		ctx->i32_0,
-- 
2.9.3



More information about the mesa-dev mailing list