xref: /aosp_15_r20/external/mesa3d/src/compiler/glsl/gl_nir_link_xfb.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 "util/u_math.h"
29 #include "main/shader_types.h"
30 #include "main/consts_exts.h"
31 
32 /**
33  * This file does the linking of GLSL transform feedback using NIR.
34  */
35 
36 void
gl_nir_link_assign_xfb_resources(const struct gl_constants * consts,struct gl_shader_program * prog)37 gl_nir_link_assign_xfb_resources(const struct gl_constants *consts,
38                                  struct gl_shader_program *prog)
39 {
40    /*
41     * From ARB_gl_spirv spec:
42     *
43     *    "- If the *Xfb* Execution Mode is set, any output variable that is at
44     *       least partially captured:
45     *       * must be decorated with an *XfbBuffer*, declaring the capturing buffer
46     *       * must have at least one captured output variable in the capturing
47     *         buffer decorated with an *XfbStride* (and all such *XfbStride* values
48     *         for the capturing buffer must be equal)
49     *     - If the *Xfb* Execution Mode is set, any captured output:
50     *       * must be a non-structure decorated with *Offset* or a member of a
51     *         structure whose type member is decorated with *Offset*"
52     *
53     * Note the "must be", meaning that explicit buffer, offset and stride are
54     * mandatory. So as this is intended to work with SPIR-V shaders we don't
55     * need to calculate the offset or the stride.
56     */
57 
58    struct gl_program *xfb_prog = prog->last_vert_prog;
59 
60    if (xfb_prog == NULL)
61       return;
62 
63    /* free existing varyings, if any */
64    for (unsigned i = 0; i < prog->TransformFeedback.NumVarying; i++)
65       free(prog->TransformFeedback.VaryingNames[i]);
66    free(prog->TransformFeedback.VaryingNames);
67 
68    nir_xfb_info *xfb_info = NULL;
69    nir_xfb_varyings_info *varyings_info = NULL;
70 
71    /* Find last stage before fragment shader */
72    for (int stage = MESA_SHADER_FRAGMENT - 1; stage >= 0; stage--) {
73       struct gl_linked_shader *sh = prog->_LinkedShaders[stage];
74 
75       if (sh && stage != MESA_SHADER_TESS_CTRL) {
76          nir_gather_xfb_info_with_varyings(sh->Program->nir, NULL, &varyings_info);
77          xfb_info = sh->Program->nir->xfb_info;
78          break;
79       }
80    }
81 
82    struct gl_transform_feedback_info *linked_xfb =
83       rzalloc(xfb_prog, struct gl_transform_feedback_info);
84    xfb_prog->sh.LinkedTransformFeedback = linked_xfb;
85 
86    if (!xfb_info) {
87       prog->TransformFeedback.NumVarying = 0;
88       linked_xfb->NumOutputs = 0;
89       linked_xfb->NumVarying = 0;
90       linked_xfb->ActiveBuffers = 0;
91       return;
92    }
93 
94    for (unsigned buf = 0; buf < MAX_FEEDBACK_BUFFERS; buf++)
95       prog->TransformFeedback.BufferStride[buf] = xfb_info->buffers[buf].stride;
96 
97    prog->TransformFeedback.NumVarying = varyings_info->varying_count;
98    prog->TransformFeedback.VaryingNames =
99       malloc(sizeof(GLchar *) * varyings_info->varying_count);
100 
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;
106 
107    linked_xfb->Varyings =
108       rzalloc_array(xfb_prog,
109                     struct gl_transform_feedback_varying_info,
110                     varyings_info->varying_count);
111    linked_xfb->NumVarying = varyings_info->varying_count;
112 
113    int buffer_index = 0; /* Corresponds to GL_TRANSFORM_FEEDBACK_BUFFER_INDEX */
114    int xfb_buffer =
115       (varyings_info->varying_count > 0) ?
116       xfb_info->outputs[0].buffer : 0;
117 
118    for (unsigned i = 0; i < varyings_info->varying_count; i++) {
119       nir_xfb_varying_info *xfb_varying = &varyings_info->varyings[i];
120 
121       /* From ARB_gl_spirv spec:
122        *
123        *    "19. How should the program interface query operations behave for
124        *         program objects created from SPIR-V shaders?
125        *
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."
133        *
134        *     Options:"
135        *
136        *     <skip>
137        *
138        *     "RESOLVED.  Pick (c), but also allow debug names to be returned
139        *      if an implementation wants to."
140        *
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
144        */
145       prog->TransformFeedback.VaryingNames[i] = NULL;
146 
147       if (xfb_buffer != xfb_varying->buffer) {
148          buffer_index++;
149          xfb_buffer = xfb_varying->buffer;
150       }
151 
152       struct gl_transform_feedback_varying_info *varying =
153          linked_xfb->Varyings + i;
154 
155       /* ARB_gl_spirv: see above. */
156       varying->name.string = NULL;
157       resource_name_updated(&varying->name);
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(consts->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(varyings_info);
196 }
197 
198 struct nir_xfb_info *
gl_to_nir_xfb_info(struct gl_transform_feedback_info * info,void * mem_ctx)199 gl_to_nir_xfb_info(struct gl_transform_feedback_info *info, void *mem_ctx)
200 {
201    if (info == NULL || info->NumOutputs == 0)
202       return NULL;
203 
204    nir_xfb_info *xfb =
205       rzalloc_size(mem_ctx, nir_xfb_info_size(info->NumOutputs));
206 
207    xfb->output_count = info->NumOutputs;
208 
209    for (unsigned i = 0; i < MAX_FEEDBACK_BUFFERS; i++) {
210       xfb->buffers[i].stride = info->Buffers[i].Stride * 4;
211       xfb->buffers[i].varying_count = info->Buffers[i].NumVaryings;
212       xfb->buffer_to_stream[i] = info->Buffers[i].Stream;
213    }
214 
215    for (unsigned i = 0; i < info->NumOutputs; i++) {
216       xfb->outputs[i].buffer = info->Outputs[i].OutputBuffer;
217       xfb->outputs[i].offset = info->Outputs[i].DstOffset * 4;
218       xfb->outputs[i].location = info->Outputs[i].OutputRegister;
219       xfb->outputs[i].component_offset = info->Outputs[i].ComponentOffset;
220       xfb->outputs[i].component_mask =
221          BITFIELD_RANGE(info->Outputs[i].ComponentOffset,
222                         info->Outputs[i].NumComponents);
223       xfb->buffers_written |= BITFIELD_BIT(info->Outputs[i].OutputBuffer);
224       xfb->streams_written |= BITFIELD_BIT(info->Outputs[i].StreamId);
225    }
226 
227    return xfb;
228 }
229