• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2015 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 
24 #include "main/mtypes.h"
25 #include "nir.h"
26 
27 static void
set_io_mask(nir_shader * shader,nir_variable * var,int offset,int len,bool is_output_read)28 set_io_mask(nir_shader *shader, nir_variable *var, int offset, int len,
29             bool is_output_read)
30 {
31    for (int i = 0; i < len; i++) {
32       assert(var->data.location != -1);
33 
34       int idx = var->data.location + offset + i;
35       bool is_patch_generic = var->data.patch &&
36                               idx != VARYING_SLOT_TESS_LEVEL_INNER &&
37                               idx != VARYING_SLOT_TESS_LEVEL_OUTER &&
38                               idx != VARYING_SLOT_BOUNDING_BOX0 &&
39                               idx != VARYING_SLOT_BOUNDING_BOX1;
40       uint64_t bitfield;
41 
42       if (is_patch_generic) {
43          assert(idx >= VARYING_SLOT_PATCH0 && idx < VARYING_SLOT_TESS_MAX);
44          bitfield = BITFIELD64_BIT(idx - VARYING_SLOT_PATCH0);
45       }
46       else {
47          assert(idx < VARYING_SLOT_MAX);
48          bitfield = BITFIELD64_BIT(idx);
49       }
50 
51       if (var->data.mode == nir_var_shader_in) {
52          if (is_patch_generic)
53             shader->info.patch_inputs_read |= bitfield;
54          else
55             shader->info.inputs_read |= bitfield;
56 
57          if (shader->info.stage == MESA_SHADER_FRAGMENT) {
58             shader->info.fs.uses_sample_qualifier |= var->data.sample;
59          }
60       } else {
61          assert(var->data.mode == nir_var_shader_out);
62          if (is_output_read) {
63             if (is_patch_generic) {
64                shader->info.patch_outputs_read |= bitfield;
65             } else {
66                shader->info.outputs_read |= bitfield;
67             }
68          } else {
69 	    if (is_patch_generic) {
70 	       shader->info.patch_outputs_written |= bitfield;
71 	    } else if (!var->data.read_only) {
72 	       shader->info.outputs_written |= bitfield;
73 	    }
74 	 }
75 
76 
77          if (var->data.fb_fetch_output)
78             shader->info.outputs_read |= bitfield;
79       }
80    }
81 }
82 
83 /**
84  * Mark an entire variable as used.  Caller must ensure that the variable
85  * represents a shader input or output.
86  */
87 static void
mark_whole_variable(nir_shader * shader,nir_variable * var,bool is_output_read)88 mark_whole_variable(nir_shader *shader, nir_variable *var, bool is_output_read)
89 {
90    const struct glsl_type *type = var->type;
91 
92    if (nir_is_per_vertex_io(var, shader->info.stage)) {
93       assert(glsl_type_is_array(type));
94       type = glsl_get_array_element(type);
95    }
96 
97    const unsigned slots =
98       var->data.compact ? DIV_ROUND_UP(glsl_get_length(type), 4)
99                         : glsl_count_attribute_slots(type, false);
100 
101    set_io_mask(shader, var, 0, slots, is_output_read);
102 }
103 
104 static unsigned
get_io_offset(nir_deref_var * deref)105 get_io_offset(nir_deref_var *deref)
106 {
107    unsigned offset = 0;
108 
109    nir_deref *tail = &deref->deref;
110    while (tail->child != NULL) {
111       tail = tail->child;
112 
113       if (tail->deref_type == nir_deref_type_array) {
114          nir_deref_array *deref_array = nir_deref_as_array(tail);
115 
116          if (deref_array->deref_array_type == nir_deref_array_type_indirect) {
117             return -1;
118          }
119 
120          offset += glsl_count_attribute_slots(tail->type, false) *
121             deref_array->base_offset;
122       }
123       /* TODO: we can get the offset for structs here see nir_lower_io() */
124    }
125 
126    return offset;
127 }
128 
129 /**
130  * Try to mark a portion of the given varying as used.  Caller must ensure
131  * that the variable represents a shader input or output.
132  *
133  * If the index can't be interpreted as a constant, or some other problem
134  * occurs, then nothing will be marked and false will be returned.
135  */
136 static bool
try_mask_partial_io(nir_shader * shader,nir_deref_var * deref,bool is_output_read)137 try_mask_partial_io(nir_shader *shader, nir_deref_var *deref, bool is_output_read)
138 {
139    nir_variable *var = deref->var;
140    const struct glsl_type *type = var->type;
141 
142    if (nir_is_per_vertex_io(var, shader->info.stage)) {
143       assert(glsl_type_is_array(type));
144       type = glsl_get_array_element(type);
145    }
146 
147    /* The code below only handles:
148     *
149     * - Indexing into matrices
150     * - Indexing into arrays of (arrays, matrices, vectors, or scalars)
151     *
152     * For now, we just give up if we see varying structs and arrays of structs
153     * here marking the entire variable as used.
154     */
155    if (!(glsl_type_is_matrix(type) ||
156          (glsl_type_is_array(type) && !var->data.compact &&
157           (glsl_type_is_numeric(glsl_without_array(type)) ||
158            glsl_type_is_boolean(glsl_without_array(type)))))) {
159 
160       /* If we don't know how to handle this case, give up and let the
161        * caller mark the whole variable as used.
162        */
163       return false;
164    }
165 
166    unsigned offset = get_io_offset(deref);
167    if (offset == -1)
168       return false;
169 
170    unsigned num_elems;
171    unsigned elem_width = 1;
172    unsigned mat_cols = 1;
173    if (glsl_type_is_array(type)) {
174       num_elems = glsl_get_aoa_size(type);
175       if (glsl_type_is_matrix(glsl_without_array(type)))
176          mat_cols = glsl_get_matrix_columns(glsl_without_array(type));
177    } else {
178       num_elems = glsl_get_matrix_columns(type);
179    }
180 
181    /* double element width for double types that takes two slots */
182    if (glsl_type_is_dual_slot(glsl_without_array(type))) {
183       elem_width *= 2;
184    }
185 
186    if (offset >= num_elems * elem_width * mat_cols) {
187       /* Constant index outside the bounds of the matrix/array.  This could
188        * arise as a result of constant folding of a legal GLSL program.
189        *
190        * Even though the spec says that indexing outside the bounds of a
191        * matrix/array results in undefined behaviour, we don't want to pass
192        * out-of-range values to set_io_mask() (since this could result in
193        * slots that don't exist being marked as used), so just let the caller
194        * mark the whole variable as used.
195        */
196       return false;
197    }
198 
199    set_io_mask(shader, var, offset, elem_width, is_output_read);
200    return true;
201 }
202 
203 static void
gather_intrinsic_info(nir_intrinsic_instr * instr,nir_shader * shader)204 gather_intrinsic_info(nir_intrinsic_instr *instr, nir_shader *shader)
205 {
206    switch (instr->intrinsic) {
207    case nir_intrinsic_discard:
208    case nir_intrinsic_discard_if:
209       assert(shader->info.stage == MESA_SHADER_FRAGMENT);
210       shader->info.fs.uses_discard = true;
211       break;
212 
213    case nir_intrinsic_interp_var_at_centroid:
214    case nir_intrinsic_interp_var_at_sample:
215    case nir_intrinsic_interp_var_at_offset:
216    case nir_intrinsic_load_var:
217    case nir_intrinsic_store_var: {
218       nir_variable *var = instr->variables[0]->var;
219 
220       if (var->data.mode == nir_var_shader_in ||
221           var->data.mode == nir_var_shader_out) {
222          bool is_output_read = false;
223          if (var->data.mode == nir_var_shader_out &&
224              instr->intrinsic == nir_intrinsic_load_var)
225             is_output_read = true;
226 
227          if (!try_mask_partial_io(shader, instr->variables[0], is_output_read))
228             mark_whole_variable(shader, var, is_output_read);
229 
230          /* We need to track which input_reads bits correspond to a
231           * dvec3/dvec4 input attribute */
232          if (shader->info.stage == MESA_SHADER_VERTEX &&
233              var->data.mode == nir_var_shader_in &&
234              glsl_type_is_dual_slot(glsl_without_array(var->type))) {
235             for (uint i = 0; i < glsl_count_attribute_slots(var->type, false); i++) {
236                int idx = var->data.location + i;
237                shader->info.double_inputs_read |= BITFIELD64_BIT(idx);
238             }
239          }
240       }
241       break;
242    }
243 
244    case nir_intrinsic_load_draw_id:
245    case nir_intrinsic_load_frag_coord:
246    case nir_intrinsic_load_front_face:
247    case nir_intrinsic_load_vertex_id:
248    case nir_intrinsic_load_vertex_id_zero_base:
249    case nir_intrinsic_load_base_vertex:
250    case nir_intrinsic_load_base_instance:
251    case nir_intrinsic_load_instance_id:
252    case nir_intrinsic_load_sample_id:
253    case nir_intrinsic_load_sample_pos:
254    case nir_intrinsic_load_sample_mask_in:
255    case nir_intrinsic_load_primitive_id:
256    case nir_intrinsic_load_invocation_id:
257    case nir_intrinsic_load_local_invocation_id:
258    case nir_intrinsic_load_local_invocation_index:
259    case nir_intrinsic_load_work_group_id:
260    case nir_intrinsic_load_num_work_groups:
261    case nir_intrinsic_load_tess_coord:
262    case nir_intrinsic_load_tess_level_outer:
263    case nir_intrinsic_load_tess_level_inner:
264    case nir_intrinsic_load_patch_vertices_in:
265       shader->info.system_values_read |=
266          (1ull << nir_system_value_from_intrinsic(instr->intrinsic));
267       break;
268 
269    case nir_intrinsic_end_primitive:
270    case nir_intrinsic_end_primitive_with_counter:
271       assert(shader->info.stage == MESA_SHADER_GEOMETRY);
272       shader->info.gs.uses_end_primitive = 1;
273       break;
274 
275    default:
276       break;
277    }
278 }
279 
280 static void
gather_tex_info(nir_tex_instr * instr,nir_shader * shader)281 gather_tex_info(nir_tex_instr *instr, nir_shader *shader)
282 {
283    switch (instr->op) {
284    case nir_texop_tg4:
285       shader->info.uses_texture_gather = true;
286       break;
287    case nir_texop_txf:
288    case nir_texop_txf_ms:
289    case nir_texop_txf_ms_mcs:
290       shader->info.textures_used_by_txf |=
291          ((1 << MAX2(instr->texture_array_size, 1)) - 1) <<
292          instr->texture_index;
293       break;
294    default:
295       break;
296    }
297 }
298 
299 static void
gather_alu_info(nir_alu_instr * instr,nir_shader * shader)300 gather_alu_info(nir_alu_instr *instr, nir_shader *shader)
301 {
302    switch (instr->op) {
303    case nir_op_fddx:
304    case nir_op_fddy:
305       shader->info.uses_fddx_fddy = true;
306       break;
307    default:
308       break;
309    }
310 }
311 
312 static void
gather_info_block(nir_block * block,nir_shader * shader)313 gather_info_block(nir_block *block, nir_shader *shader)
314 {
315    nir_foreach_instr(instr, block) {
316       switch (instr->type) {
317       case nir_instr_type_alu:
318          gather_alu_info(nir_instr_as_alu(instr), shader);
319          break;
320       case nir_instr_type_intrinsic:
321          gather_intrinsic_info(nir_instr_as_intrinsic(instr), shader);
322          break;
323       case nir_instr_type_tex:
324          gather_tex_info(nir_instr_as_tex(instr), shader);
325          break;
326       case nir_instr_type_call:
327          assert(!"nir_shader_gather_info only works if functions are inlined");
328          break;
329       default:
330          break;
331       }
332    }
333 }
334 
335 void
nir_shader_gather_info(nir_shader * shader,nir_function_impl * entrypoint)336 nir_shader_gather_info(nir_shader *shader, nir_function_impl *entrypoint)
337 {
338    shader->info.num_textures = 0;
339    shader->info.num_images = 0;
340    nir_foreach_variable(var, &shader->uniforms) {
341       const struct glsl_type *type = var->type;
342       unsigned count = 1;
343       if (glsl_type_is_array(type)) {
344          count = glsl_get_aoa_size(type);
345          type = glsl_without_array(type);
346       }
347 
348       if (glsl_type_is_image(type)) {
349          shader->info.num_images += count;
350       } else if (glsl_type_is_sampler(type)) {
351          shader->info.num_textures += count;
352       }
353    }
354 
355    shader->info.inputs_read = 0;
356    shader->info.outputs_written = 0;
357    shader->info.outputs_read = 0;
358    shader->info.patch_outputs_read = 0;
359    shader->info.double_inputs_read = 0;
360    shader->info.patch_inputs_read = 0;
361    shader->info.patch_outputs_written = 0;
362    shader->info.system_values_read = 0;
363    if (shader->info.stage == MESA_SHADER_FRAGMENT) {
364       shader->info.fs.uses_sample_qualifier = false;
365    }
366    nir_foreach_block(block, entrypoint) {
367       gather_info_block(block, shader);
368    }
369 }
370