• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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