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_gl_types.h"
26#include "nir_xfb_info.h"
27#include "gl_nir_linker.h"
28#include "linker_util.h"
29#include "util/u_math.h"
30#include "main/shader_types.h"
31#include "main/consts_exts.h"
32
33/**
34 * This file does the linking of GLSL transform feedback using NIR.
35 */
36
37void
38gl_nir_link_assign_xfb_resources(const struct gl_constants *consts,
39                                 struct gl_shader_program *prog)
40{
41   /*
42    * From ARB_gl_spirv spec:
43    *
44    *    "- If the *Xfb* Execution Mode is set, any output variable that is at
45    *       least partially captured:
46    *       * must be decorated with an *XfbBuffer*, declaring the capturing buffer
47    *       * must have at least one captured output variable in the capturing
48    *         buffer decorated with an *XfbStride* (and all such *XfbStride* values
49    *         for the capturing buffer must be equal)
50    *     - If the *Xfb* Execution Mode is set, any captured output:
51    *       * must be a non-structure decorated with *Offset* or a member of a
52    *         structure whose type member is decorated with *Offset*"
53    *
54    * Note the "must be", meaning that explicit buffer, offset and stride are
55    * mandatory. So as this is intended to work with SPIR-V shaders we don't
56    * need to calculate the offset or the stride.
57    */
58
59   struct gl_program *xfb_prog = prog->last_vert_prog;
60
61   if (xfb_prog == NULL)
62      return;
63
64   /* free existing varyings, if any */
65   for (unsigned i = 0; i < prog->TransformFeedback.NumVarying; i++)
66      free(prog->TransformFeedback.VaryingNames[i]);
67   free(prog->TransformFeedback.VaryingNames);
68
69   nir_xfb_info *xfb_info = NULL;
70   nir_xfb_varyings_info *varyings_info = NULL;
71
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];
75
76      if (sh && stage != MESA_SHADER_TESS_CTRL) {
77         nir_gather_xfb_info_with_varyings(sh->Program->nir, NULL, &varyings_info);
78         xfb_info = sh->Program->nir->xfb_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.string = NULL;
158      resource_name_updated(&varying->name);
159      varying->Type = glsl_get_gl_type(xfb_varying->type);
160      varying->BufferIndex = buffer_index;
161      varying->Size = glsl_type_is_array(xfb_varying->type) ?
162         glsl_get_length(xfb_varying->type) : 1;
163      varying->Offset = xfb_varying->offset;
164   }
165
166   for (unsigned i = 0; i < xfb_info->output_count; i++) {
167      nir_xfb_output_info *xfb_output = &xfb_info->outputs[i];
168
169      struct gl_transform_feedback_output *output =
170         linked_xfb->Outputs + i;
171
172      output->OutputRegister = xfb_output->location;
173      output->OutputBuffer = xfb_output->buffer;
174      output->NumComponents = util_bitcount(xfb_output->component_mask);
175      output->StreamId = xfb_info->buffer_to_stream[xfb_output->buffer];
176      output->DstOffset = xfb_output->offset / 4;
177      output->ComponentOffset = xfb_output->component_offset;
178   }
179
180   /* Make sure MaxTransformFeedbackBuffers is <= 32 so the bitmask for
181    * tracking the number of buffers doesn't overflow.
182    */
183   unsigned buffers = 0;
184   assert(consts->MaxTransformFeedbackBuffers <= sizeof(buffers) * 8);
185
186   for (unsigned buf = 0; buf < MAX_FEEDBACK_BUFFERS; buf++) {
187      if (xfb_info->buffers[buf].stride > 0) {
188         linked_xfb->Buffers[buf].Stride = xfb_info->buffers[buf].stride / 4;
189         linked_xfb->Buffers[buf].NumVaryings = xfb_info->buffers[buf].varying_count;
190         buffers |= 1 << buf;
191      }
192   }
193
194   linked_xfb->ActiveBuffers = buffers;
195
196   ralloc_free(varyings_info);
197}
198
199struct nir_xfb_info *
200gl_to_nir_xfb_info(struct gl_transform_feedback_info *info, void *mem_ctx)
201{
202   if (info == NULL || info->NumOutputs == 0)
203      return NULL;
204
205   nir_xfb_info *xfb =
206      rzalloc_size(mem_ctx, nir_xfb_info_size(info->NumOutputs));
207
208   xfb->output_count = info->NumOutputs;
209
210   for (unsigned i = 0; i < MAX_FEEDBACK_BUFFERS; i++) {
211      xfb->buffers[i].stride = info->Buffers[i].Stride * 4;
212      xfb->buffers[i].varying_count = info->Buffers[i].NumVaryings;
213      xfb->buffer_to_stream[i] = info->Buffers[i].Stream;
214   }
215
216   for (unsigned i = 0; i < info->NumOutputs; i++) {
217      xfb->outputs[i].buffer = info->Outputs[i].OutputBuffer;
218      xfb->outputs[i].offset = info->Outputs[i].DstOffset * 4;
219      xfb->outputs[i].location = info->Outputs[i].OutputRegister;
220      xfb->outputs[i].component_offset = info->Outputs[i].ComponentOffset;
221      xfb->outputs[i].component_mask =
222         BITFIELD_RANGE(info->Outputs[i].ComponentOffset,
223                        info->Outputs[i].NumComponents);
224      xfb->buffers_written |= BITFIELD_BIT(info->Outputs[i].OutputBuffer);
225      xfb->streams_written |= BITFIELD_BIT(info->Outputs[i].StreamId);
226   }
227
228   return xfb;
229}
230