Home | History | Annotate | Line # | Download | only in nir
      1 /**************************************************************************
      2  *
      3  * Copyright 2019 Red Hat.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included
     14  * in all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22  * SOFTWARE.
     23  *
     24  **************************************************************************/
     25 
     26 /*
     27  * NIR lowering passes to handle the draw stages for
     28  * - pstipple
     29  * - aaline
     30  * - aapoint.
     31  *
     32  * These are all ported from the equivalent TGSI transforms.
     33  */
     34 
     35 #include "nir.h"
     36 #include "tgsi/tgsi_from_mesa.h"
     37 #include "nir_builder.h"
     38 
     39 #include "nir_draw_helpers.h"
     40 
     41 typedef struct {
     42    nir_builder b;
     43    nir_shader *shader;
     44    bool fs_pos_is_sysval;
     45    nir_variable *stip_tex;
     46    nir_ssa_def *fragcoord;
     47 } lower_pstipple;
     48 
     49 static nir_ssa_def *
     50 load_frag_coord(nir_builder *b)
     51 {
     52    nir_foreach_shader_in_variable(var, b->shader) {
     53       if (var->data.location == VARYING_SLOT_POS)
     54          return nir_load_var(b, var);
     55    }
     56 
     57    nir_variable *pos = nir_variable_create(b->shader, nir_var_shader_in,
     58                                            glsl_vec4_type(), NULL);
     59    pos->data.location = VARYING_SLOT_POS;
     60    pos->data.interpolation = INTERP_MODE_NOPERSPECTIVE;
     61    pos->data.driver_location = b->shader->num_inputs++;
     62    return nir_load_var(b, pos);
     63 }
     64 
     65 static void
     66 nir_lower_pstipple_block(nir_block *block,
     67                          lower_pstipple *state)
     68 {
     69    nir_builder *b = &state->b;
     70    nir_ssa_def *texcoord;
     71 
     72    b->cursor = nir_before_block(block);
     73 
     74    nir_ssa_def *frag_coord = state->fs_pos_is_sysval ? nir_load_frag_coord(b) : load_frag_coord(b);
     75 
     76    texcoord = nir_fmul(b, nir_channels(b, frag_coord, 0x3),
     77                        nir_imm_vec2(b, 1.0/32.0, 1.0/32.0));
     78 
     79    nir_tex_instr *tex = nir_tex_instr_create(b->shader, 1);
     80    tex->op = nir_texop_tex;
     81    tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
     82    tex->coord_components = 2;
     83    tex->dest_type = nir_type_float32;
     84    tex->texture_index = state->stip_tex->data.binding;
     85    tex->sampler_index = state->stip_tex->data.binding;
     86    tex->src[0].src_type = nir_tex_src_coord;
     87    tex->src[0].src = nir_src_for_ssa(texcoord);
     88    nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL);
     89 
     90    nir_builder_instr_insert(b, &tex->instr);
     91 
     92    nir_ssa_def *condition = nir_f2b32(b, nir_channel(b, &tex->dest.ssa, 3));
     93    nir_discard_if(b, condition);
     94    b->shader->info.fs.uses_discard = true;
     95 }
     96 
     97 static void
     98 nir_lower_pstipple_impl(nir_function_impl *impl,
     99                         lower_pstipple *state)
    100 {
    101    nir_builder *b = &state->b;
    102 
    103    nir_builder_init(b, impl);
    104 
    105    nir_block *start = nir_start_block(impl);
    106    nir_lower_pstipple_block(start, state);
    107 }
    108 
    109 void
    110 nir_lower_pstipple_fs(struct nir_shader *shader,
    111                       unsigned *samplerUnitOut,
    112                       unsigned fixedUnit,
    113                       bool fs_pos_is_sysval)
    114 {
    115    lower_pstipple state = {
    116       .shader = shader,
    117       .fs_pos_is_sysval = fs_pos_is_sysval,
    118    };
    119    if (shader->info.stage != MESA_SHADER_FRAGMENT)
    120       return;
    121 
    122    int binding = 0;
    123    nir_foreach_uniform_variable(var, shader) {
    124       if (glsl_type_is_sampler(var->type)) {
    125          if (var->data.binding >= binding)
    126             binding = var->data.binding + 1;
    127       }
    128    }
    129    const struct glsl_type *sampler2D =
    130       glsl_sampler_type(GLSL_SAMPLER_DIM_2D, false, false, GLSL_TYPE_FLOAT);
    131 
    132    nir_variable *tex_var = nir_variable_create(shader, nir_var_uniform, sampler2D, "stipple_tex");
    133    tex_var->data.binding = binding;
    134    tex_var->data.explicit_binding = true;
    135    tex_var->data.how_declared = nir_var_hidden;
    136 
    137    BITSET_SET(shader->info.textures_used, binding);
    138    state.stip_tex = tex_var;
    139 
    140    nir_foreach_function(function, shader) {
    141       if (function->impl) {
    142          nir_lower_pstipple_impl(function->impl, &state);
    143       }
    144    }
    145    *samplerUnitOut = binding;
    146 }
    147 
    148 typedef struct {
    149    nir_builder b;
    150    nir_shader *shader;
    151    nir_variable *line_width_input;
    152 } lower_aaline;
    153 
    154 static void
    155 nir_lower_aaline_block(nir_block *block,
    156                        lower_aaline *state)
    157 {
    158   nir_builder *b = &state->b;
    159   nir_foreach_instr(instr, block) {
    160       if (instr->type != nir_instr_type_intrinsic)
    161          continue;
    162 
    163       nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
    164       if (intrin->intrinsic != nir_intrinsic_store_deref)
    165          continue;
    166 
    167       nir_variable *var = nir_intrinsic_get_var(intrin, 0);
    168       if (var->data.mode != nir_var_shader_out)
    169          continue;
    170       if (var->data.location < FRAG_RESULT_DATA0 && var->data.location != FRAG_RESULT_COLOR)
    171          continue;
    172 
    173       nir_ssa_def *out_input = intrin->src[1].ssa;
    174       b->cursor = nir_before_instr(instr);
    175       nir_ssa_def *lw = nir_load_var(b, state->line_width_input);
    176       nir_ssa_def *tmp = nir_fsat(b, nir_fadd(b, nir_channel(b, lw, 1),
    177                                               nir_fneg(b, nir_fabs(b, nir_channel(b, lw, 0)))));
    178       nir_ssa_def *tmp1 = nir_fsat(b, nir_fadd(b, nir_channel(b, lw, 3),
    179                                                nir_fneg(b, nir_fabs(b, nir_channel(b, lw, 2)))));
    180 
    181       tmp = nir_fmul(b, tmp, tmp1);
    182       tmp = nir_fmul(b, nir_channel(b, out_input, 3), tmp);
    183 
    184       nir_ssa_def *out = nir_vec4(b, nir_channel(b, out_input, 0),
    185                                   nir_channel(b, out_input, 1),
    186                                   nir_channel(b, out_input, 2),
    187                                   tmp);
    188       nir_instr_rewrite_src(instr, &intrin->src[1], nir_src_for_ssa(out));
    189    }
    190 
    191 }
    192 
    193 static void
    194 nir_lower_aaline_impl(nir_function_impl *impl,
    195                       lower_aaline *state)
    196 {
    197    nir_builder *b = &state->b;
    198 
    199    nir_builder_init(b, impl);
    200 
    201    nir_foreach_block(block, impl) {
    202       nir_lower_aaline_block(block, state);
    203    }
    204 }
    205 
    206 void
    207 nir_lower_aaline_fs(struct nir_shader *shader, int *varying)
    208 {
    209    lower_aaline state = {
    210       .shader = shader,
    211    };
    212    if (shader->info.stage != MESA_SHADER_FRAGMENT)
    213       return;
    214 
    215    int highest_location = -1, highest_drv_location = -1;
    216    nir_foreach_shader_in_variable(var, shader) {
    217      if ((int)var->data.location > highest_location)
    218          highest_location = var->data.location;
    219      if ((int)var->data.driver_location > highest_drv_location)
    220          highest_drv_location = var->data.driver_location;
    221    }
    222 
    223    nir_variable *line_width = nir_variable_create(shader, nir_var_shader_in,
    224                                                   glsl_vec4_type(), "aaline");
    225    if (highest_location == -1 || highest_location < VARYING_SLOT_VAR0) {
    226      line_width->data.location = VARYING_SLOT_VAR0;
    227      line_width->data.driver_location = highest_drv_location + 1;
    228    } else {
    229      line_width->data.location = highest_location + 1;
    230      line_width->data.driver_location = highest_drv_location + 1;
    231    }
    232    shader->num_inputs++;
    233    *varying = tgsi_get_generic_gl_varying_index(line_width->data.location, true);
    234    state.line_width_input = line_width;
    235 
    236    nir_foreach_function(function, shader) {
    237       if (function->impl) {
    238          nir_lower_aaline_impl(function->impl, &state);
    239       }
    240    }
    241 }
    242 
    243 typedef struct {
    244    nir_builder b;
    245    nir_shader *shader;
    246    nir_variable *input;
    247 } lower_aapoint;
    248 
    249 static void
    250 nir_lower_aapoint_block(nir_block *block,
    251                         lower_aapoint *state, nir_ssa_def *sel)
    252 {
    253   nir_builder *b = &state->b;
    254   nir_foreach_instr(instr, block) {
    255       if (instr->type != nir_instr_type_intrinsic)
    256          continue;
    257 
    258       nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
    259       if (intrin->intrinsic != nir_intrinsic_store_deref)
    260          continue;
    261 
    262       nir_variable *var = nir_intrinsic_get_var(intrin, 0);
    263       if (var->data.mode != nir_var_shader_out)
    264          continue;
    265       if (var->data.location < FRAG_RESULT_DATA0 && var->data.location != FRAG_RESULT_COLOR)
    266          continue;
    267 
    268       nir_ssa_def *out_input = intrin->src[1].ssa;
    269       b->cursor = nir_before_instr(instr);
    270 
    271       nir_ssa_def *tmp = nir_fmul(b, nir_channel(b, out_input, 3), sel);
    272       nir_ssa_def *out = nir_vec4(b, nir_channel(b, out_input, 0),
    273                                   nir_channel(b, out_input, 1),
    274                                   nir_channel(b, out_input, 2),
    275                                   tmp);
    276       nir_instr_rewrite_src(instr, &intrin->src[1], nir_src_for_ssa(out));
    277    }
    278 
    279 }
    280 
    281 static void
    282 nir_lower_aapoint_impl(nir_function_impl *impl,
    283                       lower_aapoint *state)
    284 {
    285    nir_builder *b = &state->b;
    286 
    287    nir_builder_init(b, impl);
    288 
    289    nir_block *block = nir_start_block(impl);
    290    b->cursor = nir_before_block(block);
    291 
    292    nir_ssa_def *aainput = nir_load_var(b, state->input);
    293 
    294    nir_ssa_def *dist = nir_fadd(b, nir_fmul(b, nir_channel(b, aainput, 0), nir_channel(b, aainput, 0)),
    295                                 nir_fmul(b, nir_channel(b, aainput, 1), nir_channel(b, aainput, 1)));
    296 
    297    nir_ssa_def *k = nir_channel(b, aainput, 2);
    298    nir_ssa_def *chan_val_one = nir_channel(b, aainput, 3);
    299    nir_ssa_def *comp = nir_flt32(b, chan_val_one, dist);
    300 
    301    nir_discard_if(b, comp);
    302    b->shader->info.fs.uses_discard = true;
    303 
    304    /* compute coverage factor = (1-d)/(1-k) */
    305    /* 1 - k */
    306    nir_ssa_def *tmp = nir_fadd(b, chan_val_one, nir_fneg(b, k));
    307    /* 1.0 / (1 - k) */
    308    tmp = nir_frcp(b, tmp);
    309 
    310    /* 1 - d */
    311    nir_ssa_def *tmp2 = nir_fadd(b, chan_val_one, nir_fneg(b, dist));
    312 
    313    /* (1 - d) / (1 - k) */
    314    nir_ssa_def *coverage = nir_fmul(b, tmp, tmp2);
    315 
    316    /* if (k >= distance)
    317     *    sel = coverage;
    318     * else
    319     *    sel = 1.0;
    320     */
    321    nir_ssa_def *sel = nir_b32csel(b, nir_fge32(b, k, dist), coverage, chan_val_one);
    322 
    323    nir_foreach_block(block, impl) {
    324      nir_lower_aapoint_block(block, state, sel);
    325    }
    326 }
    327 
    328 void
    329 nir_lower_aapoint_fs(struct nir_shader *shader, int *varying)
    330 {
    331    lower_aapoint state = {
    332       .shader = shader,
    333    };
    334    if (shader->info.stage != MESA_SHADER_FRAGMENT)
    335       return;
    336 
    337    int highest_location = -1, highest_drv_location = -1;
    338    nir_foreach_shader_in_variable(var, shader) {
    339      if ((int)var->data.location > highest_location)
    340          highest_location = var->data.location;
    341      if ((int)var->data.driver_location > highest_drv_location)
    342          highest_drv_location = var->data.driver_location;
    343    }
    344 
    345    nir_variable *aapoint_input = nir_variable_create(shader, nir_var_shader_in,
    346                                                      glsl_vec4_type(), "aapoint");
    347    if (highest_location == -1 || highest_location < VARYING_SLOT_VAR0) {
    348      aapoint_input->data.location = VARYING_SLOT_VAR0;
    349    } else {
    350      aapoint_input->data.location = highest_location + 1;
    351    }
    352    aapoint_input->data.driver_location = highest_drv_location + 1;
    353 
    354    shader->num_inputs++;
    355    *varying = tgsi_get_generic_gl_varying_index(aapoint_input->data.location, true);
    356    state.input = aapoint_input;
    357 
    358    nir_foreach_function(function, shader) {
    359       if (function->impl) {
    360          nir_lower_aapoint_impl(function->impl, &state);
    361       }
    362    }
    363 }
    364