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. namespace {
  69.  
  70. class flatten_named_interface_blocks_declarations : public ir_rvalue_visitor
  71. {
  72. public:
  73.    void * const mem_ctx;
  74.    hash_table *interface_namespace;
  75.  
  76.    flatten_named_interface_blocks_declarations(void *mem_ctx)
  77.       : mem_ctx(mem_ctx),
  78.         interface_namespace(NULL)
  79.    {
  80.    }
  81.  
  82.    void run(exec_list *instructions);
  83.  
  84.    virtual ir_visitor_status visit_leave(ir_assignment *);
  85.    virtual void handle_rvalue(ir_rvalue **rvalue);
  86. };
  87.  
  88. } /* anonymous namespace */
  89.  
  90. void
  91. flatten_named_interface_blocks_declarations::run(exec_list *instructions)
  92. {
  93.    interface_namespace = hash_table_ctor(0, hash_table_string_hash,
  94.                                          hash_table_string_compare);
  95.  
  96.    /* First pass: adjust instance block variables with an instance name
  97.     * to not have an instance name.
  98.     *
  99.     * The interface block variables are stored in the interface_namespace
  100.     * hash table so they can be used in the second pass.
  101.     */
  102.    foreach_in_list_safe(ir_instruction, node, instructions) {
  103.       ir_variable *var = node->as_variable();
  104.       if (!var || !var->is_interface_instance())
  105.          continue;
  106.  
  107.       /* It should be possible to handle uniforms during this pass,
  108.        * but, this will require changes to the other uniform block
  109.        * support code.
  110.        */
  111.       if (var->data.mode == ir_var_uniform)
  112.          continue;
  113.  
  114.       const glsl_type * iface_t = var->type;
  115.       const glsl_type * array_t = NULL;
  116.       exec_node *insert_pos = var;
  117.  
  118.       if (iface_t->is_array()) {
  119.          array_t = iface_t;
  120.          iface_t = array_t->fields.array;
  121.       }
  122.  
  123.       assert (iface_t->is_interface());
  124.  
  125.       for (unsigned i = 0; i < iface_t->length; i++) {
  126.          const char * field_name = iface_t->fields.structure[i].name;
  127.          char *iface_field_name =
  128.             ralloc_asprintf(mem_ctx, "%s.%s.%s",
  129.                             iface_t->name, var->name, field_name);
  130.  
  131.          ir_variable *found_var =
  132.             (ir_variable *) hash_table_find(interface_namespace,
  133.                                             iface_field_name);
  134.          if (!found_var) {
  135.             ir_variable *new_var;
  136.             char *var_name =
  137.                ralloc_strdup(mem_ctx, iface_t->fields.structure[i].name);
  138.             if (array_t == NULL) {
  139.                new_var =
  140.                   new(mem_ctx) ir_variable(iface_t->fields.structure[i].type,
  141.                                            var_name,
  142.                                            (ir_variable_mode) var->data.mode);
  143.                new_var->data.from_named_ifc_block_nonarray = 1;
  144.             } else {
  145.                const glsl_type *new_array_type =
  146.                   glsl_type::get_array_instance(
  147.                      iface_t->fields.structure[i].type,
  148.                      array_t->length);
  149.                new_var =
  150.                   new(mem_ctx) ir_variable(new_array_type,
  151.                                            var_name,
  152.                                            (ir_variable_mode) var->data.mode);
  153.                new_var->data.from_named_ifc_block_array = 1;
  154.             }
  155.             new_var->data.location = iface_t->fields.structure[i].location;
  156.             new_var->data.explicit_location = (new_var->data.location >= 0);
  157.             new_var->data.interpolation =
  158.                iface_t->fields.structure[i].interpolation;
  159.             new_var->data.centroid = iface_t->fields.structure[i].centroid;
  160.             new_var->data.sample = iface_t->fields.structure[i].sample;
  161.  
  162.             new_var->init_interface_type(iface_t);
  163.             hash_table_insert(interface_namespace, new_var,
  164.                               iface_field_name);
  165.             insert_pos->insert_after(new_var);
  166.             insert_pos = new_var;
  167.          }
  168.       }
  169.       var->remove();
  170.    }
  171.  
  172.    /* Second pass: visit all ir_dereference_record instances, and if they
  173.     * reference an interface block, then flatten the refererence out.
  174.     */
  175.    visit_list_elements(this, instructions);
  176.    hash_table_dtor(interface_namespace);
  177.    interface_namespace = NULL;
  178. }
  179.  
  180. ir_visitor_status
  181. flatten_named_interface_blocks_declarations::visit_leave(ir_assignment *ir)
  182. {
  183.    ir_dereference_record *lhs_rec = ir->lhs->as_dereference_record();
  184.    if (lhs_rec) {
  185.       ir_rvalue *lhs_rec_tmp = lhs_rec;
  186.       handle_rvalue(&lhs_rec_tmp);
  187.       if (lhs_rec_tmp != lhs_rec) {
  188.          ir->set_lhs(lhs_rec_tmp);
  189.       }
  190.    }
  191.    return rvalue_visit(ir);
  192. }
  193.  
  194. void
  195. flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue **rvalue)
  196. {
  197.    if (*rvalue == NULL)
  198.       return;
  199.  
  200.    ir_dereference_record *ir = (*rvalue)->as_dereference_record();
  201.    if (ir == NULL)
  202.       return;
  203.  
  204.    ir_variable *var = ir->variable_referenced();
  205.    if (var == NULL)
  206.       return;
  207.  
  208.    if (!var->is_interface_instance())
  209.       return;
  210.  
  211.    /* It should be possible to handle uniforms during this pass,
  212.     * but, this will require changes to the other uniform block
  213.     * support code.
  214.     */
  215.    if (var->data.mode == ir_var_uniform)
  216.       return;
  217.  
  218.    if (var->get_interface_type() != NULL) {
  219.       char *iface_field_name =
  220.          ralloc_asprintf(mem_ctx, "%s.%s.%s", var->get_interface_type()->name,
  221.                          var->name, ir->field);
  222.       /* Find the variable in the set of flattened interface blocks */
  223.       ir_variable *found_var =
  224.          (ir_variable *) hash_table_find(interface_namespace,
  225.                                          iface_field_name);
  226.       assert(found_var);
  227.  
  228.       ir_dereference_variable *deref_var =
  229.          new(mem_ctx) ir_dereference_variable(found_var);
  230.  
  231.       ir_dereference_array *deref_array =
  232.          ir->record->as_dereference_array();
  233.       if (deref_array != NULL) {
  234.          *rvalue =
  235.             new(mem_ctx) ir_dereference_array(deref_var,
  236.                                               deref_array->array_index);
  237.       } else {
  238.          *rvalue = deref_var;
  239.       }
  240.    }
  241. }
  242.  
  243. void
  244. lower_named_interface_blocks(void *mem_ctx, gl_shader *shader)
  245. {
  246.    flatten_named_interface_blocks_declarations v_decl(mem_ctx);
  247.    v_decl.run(shader->ir);
  248. }
  249.  
  250.