nir/xfb: move varyings info out of nir_xfb_info
[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 "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"
30
31 /*
32 * This file does the linking of GLSL transform feedback using NIR.
33 *
34 * Note: This linking pass is currently tailored for ARB_gl_spirv needs and
35 * particularities.
36 */
37
38 void
39 gl_nir_link_assign_xfb_resources(struct gl_context *ctx,
40 struct gl_shader_program *prog)
41 {
42 /*
43 * From ARB_gl_spirv spec:
44 *
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*"
54 *
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.
58 */
59
60 struct gl_program *xfb_prog = prog->last_vert_prog;
61
62 if (xfb_prog == NULL)
63 return;
64
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);
69
70 nir_xfb_info *xfb_info = NULL;
71 nir_xfb_varyings_info *varyings_info = NULL;
72
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];
76
77 if (sh && stage != MESA_SHADER_TESS_CTRL) {
78 xfb_info = nir_gather_xfb_info_with_varyings(sh->Program->nir, NULL, &varyings_info);
79 break;
80 }
81 }
82
83 struct gl_transform_feedback_info *linked_xfb =
84 rzalloc(xfb_prog, struct gl_transform_feedback_info);
85 xfb_prog->sh.LinkedTransformFeedback = linked_xfb;
86
87 if (!xfb_info) {
88 prog->TransformFeedback.NumVarying = 0;
89 linked_xfb->NumOutputs = 0;
90 linked_xfb->NumVarying = 0;
91 linked_xfb->ActiveBuffers = 0;
92 return;
93 }
94
95 for (unsigned buf = 0; buf < MAX_FEEDBACK_BUFFERS; buf++)
96 prog->TransformFeedback.BufferStride[buf] = xfb_info->buffers[buf].stride;
97
98 prog->TransformFeedback.NumVarying = varyings_info->varying_count;
99 prog->TransformFeedback.VaryingNames =
100 malloc(sizeof(GLchar *) * varyings_info->varying_count);
101
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;
107
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;
113
114 int buffer_index = 0; /* Corresponds to GL_TRANSFORM_FEEDBACK_BUFFER_INDEX */
115 int xfb_buffer =
116 (varyings_info->varying_count > 0) ?
117 xfb_info->outputs[0].buffer : 0;
118
119 for (unsigned i = 0; i < varyings_info->varying_count; i++) {
120 nir_xfb_varying_info *xfb_varying = &varyings_info->varyings[i];
121
122 /* From ARB_gl_spirv spec:
123 *
124 * "19. How should the program interface query operations behave for
125 * program objects created from SPIR-V shaders?
126 *
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."
134 *
135 * Options:"
136 *
137 * <skip>
138 *
139 * "RESOLVED. Pick (c), but also allow debug names to be returned
140 * if an implementation wants to."
141 *
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
145 */
146 prog->TransformFeedback.VaryingNames[i] = NULL;
147
148 if (xfb_buffer != xfb_varying->buffer) {
149 buffer_index++;
150 xfb_buffer = xfb_varying->buffer;
151 }
152
153 struct gl_transform_feedback_varying_info *varying =
154 linked_xfb->Varyings + i;
155
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;
163 }
164
165 for (unsigned i = 0; i < xfb_info->output_count; i++) {
166 nir_xfb_output_info *xfb_output = &xfb_info->outputs[i];
167
168 struct gl_transform_feedback_output *output =
169 linked_xfb->Outputs + i;
170
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;
177 }
178
179 /* Make sure MaxTransformFeedbackBuffers is <= 32 so the bitmask for
180 * tracking the number of buffers doesn't overflow.
181 */
182 unsigned buffers = 0;
183 assert(ctx->Const.MaxTransformFeedbackBuffers <= sizeof(buffers) * 8);
184
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;
189 buffers |= 1 << buf;
190 }
191 }
192
193 linked_xfb->ActiveBuffers = buffers;
194
195 ralloc_free(xfb_info);
196 }