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