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
;
72 /* Find last stage before fragment shader */
73 for (int stage
= MESA_SHADER_FRAGMENT
- 1; stage
>= 0; stage
--) {
74 struct gl_linked_shader
*sh
= prog
->_LinkedShaders
[stage
];
76 if (sh
&& stage
!= MESA_SHADER_TESS_CTRL
) {
77 xfb_info
= nir_gather_xfb_info(sh
->Program
->nir
, NULL
);
82 struct gl_transform_feedback_info
*linked_xfb
=
83 rzalloc(xfb_prog
, struct gl_transform_feedback_info
);
84 xfb_prog
->sh
.LinkedTransformFeedback
= linked_xfb
;
87 prog
->TransformFeedback
.NumVarying
= 0;
88 linked_xfb
->NumOutputs
= 0;
89 linked_xfb
->NumVarying
= 0;
90 linked_xfb
->ActiveBuffers
= 0;
94 for (unsigned buf
= 0; buf
< MAX_FEEDBACK_BUFFERS
; buf
++)
95 prog
->TransformFeedback
.BufferStride
[buf
] = xfb_info
->buffers
[buf
].stride
;
97 prog
->TransformFeedback
.NumVarying
= xfb_info
->varying_count
;
98 prog
->TransformFeedback
.VaryingNames
=
99 malloc(sizeof(GLchar
*) * xfb_info
->varying_count
);
101 linked_xfb
->Outputs
=
102 rzalloc_array(xfb_prog
,
103 struct gl_transform_feedback_output
,
104 xfb_info
->output_count
);
105 linked_xfb
->NumOutputs
= xfb_info
->output_count
;
107 linked_xfb
->Varyings
=
108 rzalloc_array(xfb_prog
,
109 struct gl_transform_feedback_varying_info
,
110 xfb_info
->varying_count
);
111 linked_xfb
->NumVarying
= xfb_info
->varying_count
;
113 int buffer_index
= 0; /* Corresponds to GL_TRANSFORM_FEEDBACK_BUFFER_INDEX */
115 (xfb_info
->varying_count
> 0) ?
116 xfb_info
->outputs
[0].buffer
: 0;
118 for (unsigned i
= 0; i
< xfb_info
->varying_count
; i
++) {
119 nir_xfb_varying_info
*xfb_varying
= &xfb_info
->varyings
[i
];
121 /* From ARB_gl_spirv spec:
123 * "19. How should the program interface query operations behave for
124 * program objects created from SPIR-V shaders?
126 * DISCUSSION: we previously said we didn't need reflection to work
127 * for SPIR-V shaders (at least for the first version), however we
128 * are left with specifying how it should "not work". The primary
129 * issue is that SPIR-V binaries are not required to have names
130 * associated with variables. They can be associated in debug
131 * information, but there is no requirement for that to be present,
132 * and it should not be relied upon."
138 * "RESOLVED. Pick (c), but also allow debug names to be returned
139 * if an implementation wants to."
141 * So names are considered optional debug info, so the linker needs to
142 * work without them, and returning them is optional. For simplicity at
143 * this point we are ignoring names
145 prog
->TransformFeedback
.VaryingNames
[i
] = NULL
;
147 if (xfb_buffer
!= xfb_varying
->buffer
) {
149 xfb_buffer
= xfb_varying
->buffer
;
152 struct gl_transform_feedback_varying_info
*varying
=
153 linked_xfb
->Varyings
+ i
;
155 /* ARB_gl_spirv: see above. */
156 varying
->Name
= NULL
;
157 varying
->Type
= glsl_get_gl_type(xfb_varying
->type
);
158 varying
->BufferIndex
= buffer_index
;
159 varying
->Size
= glsl_type_is_array(xfb_varying
->type
) ?
160 glsl_get_length(xfb_varying
->type
) : 1;
161 varying
->Offset
= xfb_varying
->offset
;
164 for (unsigned i
= 0; i
< xfb_info
->output_count
; i
++) {
165 nir_xfb_output_info
*xfb_output
= &xfb_info
->outputs
[i
];
167 struct gl_transform_feedback_output
*output
=
168 linked_xfb
->Outputs
+ i
;
170 output
->OutputRegister
= xfb_output
->location
;
171 output
->OutputBuffer
= xfb_output
->buffer
;
172 output
->NumComponents
= util_bitcount(xfb_output
->component_mask
);
173 output
->StreamId
= xfb_info
->buffer_to_stream
[xfb_output
->buffer
];
174 output
->DstOffset
= xfb_output
->offset
/ 4;
175 output
->ComponentOffset
= xfb_output
->component_offset
;
178 /* Make sure MaxTransformFeedbackBuffers is <= 32 so the bitmask for
179 * tracking the number of buffers doesn't overflow.
181 unsigned buffers
= 0;
182 assert(ctx
->Const
.MaxTransformFeedbackBuffers
<= sizeof(buffers
) * 8);
184 for (unsigned buf
= 0; buf
< MAX_FEEDBACK_BUFFERS
; buf
++) {
185 if (xfb_info
->buffers
[buf
].stride
> 0) {
186 linked_xfb
->Buffers
[buf
].Stride
= xfb_info
->buffers
[buf
].stride
/ 4;
187 linked_xfb
->Buffers
[buf
].NumVaryings
= xfb_info
->buffers
[buf
].varying_count
;
192 linked_xfb
->ActiveBuffers
= buffers
;
194 ralloc_free(xfb_info
);