• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2013 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 "link_uniform_block_active_visitor.h"
25 #include "program.h"
26 
27 static link_uniform_block_active *
process_block(void * mem_ctx,struct hash_table * ht,ir_variable * var)28 process_block(void *mem_ctx, struct hash_table *ht, ir_variable *var)
29 {
30    const hash_entry *const existing_block =
31       _mesa_hash_table_search(ht, var->get_interface_type()->name);
32 
33    const glsl_type *const block_type = var->is_interface_instance()
34       ? var->type : var->get_interface_type();
35 
36 
37    /* If a block with this block-name has not previously been seen, add it.
38     * If a block with this block-name has been seen, it must be identical to
39     * the block currently being examined.
40     */
41    if (existing_block == NULL) {
42       link_uniform_block_active *const b =
43          rzalloc(mem_ctx, struct link_uniform_block_active);
44 
45       b->type = block_type;
46       b->has_instance_name = var->is_interface_instance();
47       b->is_shader_storage = var->data.mode == ir_var_shader_storage;
48 
49       if (var->data.explicit_binding) {
50          b->has_binding = true;
51          b->binding = var->data.binding;
52       } else {
53          b->has_binding = false;
54          b->binding = 0;
55       }
56 
57       _mesa_hash_table_insert(ht, var->get_interface_type()->name, (void *) b);
58       return b;
59    } else {
60       link_uniform_block_active *const b =
61          (link_uniform_block_active *) existing_block->data;
62 
63       if (b->type != block_type
64           || b->has_instance_name != var->is_interface_instance())
65          return NULL;
66       else
67          return b;
68    }
69 
70    assert(!"Should not get here.");
71    return NULL;
72 }
73 
74 /* For arrays of arrays this function will give us a middle ground between
75  * detecting inactive uniform blocks and structuring them in a way that makes
76  * it easy to calculate the offset for indirect indexing.
77  *
78  * For example given the shader:
79  *
80  *   uniform ArraysOfArraysBlock
81  *   {
82  *      vec4 a;
83  *   } i[3][4][5];
84  *
85  *   void main()
86  *   {
87  *      vec4 b = i[0][1][1].a;
88  *      gl_Position = i[2][2][3].a + b;
89  *   }
90  *
91  * There are only 2 active blocks above but for the sake of indirect indexing
92  * and not over complicating the code we will end up with a count of 8.  Here
93  * each dimension has 2 different indices counted so we end up with 2*2*2
94  */
95 static struct uniform_block_array_elements **
process_arrays(void * mem_ctx,ir_dereference_array * ir,struct link_uniform_block_active * block)96 process_arrays(void *mem_ctx, ir_dereference_array *ir,
97                struct link_uniform_block_active *block)
98 {
99    if (ir) {
100       struct uniform_block_array_elements **ub_array_ptr =
101          process_arrays(mem_ctx, ir->array->as_dereference_array(), block);
102       if (*ub_array_ptr == NULL) {
103          *ub_array_ptr = rzalloc(mem_ctx, struct uniform_block_array_elements);
104          (*ub_array_ptr)->ir = ir;
105       }
106 
107       struct uniform_block_array_elements *ub_array = *ub_array_ptr;
108       ir_constant *c = ir->array_index->as_constant();
109       if (c) {
110          /* Index is a constant, so mark just that element used, if not
111           * already.
112           */
113          const unsigned idx = c->get_uint_component(0);
114 
115          unsigned i;
116          for (i = 0; i < ub_array->num_array_elements; i++) {
117             if (ub_array->array_elements[i] == idx)
118                break;
119          }
120 
121          assert(i <= ub_array->num_array_elements);
122 
123          if (i == ub_array->num_array_elements) {
124             ub_array->array_elements = reralloc(mem_ctx,
125                                                 ub_array->array_elements,
126                                                 unsigned,
127                                                 ub_array->num_array_elements + 1);
128 
129             ub_array->array_elements[ub_array->num_array_elements] = idx;
130 
131             ub_array->num_array_elements++;
132          }
133       } else {
134          /* The array index is not a constant, so mark the entire array used. */
135          assert(ir->array->type->is_array());
136          if (ub_array->num_array_elements < ir->array->type->length) {
137             ub_array->num_array_elements = ir->array->type->length;
138             ub_array->array_elements = reralloc(mem_ctx,
139                                                 ub_array->array_elements,
140                                                 unsigned,
141                                                 ub_array->num_array_elements);
142 
143             for (unsigned i = 0; i < ub_array->num_array_elements; i++) {
144                ub_array->array_elements[i] = i;
145             }
146          }
147       }
148 
149       return &ub_array->array;
150    } else {
151       return &block->array;
152    }
153 }
154 
155 ir_visitor_status
visit(ir_variable * var)156 link_uniform_block_active_visitor::visit(ir_variable *var)
157 {
158    if (!var->is_in_buffer_block())
159       return visit_continue;
160 
161    /* Section 2.11.6 (Uniform Variables) of the OpenGL ES 3.0.3 spec says:
162     *
163     *     "All members of a named uniform block declared with a shared or
164     *     std140 layout qualifier are considered active, even if they are not
165     *     referenced in any shader in the program. The uniform block itself is
166     *     also considered active, even if no member of the block is
167     *     referenced."
168     */
169    if (var->get_interface_type_packing() == GLSL_INTERFACE_PACKING_PACKED)
170       return visit_continue;
171 
172    /* Process the block.  Bail if there was an error. */
173    link_uniform_block_active *const b =
174       process_block(this->mem_ctx, this->ht, var);
175    if (b == NULL) {
176       linker_error(this->prog,
177                    "uniform block `%s' has mismatching definitions",
178                    var->get_interface_type()->name);
179       this->success = false;
180       return visit_stop;
181    }
182 
183    assert(b->array == NULL);
184    assert(b->type != NULL);
185    assert(!b->type->is_array() || b->has_instance_name);
186 
187    /* For uniform block arrays declared with a shared or std140 layout
188     * qualifier, mark all its instances as used.
189     */
190    const glsl_type *type = b->type;
191    struct uniform_block_array_elements **ub_array = &b->array;
192    while (type->is_array()) {
193       assert(b->type->length > 0);
194 
195       *ub_array = rzalloc(this->mem_ctx, struct uniform_block_array_elements);
196       (*ub_array)->num_array_elements = type->length;
197       (*ub_array)->array_elements = reralloc(this->mem_ctx,
198                                              (*ub_array)->array_elements,
199                                              unsigned,
200                                              (*ub_array)->num_array_elements);
201 
202       for (unsigned i = 0; i < (*ub_array)->num_array_elements; i++) {
203          (*ub_array)->array_elements[i] = i;
204       }
205       ub_array = &(*ub_array)->array;
206       type = type->fields.array;
207    }
208 
209    return visit_continue;
210 }
211 
212 ir_visitor_status
visit_enter(ir_dereference_array * ir)213 link_uniform_block_active_visitor::visit_enter(ir_dereference_array *ir)
214 {
215    /* cycle through arrays of arrays */
216    ir_dereference_array *base_ir = ir;
217    while (base_ir->array->ir_type == ir_type_dereference_array)
218       base_ir = base_ir->array->as_dereference_array();
219 
220    ir_dereference_variable *const d =
221       base_ir->array->as_dereference_variable();
222    ir_variable *const var = (d == NULL) ? NULL : d->var;
223 
224    /* If the r-value being dereferenced is not a variable (e.g., a field of a
225     * structure) or is not a uniform block instance, continue.
226     *
227     * WARNING: It is not enough for the variable to be part of uniform block.
228     * It must represent the entire block.  Arrays (or matrices) inside blocks
229     * that lack an instance name are handled by the ir_dereference_variable
230     * function.
231     */
232    if (var == NULL
233        || !var->is_in_buffer_block()
234        || !var->is_interface_instance())
235       return visit_continue;
236 
237    /* Process the block.  Bail if there was an error. */
238    link_uniform_block_active *const b =
239       process_block(this->mem_ctx, this->ht, var);
240    if (b == NULL) {
241       linker_error(prog,
242                    "uniform block `%s' has mismatching definitions",
243                    var->get_interface_type()->name);
244       this->success = false;
245       return visit_stop;
246    }
247 
248    /* Block arrays must be declared with an instance name.
249     */
250    assert(b->has_instance_name);
251    assert(b->type != NULL);
252 
253    /* If the block array was declared with a shared or std140 layout
254     * qualifier, all its instances have been already marked as used in
255     * link_uniform_block_active_visitor::visit(ir_variable *).
256     */
257    if (var->get_interface_type_packing() == GLSL_INTERFACE_PACKING_PACKED) {
258       b->var = var;
259       process_arrays(this->mem_ctx, ir, b);
260    }
261 
262    return visit_continue_with_parent;
263 }
264 
265 ir_visitor_status
visit(ir_dereference_variable * ir)266 link_uniform_block_active_visitor::visit(ir_dereference_variable *ir)
267 {
268    ir_variable *var = ir->var;
269 
270    if (!var->is_in_buffer_block())
271       return visit_continue;
272 
273    assert(!var->is_interface_instance() || !var->type->is_array());
274 
275    /* Process the block.  Bail if there was an error. */
276    link_uniform_block_active *const b =
277       process_block(this->mem_ctx, this->ht, var);
278    if (b == NULL) {
279       linker_error(this->prog,
280                    "uniform block `%s' has mismatching definitions",
281                    var->get_interface_type()->name);
282       this->success = false;
283       return visit_stop;
284    }
285 
286    assert(b->array == NULL);
287    assert(b->type != NULL);
288 
289    return visit_continue;
290 }
291