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

Nicolai Hähnle nhaehnle at gmail.com
Wed Nov 16 10:10:46 UTC 2016


On 16.11.2016 03:14, Tom Stellard wrote:
> ---
>  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.

When interp is *false*, right?

Apart from that: Reviewed-by: Nicolai Hähnle <nicolai.haehnle at amd.com>

>  	 */
> -	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. */
>


More information about the mesa-dev mailing list