xref: /aosp_15_r20/external/mesa3d/src/amd/vulkan/nir/radv_nir_export_multiview.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2016 Red Hat.
3  * Copyright © 2016 Bas Nieuwenhuizen
4  * Copyright © 2023 Valve Corporation
5  *
6  * SPDX-License-Identifier: MIT
7  */
8 
9 #include "nir.h"
10 #include "nir_builder.h"
11 #include "radv_nir.h"
12 
13 static nir_variable *
find_layer_out_var(nir_shader * nir)14 find_layer_out_var(nir_shader *nir)
15 {
16    nir_variable *var = nir_find_variable_with_location(nir, nir_var_shader_out, VARYING_SLOT_LAYER);
17    if (var != NULL)
18       return var;
19 
20    var = nir_variable_create(nir, nir_var_shader_out, glsl_int_type(), "layer id");
21    var->data.location = VARYING_SLOT_LAYER;
22    var->data.interpolation = INTERP_MODE_NONE;
23 
24    return var;
25 }
26 
27 bool
radv_nir_export_multiview(nir_shader * nir)28 radv_nir_export_multiview(nir_shader *nir)
29 {
30    nir_function_impl *impl = nir_shader_get_entrypoint(nir);
31    bool progress = false;
32 
33    nir_builder b = nir_builder_create(impl);
34 
35    /* This pass is not suitable for mesh shaders, because it can't know the mapping between API mesh
36     * shader invocations and output primitives. Needs to be handled in ac_nir_lower_ngg.
37     */
38    assert(nir->info.stage == MESA_SHADER_VERTEX || nir->info.stage == MESA_SHADER_TESS_EVAL ||
39           nir->info.stage == MESA_SHADER_GEOMETRY);
40 
41    /* Iterate in reverse order since there should be only one deref store to POS after
42     * lower_io_to_temporaries for vertex shaders and inject the layer there. For geometry shaders,
43     * the layer is injected right before every emit_vertex_with_counter.
44     */
45    nir_variable *layer = NULL;
46    nir_foreach_block_reverse (block, impl) {
47       nir_foreach_instr_reverse (instr, block) {
48          if (instr->type != nir_instr_type_intrinsic)
49             continue;
50 
51          if (nir->info.stage == MESA_SHADER_GEOMETRY) {
52             nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
53             if (intr->intrinsic != nir_intrinsic_emit_vertex_with_counter)
54                continue;
55 
56             b.cursor = nir_before_instr(instr);
57          } else {
58             nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
59             if (intr->intrinsic != nir_intrinsic_store_deref)
60                continue;
61 
62             nir_variable *var = nir_intrinsic_get_var(intr, 0);
63             if (var->data.mode != nir_var_shader_out || var->data.location != VARYING_SLOT_POS)
64                continue;
65 
66             b.cursor = nir_after_instr(instr);
67          }
68 
69          if (!layer)
70             layer = find_layer_out_var(nir);
71 
72          nir_store_var(&b, layer, nir_load_view_index(&b), 1);
73 
74          /* Update outputs_written to reflect that the pass added a new output. */
75          nir->info.outputs_written |= BITFIELD64_BIT(VARYING_SLOT_LAYER);
76 
77          progress = true;
78          if (nir->info.stage == MESA_SHADER_VERTEX)
79             break;
80       }
81       if (nir->info.stage == MESA_SHADER_VERTEX && progress)
82          break;
83    }
84 
85    if (progress)
86       nir_metadata_preserve(impl, nir_metadata_control_flow);
87    else
88       nir_metadata_preserve(impl, nir_metadata_all);
89 
90    return progress;
91 }
92