glsl: Allow gl_nir_lower_samplers*() without a gl_shader_program
[mesa.git] / src / compiler / glsl / gl_nir_link_xfb.c
1 /*
2 * Copyright © 2018 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "nir.h"
25 #include "gl_nir_linker.h"
26 #include "ir_uniform.h" /* for gl_uniform_storage */
27 #include "linker_util.h"
28 #include "main/context.h"
29
30 /*
31 * This file does the linking of GLSL transform feedback using NIR.
32 *
33 * Note: This linking pass is currently tailored for ARB_gl_spirv needs and
34 * particularities.
35 */
36
37 struct active_xfb_buffer {
38 GLuint stride;
39 GLuint num_varyings;
40 };
41
42 struct active_xfb_varyings {
43 unsigned num_varyings;
44 unsigned num_outputs;
45 unsigned buffer_size;
46 struct nir_variable **varyings;
47 struct active_xfb_buffer buffers[MAX_FEEDBACK_BUFFERS];
48 };
49
50 static unsigned
51 get_num_outputs(nir_variable *var)
52 {
53 return glsl_count_attribute_slots(var->type,
54 false /* is_vertex_input */);
55 }
56
57 static void
58 add_xfb_varying(struct active_xfb_varyings *active_varyings,
59 nir_variable *var)
60 {
61 if (active_varyings->num_varyings >= active_varyings->buffer_size) {
62 if (active_varyings->buffer_size == 0)
63 active_varyings->buffer_size = 1;
64 else
65 active_varyings->buffer_size *= 2;
66
67 active_varyings->varyings = realloc(active_varyings->varyings,
68 sizeof(nir_variable*) *
69 active_varyings->buffer_size);
70 }
71
72 active_varyings->varyings[active_varyings->num_varyings++] = var;
73
74 active_varyings->num_outputs += get_num_outputs(var);
75 }
76
77 static int
78 cmp_xfb_offset(const void *x_generic, const void *y_generic)
79 {
80 const nir_variable *const *x = x_generic;
81 const nir_variable *const *y = y_generic;
82
83 if ((*x)->data.xfb_buffer != (*y)->data.xfb_buffer)
84 return (*x)->data.xfb_buffer - (*y)->data.xfb_buffer;
85 return (*x)->data.offset - (*y)->data.offset;
86 }
87
88 static void
89 get_active_xfb_varyings(struct gl_shader_program *prog,
90 struct active_xfb_varyings *active_varyings)
91 {
92 for (unsigned i = 0; i < MESA_SHADER_STAGES; ++i) {
93 struct gl_linked_shader *sh = prog->_LinkedShaders[i];
94 if (sh == NULL)
95 continue;
96
97 nir_shader *nir = sh->Program->nir;
98
99 nir_foreach_variable(var, &nir->outputs) {
100 if (var->data.explicit_xfb_buffer &&
101 var->data.explicit_xfb_stride) {
102 assert(var->data.xfb_buffer < MAX_FEEDBACK_BUFFERS);
103 active_varyings->buffers[var->data.xfb_buffer].stride =
104 var->data.xfb_stride;
105 }
106
107 if (!var->data.explicit_xfb_buffer ||
108 !var->data.explicit_offset)
109 continue;
110
111 active_varyings->buffers[var->data.xfb_buffer].num_varyings++;
112
113 add_xfb_varying(active_varyings, var);
114 }
115 }
116
117 /* The xfb_offset qualifier does not have to be used in increasing order
118 * however some drivers expect to receive the list of transform feedback
119 * declarations in order so sort it now for convenience.
120 */
121 qsort(active_varyings->varyings,
122 active_varyings->num_varyings,
123 sizeof(*active_varyings->varyings),
124 cmp_xfb_offset);
125 }
126
127 static unsigned
128 add_varying_outputs(nir_variable *var,
129 const struct glsl_type *type,
130 unsigned location_offset,
131 unsigned dest_offset,
132 struct gl_transform_feedback_output *output)
133 {
134 unsigned num_outputs = 0;
135
136 if (glsl_type_is_array(type) || glsl_type_is_matrix(type)) {
137 unsigned length = glsl_get_length(type);
138 const struct glsl_type *child_type = glsl_get_array_element(type);
139 unsigned component_slots = glsl_get_component_slots(child_type);
140
141 for (unsigned i = 0; i < length; i++) {
142 unsigned child_outputs = add_varying_outputs(var,
143 child_type,
144 location_offset,
145 dest_offset,
146 output + num_outputs);
147 num_outputs += child_outputs;
148 location_offset += child_outputs;
149 dest_offset += component_slots;
150 }
151 } else if (glsl_type_is_struct(type)) {
152 unsigned length = glsl_get_length(type);
153 for (unsigned i = 0; i < length; i++) {
154 const struct glsl_type *child_type = glsl_get_struct_field(type, i);
155 unsigned child_outputs = add_varying_outputs(var,
156 child_type,
157 location_offset,
158 dest_offset,
159 output + num_outputs);
160 num_outputs += child_outputs;
161 location_offset += child_outputs;
162 dest_offset += glsl_get_component_slots(child_type);
163 }
164 } else {
165 unsigned location = var->data.location + location_offset;
166 unsigned location_frac = var->data.location_frac;
167 unsigned num_components = glsl_get_component_slots(type);
168
169 while (num_components > 0) {
170 unsigned output_size = MIN2(num_components, 4 - location_frac);
171
172 output->OutputRegister = location;
173 output->OutputBuffer = var->data.xfb_buffer;
174 output->NumComponents = output_size;
175 output->StreamId = var->data.stream;
176 output->DstOffset = var->data.offset / 4 + dest_offset;
177 output->ComponentOffset = location_frac;
178
179 dest_offset += output_size;
180 num_components -= output_size;
181 num_outputs++;
182 output++;
183 location++;
184 location_frac = 0;
185 }
186 }
187
188 return num_outputs;
189 }
190
191 void
192 gl_nir_link_assign_xfb_resources(struct gl_context *ctx,
193 struct gl_shader_program *prog)
194 {
195 /*
196 * From ARB_gl_spirv spec:
197 *
198 * "- If the *Xfb* Execution Mode is set, any output variable that is at
199 * least partially captured:
200 * * must be decorated with an *XfbBuffer*, declaring the capturing buffer
201 * * must have at least one captured output variable in the capturing
202 * buffer decorated with an *XfbStride* (and all such *XfbStride* values
203 * for the capturing buffer must be equal)
204 * - If the *Xfb* Execution Mode is set, any captured output:
205 * * must be a non-structure decorated with *Offset* or a member of a
206 * structure whose type member is decorated with *Offset*"
207 *
208 * Note the "must be", meaning that explicit buffer, offset and stride are
209 * mandatory. So as this is intended to work with SPIR-V shaders we don't
210 * need to calculate the offset or the stride.
211 */
212
213 struct gl_program *xfb_prog = prog->last_vert_prog;
214
215 if (xfb_prog == NULL)
216 return;
217
218 /* free existing varyings, if any */
219 for (unsigned i = 0; i < prog->TransformFeedback.NumVarying; i++)
220 free(prog->TransformFeedback.VaryingNames[i]);
221 free(prog->TransformFeedback.VaryingNames);
222
223 struct active_xfb_varyings active_varyings = { 0 };
224
225 get_active_xfb_varyings(prog, &active_varyings);
226
227 for (unsigned buf = 0; buf < MAX_FEEDBACK_BUFFERS; buf++)
228 prog->TransformFeedback.BufferStride[buf] = active_varyings.buffers[buf].stride;
229
230 prog->TransformFeedback.NumVarying = active_varyings.num_varyings;
231 prog->TransformFeedback.VaryingNames =
232 malloc(sizeof(GLchar *) * active_varyings.num_varyings);
233
234 struct gl_transform_feedback_info *linked_xfb =
235 rzalloc(xfb_prog, struct gl_transform_feedback_info);
236 xfb_prog->sh.LinkedTransformFeedback = linked_xfb;
237
238 linked_xfb->Outputs =
239 rzalloc_array(xfb_prog,
240 struct gl_transform_feedback_output,
241 active_varyings.num_outputs);
242 linked_xfb->NumOutputs = active_varyings.num_outputs;
243
244 linked_xfb->Varyings =
245 rzalloc_array(xfb_prog,
246 struct gl_transform_feedback_varying_info,
247 active_varyings.num_varyings);
248 linked_xfb->NumVarying = active_varyings.num_varyings;
249
250 struct gl_transform_feedback_output *output = linked_xfb->Outputs;
251 for (unsigned i = 0; i < active_varyings.num_varyings; i++) {
252 struct nir_variable *var = active_varyings.varyings[i];
253
254 /* From ARB_gl_spirv spec:
255 *
256 * "19. How should the program interface query operations behave for
257 * program objects created from SPIR-V shaders?
258 *
259 * DISCUSSION: we previously said we didn't need reflection to work
260 * for SPIR-V shaders (at least for the first version), however we
261 * are left with specifying how it should "not work". The primary
262 * issue is that SPIR-V binaries are not required to have names
263 * associated with variables. They can be associated in debug
264 * information, but there is no requirement for that to be present,
265 * and it should not be relied upon."
266 *
267 * Options:"
268 *
269 * <skip>
270 *
271 * "RESOLVED. Pick (c), but also allow debug names to be returned
272 * if an implementation wants to."
273 *
274 * So names are considered optional debug info, so the linker needs to
275 * work without them, and returning them is optional. For simplicity at
276 * this point we are ignoring names
277 */
278 prog->TransformFeedback.VaryingNames[i] = NULL;
279
280 unsigned varying_outputs = add_varying_outputs(var,
281 var->type,
282 0, /* location_offset */
283 0, /* dest_offset */
284 output);
285 assert(varying_outputs == get_num_outputs(var));
286 output = output + varying_outputs;
287
288 struct gl_transform_feedback_varying_info *varying =
289 linked_xfb->Varyings + i;
290
291 /* ARB_gl_spirv: see above. */
292 varying->Name = NULL;
293 varying->Type = glsl_get_gl_type(var->type);
294 varying->BufferIndex = var->data.xfb_buffer;
295 varying->Size = glsl_get_length(var->type);
296 varying->Offset = var->data.offset;
297 }
298
299 /* Make sure MaxTransformFeedbackBuffers is <= 32 so the bitmask for
300 * tracking the number of buffers doesn't overflow.
301 */
302 unsigned buffers = 0;
303 assert(ctx->Const.MaxTransformFeedbackBuffers <= sizeof(buffers) * 8);
304
305 for (unsigned buf = 0; buf < MAX_FEEDBACK_BUFFERS; buf++) {
306 if (active_varyings.buffers[buf].stride > 0) {
307 linked_xfb->Buffers[buf].Stride = active_varyings.buffers[buf].stride / 4;
308 linked_xfb->Buffers[buf].NumVaryings = active_varyings.buffers[buf].num_varyings;
309 buffers |= 1 << buf;
310 }
311 }
312
313 linked_xfb->ActiveBuffers = buffers;
314
315 free(active_varyings.varyings);
316 }