nir/lower_tex: support projector lowering per sampler type
[mesa.git] / src / glsl / nir / nir_lower_tex.c
1 /*
2 * Copyright © 2015 Broadcom
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
24 /*
25 * This lowering pass converts the coordinate division for texture projection
26 * to be done in ALU instructions instead of asking the texture operation to
27 * do so.
28 */
29
30 #include "nir.h"
31 #include "nir_builder.h"
32
33 typedef struct {
34 nir_builder b;
35 const nir_lower_tex_options *options;
36 } lower_tex_state;
37
38 static void
39 project_src(nir_builder *b, nir_tex_instr *tex)
40 {
41 /* Find the projector in the srcs list, if present. */
42 unsigned proj_index;
43 for (proj_index = 0; proj_index < tex->num_srcs; proj_index++) {
44 if (tex->src[proj_index].src_type == nir_tex_src_projector)
45 break;
46 }
47 if (proj_index == tex->num_srcs)
48 return;
49
50 b->cursor = nir_before_instr(&tex->instr);
51
52 nir_ssa_def *inv_proj =
53 nir_frcp(b, nir_ssa_for_src(b, tex->src[proj_index].src, 1));
54
55 /* Walk through the sources projecting the arguments. */
56 for (unsigned i = 0; i < tex->num_srcs; i++) {
57 switch (tex->src[i].src_type) {
58 case nir_tex_src_coord:
59 case nir_tex_src_comparitor:
60 break;
61 default:
62 continue;
63 }
64 nir_ssa_def *unprojected =
65 nir_ssa_for_src(b, tex->src[i].src, nir_tex_instr_src_size(tex, i));
66 nir_ssa_def *projected = nir_fmul(b, unprojected, inv_proj);
67
68 /* Array indices don't get projected, so make an new vector with the
69 * coordinate's array index untouched.
70 */
71 if (tex->is_array && tex->src[i].src_type == nir_tex_src_coord) {
72 switch (tex->coord_components) {
73 case 4:
74 projected = nir_vec4(b,
75 nir_channel(b, projected, 0),
76 nir_channel(b, projected, 1),
77 nir_channel(b, projected, 2),
78 nir_channel(b, unprojected, 3));
79 break;
80 case 3:
81 projected = nir_vec3(b,
82 nir_channel(b, projected, 0),
83 nir_channel(b, projected, 1),
84 nir_channel(b, unprojected, 2));
85 break;
86 case 2:
87 projected = nir_vec2(b,
88 nir_channel(b, projected, 0),
89 nir_channel(b, unprojected, 1));
90 break;
91 default:
92 unreachable("bad texture coord count for array");
93 break;
94 }
95 }
96
97 nir_instr_rewrite_src(&tex->instr,
98 &tex->src[i].src,
99 nir_src_for_ssa(projected));
100 }
101
102 /* Now move the later tex sources down the array so that the projector
103 * disappears.
104 */
105 nir_instr_rewrite_src(&tex->instr, &tex->src[proj_index].src,
106 NIR_SRC_INIT);
107 for (unsigned i = proj_index + 1; i < tex->num_srcs; i++) {
108 tex->src[i-1].src_type = tex->src[i].src_type;
109 nir_instr_move_src(&tex->instr, &tex->src[i-1].src, &tex->src[i].src);
110 }
111 tex->num_srcs--;
112 }
113
114 static bool
115 nir_lower_tex_block(nir_block *block, void *void_state)
116 {
117 lower_tex_state *state = void_state;
118 nir_builder *b = &state->b;
119
120 nir_foreach_instr_safe(block, instr) {
121 if (instr->type != nir_instr_type_tex)
122 continue;
123
124 nir_tex_instr *tex = nir_instr_as_tex(instr);
125 bool lower_txp = !!(state->options->lower_txp & (1 << tex->sampler_dim));
126
127 if (lower_txp)
128 project_src(b, tex);
129
130 }
131
132 return true;
133 }
134
135 static void
136 nir_lower_tex_impl(nir_function_impl *impl, lower_tex_state *state)
137 {
138 nir_builder_init(&state->b, impl);
139
140 nir_foreach_block(impl, nir_lower_tex_block, state);
141
142 nir_metadata_preserve(impl, nir_metadata_block_index |
143 nir_metadata_dominance);
144 }
145
146 void
147 nir_lower_tex(nir_shader *shader, const nir_lower_tex_options *options)
148 {
149 lower_tex_state state;
150 state.options = options;
151 nir_foreach_overload(shader, overload) {
152 if (overload->impl)
153 nir_lower_tex_impl(overload->impl, &state);
154 }
155 }