xref: /aosp_15_r20/external/mesa3d/src/panfrost/util/pan_collect_varyings.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright (c) 2022 Amazon.com, Inc. or its affiliates.
3  * Copyright (C) 2019-2022 Collabora, Ltd.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * 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 #include "compiler/nir/nir.h"
26 #include "compiler/nir/nir_builder.h"
27 #include "pan_ir.h"
28 
29 static enum pipe_format
varying_format(nir_alu_type t,unsigned ncomps)30 varying_format(nir_alu_type t, unsigned ncomps)
31 {
32    assert(ncomps >= 1 && ncomps <= 4);
33 
34 #define VARYING_FORMAT(ntype, nsz, ptype, psz)                                 \
35    {                                                                           \
36       .type = nir_type_##ntype##nsz, .formats = {                              \
37          PIPE_FORMAT_R##psz##_##ptype,                                         \
38          PIPE_FORMAT_R##psz##G##psz##_##ptype,                                 \
39          PIPE_FORMAT_R##psz##G##psz##B##psz##_##ptype,                         \
40          PIPE_FORMAT_R##psz##G##psz##B##psz##A##psz##_##ptype,                 \
41       }                                                                        \
42    }
43 
44    static const struct {
45       nir_alu_type type;
46       enum pipe_format formats[4];
47    } conv[] = {
48       VARYING_FORMAT(float, 32, FLOAT, 32),
49       VARYING_FORMAT(uint, 32, UINT, 32),
50       VARYING_FORMAT(float, 16, FLOAT, 16),
51    };
52 #undef VARYING_FORMAT
53 
54    assert(ncomps > 0 && ncomps <= ARRAY_SIZE(conv[0].formats));
55 
56    for (unsigned i = 0; i < ARRAY_SIZE(conv); i++) {
57       if (conv[i].type == t)
58          return conv[i].formats[ncomps - 1];
59    }
60 
61    unreachable("Invalid type");
62 }
63 
64 struct slot_info {
65    nir_alu_type type;
66    unsigned count;
67    unsigned index;
68 };
69 
70 struct walk_varyings_data {
71    struct pan_shader_info *info;
72    struct slot_info *slots;
73 };
74 
75 static bool
walk_varyings(UNUSED nir_builder * b,nir_instr * instr,void * data)76 walk_varyings(UNUSED nir_builder *b, nir_instr *instr, void *data)
77 {
78    struct walk_varyings_data *wv_data = data;
79    struct pan_shader_info *info = wv_data->info;
80    struct slot_info *slots = wv_data->slots;
81 
82    if (instr->type != nir_instr_type_intrinsic)
83       return false;
84 
85    nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
86    unsigned count;
87 
88    /* Only consider intrinsics that access varyings */
89    switch (intr->intrinsic) {
90    case nir_intrinsic_store_output:
91       if (b->shader->info.stage != MESA_SHADER_VERTEX)
92          return false;
93 
94       count = nir_src_num_components(intr->src[0]);
95       break;
96 
97    case nir_intrinsic_load_input:
98    case nir_intrinsic_load_interpolated_input:
99       if (b->shader->info.stage != MESA_SHADER_FRAGMENT)
100          return false;
101 
102       count = intr->def.num_components;
103       break;
104 
105    default:
106       return false;
107    }
108 
109    nir_io_semantics sem = nir_intrinsic_io_semantics(intr);
110 
111    if (sem.no_varying)
112       return false;
113 
114    /* In a fragment shader, flat shading is lowered to load_input but
115     * interpolation is lowered to load_interpolated_input, so we can check
116     * the intrinsic to distinguish.
117     *
118     * In a vertex shader, we consider everything flat, as the information
119     * will not contribute to the final linked varyings -- flatness is used
120     * only to determine the type, and the GL linker uses the type from the
121     * fragment shader instead.
122     */
123    bool flat = intr->intrinsic != nir_intrinsic_load_interpolated_input;
124    bool auto32 = !info->quirk_no_auto32;
125    nir_alu_type type = (flat && auto32) ? nir_type_uint : nir_type_float;
126 
127    /* Demote interpolated float varyings to fp16 where possible. We do not
128     * demote flat varyings, including integer varyings, due to various
129     * issues with the Midgard hardware behaviour and TGSI shaders, as well
130     * as having no demonstrable benefit in practice.
131     */
132    if (type == nir_type_float && sem.medium_precision)
133       type |= 16;
134    else
135       type |= 32;
136 
137    /* Count currently contains the number of components accessed by this
138     * intrinsics. However, we may be accessing a fractional location,
139     * indicating by the NIR component. Add that in. The final value be the
140     * maximum (component + count), an upper bound on the number of
141     * components possibly used.
142     */
143    count += nir_intrinsic_component(intr);
144 
145    /* Consider each slot separately */
146    for (unsigned offset = 0; offset < sem.num_slots; ++offset) {
147       unsigned location = sem.location + offset;
148       unsigned index = pan_res_handle_get_index(nir_intrinsic_base(intr)) + offset;
149 
150       if (slots[location].type) {
151          assert(slots[location].type == type);
152          assert(slots[location].index == index);
153       } else {
154          slots[location].type = type;
155          slots[location].index = index;
156       }
157 
158       slots[location].count = MAX2(slots[location].count, count);
159    }
160 
161    return false;
162 }
163 
164 void
pan_nir_collect_varyings(nir_shader * s,struct pan_shader_info * info)165 pan_nir_collect_varyings(nir_shader *s, struct pan_shader_info *info)
166 {
167    if (s->info.stage != MESA_SHADER_VERTEX &&
168        s->info.stage != MESA_SHADER_FRAGMENT)
169       return;
170 
171    struct slot_info slots[64] = {0};
172    struct walk_varyings_data wv_data = {info, slots};
173    nir_shader_instructions_pass(s, walk_varyings, nir_metadata_all, &wv_data);
174 
175    struct pan_shader_varying *varyings = (s->info.stage == MESA_SHADER_VERTEX)
176                                             ? info->varyings.output
177                                             : info->varyings.input;
178 
179    unsigned count = 0;
180 
181    for (unsigned i = 0; i < ARRAY_SIZE(slots); ++i) {
182       if (!slots[i].type)
183          continue;
184 
185       enum pipe_format format = varying_format(slots[i].type, slots[i].count);
186       assert(format != PIPE_FORMAT_NONE);
187 
188       unsigned index = slots[i].index;
189       count = MAX2(count, index + 1);
190 
191       varyings[index].location = i;
192       varyings[index].format = format;
193    }
194 
195    if (s->info.stage == MESA_SHADER_VERTEX)
196       info->varyings.output_count = count;
197    else
198       info->varyings.input_count = count;
199 }
200