amd: lower load_barycentric_at_offset in NIR
Reviewed-by: Timur Kristóf <timur.kristof@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/32782>
This commit is contained in:
@@ -305,6 +305,25 @@ lower_intrinsic_to_arg(nir_builder *b, nir_instr *instr, void *state)
|
||||
case nir_intrinsic_load_barycentric_model:
|
||||
replacement = ac_nir_load_arg(b, s->args, s->args->pull_model);
|
||||
break;
|
||||
case nir_intrinsic_load_barycentric_at_offset: {
|
||||
nir_def *baryc = nir_intrinsic_interp_mode(intrin) == INTERP_MODE_NOPERSPECTIVE ?
|
||||
ac_nir_load_arg(b, s->args, s->args->linear_center) :
|
||||
ac_nir_load_arg(b, s->args, s->args->persp_center);
|
||||
nir_def *i = nir_channel(b, baryc, 0);
|
||||
nir_def *j = nir_channel(b, baryc, 1);
|
||||
nir_def *offset_x = nir_channel(b, intrin->src[0].ssa, 0);
|
||||
nir_def *offset_y = nir_channel(b, intrin->src[0].ssa, 1);
|
||||
nir_def *ddx_i = nir_ddx(b, i);
|
||||
nir_def *ddx_j = nir_ddx(b, j);
|
||||
nir_def *ddy_i = nir_ddy(b, i);
|
||||
nir_def *ddy_j = nir_ddy(b, j);
|
||||
|
||||
/* Interpolate standard barycentrics by offset. */
|
||||
nir_def *offset_i = nir_ffma(b, ddy_i, offset_y, nir_ffma(b, ddx_i, offset_x, i));
|
||||
nir_def *offset_j = nir_ffma(b, ddy_j, offset_y, nir_ffma(b, ddx_j, offset_x, j));
|
||||
replacement = nir_vec2(b, offset_i, offset_j);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@@ -7895,52 +7895,6 @@ emit_rotate_by_constant(isel_context* ctx, Temp& dst, Temp src, unsigned cluster
|
||||
return dst.id() != 0;
|
||||
}
|
||||
|
||||
void
|
||||
emit_interp_center(isel_context* ctx, Temp dst, Temp bary, Temp pos1, Temp pos2)
|
||||
{
|
||||
Builder bld(ctx->program, ctx->block);
|
||||
Temp p1 = emit_extract_vector(ctx, bary, 0, v1);
|
||||
Temp p2 = emit_extract_vector(ctx, bary, 1, v1);
|
||||
|
||||
Temp ddx_1, ddx_2, ddy_1, ddy_2;
|
||||
uint32_t dpp_ctrl0 = dpp_quad_perm(0, 0, 0, 0);
|
||||
uint32_t dpp_ctrl1 = dpp_quad_perm(1, 1, 1, 1);
|
||||
uint32_t dpp_ctrl2 = dpp_quad_perm(2, 2, 2, 2);
|
||||
|
||||
/* Build DD X/Y */
|
||||
if (ctx->program->gfx_level >= GFX8) {
|
||||
Temp tl_1 = bld.vop1_dpp(aco_opcode::v_mov_b32, bld.def(v1), p1, dpp_ctrl0);
|
||||
ddx_1 = bld.vop2_dpp(aco_opcode::v_sub_f32, bld.def(v1), p1, tl_1, dpp_ctrl1);
|
||||
ddy_1 = bld.vop2_dpp(aco_opcode::v_sub_f32, bld.def(v1), p1, tl_1, dpp_ctrl2);
|
||||
Temp tl_2 = bld.vop1_dpp(aco_opcode::v_mov_b32, bld.def(v1), p2, dpp_ctrl0);
|
||||
ddx_2 = bld.vop2_dpp(aco_opcode::v_sub_f32, bld.def(v1), p2, tl_2, dpp_ctrl1);
|
||||
ddy_2 = bld.vop2_dpp(aco_opcode::v_sub_f32, bld.def(v1), p2, tl_2, dpp_ctrl2);
|
||||
} else {
|
||||
Temp tl_1 = bld.ds(aco_opcode::ds_swizzle_b32, bld.def(v1), p1, (1 << 15) | dpp_ctrl0);
|
||||
ddx_1 = bld.ds(aco_opcode::ds_swizzle_b32, bld.def(v1), p1, (1 << 15) | dpp_ctrl1);
|
||||
ddx_1 = bld.vop2(aco_opcode::v_sub_f32, bld.def(v1), ddx_1, tl_1);
|
||||
ddy_1 = bld.ds(aco_opcode::ds_swizzle_b32, bld.def(v1), p1, (1 << 15) | dpp_ctrl2);
|
||||
ddy_1 = bld.vop2(aco_opcode::v_sub_f32, bld.def(v1), ddy_1, tl_1);
|
||||
|
||||
Temp tl_2 = bld.ds(aco_opcode::ds_swizzle_b32, bld.def(v1), p2, (1 << 15) | dpp_ctrl0);
|
||||
ddx_2 = bld.ds(aco_opcode::ds_swizzle_b32, bld.def(v1), p2, (1 << 15) | dpp_ctrl1);
|
||||
ddx_2 = bld.vop2(aco_opcode::v_sub_f32, bld.def(v1), ddx_2, tl_2);
|
||||
ddy_2 = bld.ds(aco_opcode::ds_swizzle_b32, bld.def(v1), p2, (1 << 15) | dpp_ctrl2);
|
||||
ddy_2 = bld.vop2(aco_opcode::v_sub_f32, bld.def(v1), ddy_2, tl_2);
|
||||
}
|
||||
|
||||
/* res_k = p_k + ddx_k * pos1 + ddy_k * pos2 */
|
||||
aco_opcode mad =
|
||||
ctx->program->gfx_level >= GFX10_3 ? aco_opcode::v_fma_f32 : aco_opcode::v_mad_f32;
|
||||
Temp tmp1 = bld.vop3(mad, bld.def(v1), ddx_1, pos1, p1);
|
||||
Temp tmp2 = bld.vop3(mad, bld.def(v1), ddx_2, pos1, p2);
|
||||
tmp1 = bld.vop3(mad, bld.def(v1), ddy_1, pos2, tmp1);
|
||||
tmp2 = bld.vop3(mad, bld.def(v1), ddy_2, pos2, tmp2);
|
||||
bld.pseudo(aco_opcode::p_create_vector, Definition(dst), tmp1, tmp2);
|
||||
set_wqm(ctx, true);
|
||||
return;
|
||||
}
|
||||
|
||||
Temp merged_wave_info_to_mask(isel_context* ctx, unsigned i);
|
||||
Temp lanecount_to_mask(isel_context* ctx, Temp count, unsigned bit_offset);
|
||||
void pops_await_overlapped_waves(isel_context* ctx);
|
||||
@@ -8042,17 +7996,6 @@ visit_intrinsic(isel_context* ctx, nir_intrinsic_instr* instr)
|
||||
{
|
||||
Builder bld(ctx->program, ctx->block);
|
||||
switch (instr->intrinsic) {
|
||||
case nir_intrinsic_load_barycentric_at_offset: {
|
||||
Temp offset = get_ssa_temp(ctx, instr->src[0].ssa);
|
||||
RegClass rc = RegClass(offset.type(), 1);
|
||||
Temp pos1 = bld.tmp(rc), pos2 = bld.tmp(rc);
|
||||
bld.pseudo(aco_opcode::p_split_vector, Definition(pos1), Definition(pos2), offset);
|
||||
Temp bary = get_arg(ctx, nir_intrinsic_interp_mode(instr) == INTERP_MODE_NOPERSPECTIVE
|
||||
? ctx->args->linear_center
|
||||
: ctx->args->persp_center);
|
||||
emit_interp_center(ctx, get_ssa_temp(ctx, &instr->def), bary, pos1, pos2);
|
||||
break;
|
||||
}
|
||||
case nir_intrinsic_load_tess_coord: visit_load_tess_coord(ctx, instr); break;
|
||||
case nir_intrinsic_load_interpolated_input: visit_load_interpolated_input(ctx, instr); break;
|
||||
case nir_intrinsic_store_output: visit_store_output(ctx, instr); break;
|
||||
|
@@ -550,7 +550,6 @@ init_context(isel_context* ctx, nir_shader* shader)
|
||||
case nir_intrinsic_load_per_vertex_input:
|
||||
case nir_intrinsic_load_per_vertex_output:
|
||||
case nir_intrinsic_load_vertex_id_zero_base:
|
||||
case nir_intrinsic_load_barycentric_at_offset:
|
||||
case nir_intrinsic_load_interpolated_input:
|
||||
case nir_intrinsic_load_local_invocation_index:
|
||||
case nir_intrinsic_load_subgroup_invocation:
|
||||
|
@@ -3483,24 +3483,6 @@ LLVMValueRef ac_build_canonicalize(struct ac_llvm_context *ctx, LLVMValueRef src
|
||||
return ac_build_intrinsic(ctx, intr, type, params, 1, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* this takes an I,J coordinate pair,
|
||||
* and works out the X and Y derivatives.
|
||||
* it returns DDX(I), DDX(J), DDY(I), DDY(J).
|
||||
*/
|
||||
LLVMValueRef ac_build_ddxy_interp(struct ac_llvm_context *ctx, LLVMValueRef interp_ij)
|
||||
{
|
||||
LLVMValueRef result[4], a;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
a = LLVMBuildExtractElement(ctx->builder, interp_ij, LLVMConstInt(ctx->i32, i, false), "");
|
||||
result[i] = ac_build_ddxy(ctx, AC_TID_MASK_TOP_LEFT, 1, a);
|
||||
result[2 + i] = ac_build_ddxy(ctx, AC_TID_MASK_TOP_LEFT, 2, a);
|
||||
}
|
||||
return ac_build_gather_values(ctx, result, 4);
|
||||
}
|
||||
|
||||
LLVMValueRef ac_build_load_helper_invocation(struct ac_llvm_context *ctx)
|
||||
{
|
||||
LLVMValueRef result = ac_build_intrinsic(ctx, "llvm.amdgcn.live.mask", ctx->i1, NULL, 0, 0);
|
||||
|
@@ -459,8 +459,6 @@ LLVMValueRef ac_build_frexp_mant(struct ac_llvm_context *ctx, LLVMValueRef src0,
|
||||
LLVMValueRef ac_build_canonicalize(struct ac_llvm_context *ctx, LLVMValueRef src0,
|
||||
unsigned bitsize);
|
||||
|
||||
LLVMValueRef ac_build_ddxy_interp(struct ac_llvm_context *ctx, LLVMValueRef interp_ij);
|
||||
|
||||
LLVMValueRef ac_build_load_helper_invocation(struct ac_llvm_context *ctx);
|
||||
|
||||
LLVMValueRef ac_build_call(struct ac_llvm_context *ctx, LLVMTypeRef fn_type, LLVMValueRef func,
|
||||
|
@@ -2657,47 +2657,6 @@ static LLVMValueRef visit_var_atomic(struct ac_nir_context *ctx, const nir_intri
|
||||
return result;
|
||||
}
|
||||
|
||||
static LLVMValueRef barycentric_offset(struct ac_nir_context *ctx, unsigned mode,
|
||||
LLVMValueRef offset)
|
||||
{
|
||||
LLVMValueRef interp_param = mode == INTERP_MODE_NOPERSPECTIVE ?
|
||||
ac_get_arg(&ctx->ac, ctx->args->linear_center) :
|
||||
ac_get_arg(&ctx->ac, ctx->args->persp_center);
|
||||
LLVMValueRef src_c0 =
|
||||
ac_to_float(&ctx->ac, LLVMBuildExtractElement(ctx->ac.builder, offset, ctx->ac.i32_0, ""));
|
||||
LLVMValueRef src_c1 =
|
||||
ac_to_float(&ctx->ac, LLVMBuildExtractElement(ctx->ac.builder, offset, ctx->ac.i32_1, ""));
|
||||
|
||||
LLVMValueRef ij_out[2];
|
||||
LLVMValueRef ddxy_out = ac_build_ddxy_interp(&ctx->ac, 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;
|
||||
* temp1 = ddx * offset/sample.x + J;
|
||||
* interp_param.J = ddy * offset/sample.y + temp1;
|
||||
*/
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
LLVMValueRef ix_ll = LLVMConstInt(ctx->ac.i32, i, false);
|
||||
LLVMValueRef iy_ll = LLVMConstInt(ctx->ac.i32, i + 2, false);
|
||||
LLVMValueRef ddx_el = LLVMBuildExtractElement(ctx->ac.builder, ddxy_out, ix_ll, "");
|
||||
LLVMValueRef ddy_el = LLVMBuildExtractElement(ctx->ac.builder, ddxy_out, iy_ll, "");
|
||||
LLVMValueRef interp_el = LLVMBuildExtractElement(ctx->ac.builder, interp_param, ix_ll, "");
|
||||
LLVMValueRef temp1, temp2;
|
||||
|
||||
interp_el = LLVMBuildBitCast(ctx->ac.builder, interp_el, ctx->ac.f32, "");
|
||||
|
||||
temp1 = ac_build_fmad(&ctx->ac, ddx_el, src_c0, interp_el);
|
||||
temp2 = ac_build_fmad(&ctx->ac, ddy_el, src_c1, temp1);
|
||||
|
||||
ij_out[i] = LLVMBuildBitCast(ctx->ac.builder, temp2, ctx->ac.i32, "");
|
||||
}
|
||||
interp_param = ac_build_gather_values(&ctx->ac, ij_out, 2);
|
||||
return LLVMBuildBitCast(ctx->ac.builder, interp_param, ctx->ac.v2i32, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef load_interpolated_input(struct ac_nir_context *ctx, LLVMValueRef interp_param,
|
||||
unsigned index, unsigned comp_start,
|
||||
unsigned num_components, unsigned bitsize,
|
||||
@@ -3010,11 +2969,6 @@ static bool visit_intrinsic(struct ac_nir_context *ctx, nir_intrinsic_instr *ins
|
||||
result = visit_var_atomic(ctx, instr, ptr, 1);
|
||||
break;
|
||||
}
|
||||
case nir_intrinsic_load_barycentric_at_offset: {
|
||||
LLVMValueRef offset = ac_to_float(&ctx->ac, get_src(ctx, instr->src[0]));
|
||||
result = barycentric_offset(ctx, nir_intrinsic_interp_mode(instr), offset);
|
||||
break;
|
||||
}
|
||||
case nir_intrinsic_load_interpolated_input: {
|
||||
/* We assume any indirect loads have been lowered away */
|
||||
ASSERTED nir_const_value *offset = nir_src_as_const_value(instr->src[1]);
|
||||
|
Reference in New Issue
Block a user