xref: /aosp_15_r20/external/mesa3d/src/compiler/nir/nir_lower_texcoord_replace_late.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2022 Alyssa Rosenzweig
3  * Copyright 2020 Collabora, Ltd.
4  * SPDX-License-Identifier: MIT
5  */
6 
7 #include "nir.h"
8 #include "nir_builder.h"
9 #include "nir_deref.h"
10 
11 struct opts {
12    unsigned coord_replace;
13    bool point_coord_is_sysval;
14 };
15 
16 static nir_def *
nir_channel_or_undef(nir_builder * b,nir_def * def,signed int channel)17 nir_channel_or_undef(nir_builder *b, nir_def *def, signed int channel)
18 {
19    if (channel >= 0 && channel < def->num_components)
20       return nir_channel(b, def, channel);
21    else
22       return nir_undef(b, def->bit_size, 1);
23 }
24 
25 static bool
pass(nir_builder * b,nir_instr * instr,void * data)26 pass(nir_builder *b, nir_instr *instr, void *data)
27 {
28    struct opts *opts = data;
29 
30    if (instr->type != nir_instr_type_intrinsic)
31       return false;
32 
33    nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
34    if (intr->intrinsic != nir_intrinsic_load_interpolated_input &&
35        intr->intrinsic != nir_intrinsic_load_input)
36       return false;
37 
38    nir_src *offset = nir_get_io_offset_src(intr);
39    assert(nir_src_is_const(*offset) && "no indirects supported");
40 
41    nir_io_semantics sem = nir_intrinsic_io_semantics(intr);
42    unsigned location = sem.location + nir_src_as_uint(*offset);
43    signed component = nir_intrinsic_component(intr);
44 
45    if (location < VARYING_SLOT_TEX0 || location > VARYING_SLOT_TEX7)
46       return false;
47 
48    if (!(opts->coord_replace & BITFIELD_BIT(location - VARYING_SLOT_TEX0)))
49       return false;
50 
51    b->cursor = nir_before_instr(instr);
52    nir_def *channels[4] = {
53       NULL, NULL,
54       nir_imm_float(b, 0.0),
55       nir_imm_float(b, 1.0)
56    };
57 
58    if (opts->point_coord_is_sysval) {
59       nir_def *pntc = nir_load_point_coord(b);
60 
61       b->cursor = nir_after_instr(instr);
62       channels[0] = nir_channel(b, pntc, 0);
63       channels[1] = nir_channel(b, pntc, 1);
64    } else {
65       sem.location = VARYING_SLOT_PNTC;
66       nir_src_rewrite(offset, nir_imm_int(b, 0));
67       nir_intrinsic_set_io_semantics(intr, sem);
68       nir_def *raw = &intr->def;
69 
70       b->cursor = nir_after_instr(instr);
71       channels[0] = nir_channel_or_undef(b, raw, 0 - component);
72       channels[1] = nir_channel_or_undef(b, raw, 1 - component);
73    }
74 
75    nir_def *res = nir_vec(b, &channels[component], intr->num_components);
76    nir_def_rewrite_uses_after(&intr->def, res,
77                               res->parent_instr);
78    return true;
79 }
80 
81 void
nir_lower_texcoord_replace_late(nir_shader * s,unsigned coord_replace,bool point_coord_is_sysval)82 nir_lower_texcoord_replace_late(nir_shader *s, unsigned coord_replace,
83                                 bool point_coord_is_sysval)
84 {
85    assert(s->info.stage == MESA_SHADER_FRAGMENT);
86    assert(coord_replace != 0);
87 
88    uint64_t replace_mask = (((uint64_t)coord_replace) << VARYING_SLOT_TEX0);
89 
90    /* If no relevant texcoords are read, there's nothing to do */
91    if (!(s->info.inputs_read & replace_mask))
92       return;
93 
94    /* Otherwise, we're going to replace these texcoord reads with a PNTC read */
95    s->info.inputs_read &= ~(((uint64_t)coord_replace) << VARYING_SLOT_TEX0);
96 
97    if (!point_coord_is_sysval)
98       s->info.inputs_read |= BITFIELD64_BIT(VARYING_SLOT_PNTC);
99 
100    nir_shader_instructions_pass(s, pass,
101                                 nir_metadata_control_flow,
102                                 &(struct opts){
103                                    .coord_replace = coord_replace,
104                                    .point_coord_is_sysval = point_coord_is_sysval,
105                                 });
106 }
107