Home | History | Annotate | Download | only in nir
      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 (at) gmail.com)
     25  *
     26  */
     27 
     28 #include "nir.h"
     29 #include "nir_builder.h"
     30 
     31 static bool
     32 convert_block(nir_block *block, nir_builder *b)
     33 {
     34    bool progress = false;
     35 
     36    nir_foreach_instr_safe(instr, block) {
     37       if (instr->type != nir_instr_type_intrinsic)
     38          continue;
     39 
     40       nir_intrinsic_instr *load_var = nir_instr_as_intrinsic(instr);
     41 
     42       if (load_var->intrinsic != nir_intrinsic_load_var)
     43          continue;
     44 
     45       nir_variable *var = load_var->variables[0]->var;
     46       if (var->data.mode != nir_var_system_value)
     47          continue;
     48 
     49       b->cursor = nir_after_instr(&load_var->instr);
     50 
     51       nir_ssa_def *sysval = NULL;
     52       switch (var->data.location) {
     53       case SYSTEM_VALUE_GLOBAL_INVOCATION_ID: {
     54          /* From the GLSL man page for gl_GlobalInvocationID:
     55           *
     56           *    "The value of gl_GlobalInvocationID is equal to
     57           *    gl_WorkGroupID * gl_WorkGroupSize + gl_LocalInvocationID"
     58           */
     59 
     60          nir_const_value local_size;
     61          local_size.u32[0] = b->shader->info->cs.local_size[0];
     62          local_size.u32[1] = b->shader->info->cs.local_size[1];
     63          local_size.u32[2] = b->shader->info->cs.local_size[2];
     64 
     65          nir_ssa_def *group_id = nir_load_work_group_id(b);
     66          nir_ssa_def *local_id = nir_load_local_invocation_id(b);
     67 
     68          sysval = nir_iadd(b, nir_imul(b, group_id,
     69                                        nir_build_imm(b, 3, 32, local_size)),
     70                               local_id);
     71          break;
     72       }
     73 
     74       case SYSTEM_VALUE_LOCAL_INVOCATION_INDEX: {
     75          /* If lower_cs_local_index_from_id is true, then we derive the local
     76           * index from the local id.
     77           */
     78          if (!b->shader->options->lower_cs_local_index_from_id)
     79             break;
     80 
     81          /* From the GLSL man page for gl_LocalInvocationIndex:
     82           *
     83           *    "The value of gl_LocalInvocationIndex is equal to
     84           *    gl_LocalInvocationID.z * gl_WorkGroupSize.x *
     85           *    gl_WorkGroupSize.y + gl_LocalInvocationID.y *
     86           *    gl_WorkGroupSize.x + gl_LocalInvocationID.x"
     87           */
     88          nir_ssa_def *local_id = nir_load_local_invocation_id(b);
     89 
     90          nir_ssa_def *size_x =
     91             nir_imm_int(b, b->shader->info->cs.local_size[0]);
     92          nir_ssa_def *size_y =
     93             nir_imm_int(b, b->shader->info->cs.local_size[1]);
     94 
     95          sysval = nir_imul(b, nir_channel(b, local_id, 2),
     96                               nir_imul(b, size_x, size_y));
     97          sysval = nir_iadd(b, sysval,
     98                               nir_imul(b, nir_channel(b, local_id, 1), size_x));
     99          sysval = nir_iadd(b, sysval, nir_channel(b, local_id, 0));
    100          break;
    101       }
    102 
    103       case SYSTEM_VALUE_VERTEX_ID:
    104          if (b->shader->options->vertex_id_zero_based) {
    105             sysval = nir_iadd(b,
    106                               nir_load_vertex_id_zero_base(b),
    107                               nir_load_base_vertex(b));
    108          } else {
    109             sysval = nir_load_vertex_id(b);
    110          }
    111          break;
    112 
    113       case SYSTEM_VALUE_INSTANCE_INDEX:
    114          sysval = nir_iadd(b,
    115                            nir_load_instance_id(b),
    116                            nir_load_base_instance(b));
    117          break;
    118 
    119       default:
    120          break;
    121       }
    122 
    123       if (sysval == NULL) {
    124          nir_intrinsic_op sysval_op =
    125             nir_intrinsic_from_system_value(var->data.location);
    126          sysval = nir_load_system_value(b, sysval_op, 0);
    127       }
    128 
    129       nir_ssa_def_rewrite_uses(&load_var->dest.ssa, nir_src_for_ssa(sysval));
    130       nir_instr_remove(&load_var->instr);
    131 
    132       progress = true;
    133    }
    134 
    135    return progress;
    136 }
    137 
    138 static bool
    139 convert_impl(nir_function_impl *impl)
    140 {
    141    bool progress = false;
    142    nir_builder builder;
    143    nir_builder_init(&builder, impl);
    144 
    145    nir_foreach_block(block, impl) {
    146       progress |= convert_block(block, &builder);
    147    }
    148 
    149    nir_metadata_preserve(impl, nir_metadata_block_index |
    150                                nir_metadata_dominance);
    151    return progress;
    152 }
    153 
    154 bool
    155 nir_lower_system_values(nir_shader *shader)
    156 {
    157    bool progress = false;
    158 
    159    nir_foreach_function(function, shader) {
    160       if (function->impl)
    161          progress = convert_impl(function->impl) || progress;
    162    }
    163 
    164    exec_list_make_empty(&shader->system_values);
    165 
    166    return progress;
    167 }
    168