Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 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
 * NOTE: This pass really only works for scalar backends at the moment due
34
 * to the way it packes the input/output data.
35
 */
36
 
37
#include "nir.h"
38
 
39
struct lower_io_state {
40
   void *mem_ctx;
41
};
42
 
43
static unsigned
44
type_size(const struct glsl_type *type)
45
{
46
   unsigned int size, i;
47
 
48
   switch (glsl_get_base_type(type)) {
49
   case GLSL_TYPE_UINT:
50
   case GLSL_TYPE_INT:
51
   case GLSL_TYPE_FLOAT:
52
   case GLSL_TYPE_BOOL:
53
      return glsl_get_components(type);
54
   case GLSL_TYPE_ARRAY:
55
      return type_size(glsl_get_array_element(type)) * glsl_get_length(type);
56
   case GLSL_TYPE_STRUCT:
57
      size = 0;
58
      for (i = 0; i < glsl_get_length(type); i++) {
59
         size += type_size(glsl_get_struct_field(type, i));
60
      }
61
      return size;
62
   case GLSL_TYPE_SAMPLER:
63
      return 0;
64
   case GLSL_TYPE_ATOMIC_UINT:
65
      return 0;
66
   case GLSL_TYPE_INTERFACE:
67
      return 0;
68
   case GLSL_TYPE_IMAGE:
69
      return 0;
70
   case GLSL_TYPE_VOID:
71
   case GLSL_TYPE_ERROR:
72
   case GLSL_TYPE_DOUBLE:
73
      unreachable("not reached");
74
   }
75
 
76
   return 0;
77
}
78
 
79
void
80
nir_assign_var_locations_scalar(struct exec_list *var_list, unsigned *size)
81
{
82
   unsigned location = 0;
83
 
84
   foreach_list_typed(nir_variable, var, node, var_list) {
85
      /*
86
       * UBO's have their own address spaces, so don't count them towards the
87
       * number of global uniforms
88
       */
89
      if (var->data.mode == nir_var_uniform && var->interface_type != NULL)
90
         continue;
91
 
92
      var->data.driver_location = location;
93
      location += type_size(var->type);
94
   }
95
 
96
   *size = location;
97
}
98
 
99
static bool
100
deref_has_indirect(nir_deref_var *deref)
101
{
102
   for (nir_deref *tail = deref->deref.child; tail; tail = tail->child) {
103
      if (tail->deref_type == nir_deref_type_array) {
104
         nir_deref_array *arr = nir_deref_as_array(tail);
105
         if (arr->deref_array_type == nir_deref_array_type_indirect)
106
            return true;
107
      }
108
   }
109
 
110
   return false;
111
}
112
 
113
static bool
114
mark_indirect_uses_block(nir_block *block, void *void_state)
115
{
116
   struct set *indirect_set = void_state;
117
 
118
   nir_foreach_instr(block, instr) {
119
      if (instr->type != nir_instr_type_intrinsic)
120
         continue;
121
 
122
      nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
123
 
124
      for (unsigned i = 0;
125
           i < nir_intrinsic_infos[intrin->intrinsic].num_variables; i++) {
126
         if (deref_has_indirect(intrin->variables[i]))
127
            _mesa_set_add(indirect_set, intrin->variables[i]->var);
128
      }
129
   }
130
 
131
   return true;
132
}
133
 
134
/* Identical to nir_assign_var_locations_packed except that it assigns
135
 * locations to the variables that are used 100% directly first and then
136
 * assigns locations to variables that are used indirectly.
137
 */
138
void
139
nir_assign_var_locations_scalar_direct_first(nir_shader *shader,
140
                                             struct exec_list *var_list,
141
                                             unsigned *direct_size,
142
                                             unsigned *size)
143
{
144
   struct set *indirect_set = _mesa_set_create(NULL, _mesa_hash_pointer,
145
                                               _mesa_key_pointer_equal);
146
 
147
   nir_foreach_overload(shader, overload) {
148
      if (overload->impl)
149
         nir_foreach_block(overload->impl, mark_indirect_uses_block,
150
                           indirect_set);
151
   }
152
 
153
   unsigned location = 0;
154
 
155
   foreach_list_typed(nir_variable, var, node, var_list) {
156
      if (var->data.mode == nir_var_uniform && var->interface_type != NULL)
157
         continue;
158
 
159
      if (_mesa_set_search(indirect_set, var))
160
         continue;
161
 
162
      var->data.driver_location = location;
163
      location += type_size(var->type);
164
   }
165
 
166
   *direct_size = location;
167
 
168
   foreach_list_typed(nir_variable, var, node, var_list) {
169
      if (var->data.mode == nir_var_uniform && var->interface_type != NULL)
170
         continue;
171
 
172
      if (!_mesa_set_search(indirect_set, var))
173
         continue;
174
 
175
      var->data.driver_location = location;
176
      location += type_size(var->type);
177
   }
178
 
179
   *size = location;
180
 
181
   _mesa_set_destroy(indirect_set, NULL);
182
}
183
 
184
static unsigned
185
get_io_offset(nir_deref_var *deref, nir_instr *instr, nir_src *indirect,
186
              struct lower_io_state *state)
187
{
188
   bool found_indirect = false;
189
   unsigned base_offset = 0;
190
 
191
   nir_deref *tail = &deref->deref;
192
   while (tail->child != NULL) {
193
      const struct glsl_type *parent_type = tail->type;
194
      tail = tail->child;
195
 
196
      if (tail->deref_type == nir_deref_type_array) {
197
         nir_deref_array *deref_array = nir_deref_as_array(tail);
198
         unsigned size = type_size(tail->type);
199
 
200
         base_offset += size * deref_array->base_offset;
201
 
202
         if (deref_array->deref_array_type == nir_deref_array_type_indirect) {
203
            nir_load_const_instr *load_const =
204
               nir_load_const_instr_create(state->mem_ctx, 1);
205
            load_const->value.u[0] = size;
206
            nir_instr_insert_before(instr, &load_const->instr);
207
 
208
            nir_alu_instr *mul = nir_alu_instr_create(state->mem_ctx,
209
                                                      nir_op_imul);
210
            mul->src[0].src.is_ssa = true;
211
            mul->src[0].src.ssa = &load_const->def;
212
            nir_src_copy(&mul->src[1].src, &deref_array->indirect,
213
                         state->mem_ctx);
214
            mul->dest.write_mask = 1;
215
            nir_ssa_dest_init(&mul->instr, &mul->dest.dest, 1, NULL);
216
            nir_instr_insert_before(instr, &mul->instr);
217
 
218
            if (found_indirect) {
219
               nir_alu_instr *add = nir_alu_instr_create(state->mem_ctx,
220
                                                         nir_op_iadd);
221
               add->src[0].src = *indirect;
222
               add->src[1].src.is_ssa = true;
223
               add->src[1].src.ssa = &mul->dest.dest.ssa;
224
               add->dest.write_mask = 1;
225
               nir_ssa_dest_init(&add->instr, &add->dest.dest, 1, NULL);
226
               nir_instr_insert_before(instr, &add->instr);
227
 
228
               indirect->is_ssa = true;
229
               indirect->ssa = &add->dest.dest.ssa;
230
            } else {
231
               indirect->is_ssa = true;
232
               indirect->ssa = &mul->dest.dest.ssa;
233
               found_indirect = true;
234
            }
235
         }
236
      } else if (tail->deref_type == nir_deref_type_struct) {
237
         nir_deref_struct *deref_struct = nir_deref_as_struct(tail);
238
 
239
         for (unsigned i = 0; i < deref_struct->index; i++)
240
            base_offset += type_size(glsl_get_struct_field(parent_type, i));
241
      }
242
   }
243
 
244
   return base_offset;
245
}
246
 
247
static bool
248
nir_lower_io_block(nir_block *block, void *void_state)
249
{
250
   struct lower_io_state *state = void_state;
251
 
252
   nir_foreach_instr_safe(block, instr) {
253
      if (instr->type != nir_instr_type_intrinsic)
254
         continue;
255
 
256
      nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
257
 
258
      switch (intrin->intrinsic) {
259
      case nir_intrinsic_load_var: {
260
         nir_variable_mode mode = intrin->variables[0]->var->data.mode;
261
         if (mode != nir_var_shader_in && mode != nir_var_uniform)
262
            continue;
263
 
264
         bool has_indirect = deref_has_indirect(intrin->variables[0]);
265
 
266
         /* Figure out the opcode */
267
         nir_intrinsic_op load_op;
268
         switch (mode) {
269
         case nir_var_shader_in:
270
            load_op = has_indirect ? nir_intrinsic_load_input_indirect :
271
                                     nir_intrinsic_load_input;
272
            break;
273
         case nir_var_uniform:
274
            load_op = has_indirect ? nir_intrinsic_load_uniform_indirect :
275
                                     nir_intrinsic_load_uniform;
276
            break;
277
         default:
278
            unreachable("Unknown variable mode");
279
         }
280
 
281
         nir_intrinsic_instr *load = nir_intrinsic_instr_create(state->mem_ctx,
282
                                                                load_op);
283
         load->num_components = intrin->num_components;
284
 
285
         nir_src indirect;
286
         unsigned offset = get_io_offset(intrin->variables[0],
287
                                         &intrin->instr, &indirect, state);
288
         offset += intrin->variables[0]->var->data.driver_location;
289
 
290
         load->const_index[0] = offset;
291
         load->const_index[1] = 1;
292
 
293
         if (has_indirect)
294
            load->src[0] = indirect;
295
 
296
         if (intrin->dest.is_ssa) {
297
            nir_ssa_dest_init(&load->instr, &load->dest,
298
                              intrin->num_components, NULL);
299
            nir_ssa_def_rewrite_uses(&intrin->dest.ssa,
300
                                     nir_src_for_ssa(&load->dest.ssa),
301
                                     state->mem_ctx);
302
         } else {
303
            nir_dest_copy(&load->dest, &intrin->dest, state->mem_ctx);
304
         }
305
 
306
         nir_instr_insert_before(&intrin->instr, &load->instr);
307
         nir_instr_remove(&intrin->instr);
308
         break;
309
      }
310
 
311
      case nir_intrinsic_store_var: {
312
         if (intrin->variables[0]->var->data.mode != nir_var_shader_out)
313
            continue;
314
 
315
         bool has_indirect = deref_has_indirect(intrin->variables[0]);
316
 
317
         nir_intrinsic_op store_op;
318
         if (has_indirect) {
319
            store_op = nir_intrinsic_store_output_indirect;
320
         } else {
321
            store_op = nir_intrinsic_store_output;
322
         }
323
 
324
         nir_intrinsic_instr *store = nir_intrinsic_instr_create(state->mem_ctx,
325
                                                                 store_op);
326
         store->num_components = intrin->num_components;
327
 
328
         nir_src indirect;
329
         unsigned offset = get_io_offset(intrin->variables[0],
330
                                         &intrin->instr, &indirect, state);
331
         offset += intrin->variables[0]->var->data.driver_location;
332
 
333
         store->const_index[0] = offset;
334
         store->const_index[1] = 1;
335
 
336
         nir_src_copy(&store->src[0], &intrin->src[0], state->mem_ctx);
337
 
338
         if (has_indirect)
339
            store->src[1] = indirect;
340
 
341
         nir_instr_insert_before(&intrin->instr, &store->instr);
342
         nir_instr_remove(&intrin->instr);
343
         break;
344
      }
345
 
346
      default:
347
         break;
348
      }
349
   }
350
 
351
   return true;
352
}
353
 
354
static void
355
nir_lower_io_impl(nir_function_impl *impl)
356
{
357
   struct lower_io_state state;
358
 
359
   state.mem_ctx = ralloc_parent(impl);
360
 
361
   nir_foreach_block(impl, nir_lower_io_block, &state);
362
 
363
   nir_metadata_preserve(impl, nir_metadata_block_index |
364
                               nir_metadata_dominance);
365
}
366
 
367
void
368
nir_lower_io(nir_shader *shader)
369
{
370
   nir_foreach_overload(shader, overload) {
371
      if (overload->impl)
372
         nir_lower_io_impl(overload->impl);
373
   }
374
}