2 * Copyright © 2018 Intel Corporation
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:
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
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
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"
31 * This file does the linking of GLSL transform feedback using NIR.
33 * Note: This linking pass is currently tailored for ARB_gl_spirv needs and
37 struct active_xfb_buffer
{
42 struct active_xfb_varyings
{
43 unsigned num_varyings
;
46 struct nir_variable
**varyings
;
47 struct active_xfb_buffer buffers
[MAX_FEEDBACK_BUFFERS
];
51 get_num_outputs(nir_variable
*var
)
53 return glsl_count_attribute_slots(var
->type
,
54 false /* is_vertex_input */);
58 add_xfb_varying(struct active_xfb_varyings
*active_varyings
,
61 if (active_varyings
->num_varyings
>= active_varyings
->buffer_size
) {
62 if (active_varyings
->buffer_size
== 0)
63 active_varyings
->buffer_size
= 1;
65 active_varyings
->buffer_size
*= 2;
67 active_varyings
->varyings
= realloc(active_varyings
->varyings
,
68 sizeof(nir_variable
*) *
69 active_varyings
->buffer_size
);
72 active_varyings
->varyings
[active_varyings
->num_varyings
++] = var
;
74 active_varyings
->num_outputs
+= get_num_outputs(var
);
78 cmp_xfb_offset(const void *x_generic
, const void *y_generic
)
80 const nir_variable
*const *x
= x_generic
;
81 const nir_variable
*const *y
= y_generic
;
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
;
89 get_active_xfb_varyings(struct gl_shader_program
*prog
,
90 struct active_xfb_varyings
*active_varyings
)
92 for (unsigned i
= 0; i
< MESA_SHADER_STAGES
; ++i
) {
93 struct gl_linked_shader
*sh
= prog
->_LinkedShaders
[i
];
97 nir_shader
*nir
= sh
->Program
->nir
;
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
;
107 if (!var
->data
.explicit_xfb_buffer
||
108 !var
->data
.explicit_offset
)
111 active_varyings
->buffers
[var
->data
.xfb_buffer
].num_varyings
++;
113 add_xfb_varying(active_varyings
, var
);
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.
121 qsort(active_varyings
->varyings
,
122 active_varyings
->num_varyings
,
123 sizeof(*active_varyings
->varyings
),
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
)
134 unsigned num_outputs
= 0;
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
);
141 for (unsigned i
= 0; i
< length
; i
++) {
142 unsigned child_outputs
= add_varying_outputs(var
,
146 output
+ num_outputs
);
147 num_outputs
+= child_outputs
;
148 location_offset
+= child_outputs
;
149 dest_offset
+= component_slots
;
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
,
159 output
+ num_outputs
);
160 num_outputs
+= child_outputs
;
161 location_offset
+= child_outputs
;
162 dest_offset
+= glsl_get_component_slots(child_type
);
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
);
169 while (num_components
> 0) {
170 unsigned output_size
= MIN2(num_components
, 4 - location_frac
);
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
;
179 dest_offset
+= output_size
;
180 num_components
-= output_size
;
192 gl_nir_link_assign_xfb_resources(struct gl_context
*ctx
,
193 struct gl_shader_program
*prog
)
196 * From ARB_gl_spirv spec:
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*"
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.
213 struct gl_program
*xfb_prog
= prog
->last_vert_prog
;
215 if (xfb_prog
== NULL
)
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
);
223 struct active_xfb_varyings active_varyings
= { 0 };
225 get_active_xfb_varyings(prog
, &active_varyings
);
227 for (unsigned buf
= 0; buf
< MAX_FEEDBACK_BUFFERS
; buf
++)
228 prog
->TransformFeedback
.BufferStride
[buf
] = active_varyings
.buffers
[buf
].stride
;
230 prog
->TransformFeedback
.NumVarying
= active_varyings
.num_varyings
;
231 prog
->TransformFeedback
.VaryingNames
=
232 malloc(sizeof(GLchar
*) * active_varyings
.num_varyings
);
234 struct gl_transform_feedback_info
*linked_xfb
=
235 rzalloc(xfb_prog
, struct gl_transform_feedback_info
);
236 xfb_prog
->sh
.LinkedTransformFeedback
= linked_xfb
;
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
;
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
;
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
];
254 /* From ARB_gl_spirv spec:
256 * "19. How should the program interface query operations behave for
257 * program objects created from SPIR-V shaders?
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."
271 * "RESOLVED. Pick (c), but also allow debug names to be returned
272 * if an implementation wants to."
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
278 prog
->TransformFeedback
.VaryingNames
[i
] = NULL
;
280 unsigned varying_outputs
= add_varying_outputs(var
,
282 0, /* location_offset */
285 assert(varying_outputs
== get_num_outputs(var
));
286 output
= output
+ varying_outputs
;
288 struct gl_transform_feedback_varying_info
*varying
=
289 linked_xfb
->Varyings
+ i
;
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
;
299 /* Make sure MaxTransformFeedbackBuffers is <= 32 so the bitmask for
300 * tracking the number of buffers doesn't overflow.
302 unsigned buffers
= 0;
303 assert(ctx
->Const
.MaxTransformFeedbackBuffers
<= sizeof(buffers
) * 8);
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
;
313 linked_xfb
->ActiveBuffers
= buffers
;
315 free(active_varyings
.varyings
);