Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 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. /**
  25.  * \file lower_named_interface_blocks.cpp
  26.  *
  27.  * This lowering pass converts all interface blocks with instance names
  28.  * into interface blocks without an instance name.
  29.  *
  30.  * For example, the following shader:
  31.  *
  32.  *   out block {
  33.  *     float block_var;
  34.  *   } inst_name;
  35.  *
  36.  *   main()
  37.  *   {
  38.  *     inst_name.block_var = 0.0;
  39.  *   }
  40.  *
  41.  * Is rewritten to:
  42.  *
  43.  *   out block {
  44.  *     float block_var;
  45.  *   };
  46.  *
  47.  *   main()
  48.  *   {
  49.  *     block_var = 0.0;
  50.  *   }
  51.  *
  52.  * This takes place after the shader code has already been verified with
  53.  * the interface name in place.
  54.  *
  55.  * The linking phase will use the interface block name rather than the
  56.  * interface's instance name when linking interfaces.
  57.  *
  58.  * This modification to the ir allows our currently existing dead code
  59.  * elimination to work with interface blocks without changes.
  60.  */
  61.  
  62. #include "glsl_symbol_table.h"
  63. #include "ir.h"
  64. #include "ir_optimization.h"
  65. #include "ir_rvalue_visitor.h"
  66. #include "program/hash_table.h"
  67.  
  68. class flatten_named_interface_blocks_declarations : public ir_rvalue_visitor
  69. {
  70. public:
  71.    void * const mem_ctx;
  72.    hash_table *interface_namespace;
  73.  
  74.    flatten_named_interface_blocks_declarations(void *mem_ctx)
  75.       : mem_ctx(mem_ctx),
  76.         interface_namespace(NULL)
  77.    {
  78.    }
  79.  
  80.    void run(exec_list *instructions);
  81.  
  82.    virtual ir_visitor_status visit_leave(ir_assignment *);
  83.    virtual void handle_rvalue(ir_rvalue **rvalue);
  84. };
  85.  
  86. void
  87. flatten_named_interface_blocks_declarations::run(exec_list *instructions)
  88. {
  89.    interface_namespace = hash_table_ctor(0, hash_table_string_hash,
  90.                                          hash_table_string_compare);
  91.  
  92.    /* First pass: adjust instance block variables with an instance name
  93.     * to not have an instance name.
  94.     *
  95.     * The interface block variables are stored in the interface_namespace
  96.     * hash table so they can be used in the second pass.
  97.     */
  98.    foreach_list_safe(node, instructions) {
  99.       ir_variable *var = ((ir_instruction *) node)->as_variable();
  100.       if (!var || !var->is_interface_instance())
  101.          continue;
  102.  
  103.       /* It should be possible to handle uniforms during this pass,
  104.        * but, this will require changes to the other uniform block
  105.        * support code.
  106.        */
  107.       if (var->mode == ir_var_uniform)
  108.          continue;
  109.  
  110.       const glsl_type * iface_t = var->type;
  111.       const glsl_type * array_t = NULL;
  112.       exec_node *insert_pos = var;
  113.  
  114.       if (iface_t->is_array()) {
  115.          array_t = iface_t;
  116.          iface_t = array_t->fields.array;
  117.       }
  118.  
  119.       assert (iface_t->is_interface());
  120.  
  121.       for (unsigned i = 0; i < iface_t->length; i++) {
  122.          const char * field_name = iface_t->fields.structure[i].name;
  123.          char *iface_field_name =
  124.             ralloc_asprintf(mem_ctx, "%s.%s",
  125.                             iface_t->name, field_name);
  126.  
  127.          ir_variable *found_var =
  128.             (ir_variable *) hash_table_find(interface_namespace,
  129.                                             iface_field_name);
  130.          if (!found_var) {
  131.             ir_variable *new_var;
  132.             if (array_t == NULL) {
  133.                char *var_name =
  134.                   ralloc_strdup(mem_ctx, iface_t->fields.structure[i].name);
  135.                new_var =
  136.                   new(mem_ctx) ir_variable(iface_t->fields.structure[i].type,
  137.                                            var_name,
  138.                                            (ir_variable_mode) var->mode);
  139.             } else {
  140.                const glsl_type *new_array_type =
  141.                   glsl_type::get_array_instance(
  142.                      iface_t->fields.structure[i].type,
  143.                      array_t->length);
  144.                char *var_name =
  145.                   ralloc_asprintf(mem_ctx, "%s[%d]",
  146.                                   iface_t->fields.structure[i].name,
  147.                                   array_t->length);
  148.                new_var =
  149.                   new(mem_ctx) ir_variable(new_array_type,
  150.                                            var_name,
  151.                                            (ir_variable_mode) var->mode);
  152.             }
  153.  
  154.             new_var->interface_type = iface_t;
  155.             hash_table_insert(interface_namespace, new_var,
  156.                               iface_field_name);
  157.             insert_pos->insert_after(new_var);
  158.             insert_pos = new_var;
  159.          }
  160.       }
  161.       var->remove();
  162.    }
  163.  
  164.    /* Second pass: visit all ir_dereference_record instances, and if they
  165.     * reference an interface block, then flatten the refererence out.
  166.     */
  167.    visit_list_elements(this, instructions);
  168.    hash_table_dtor(interface_namespace);
  169.    interface_namespace = NULL;
  170. }
  171.  
  172. ir_visitor_status
  173. flatten_named_interface_blocks_declarations::visit_leave(ir_assignment *ir)
  174. {
  175.    ir_dereference_record *lhs_rec = ir->lhs->as_dereference_record();
  176.    if (lhs_rec) {
  177.       ir_rvalue *lhs_rec_tmp = lhs_rec;
  178.       handle_rvalue(&lhs_rec_tmp);
  179.       if (lhs_rec_tmp != lhs_rec) {
  180.          ir->set_lhs(lhs_rec_tmp);
  181.       }
  182.    }
  183.    return rvalue_visit(ir);
  184. }
  185.  
  186. void
  187. flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue **rvalue)
  188. {
  189.    if (*rvalue == NULL)
  190.       return;
  191.  
  192.    ir_dereference_record *ir = (*rvalue)->as_dereference_record();
  193.    if (ir == NULL)
  194.       return;
  195.  
  196.    ir_variable *var = ir->variable_referenced();
  197.    if (var == NULL)
  198.       return;
  199.  
  200.    if (!var->is_interface_instance())
  201.       return;
  202.  
  203.    /* It should be possible to handle uniforms during this pass,
  204.     * but, this will require changes to the other uniform block
  205.     * support code.
  206.     */
  207.    if (var->mode == ir_var_uniform)
  208.       return;
  209.  
  210.    if (var->interface_type != NULL) {
  211.       char *iface_field_name =
  212.          ralloc_asprintf(mem_ctx, "%s.%s", var->interface_type->name,
  213.                          ir->field);
  214.       /* Find the variable in the set of flattened interface blocks */
  215.       ir_variable *found_var =
  216.          (ir_variable *) hash_table_find(interface_namespace,
  217.                                          iface_field_name);
  218.       assert(found_var);
  219.  
  220.       ir_dereference_variable *deref_var =
  221.          new(mem_ctx) ir_dereference_variable(found_var);
  222.  
  223.       ir_dereference_array *deref_array =
  224.          ir->record->as_dereference_array();
  225.       if (deref_array != NULL) {
  226.          *rvalue =
  227.             new(mem_ctx) ir_dereference_array(deref_var,
  228.                                               deref_array->array_index);
  229.       } else {
  230.          *rvalue = deref_var;
  231.       }
  232.    }
  233. }
  234.  
  235. void
  236. lower_named_interface_blocks(void *mem_ctx, gl_shader *shader)
  237. {
  238.    flatten_named_interface_blocks_declarations v_decl(mem_ctx);
  239.    v_decl.run(shader->ir);
  240. }
  241.  
  242.