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 bool
pass(nir_builder * b,nir_instr * instr,void * data)17 pass(nir_builder *b, nir_instr *instr, void *data)
18 {
19 struct opts *opts = data;
20
21 if (instr->type != nir_instr_type_intrinsic)
22 return false;
23
24 nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
25 if (intr->intrinsic != nir_intrinsic_load_interpolated_input &&
26 intr->intrinsic != nir_intrinsic_load_input)
27 return false;
28
29 nir_src *offset = nir_get_io_offset_src(intr);
30 assert(nir_src_is_const(*offset) && "no indirects supported");
31
32 nir_io_semantics sem = nir_intrinsic_io_semantics(intr);
33 unsigned location = sem.location + nir_src_as_uint(*offset);
34 signed component = nir_intrinsic_component(intr);
35
36 if (location < VARYING_SLOT_TEX0 || location > VARYING_SLOT_TEX7)
37 return false;
38
39 if (!(opts->coord_replace & BITFIELD_BIT(location - VARYING_SLOT_TEX0)))
40 return false;
41
42 b->cursor = nir_before_instr(instr);
43 nir_def *channels[4] = {
44 NULL, NULL,
45 nir_imm_float(b, 0.0),
46 nir_imm_float(b, 1.0)
47 };
48
49 if (opts->point_coord_is_sysval) {
50 nir_def *pntc = nir_load_point_coord(b);
51
52 b->cursor = nir_after_instr(instr);
53 channels[0] = nir_channel(b, pntc, 0);
54 channels[1] = nir_channel(b, pntc, 1);
55 } else {
56 sem.location = VARYING_SLOT_PNTC;
57 nir_src_rewrite(offset, nir_imm_int(b, 0));
58 nir_intrinsic_set_io_semantics(intr, sem);
59 nir_def *raw = &intr->def;
60
61 b->cursor = nir_after_instr(instr);
62 channels[0] = nir_channel_or_undef(b, raw, 0 - component);
63 channels[1] = nir_channel_or_undef(b, raw, 1 - component);
64 }
65
66 nir_def *res = nir_vec(b, &channels[component], intr->num_components);
67 nir_def_rewrite_uses_after(&intr->def, res,
68 res->parent_instr);
69 return true;
70 }
71
72 bool
nir_lower_texcoord_replace_late(nir_shader * s,unsigned coord_replace,bool point_coord_is_sysval)73 nir_lower_texcoord_replace_late(nir_shader *s, unsigned coord_replace,
74 bool point_coord_is_sysval)
75 {
76 assert(s->info.stage == MESA_SHADER_FRAGMENT);
77 assert(coord_replace != 0);
78
79 uint64_t replace_mask = (((uint64_t)coord_replace) << VARYING_SLOT_TEX0);
80
81 /* If no relevant texcoords are read, there's nothing to do */
82 if (!(s->info.inputs_read & replace_mask))
83 return false;
84
85 /* Otherwise, we're going to replace these texcoord reads with a PNTC read */
86 s->info.inputs_read &= ~(((uint64_t)coord_replace) << VARYING_SLOT_TEX0);
87
88 if (!point_coord_is_sysval)
89 s->info.inputs_read |= BITFIELD64_BIT(VARYING_SLOT_PNTC);
90
91 return nir_shader_instructions_pass(s, pass,
92 nir_metadata_control_flow,
93 &(struct opts){
94 .coord_replace = coord_replace,
95 .point_coord_is_sysval = point_coord_is_sysval,
96 });
97 }
98