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 "nir_xfb_info.h"
26 #include "gl_nir_linker.h"
27 #include "linker_util.h"
28 #include "main/context.h"
29 #include "util/u_math.h"
32 * This file does the linking of GLSL transform feedback using NIR.
34 * Note: This linking pass is currently tailored for ARB_gl_spirv needs and
39 gl_nir_link_assign_xfb_resources(struct gl_context
*ctx
,
40 struct gl_shader_program
*prog
)
43 * From ARB_gl_spirv spec:
45 * "- If the *Xfb* Execution Mode is set, any output variable that is at
46 * least partially captured:
47 * * must be decorated with an *XfbBuffer*, declaring the capturing buffer
48 * * must have at least one captured output variable in the capturing
49 * buffer decorated with an *XfbStride* (and all such *XfbStride* values
50 * for the capturing buffer must be equal)
51 * - If the *Xfb* Execution Mode is set, any captured output:
52 * * must be a non-structure decorated with *Offset* or a member of a
53 * structure whose type member is decorated with *Offset*"
55 * Note the "must be", meaning that explicit buffer, offset and stride are
56 * mandatory. So as this is intended to work with SPIR-V shaders we don't
57 * need to calculate the offset or the stride.
60 struct gl_program
*xfb_prog
= prog
->last_vert_prog
;
65 /* free existing varyings, if any */
66 for (unsigned i
= 0; i
< prog
->TransformFeedback
.NumVarying
; i
++)
67 free(prog
->TransformFeedback
.VaryingNames
[i
]);
68 free(prog
->TransformFeedback
.VaryingNames
);
70 nir_xfb_info
*xfb_info
= NULL
;
71 nir_xfb_varyings_info
*varyings_info
= NULL
;
73 /* Find last stage before fragment shader */
74 for (int stage
= MESA_SHADER_FRAGMENT
- 1; stage
>= 0; stage
--) {
75 struct gl_linked_shader
*sh
= prog
->_LinkedShaders
[stage
];
77 if (sh
&& stage
!= MESA_SHADER_TESS_CTRL
) {
78 xfb_info
= nir_gather_xfb_info_with_varyings(sh
->Program
->nir
, NULL
, &varyings_info
);
83 struct gl_transform_feedback_info
*linked_xfb
=
84 rzalloc(xfb_prog
, struct gl_transform_feedback_info
);
85 xfb_prog
->sh
.LinkedTransformFeedback
= linked_xfb
;
88 prog
->TransformFeedback
.NumVarying
= 0;
89 linked_xfb
->NumOutputs
= 0;
90 linked_xfb
->NumVarying
= 0;
91 linked_xfb
->ActiveBuffers
= 0;
95 for (unsigned buf
= 0; buf
< MAX_FEEDBACK_BUFFERS
; buf
++)
96 prog
->TransformFeedback
.BufferStride
[buf
] = xfb_info
->buffers
[buf
].stride
;
98 prog
->TransformFeedback
.NumVarying
= varyings_info
->varying_count
;
99 prog
->TransformFeedback
.VaryingNames
=
100 malloc(sizeof(GLchar
*) * varyings_info
->varying_count
);
102 linked_xfb
->Outputs
=
103 rzalloc_array(xfb_prog
,
104 struct gl_transform_feedback_output
,
105 xfb_info
->output_count
);
106 linked_xfb
->NumOutputs
= xfb_info
->output_count
;
108 linked_xfb
->Varyings
=
109 rzalloc_array(xfb_prog
,
110 struct gl_transform_feedback_varying_info
,
111 varyings_info
->varying_count
);
112 linked_xfb
->NumVarying
= varyings_info
->varying_count
;
114 int buffer_index
= 0; /* Corresponds to GL_TRANSFORM_FEEDBACK_BUFFER_INDEX */
116 (varyings_info
->varying_count
> 0) ?
117 xfb_info
->outputs
[0].buffer
: 0;
119 for (unsigned i
= 0; i
< varyings_info
->varying_count
; i
++) {
120 nir_xfb_varying_info
*xfb_varying
= &varyings_info
->varyings
[i
];
122 /* From ARB_gl_spirv spec:
124 * "19. How should the program interface query operations behave for
125 * program objects created from SPIR-V shaders?
127 * DISCUSSION: we previously said we didn't need reflection to work
128 * for SPIR-V shaders (at least for the first version), however we
129 * are left with specifying how it should "not work". The primary
130 * issue is that SPIR-V binaries are not required to have names
131 * associated with variables. They can be associated in debug
132 * information, but there is no requirement for that to be present,
133 * and it should not be relied upon."
139 * "RESOLVED. Pick (c), but also allow debug names to be returned
140 * if an implementation wants to."
142 * So names are considered optional debug info, so the linker needs to
143 * work without them, and returning them is optional. For simplicity at
144 * this point we are ignoring names
146 prog
->TransformFeedback
.VaryingNames
[i
] = NULL
;
148 if (xfb_buffer
!= xfb_varying
->buffer
) {
150 xfb_buffer
= xfb_varying
->buffer
;
153 struct gl_transform_feedback_varying_info
*varying
=
154 linked_xfb
->Varyings
+ i
;
156 /* ARB_gl_spirv: see above. */
157 varying
->Name
= NULL
;
158 varying
->Type
= glsl_get_gl_type(xfb_varying
->type
);
159 varying
->BufferIndex
= buffer_index
;
160 varying
->Size
= glsl_type_is_array(xfb_varying
->type
) ?
161 glsl_get_length(xfb_varying
->type
) : 1;
162 varying
->Offset
= xfb_varying
->offset
;
165 for (unsigned i
= 0; i
< xfb_info
->output_count
; i
++) {
166 nir_xfb_output_info
*xfb_output
= &xfb_info
->outputs
[i
];
168 struct gl_transform_feedback_output
*output
=
169 linked_xfb
->Outputs
+ i
;
171 output
->OutputRegister
= xfb_output
->location
;
172 output
->OutputBuffer
= xfb_output
->buffer
;
173 output
->NumComponents
= util_bitcount(xfb_output
->component_mask
);
174 output
->StreamId
= xfb_info
->buffer_to_stream
[xfb_output
->buffer
];
175 output
->DstOffset
= xfb_output
->offset
/ 4;
176 output
->ComponentOffset
= xfb_output
->component_offset
;
179 /* Make sure MaxTransformFeedbackBuffers is <= 32 so the bitmask for
180 * tracking the number of buffers doesn't overflow.
182 unsigned buffers
= 0;
183 assert(ctx
->Const
.MaxTransformFeedbackBuffers
<= sizeof(buffers
) * 8);
185 for (unsigned buf
= 0; buf
< MAX_FEEDBACK_BUFFERS
; buf
++) {
186 if (xfb_info
->buffers
[buf
].stride
> 0) {
187 linked_xfb
->Buffers
[buf
].Stride
= xfb_info
->buffers
[buf
].stride
/ 4;
188 linked_xfb
->Buffers
[buf
].NumVaryings
= xfb_info
->buffers
[buf
].varying_count
;
193 linked_xfb
->ActiveBuffers
= buffers
;
195 ralloc_free(xfb_info
);