Home | History | Annotate | Line # | Download | only in common
      1 /*
      2  * Copyright  2021 Valve 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  */
     24 
     25 #include "ac_nir.h"
     26 #include "nir_builder.h"
     27 
     28 /*
     29  * Lower NIR cross-stage I/O intrinsics into the memory accesses that actually happen on the HW.
     30  *
     31  * These HW stages are used only when a Geometry Shader is used.
     32  * Export Shader (ES) runs the SW stage before GS, can be either VS or TES.
     33  *
     34  * * GFX6-8:
     35  *   ES and GS are separate HW stages.
     36  *   I/O is passed between them through VRAM.
     37  * * GFX9+:
     38  *   ES and GS are merged into a single HW stage.
     39  *   I/O is passed between them through LDS.
     40  *
     41  */
     42 
     43 typedef struct {
     44    /* Which hardware generation we're dealing with */
     45    enum chip_class chip_class;
     46 
     47    /* Number of ES outputs for which memory should be reserved.
     48     * When compacted, this should be the number of linked ES outputs.
     49     */
     50    unsigned num_reserved_es_outputs;
     51 } lower_esgs_io_state;
     52 
     53 static nir_ssa_def *
     54 emit_split_buffer_load(nir_builder *b, nir_ssa_def *desc, nir_ssa_def *v_off, nir_ssa_def *s_off,
     55                        unsigned component_stride, unsigned num_components, unsigned bit_size)
     56 {
     57    unsigned total_bytes = num_components * bit_size / 8u;
     58    unsigned full_dwords = total_bytes / 4u;
     59    unsigned remaining_bytes = total_bytes - full_dwords * 4u;
     60 
     61    /* Accomodate max number of split 64-bit loads */
     62    nir_ssa_def *comps[NIR_MAX_VEC_COMPONENTS * 2u];
     63 
     64    /* Assume that 1x32-bit load is better than 1x16-bit + 1x8-bit */
     65    if (remaining_bytes == 3) {
     66       remaining_bytes = 0;
     67       full_dwords++;
     68    }
     69 
     70    for (unsigned i = 0; i < full_dwords; ++i)
     71       comps[i] = nir_build_load_buffer_amd(b, 1, 32, desc, v_off, s_off,
     72                                            .base = component_stride * i, .memory_modes = nir_var_shader_in);
     73 
     74    if (remaining_bytes)
     75       comps[full_dwords] = nir_build_load_buffer_amd(b, 1, remaining_bytes * 8, desc, v_off, s_off,
     76                                                      .base = component_stride * full_dwords, .memory_modes = nir_var_shader_in);
     77 
     78    return nir_extract_bits(b, comps, full_dwords + !!remaining_bytes, 0, num_components, bit_size);
     79 }
     80 
     81 static void
     82 emit_split_buffer_store(nir_builder *b, nir_ssa_def *d, nir_ssa_def *desc, nir_ssa_def *v_off, nir_ssa_def *s_off,
     83                         unsigned component_stride, unsigned num_components, unsigned bit_size,
     84                         unsigned writemask, bool swizzled, bool slc)
     85 {
     86    while (writemask) {
     87       int start, count;
     88       u_bit_scan_consecutive_range(&writemask, &start, &count);
     89       assert(start >= 0 && count >= 0);
     90 
     91       unsigned bytes = count * bit_size / 8u;
     92       unsigned start_byte = start * bit_size / 8u;
     93 
     94       while (bytes) {
     95          unsigned store_bytes = MIN2(bytes, 4u);
     96          if ((start_byte % 4) == 1 || (start_byte % 4) == 3)
     97             store_bytes = MIN2(store_bytes, 1);
     98          else if ((start_byte % 4) == 2)
     99             store_bytes = MIN2(store_bytes, 2);
    100 
    101          nir_ssa_def *store_val = nir_extract_bits(b, &d, 1, start_byte * 8u, 1, store_bytes * 8u);
    102          nir_build_store_buffer_amd(b, store_val, desc, v_off, s_off, .is_swizzled = swizzled, .slc_amd = slc,
    103                                     .base = start_byte, .write_mask = 1u, .memory_modes = nir_var_shader_out);
    104 
    105          start_byte += store_bytes;
    106          bytes -= store_bytes;
    107       }
    108    }
    109 }
    110 
    111 static bool
    112 lower_es_output_store(nir_builder *b,
    113                       nir_instr *instr,
    114                       void *state)
    115 {
    116    if (instr->type != nir_instr_type_intrinsic)
    117       return false;
    118 
    119    nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
    120 
    121    if (intrin->intrinsic != nir_intrinsic_store_output)
    122       return false;
    123 
    124    lower_esgs_io_state *st = (lower_esgs_io_state *) state;
    125    unsigned write_mask = nir_intrinsic_write_mask(intrin);
    126 
    127    b->cursor = nir_before_instr(instr);
    128    nir_ssa_def *io_off = nir_build_calc_io_offset(b, intrin, nir_imm_int(b, 16u), 4u);
    129 
    130    if (st->chip_class <= GFX8) {
    131       /* GFX6-8: ES is a separate HW stage, data is passed from ES to GS in VRAM. */
    132       nir_ssa_def *ring = nir_build_load_ring_esgs_amd(b);
    133       nir_ssa_def *es2gs_off = nir_build_load_ring_es2gs_offset_amd(b);
    134       emit_split_buffer_store(b, intrin->src[0].ssa, ring, io_off, es2gs_off, 4u,
    135                               intrin->src[0].ssa->num_components, intrin->src[0].ssa->bit_size,
    136                               write_mask, true, true);
    137    } else {
    138       /* GFX9+: ES is merged into GS, data is passed through LDS. */
    139       unsigned esgs_itemsize = st->num_reserved_es_outputs * 16u;
    140       nir_ssa_def *vertex_idx = nir_build_load_local_invocation_index(b);
    141       nir_ssa_def *off = nir_iadd(b, nir_imul_imm(b, vertex_idx, esgs_itemsize), io_off);
    142       nir_build_store_shared(b, intrin->src[0].ssa, off, .write_mask = write_mask,
    143                              .align_mul = 16u, .align_offset = (nir_intrinsic_component(intrin) * 4u) % 16u);
    144    }
    145 
    146    nir_instr_remove(instr);
    147    return true;
    148 }
    149 
    150 static nir_ssa_def *
    151 gs_per_vertex_input_vertex_offset_gfx6(nir_builder *b, nir_src *vertex_src)
    152 {
    153    if (nir_src_is_const(*vertex_src))
    154       return nir_build_load_gs_vertex_offset_amd(b, .base = nir_src_as_uint(*vertex_src));
    155 
    156    nir_ssa_def *vertex_offset = nir_build_load_gs_vertex_offset_amd(b, .base = 0);
    157 
    158    for (unsigned i = 1; i < b->shader->info.gs.vertices_in; ++i) {
    159       nir_ssa_def *cond = nir_ieq_imm(b, vertex_src->ssa, i);
    160       nir_ssa_def *elem = nir_build_load_gs_vertex_offset_amd(b, .base = i);
    161       vertex_offset = nir_bcsel(b, cond, elem, vertex_offset);
    162    }
    163 
    164    return vertex_offset;
    165 }
    166 
    167 static nir_ssa_def *
    168 gs_per_vertex_input_vertex_offset_gfx9(nir_builder *b, nir_src *vertex_src)
    169 {
    170    if (nir_src_is_const(*vertex_src)) {
    171       unsigned vertex = nir_src_as_uint(*vertex_src);
    172       return nir_ubfe(b, nir_build_load_gs_vertex_offset_amd(b, .base = vertex / 2u),
    173                       nir_imm_int(b, (vertex & 1u) * 16u), nir_imm_int(b, 16u));
    174    }
    175 
    176    nir_ssa_def *vertex_offset = nir_build_load_gs_vertex_offset_amd(b, .base = 0);
    177 
    178    for (unsigned i = 1; i < b->shader->info.gs.vertices_in; i++) {
    179       nir_ssa_def *cond = nir_ieq_imm(b, vertex_src->ssa, i);
    180       nir_ssa_def *elem = nir_build_load_gs_vertex_offset_amd(b, .base = i / 2u * 2u);
    181       if (i % 2u)
    182          elem = nir_ishr_imm(b, elem, 16u);
    183 
    184       vertex_offset = nir_bcsel(b, cond, elem, vertex_offset);
    185    }
    186 
    187    return nir_iand_imm(b, vertex_offset, 0xffffu);
    188 }
    189 
    190 static nir_ssa_def *
    191 gs_per_vertex_input_offset(nir_builder *b,
    192                            lower_esgs_io_state *st,
    193                            nir_intrinsic_instr *instr)
    194 {
    195    nir_src *vertex_src = nir_get_io_vertex_index_src(instr);
    196    nir_ssa_def *vertex_offset = st->chip_class >= GFX9
    197                                 ? gs_per_vertex_input_vertex_offset_gfx9(b, vertex_src)
    198                                 : gs_per_vertex_input_vertex_offset_gfx6(b, vertex_src);
    199 
    200    unsigned base_stride = st->chip_class >= GFX9 ? 1 : 64 /* Wave size on GFX6-8 */;
    201    nir_ssa_def *io_off = nir_build_calc_io_offset(b, instr, nir_imm_int(b, base_stride * 4u), base_stride);
    202    nir_ssa_def *off = nir_iadd(b, io_off, vertex_offset);
    203    return nir_imul_imm(b, off, 4u);
    204 }
    205 
    206 static nir_ssa_def *
    207 lower_gs_per_vertex_input_load(nir_builder *b,
    208                                nir_instr *instr,
    209                                void *state)
    210 {
    211    lower_esgs_io_state *st = (lower_esgs_io_state *) state;
    212    nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
    213    nir_ssa_def *off = gs_per_vertex_input_offset(b, st, intrin);
    214 
    215    if (st->chip_class >= GFX9)
    216       return nir_build_load_shared(b, intrin->dest.ssa.num_components, intrin->dest.ssa.bit_size, off,
    217                                    .align_mul = 16u, .align_offset = (nir_intrinsic_component(intrin) * 4u) % 16u);
    218 
    219    unsigned wave_size = 64u; /* GFX6-8 only support wave64 */
    220    nir_ssa_def *ring = nir_build_load_ring_esgs_amd(b);
    221    return emit_split_buffer_load(b, ring, off, nir_imm_zero(b, 1, 32), 4u * wave_size,
    222                                  intrin->dest.ssa.num_components, intrin->dest.ssa.bit_size);
    223 }
    224 
    225 static bool
    226 filter_load_per_vertex_input(const nir_instr *instr, UNUSED const void *state)
    227 {
    228    return instr->type == nir_instr_type_intrinsic && nir_instr_as_intrinsic(instr)->intrinsic == nir_intrinsic_load_per_vertex_input;
    229 }
    230 
    231 void
    232 ac_nir_lower_es_outputs_to_mem(nir_shader *shader,
    233                                enum chip_class chip_class,
    234                                unsigned num_reserved_es_outputs)
    235 {
    236    lower_esgs_io_state state = {
    237       .chip_class = chip_class,
    238       .num_reserved_es_outputs = num_reserved_es_outputs,
    239    };
    240 
    241    nir_shader_instructions_pass(shader,
    242                                 lower_es_output_store,
    243                                 nir_metadata_block_index | nir_metadata_dominance,
    244                                 &state);
    245 }
    246 
    247 void
    248 ac_nir_lower_gs_inputs_to_mem(nir_shader *shader,
    249                               enum chip_class chip_class,
    250                               unsigned num_reserved_es_outputs)
    251 {
    252    lower_esgs_io_state state = {
    253       .chip_class = chip_class,
    254       .num_reserved_es_outputs = num_reserved_es_outputs,
    255    };
    256 
    257    nir_shader_lower_instructions(shader,
    258                                  filter_load_per_vertex_input,
    259                                  lower_gs_per_vertex_input_load,
    260                                  &state);
    261 }
    262