xref: /aosp_15_r20/external/mesa3d/src/compiler/nir/nir_lower_texcoord_replace.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2020 Collabora, Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *    Erik Faye-Lund <[email protected]>
25  */
26 
27 #include "nir.h"
28 #include "nir_builder.h"
29 #include "nir_deref.h"
30 
31 static nir_def *
get_io_index(nir_builder * b,nir_deref_instr * deref)32 get_io_index(nir_builder *b, nir_deref_instr *deref)
33 {
34    nir_deref_path path;
35    nir_deref_path_init(&path, deref, NULL);
36 
37    assert(path.path[0]->deref_type == nir_deref_type_var);
38    nir_deref_instr **p = &path.path[1];
39 
40    /* Just emit code and let constant-folding go to town */
41    nir_def *offset = nir_imm_int(b, 0);
42 
43    for (; *p; p++) {
44       if ((*p)->deref_type == nir_deref_type_array) {
45          unsigned size = glsl_get_length((*p)->type);
46 
47          nir_def *mul =
48             nir_amul_imm(b, (*p)->arr.index.ssa, size);
49 
50          offset = nir_iadd(b, offset, mul);
51       } else
52          unreachable("Unsupported deref type");
53    }
54 
55    nir_deref_path_finish(&path);
56 
57    return offset;
58 }
59 
60 static void
nir_lower_texcoord_replace_impl(nir_function_impl * impl,unsigned coord_replace,bool point_coord_is_sysval,bool yinvert)61 nir_lower_texcoord_replace_impl(nir_function_impl *impl,
62                                 unsigned coord_replace,
63                                 bool point_coord_is_sysval,
64                                 bool yinvert)
65 {
66    nir_builder b = nir_builder_at(nir_before_impl(impl));
67 
68    nir_def *new_coord;
69    if (point_coord_is_sysval) {
70       new_coord = nir_load_system_value(&b, nir_intrinsic_load_point_coord,
71                                         0, 2, 32);
72       BITSET_SET(b.shader->info.system_values_read, SYSTEM_VALUE_POINT_COORD);
73    } else {
74       /* find or create pntc */
75       nir_variable *pntc = nir_get_variable_with_location(b.shader, nir_var_shader_in,
76                                                           VARYING_SLOT_PNTC, glsl_vec_type(2));
77       b.shader->info.inputs_read |= BITFIELD64_BIT(VARYING_SLOT_PNTC);
78       new_coord = nir_load_var(&b, pntc);
79    }
80 
81    /* point-coord is two-component, need to add two implicit ones in case of
82     * projective texturing etc.
83     */
84    nir_def *zero = nir_imm_zero(&b, 1, new_coord->bit_size);
85    nir_def *one = nir_imm_floatN_t(&b, 1.0, new_coord->bit_size);
86    nir_def *y = nir_channel(&b, new_coord, 1);
87    if (yinvert)
88       y = nir_fsub_imm(&b, 1.0, y);
89    new_coord = nir_vec4(&b, nir_channel(&b, new_coord, 0),
90                         y,
91                         zero, one);
92 
93    nir_foreach_block(block, impl) {
94       nir_foreach_instr_safe(instr, block) {
95          if (instr->type != nir_instr_type_intrinsic)
96             continue;
97 
98          nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
99          if (intrin->intrinsic != nir_intrinsic_load_deref)
100             continue;
101 
102          nir_variable *var = nir_intrinsic_get_var(intrin, 0);
103          if (var->data.mode != nir_var_shader_in ||
104              var->data.location < VARYING_SLOT_TEX0 ||
105              var->data.location > VARYING_SLOT_TEX7)
106             continue;
107          unsigned base = var->data.location - VARYING_SLOT_TEX0;
108 
109          b.cursor = nir_after_instr(instr);
110          uint32_t component_mask = BITFIELD_MASK(glsl_get_vector_elements(var->type)) << var->data.location_frac;
111          nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
112          nir_def *index = get_io_index(&b, deref);
113          nir_def *mask =
114             nir_ishl(&b, nir_imm_int(&b, 1),
115                      nir_iadd_imm(&b, index, base));
116 
117          nir_def *cond = nir_test_mask(&b, mask, coord_replace);
118          nir_def *result = nir_bcsel(&b, cond, nir_channels(&b, new_coord, component_mask),
119                                      &intrin->def);
120 
121          nir_def_rewrite_uses_after(&intrin->def,
122                                     result,
123                                     result->parent_instr);
124       }
125    }
126 
127    nir_metadata_preserve(impl, nir_metadata_control_flow);
128 }
129 
130 void
nir_lower_texcoord_replace(nir_shader * s,unsigned coord_replace,bool point_coord_is_sysval,bool yinvert)131 nir_lower_texcoord_replace(nir_shader *s, unsigned coord_replace,
132                            bool point_coord_is_sysval, bool yinvert)
133 {
134    assert(s->info.stage == MESA_SHADER_FRAGMENT);
135    assert(coord_replace != 0);
136 
137    nir_foreach_function_impl(impl, s) {
138       nir_lower_texcoord_replace_impl(impl, coord_replace,
139                                       point_coord_is_sysval, yinvert);
140    }
141 }
142