Home | History | Annotate | Download | only in glsl
      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 *
     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 **
     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
    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
    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
    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