nir/lower_io: Separate driver_location and base offset for uniforms
[mesa.git] / src / glsl / nir / nir_lower_io.c
1 /*
2 * Copyright © 2014 Intel Corporation
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 * Connor Abbott (cwabbott0@gmail.com)
25 * Jason Ekstrand (jason@jlekstrand.net)
26 *
27 */
28
29 /*
30 * This lowering pass converts references to input/output variables with
31 * loads/stores to actual input/output intrinsics.
32 */
33
34 #include "nir.h"
35 #include "nir_builder.h"
36
37 struct lower_io_state {
38 nir_builder builder;
39 void *mem_ctx;
40 int (*type_size)(const struct glsl_type *type);
41 };
42
43 void
44 nir_assign_var_locations(struct exec_list *var_list, unsigned *size,
45 int (*type_size)(const struct glsl_type *))
46 {
47 unsigned location = 0;
48
49 foreach_list_typed(nir_variable, var, node, var_list) {
50 /*
51 * UBO's have their own address spaces, so don't count them towards the
52 * number of global uniforms
53 */
54 if ((var->data.mode == nir_var_uniform || var->data.mode == nir_var_shader_storage) &&
55 var->interface_type != NULL)
56 continue;
57
58 var->data.driver_location = location;
59 location += type_size(var->type);
60 }
61
62 *size = location;
63 }
64
65 static bool
66 deref_has_indirect(nir_deref_var *deref)
67 {
68 for (nir_deref *tail = deref->deref.child; tail; tail = tail->child) {
69 if (tail->deref_type == nir_deref_type_array) {
70 nir_deref_array *arr = nir_deref_as_array(tail);
71 if (arr->deref_array_type == nir_deref_array_type_indirect)
72 return true;
73 }
74 }
75
76 return false;
77 }
78
79 static bool
80 mark_indirect_uses_block(nir_block *block, void *void_state)
81 {
82 struct set *indirect_set = void_state;
83
84 nir_foreach_instr(block, instr) {
85 if (instr->type != nir_instr_type_intrinsic)
86 continue;
87
88 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
89
90 for (unsigned i = 0;
91 i < nir_intrinsic_infos[intrin->intrinsic].num_variables; i++) {
92 if (deref_has_indirect(intrin->variables[i]))
93 _mesa_set_add(indirect_set, intrin->variables[i]->var);
94 }
95 }
96
97 return true;
98 }
99
100 /* Identical to nir_assign_var_locations_packed except that it assigns
101 * locations to the variables that are used 100% directly first and then
102 * assigns locations to variables that are used indirectly.
103 */
104 void
105 nir_assign_var_locations_direct_first(nir_shader *shader,
106 struct exec_list *var_list,
107 unsigned *direct_size,
108 unsigned *size,
109 int (*type_size)(const struct glsl_type *))
110 {
111 struct set *indirect_set = _mesa_set_create(NULL, _mesa_hash_pointer,
112 _mesa_key_pointer_equal);
113
114 nir_foreach_overload(shader, overload) {
115 if (overload->impl)
116 nir_foreach_block(overload->impl, mark_indirect_uses_block,
117 indirect_set);
118 }
119
120 unsigned location = 0;
121
122 foreach_list_typed(nir_variable, var, node, var_list) {
123 if ((var->data.mode == nir_var_uniform || var->data.mode == nir_var_shader_storage) &&
124 var->interface_type != NULL)
125 continue;
126
127 if (_mesa_set_search(indirect_set, var))
128 continue;
129
130 var->data.driver_location = location;
131 location += type_size(var->type);
132 }
133
134 *direct_size = location;
135
136 foreach_list_typed(nir_variable, var, node, var_list) {
137 if ((var->data.mode == nir_var_uniform || var->data.mode == nir_var_shader_storage) &&
138 var->interface_type != NULL)
139 continue;
140
141 if (!_mesa_set_search(indirect_set, var))
142 continue;
143
144 var->data.driver_location = location;
145 location += type_size(var->type);
146 }
147
148 *size = location;
149
150 _mesa_set_destroy(indirect_set, NULL);
151 }
152
153 static unsigned
154 get_io_offset(nir_deref_var *deref, nir_instr *instr, nir_src *indirect,
155 struct lower_io_state *state)
156 {
157 bool found_indirect = false;
158 unsigned base_offset = 0;
159
160 nir_builder *b = &state->builder;
161 nir_builder_insert_before_instr(b, instr);
162
163 nir_deref *tail = &deref->deref;
164 while (tail->child != NULL) {
165 const struct glsl_type *parent_type = tail->type;
166 tail = tail->child;
167
168 if (tail->deref_type == nir_deref_type_array) {
169 nir_deref_array *deref_array = nir_deref_as_array(tail);
170 unsigned size = state->type_size(tail->type);
171
172 base_offset += size * deref_array->base_offset;
173
174 if (deref_array->deref_array_type == nir_deref_array_type_indirect) {
175 nir_ssa_def *mul =
176 nir_imul(b, nir_imm_int(b, size),
177 nir_ssa_for_src(b, deref_array->indirect, 1));
178
179 if (found_indirect) {
180 indirect->ssa =
181 nir_iadd(b, nir_ssa_for_src(b, *indirect, 1), mul);
182 } else {
183 indirect->ssa = mul;
184 }
185 indirect->is_ssa = true;
186 found_indirect = true;
187 }
188 } else if (tail->deref_type == nir_deref_type_struct) {
189 nir_deref_struct *deref_struct = nir_deref_as_struct(tail);
190
191 for (unsigned i = 0; i < deref_struct->index; i++) {
192 base_offset +=
193 state->type_size(glsl_get_struct_field(parent_type, i));
194 }
195 }
196 }
197
198 return base_offset;
199 }
200
201 static nir_intrinsic_op
202 load_op(nir_variable_mode mode, bool has_indirect)
203 {
204 nir_intrinsic_op op;
205 switch (mode) {
206 case nir_var_shader_in:
207 op = has_indirect ? nir_intrinsic_load_input_indirect :
208 nir_intrinsic_load_input;
209 break;
210 case nir_var_uniform:
211 op = has_indirect ? nir_intrinsic_load_uniform_indirect :
212 nir_intrinsic_load_uniform;
213 break;
214 default:
215 unreachable("Unknown variable mode");
216 }
217 return op;
218 }
219
220 static bool
221 nir_lower_io_block(nir_block *block, void *void_state)
222 {
223 struct lower_io_state *state = void_state;
224
225 nir_foreach_instr_safe(block, instr) {
226 if (instr->type != nir_instr_type_intrinsic)
227 continue;
228
229 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
230
231 switch (intrin->intrinsic) {
232 case nir_intrinsic_load_var: {
233 nir_variable_mode mode = intrin->variables[0]->var->data.mode;
234 if (mode != nir_var_shader_in && mode != nir_var_uniform)
235 continue;
236
237 bool has_indirect = deref_has_indirect(intrin->variables[0]);
238
239 nir_intrinsic_instr *load =
240 nir_intrinsic_instr_create(state->mem_ctx,
241 load_op(mode, has_indirect));
242 load->num_components = intrin->num_components;
243
244 nir_src indirect;
245 unsigned offset = get_io_offset(intrin->variables[0],
246 &intrin->instr, &indirect, state);
247
248 unsigned location = intrin->variables[0]->var->data.driver_location;
249 if (mode == nir_var_uniform) {
250 load->const_index[0] = location;
251 load->const_index[1] = offset;
252 } else {
253 load->const_index[0] = location + offset;
254 }
255
256 if (has_indirect)
257 load->src[0] = indirect;
258
259 if (intrin->dest.is_ssa) {
260 nir_ssa_dest_init(&load->instr, &load->dest,
261 intrin->num_components, NULL);
262 nir_ssa_def_rewrite_uses(&intrin->dest.ssa,
263 nir_src_for_ssa(&load->dest.ssa),
264 state->mem_ctx);
265 } else {
266 nir_dest_copy(&load->dest, &intrin->dest, state->mem_ctx);
267 }
268
269 nir_instr_insert_before(&intrin->instr, &load->instr);
270 nir_instr_remove(&intrin->instr);
271 break;
272 }
273
274 case nir_intrinsic_store_var: {
275 if (intrin->variables[0]->var->data.mode != nir_var_shader_out)
276 continue;
277
278 bool has_indirect = deref_has_indirect(intrin->variables[0]);
279
280 nir_intrinsic_op store_op;
281 if (has_indirect) {
282 store_op = nir_intrinsic_store_output_indirect;
283 } else {
284 store_op = nir_intrinsic_store_output;
285 }
286
287 nir_intrinsic_instr *store = nir_intrinsic_instr_create(state->mem_ctx,
288 store_op);
289 store->num_components = intrin->num_components;
290
291 nir_src indirect;
292 unsigned offset = get_io_offset(intrin->variables[0],
293 &intrin->instr, &indirect, state);
294 offset += intrin->variables[0]->var->data.driver_location;
295
296 store->const_index[0] = offset;
297
298 nir_src_copy(&store->src[0], &intrin->src[0], state->mem_ctx);
299
300 if (has_indirect)
301 store->src[1] = indirect;
302
303 nir_instr_insert_before(&intrin->instr, &store->instr);
304 nir_instr_remove(&intrin->instr);
305 break;
306 }
307
308 default:
309 break;
310 }
311 }
312
313 return true;
314 }
315
316 static void
317 nir_lower_io_impl(nir_function_impl *impl, int(*type_size)(const struct glsl_type *))
318 {
319 struct lower_io_state state;
320
321 nir_builder_init(&state.builder, impl);
322 state.mem_ctx = ralloc_parent(impl);
323 state.type_size = type_size;
324
325 nir_foreach_block(impl, nir_lower_io_block, &state);
326
327 nir_metadata_preserve(impl, nir_metadata_block_index |
328 nir_metadata_dominance);
329 }
330
331 void
332 nir_lower_io(nir_shader *shader, int(*type_size)(const struct glsl_type *))
333 {
334 nir_foreach_overload(shader, overload) {
335 if (overload->impl)
336 nir_lower_io_impl(overload->impl, type_size);
337 }
338 }