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