nir: Add a new load_input_attachment_coord intrinsic

This hoists all the annoyance of figuring out the current pixel's input
attachment coordinates to the driver.  The pass still deals with all the
annoyance of turning an image instruciton into a texture instruction but
it gives the driver more control over the position.  For most drivers,
this will be something like ivec3(int(gl_FragCoord.xy), gl_Layer) or
similar, some drivers need something more nuanced.  Turnip, for
instance, needs unscaled coordinates for some attachments and NVK
doesn't really want gl_Layer or gl_ViewIndex for the layer.  It's better
to just have a new system value that drivers can make what they want.

Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35551>
This commit is contained in:
Faith Ekstrand 2025-06-16 09:26:03 -04:00 committed by Marge Bot
parent 2c13e1e655
commit 9f9cde04ec
4 changed files with 41 additions and 17 deletions

View file

@ -5711,6 +5711,7 @@ typedef struct nir_lower_idiv_options {
bool nir_lower_idiv(nir_shader *shader, const nir_lower_idiv_options *options);
typedef struct nir_input_attachment_options {
bool use_ia_coord_intrin;
bool use_fragcoord_sysval;
bool use_layer_id_sysval;
bool use_view_id_for_layer;

View file

@ -782,6 +782,7 @@ visit_intrinsic(nir_intrinsic_instr *instr, struct divergence_state *state)
case nir_intrinsic_load_barycentric_coord_at_sample:
case nir_intrinsic_load_barycentric_coord_at_offset:
case nir_intrinsic_load_persp_center_rhw_ir3:
case nir_intrinsic_load_input_attachment_coord:
case nir_intrinsic_interp_deref_at_offset:
case nir_intrinsic_interp_deref_at_sample:
case nir_intrinsic_interp_deref_at_centroid:

View file

@ -1125,6 +1125,13 @@ barycentric("coord_at_offset", 3, [2])
intrinsic("load_sample_pos_from_id", src_comp=[1], dest_comp=2,
flags=[CAN_ELIMINATE, CAN_REORDER])
# Load input attachment coordinate:
#
# Takes an input attachment index and returns an ivec with the position in
# input attachment space in .xy and the input attachment array index in .z.
intrinsic("load_input_attachment_coord", src_comp=[1], dest_comp=3,
bit_sizes=[32], flags=[CAN_ELIMINATE, CAN_REORDER])
# Demote a subset of samples given by a specified sample mask. This acts like a
# per-sample demote, or an inverted accumulating gl_SampleMask write.
intrinsic("demote_samples", src_comp=[1])

View file

@ -83,6 +83,29 @@ load_layer_id(nir_builder *b, const nir_input_attachment_options *options)
return nir_load_var(b, layer_id);
}
static nir_def *
load_coord(nir_builder *b, nir_deref_instr *deref,
const nir_input_attachment_options *options)
{
if (options->use_ia_coord_intrin) {
nir_def *index;
if (deref->deref_type == nir_deref_type_array) {
ASSERTED nir_deref_instr *parent = nir_deref_instr_parent(deref);
assert(parent->deref_type == nir_deref_type_var);
index = deref->arr.index.ssa;
} else {
assert(deref->deref_type == nir_deref_type_var);
index = nir_imm_int(b, 0);
}
return nir_load_input_attachment_coord(b, index);
} else {
nir_def *pos = nir_f2i32(b, load_frag_coord(b, deref, options));
nir_def *layer = load_layer_id(b, options);
return nir_vec3(b, nir_channel(b, pos, 0), nir_channel(b, pos, 1), layer);
}
}
static bool
try_lower_input_load(nir_builder *b, nir_intrinsic_instr *load,
const nir_input_attachment_options *options)
@ -99,14 +122,10 @@ try_lower_input_load(nir_builder *b, nir_intrinsic_instr *load,
b->cursor = nir_instr_remove(&load->instr);
nir_def *frag_coord = load_frag_coord(b, deref, options);
frag_coord = nir_f2i32(b, frag_coord);
nir_def *offset = nir_trim_vector(b, load->src[1].ssa, 2);
nir_def *pos = nir_iadd(b, frag_coord, offset);
nir_def *layer = load_layer_id(b, options);
nir_def *coord =
nir_vec3(b, nir_channel(b, pos, 0), nir_channel(b, pos, 1), layer);
nir_def *offset = nir_vec3(b, nir_channel(b, load->src[1].ssa, 0),
nir_channel(b, load->src[1].ssa, 1),
nir_imm_int(b, 0));
nir_def *coord = nir_iadd(b, load_coord(b, deref, options), offset);
nir_tex_instr *tex = nir_tex_instr_create(b->shader, 3 + multisampled);
@ -174,15 +193,11 @@ try_lower_input_texop(nir_builder *b, nir_tex_instr *tex,
b->cursor = nir_before_instr(&tex->instr);
nir_def *frag_coord = load_frag_coord(b, deref, options);
frag_coord = nir_f2i32(b, frag_coord);
nir_def *offset = nir_trim_vector(b, tex->src[coord_src_idx].src.ssa, 2);
nir_def *pos = nir_iadd(b, frag_coord, offset);
nir_def *layer = load_layer_id(b, options);
nir_def *coord = nir_vec3(b, nir_channel(b, pos, 0),
nir_channel(b, pos, 1), layer);
nir_def *offset = tex->src[coord_src_idx].src.ssa;
offset = nir_vec3(b, nir_channel(b, offset, 0),
nir_channel(b, offset, 1),
nir_imm_int(b, 0));
nir_def *coord = nir_iadd(b, load_coord(b, deref, options), offset);
tex->coord_components = 3;