• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2019 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
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "compiler/nir/nir.h"
25 #include "compiler/nir/nir_builder.h"
26 #include "gl_nir.h"
27 
28 #include "util/compiler.h"
29 #include "main/shader_types.h"
30 
31 static nir_def *
get_block_array_index(nir_builder * b,nir_deref_instr * deref,const struct gl_shader_program * shader_program)32 get_block_array_index(nir_builder *b, nir_deref_instr *deref,
33                       const struct gl_shader_program *shader_program)
34 {
35    unsigned array_elements = 1;
36 
37    /* Build a block name such as "block[2][0]" for finding in the list of
38     * blocks later on as well as an optional dynamic index which gets added
39     * to the block index later.
40     */
41    int const_array_offset = 0;
42    const char *block_name = "";
43    nir_def *nonconst_index = NULL;
44    while (deref->deref_type == nir_deref_type_array) {
45       nir_deref_instr *parent = nir_deref_instr_parent(deref);
46       assert(parent && glsl_type_is_array(parent->type));
47       unsigned arr_size = glsl_get_length(parent->type);
48 
49       if (nir_src_is_const(deref->arr.index)) {
50          unsigned arr_index = nir_src_as_uint(deref->arr.index);
51 
52          /* We're walking the deref from the tail so prepend the array index */
53          block_name = ralloc_asprintf(b->shader, "[%u]%s", arr_index,
54                                       block_name);
55 
56          const_array_offset += arr_index * array_elements;
57       } else {
58          nir_def *arr_index = deref->arr.index.ssa;
59          arr_index = nir_umin(b, arr_index, nir_imm_int(b, arr_size - 1));
60          nir_def *arr_offset = nir_amul_imm(b, arr_index, array_elements);
61          if (nonconst_index)
62             nonconst_index = nir_iadd(b, nonconst_index, arr_offset);
63          else
64             nonconst_index = arr_offset;
65 
66          /* We're walking the deref from the tail so prepend the array index */
67          block_name = ralloc_asprintf(b->shader, "[0]%s", block_name);
68       }
69 
70       array_elements *= arr_size;
71       deref = parent;
72    }
73 
74    assert(deref->deref_type == nir_deref_type_var);
75    int binding = const_array_offset + deref->var->data.binding;
76    block_name = ralloc_asprintf(b->shader, "%s%s",
77                                 glsl_get_type_name(deref->var->interface_type),
78                                 block_name);
79 
80    struct gl_linked_shader *linked_shader =
81       shader_program->_LinkedShaders[b->shader->info.stage];
82 
83    unsigned num_blocks;
84    struct gl_uniform_block **blocks;
85    if (nir_deref_mode_is(deref, nir_var_mem_ubo)) {
86       num_blocks = linked_shader->Program->info.num_ubos;
87       blocks = linked_shader->Program->sh.UniformBlocks;
88    } else {
89       assert(nir_deref_mode_is(deref, nir_var_mem_ssbo));
90       num_blocks = linked_shader->Program->info.num_ssbos;
91       blocks = linked_shader->Program->sh.ShaderStorageBlocks;
92    }
93 
94    /* Block names are optional with ARB_gl_spirv so use the binding instead. */
95    bool use_bindings = shader_program->data->spirv;
96 
97    for (unsigned i = 0; i < num_blocks; i++) {
98       if (( use_bindings && binding == blocks[i]->Binding) ||
99           (!use_bindings && strcmp(block_name, blocks[i]->name.string) == 0)) {
100          deref->var->data.driver_location = i - const_array_offset;
101          if (nonconst_index)
102             return nir_iadd_imm(b, nonconst_index, i);
103          else
104             return nir_imm_int(b, i);
105       }
106    }
107 
108    /* TODO: Investigate if we could change the code to assign Bindings to the
109     * blocks that were not explicitly assigned, so we can always compare
110     * bindings.
111     */
112 
113    if (use_bindings)
114       unreachable("Failed to find the block by binding");
115    else
116       unreachable("Failed to find the block by name");
117 }
118 
119 static void
get_block_index_offset(nir_variable * var,const struct gl_shader_program * shader_program,gl_shader_stage stage,unsigned * index,unsigned * offset)120 get_block_index_offset(nir_variable *var,
121                        const struct gl_shader_program *shader_program,
122                        gl_shader_stage stage,
123                        unsigned *index, unsigned *offset)
124 {
125 
126    struct gl_linked_shader *linked_shader =
127       shader_program->_LinkedShaders[stage];
128 
129    unsigned num_blocks;
130    struct gl_uniform_block **blocks;
131    if (var->data.mode == nir_var_mem_ubo) {
132       num_blocks = linked_shader->Program->info.num_ubos;
133       blocks = linked_shader->Program->sh.UniformBlocks;
134    } else {
135       assert(var->data.mode == nir_var_mem_ssbo);
136       num_blocks = linked_shader->Program->info.num_ssbos;
137       blocks = linked_shader->Program->sh.ShaderStorageBlocks;
138    }
139 
140    /* Block names are optional with ARB_gl_spirv so use the binding instead. */
141    bool use_bindings = shader_program->data->spirv;
142 
143    for (unsigned i = 0; i < num_blocks; i++) {
144       const char *block_name = glsl_get_type_name(var->interface_type);
145       if (( use_bindings && blocks[i]->Binding == var->data.binding) ||
146           (!use_bindings && strcmp(block_name, blocks[i]->name.string) == 0)) {
147          var->data.driver_location = i;
148          *index = i;
149          *offset = blocks[i]->Uniforms[var->data.location].Offset;
150          return;
151       }
152    }
153 
154    if (use_bindings)
155       unreachable("Failed to find the block by binding");
156    else
157       unreachable("Failed to find the block by name");
158 }
159 
160 static bool
lower_buffer_interface_derefs_impl(nir_function_impl * impl,const struct gl_shader_program * shader_program)161 lower_buffer_interface_derefs_impl(nir_function_impl *impl,
162                                    const struct gl_shader_program *shader_program)
163 {
164    bool progress = false;
165 
166    nir_builder b = nir_builder_create(impl);
167 
168    /* this must be a separate loop before the main pass in order to ensure that
169     * access info is fully propagated prior to the info being lost during rewrites
170     */
171    nir_foreach_block(block, impl) {
172       nir_foreach_instr(instr, block) {
173          if (instr->type != nir_instr_type_intrinsic)
174             continue;
175 
176          nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
177          if (intrin->intrinsic == nir_intrinsic_load_deref ||
178              intrin->intrinsic == nir_intrinsic_store_deref) {
179             nir_variable *var = nir_intrinsic_get_var(intrin, 0);
180             assert(var);
181             nir_intrinsic_set_access(intrin, nir_intrinsic_access(intrin) | var->data.access);
182          }
183       }
184    }
185 
186    nir_foreach_block(block, impl) {
187       nir_foreach_instr_safe(instr, block) {
188          switch (instr->type) {
189          case nir_instr_type_deref: {
190             nir_deref_instr *deref = nir_instr_as_deref(instr);
191             if (!nir_deref_mode_is_one_of(deref, nir_var_mem_ubo |
192                                                  nir_var_mem_ssbo))
193                break;
194 
195             /* We use nir_address_format_32bit_index_offset */
196             assert(deref->def.bit_size == 32);
197             deref->def.num_components = 2;
198 
199             progress = true;
200 
201             b.cursor = nir_before_instr(&deref->instr);
202 
203             unsigned offset = 0;
204             nir_def *ptr;
205             if (deref->deref_type == nir_deref_type_var &&
206                 !glsl_type_is_interface(glsl_without_array(deref->var->type))) {
207                /* This variable is contained in an interface block rather than
208                 * containing one.  We need the block index and its offset
209                 * inside that block
210                 */
211                unsigned index;
212                get_block_index_offset(deref->var, shader_program,
213                                       b.shader->info.stage,
214                                       &index, &offset);
215                ptr = nir_imm_ivec2(&b, index, offset);
216             } else if (glsl_type_is_interface(deref->type)) {
217                /* This is the last deref before the block boundary.
218                 * Everything after this point is a byte offset and will be
219                 * handled by nir_lower_explicit_io().
220                 */
221                nir_def *index = get_block_array_index(&b, deref,
222                                                           shader_program);
223                ptr = nir_vec2(&b, index, nir_imm_int(&b, offset));
224             } else {
225                /* This will get handled by nir_lower_explicit_io(). */
226                break;
227             }
228 
229             nir_deref_instr *cast = nir_build_deref_cast(&b, ptr, deref->modes,
230                                                          deref->type, 0);
231             /* Set the alignment on the cast so that we get good alignment out
232              * of nir_lower_explicit_io.  Our offset to the start of the UBO
233              * variable is always a constant, so we can use the maximum
234              * align_mul.
235              */
236             cast->cast.align_mul = NIR_ALIGN_MUL_MAX;
237             cast->cast.align_offset = offset % NIR_ALIGN_MUL_MAX;
238 
239             nir_def_rewrite_uses(&deref->def,
240                                      &cast->def);
241             nir_deref_instr_remove_if_unused(deref);
242             break;
243          }
244 
245          case nir_instr_type_intrinsic: {
246             nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
247             switch (intrin->intrinsic) {
248             case nir_intrinsic_load_deref: {
249                nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
250                if (!nir_deref_mode_is_one_of(deref, nir_var_mem_ubo |
251                                                     nir_var_mem_ssbo))
252                   break;
253 
254                /* UBO and SSBO Booleans are 32-bit integers where any non-zero
255                 * value is considered true.  NIR Booleans, on the other hand
256                 * are 1-bit values until you get to a very late stage of the
257                 * compilation process.  We need to turn those 1-bit loads into
258                 * a 32-bit load wrapped in an i2b to get a proper NIR boolean
259                 * from the SSBO.
260                 */
261                if (glsl_type_is_boolean(deref->type)) {
262                   b.cursor = nir_after_instr(&intrin->instr);
263                   intrin->def.bit_size = 32;
264                   nir_def *bval = nir_i2b(&b, &intrin->def);
265                   nir_def_rewrite_uses_after(&intrin->def,
266                                                  bval,
267                                                  bval->parent_instr);
268                   progress = true;
269                }
270                break;
271             }
272 
273             case nir_intrinsic_store_deref: {
274                nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
275                if (!nir_deref_mode_is_one_of(deref, nir_var_mem_ubo |
276                                                     nir_var_mem_ssbo))
277                   break;
278 
279                /* SSBO Booleans are 32-bit integers where any non-zero value
280                 * is considered true.  NIR Booleans, on the other hand are
281                 * 1-bit values until you get to a very late stage of the
282                 * compilation process.  We need to turn those 1-bit stores
283                 * into a b2i32 followed by a 32-bit store.  Technically the
284                 * value we write doesn't have to be 0/1 so once Booleans are
285                 * lowered to 32-bit values, we have an unneeded sanitation
286                 * step but in practice it doesn't cost much.
287                 */
288                if (glsl_type_is_boolean(deref->type)) {
289                   b.cursor = nir_before_instr(&intrin->instr);
290                   nir_def *ival = nir_b2i32(&b, intrin->src[1].ssa);
291                   nir_src_rewrite(&intrin->src[1], ival);
292                   progress = true;
293                }
294                break;
295             }
296 
297             case nir_intrinsic_copy_deref:
298                unreachable("copy_deref should be lowered by now");
299                break;
300 
301             default:
302                /* Nothing to do */
303                break;
304             }
305             break;
306          }
307 
308          default:
309             break; /* Nothing to do */
310          }
311       }
312    }
313 
314    if (progress) {
315       nir_metadata_preserve(impl, nir_metadata_control_flow);
316    } else {
317       nir_metadata_preserve(impl, nir_metadata_all);
318    }
319 
320    return progress;
321 }
322 
323 bool
gl_nir_lower_buffers(nir_shader * shader,const struct gl_shader_program * shader_program)324 gl_nir_lower_buffers(nir_shader *shader,
325                      const struct gl_shader_program *shader_program)
326 {
327    bool progress = false;
328 
329    nir_foreach_variable_with_modes(var, shader, nir_var_mem_ubo | nir_var_mem_ssbo) {
330       var->data.driver_location = -1;
331       progress = true;
332    }
333 
334    /* First, we lower the derefs to turn block variable and array derefs into
335     * a nir_address_format_32bit_index_offset pointer.  From there forward,
336     * we leave the derefs in place and let nir_lower_explicit_io handle them.
337     */
338    nir_foreach_function_impl(impl, shader) {
339       if (lower_buffer_interface_derefs_impl(impl, shader_program))
340          progress = true;
341    }
342 
343    /* If that did something, we validate and then call nir_lower_explicit_io
344     * to finish the process.
345     */
346    if (progress) {
347       nir_validate_shader(shader, "Lowering buffer interface derefs");
348       nir_lower_explicit_io(shader, nir_var_mem_ubo | nir_var_mem_ssbo,
349                             nir_address_format_32bit_index_offset);
350    }
351 
352    return progress;
353 }
354