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