Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright © 2014 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 DEALINGS
  21.  * IN THE SOFTWARE.
  22.  *
  23.  * Authors:
  24.  *    Connor Abbott (cwabbott0@gmail.com)
  25.  *    Jason Ekstrand (jason@jlekstrand.net)
  26.  *
  27.  */
  28.  
  29. /*
  30.  * This lowering pass converts references to input/output variables with
  31.  * loads/stores to actual input/output intrinsics.
  32.  *
  33.  * NOTE: This pass really only works for scalar backends at the moment due
  34.  * to the way it packes the input/output data.
  35.  */
  36.  
  37. #include "nir.h"
  38.  
  39. struct lower_io_state {
  40.    void *mem_ctx;
  41. };
  42.  
  43. static unsigned
  44. type_size(const struct glsl_type *type)
  45. {
  46.    unsigned int size, i;
  47.  
  48.    switch (glsl_get_base_type(type)) {
  49.    case GLSL_TYPE_UINT:
  50.    case GLSL_TYPE_INT:
  51.    case GLSL_TYPE_FLOAT:
  52.    case GLSL_TYPE_BOOL:
  53.       return glsl_get_components(type);
  54.    case GLSL_TYPE_ARRAY:
  55.       return type_size(glsl_get_array_element(type)) * glsl_get_length(type);
  56.    case GLSL_TYPE_STRUCT:
  57.       size = 0;
  58.       for (i = 0; i < glsl_get_length(type); i++) {
  59.          size += type_size(glsl_get_struct_field(type, i));
  60.       }
  61.       return size;
  62.    case GLSL_TYPE_SAMPLER:
  63.       return 0;
  64.    case GLSL_TYPE_ATOMIC_UINT:
  65.       return 0;
  66.    case GLSL_TYPE_INTERFACE:
  67.       return 0;
  68.    case GLSL_TYPE_IMAGE:
  69.       return 0;
  70.    case GLSL_TYPE_VOID:
  71.    case GLSL_TYPE_ERROR:
  72.    case GLSL_TYPE_DOUBLE:
  73.       unreachable("not reached");
  74.    }
  75.  
  76.    return 0;
  77. }
  78.  
  79. void
  80. nir_assign_var_locations_scalar(struct exec_list *var_list, unsigned *size)
  81. {
  82.    unsigned location = 0;
  83.  
  84.    foreach_list_typed(nir_variable, var, node, var_list) {
  85.       /*
  86.        * UBO's have their own address spaces, so don't count them towards the
  87.        * number of global uniforms
  88.        */
  89.       if (var->data.mode == nir_var_uniform && var->interface_type != NULL)
  90.          continue;
  91.  
  92.       var->data.driver_location = location;
  93.       location += type_size(var->type);
  94.    }
  95.  
  96.    *size = location;
  97. }
  98.  
  99. static bool
  100. deref_has_indirect(nir_deref_var *deref)
  101. {
  102.    for (nir_deref *tail = deref->deref.child; tail; tail = tail->child) {
  103.       if (tail->deref_type == nir_deref_type_array) {
  104.          nir_deref_array *arr = nir_deref_as_array(tail);
  105.          if (arr->deref_array_type == nir_deref_array_type_indirect)
  106.             return true;
  107.       }
  108.    }
  109.  
  110.    return false;
  111. }
  112.  
  113. static bool
  114. mark_indirect_uses_block(nir_block *block, void *void_state)
  115. {
  116.    struct set *indirect_set = void_state;
  117.  
  118.    nir_foreach_instr(block, instr) {
  119.       if (instr->type != nir_instr_type_intrinsic)
  120.          continue;
  121.  
  122.       nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
  123.  
  124.       for (unsigned i = 0;
  125.            i < nir_intrinsic_infos[intrin->intrinsic].num_variables; i++) {
  126.          if (deref_has_indirect(intrin->variables[i]))
  127.             _mesa_set_add(indirect_set, intrin->variables[i]->var);
  128.       }
  129.    }
  130.  
  131.    return true;
  132. }
  133.  
  134. /* Identical to nir_assign_var_locations_packed except that it assigns
  135.  * locations to the variables that are used 100% directly first and then
  136.  * assigns locations to variables that are used indirectly.
  137.  */
  138. void
  139. nir_assign_var_locations_scalar_direct_first(nir_shader *shader,
  140.                                              struct exec_list *var_list,
  141.                                              unsigned *direct_size,
  142.                                              unsigned *size)
  143. {
  144.    struct set *indirect_set = _mesa_set_create(NULL, _mesa_hash_pointer,
  145.                                                _mesa_key_pointer_equal);
  146.  
  147.    nir_foreach_overload(shader, overload) {
  148.       if (overload->impl)
  149.          nir_foreach_block(overload->impl, mark_indirect_uses_block,
  150.                            indirect_set);
  151.    }
  152.  
  153.    unsigned location = 0;
  154.  
  155.    foreach_list_typed(nir_variable, var, node, var_list) {
  156.       if (var->data.mode == nir_var_uniform && var->interface_type != NULL)
  157.          continue;
  158.  
  159.       if (_mesa_set_search(indirect_set, var))
  160.          continue;
  161.  
  162.       var->data.driver_location = location;
  163.       location += type_size(var->type);
  164.    }
  165.  
  166.    *direct_size = location;
  167.  
  168.    foreach_list_typed(nir_variable, var, node, var_list) {
  169.       if (var->data.mode == nir_var_uniform && var->interface_type != NULL)
  170.          continue;
  171.  
  172.       if (!_mesa_set_search(indirect_set, var))
  173.          continue;
  174.  
  175.       var->data.driver_location = location;
  176.       location += type_size(var->type);
  177.    }
  178.  
  179.    *size = location;
  180.  
  181.    _mesa_set_destroy(indirect_set, NULL);
  182. }
  183.  
  184. static unsigned
  185. get_io_offset(nir_deref_var *deref, nir_instr *instr, nir_src *indirect,
  186.               struct lower_io_state *state)
  187. {
  188.    bool found_indirect = false;
  189.    unsigned base_offset = 0;
  190.  
  191.    nir_deref *tail = &deref->deref;
  192.    while (tail->child != NULL) {
  193.       const struct glsl_type *parent_type = tail->type;
  194.       tail = tail->child;
  195.  
  196.       if (tail->deref_type == nir_deref_type_array) {
  197.          nir_deref_array *deref_array = nir_deref_as_array(tail);
  198.          unsigned size = type_size(tail->type);
  199.  
  200.          base_offset += size * deref_array->base_offset;
  201.  
  202.          if (deref_array->deref_array_type == nir_deref_array_type_indirect) {
  203.             nir_load_const_instr *load_const =
  204.                nir_load_const_instr_create(state->mem_ctx, 1);
  205.             load_const->value.u[0] = size;
  206.             nir_instr_insert_before(instr, &load_const->instr);
  207.  
  208.             nir_alu_instr *mul = nir_alu_instr_create(state->mem_ctx,
  209.                                                       nir_op_imul);
  210.             mul->src[0].src.is_ssa = true;
  211.             mul->src[0].src.ssa = &load_const->def;
  212.             nir_src_copy(&mul->src[1].src, &deref_array->indirect,
  213.                          state->mem_ctx);
  214.             mul->dest.write_mask = 1;
  215.             nir_ssa_dest_init(&mul->instr, &mul->dest.dest, 1, NULL);
  216.             nir_instr_insert_before(instr, &mul->instr);
  217.  
  218.             if (found_indirect) {
  219.                nir_alu_instr *add = nir_alu_instr_create(state->mem_ctx,
  220.                                                          nir_op_iadd);
  221.                add->src[0].src = *indirect;
  222.                add->src[1].src.is_ssa = true;
  223.                add->src[1].src.ssa = &mul->dest.dest.ssa;
  224.                add->dest.write_mask = 1;
  225.                nir_ssa_dest_init(&add->instr, &add->dest.dest, 1, NULL);
  226.                nir_instr_insert_before(instr, &add->instr);
  227.  
  228.                indirect->is_ssa = true;
  229.                indirect->ssa = &add->dest.dest.ssa;
  230.             } else {
  231.                indirect->is_ssa = true;
  232.                indirect->ssa = &mul->dest.dest.ssa;
  233.                found_indirect = true;
  234.             }
  235.          }
  236.       } else if (tail->deref_type == nir_deref_type_struct) {
  237.          nir_deref_struct *deref_struct = nir_deref_as_struct(tail);
  238.  
  239.          for (unsigned i = 0; i < deref_struct->index; i++)
  240.             base_offset += type_size(glsl_get_struct_field(parent_type, i));
  241.       }
  242.    }
  243.  
  244.    return base_offset;
  245. }
  246.  
  247. static bool
  248. nir_lower_io_block(nir_block *block, void *void_state)
  249. {
  250.    struct lower_io_state *state = void_state;
  251.  
  252.    nir_foreach_instr_safe(block, instr) {
  253.       if (instr->type != nir_instr_type_intrinsic)
  254.          continue;
  255.  
  256.       nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
  257.  
  258.       switch (intrin->intrinsic) {
  259.       case nir_intrinsic_load_var: {
  260.          nir_variable_mode mode = intrin->variables[0]->var->data.mode;
  261.          if (mode != nir_var_shader_in && mode != nir_var_uniform)
  262.             continue;
  263.  
  264.          bool has_indirect = deref_has_indirect(intrin->variables[0]);
  265.  
  266.          /* Figure out the opcode */
  267.          nir_intrinsic_op load_op;
  268.          switch (mode) {
  269.          case nir_var_shader_in:
  270.             load_op = has_indirect ? nir_intrinsic_load_input_indirect :
  271.                                      nir_intrinsic_load_input;
  272.             break;
  273.          case nir_var_uniform:
  274.             load_op = has_indirect ? nir_intrinsic_load_uniform_indirect :
  275.                                      nir_intrinsic_load_uniform;
  276.             break;
  277.          default:
  278.             unreachable("Unknown variable mode");
  279.          }
  280.  
  281.          nir_intrinsic_instr *load = nir_intrinsic_instr_create(state->mem_ctx,
  282.                                                                 load_op);
  283.          load->num_components = intrin->num_components;
  284.  
  285.          nir_src indirect;
  286.          unsigned offset = get_io_offset(intrin->variables[0],
  287.                                          &intrin->instr, &indirect, state);
  288.          offset += intrin->variables[0]->var->data.driver_location;
  289.  
  290.          load->const_index[0] = offset;
  291.          load->const_index[1] = 1;
  292.  
  293.          if (has_indirect)
  294.             load->src[0] = indirect;
  295.  
  296.          if (intrin->dest.is_ssa) {
  297.             nir_ssa_dest_init(&load->instr, &load->dest,
  298.                               intrin->num_components, NULL);
  299.             nir_ssa_def_rewrite_uses(&intrin->dest.ssa,
  300.                                      nir_src_for_ssa(&load->dest.ssa),
  301.                                      state->mem_ctx);
  302.          } else {
  303.             nir_dest_copy(&load->dest, &intrin->dest, state->mem_ctx);
  304.          }
  305.  
  306.          nir_instr_insert_before(&intrin->instr, &load->instr);
  307.          nir_instr_remove(&intrin->instr);
  308.          break;
  309.       }
  310.  
  311.       case nir_intrinsic_store_var: {
  312.          if (intrin->variables[0]->var->data.mode != nir_var_shader_out)
  313.             continue;
  314.  
  315.          bool has_indirect = deref_has_indirect(intrin->variables[0]);
  316.  
  317.          nir_intrinsic_op store_op;
  318.          if (has_indirect) {
  319.             store_op = nir_intrinsic_store_output_indirect;
  320.          } else {
  321.             store_op = nir_intrinsic_store_output;
  322.          }
  323.  
  324.          nir_intrinsic_instr *store = nir_intrinsic_instr_create(state->mem_ctx,
  325.                                                                  store_op);
  326.          store->num_components = intrin->num_components;
  327.  
  328.          nir_src indirect;
  329.          unsigned offset = get_io_offset(intrin->variables[0],
  330.                                          &intrin->instr, &indirect, state);
  331.          offset += intrin->variables[0]->var->data.driver_location;
  332.  
  333.          store->const_index[0] = offset;
  334.          store->const_index[1] = 1;
  335.  
  336.          nir_src_copy(&store->src[0], &intrin->src[0], state->mem_ctx);
  337.  
  338.          if (has_indirect)
  339.             store->src[1] = indirect;
  340.  
  341.          nir_instr_insert_before(&intrin->instr, &store->instr);
  342.          nir_instr_remove(&intrin->instr);
  343.          break;
  344.       }
  345.  
  346.       default:
  347.          break;
  348.       }
  349.    }
  350.  
  351.    return true;
  352. }
  353.  
  354. static void
  355. nir_lower_io_impl(nir_function_impl *impl)
  356. {
  357.    struct lower_io_state state;
  358.  
  359.    state.mem_ctx = ralloc_parent(impl);
  360.  
  361.    nir_foreach_block(impl, nir_lower_io_block, &state);
  362.  
  363.    nir_metadata_preserve(impl, nir_metadata_block_index |
  364.                                nir_metadata_dominance);
  365. }
  366.  
  367. void
  368. nir_lower_io(nir_shader *shader)
  369. {
  370.    nir_foreach_overload(shader, overload) {
  371.       if (overload->impl)
  372.          nir_lower_io_impl(overload->impl);
  373.    }
  374. }
  375.