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 static bool
walk_varyings(UNUSED nir_builder * b,nir_instr * instr,void * data)71 walk_varyings(UNUSED nir_builder *b, nir_instr *instr, void *data)
72 {
73 struct slot_info *slots = data;
74
75 if (instr->type != nir_instr_type_intrinsic)
76 return false;
77
78 nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
79 unsigned count;
80
81 /* Only consider intrinsics that access varyings */
82 switch (intr->intrinsic) {
83 case nir_intrinsic_store_output:
84 if (b->shader->info.stage != MESA_SHADER_VERTEX)
85 return false;
86
87 count = nir_src_num_components(intr->src[0]);
88 break;
89
90 case nir_intrinsic_load_input:
91 case nir_intrinsic_load_interpolated_input:
92 if (b->shader->info.stage != MESA_SHADER_FRAGMENT)
93 return false;
94
95 count = intr->def.num_components;
96 break;
97
98 default:
99 return false;
100 }
101
102 nir_io_semantics sem = nir_intrinsic_io_semantics(intr);
103
104 if (sem.no_varying)
105 return false;
106
107 /* In a fragment shader, flat shading is lowered to load_input but
108 * interpolation is lowered to load_interpolated_input, so we can check
109 * the intrinsic to distinguish.
110 *
111 * In a vertex shader, we consider everything flat, as the information
112 * will not contribute to the final linked varyings -- flatness is used
113 * only to determine the type, and the GL linker uses the type from the
114 * fragment shader instead.
115 */
116 bool flat = (intr->intrinsic != nir_intrinsic_load_interpolated_input);
117 nir_alu_type type = flat ? nir_type_uint : nir_type_float;
118
119 /* Demote interpolated float varyings to fp16 where possible. We do not
120 * demote flat varyings, including integer varyings, due to various
121 * issues with the Midgard hardware behaviour and TGSI shaders, as well
122 * as having no demonstrable benefit in practice.
123 */
124 if (type == nir_type_float && sem.medium_precision)
125 type |= 16;
126 else
127 type |= 32;
128
129 /* Count currently contains the number of components accessed by this
130 * intrinsics. However, we may be accessing a fractional location,
131 * indicating by the NIR component. Add that in. The final value be the
132 * maximum (component + count), an upper bound on the number of
133 * components possibly used.
134 */
135 count += nir_intrinsic_component(intr);
136
137 /* Consider each slot separately */
138 for (unsigned offset = 0; offset < sem.num_slots; ++offset) {
139 unsigned location = sem.location + offset;
140 unsigned index = nir_intrinsic_base(intr) + offset;
141
142 if (slots[location].type) {
143 assert(slots[location].type == type);
144 assert(slots[location].index == index);
145 } else {
146 slots[location].type = type;
147 slots[location].index = index;
148 }
149
150 slots[location].count = MAX2(slots[location].count, count);
151 }
152
153 return false;
154 }
155
156 void
pan_nir_collect_varyings(nir_shader * s,struct pan_shader_info * info)157 pan_nir_collect_varyings(nir_shader *s, struct pan_shader_info *info)
158 {
159 if (s->info.stage != MESA_SHADER_VERTEX &&
160 s->info.stage != MESA_SHADER_FRAGMENT)
161 return;
162
163 struct slot_info slots[64] = {0};
164 nir_shader_instructions_pass(s, walk_varyings, nir_metadata_all, slots);
165
166 struct pan_shader_varying *varyings = (s->info.stage == MESA_SHADER_VERTEX)
167 ? info->varyings.output
168 : info->varyings.input;
169
170 unsigned count = 0;
171
172 for (unsigned i = 0; i < ARRAY_SIZE(slots); ++i) {
173 if (!slots[i].type)
174 continue;
175
176 enum pipe_format format = varying_format(slots[i].type, slots[i].count);
177 assert(format != PIPE_FORMAT_NONE);
178
179 unsigned index = slots[i].index;
180 count = MAX2(count, index + 1);
181
182 varyings[index].location = i;
183 varyings[index].format = format;
184 }
185
186 if (s->info.stage == MESA_SHADER_VERTEX)
187 info->varyings.output_count = count;
188 else
189 info->varyings.input_count = count;
190 }
191