1/*
2 * Copyright © 2012 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
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#ifndef GLSL_LINK_VARYINGS_H
25#define GLSL_LINK_VARYINGS_H
26
27/**
28 * \file link_varyings.h
29 *
30 * Linker functions related specifically to linking varyings between shader
31 * stages.
32 */
33
34
35#include "main/glheader.h"
36#include "program/prog_parameter.h"
37#include "util/bitset.h"
38
39struct gl_shader_program;
40struct gl_shader;
41class ir_variable;
42
43
44/**
45 * Data structure describing a varying which is available for use in transform
46 * feedback.
47 *
48 * For example, if the vertex shader contains:
49 *
50 *     struct S {
51 *       vec4 foo;
52 *       float[3] bar;
53 *     };
54 *
55 *     varying S[2] v;
56 *
57 * Then there would be tfeedback_candidate objects corresponding to the
58 * following varyings:
59 *
60 *     v[0].foo
61 *     v[0].bar
62 *     v[1].foo
63 *     v[1].bar
64 */
65struct tfeedback_candidate
66{
67   /**
68    * Toplevel variable containing this varying.  In the above example, this
69    * would point to the declaration of the varying v.
70    */
71   ir_variable *toplevel_var;
72
73   /**
74    * Type of this varying.  In the above example, this would point to the
75    * glsl_type for "vec4" or "float[3]".
76    */
77   const glsl_type *type;
78
79   /**
80    * Offset within the toplevel variable where this varying occurs.
81    * Counted in floats.
82    */
83   unsigned struct_offset_floats;
84
85   /**
86    * Offset within the xfb with respect to alignment requirements.
87    * Counted in floats.
88    */
89   unsigned xfb_offset_floats;
90};
91
92
93/**
94 * Data structure tracking information about a transform feedback declaration
95 * during linking.
96 */
97class tfeedback_decl
98{
99public:
100   void init(struct gl_context *ctx, const void *mem_ctx, const char *input);
101   static bool is_same(const tfeedback_decl &x, const tfeedback_decl &y);
102   bool assign_location(struct gl_context *ctx,
103                        struct gl_shader_program *prog);
104   unsigned get_num_outputs() const;
105   bool store(struct gl_context *ctx, struct gl_shader_program *prog,
106              struct gl_transform_feedback_info *info, unsigned buffer,
107              unsigned buffer_index, const unsigned max_outputs,
108              BITSET_WORD *used_components[MAX_FEEDBACK_BUFFERS],
109              bool *explicit_stride, unsigned *max_member_alignment,
110              bool has_xfb_qualifiers, const void *mem_ctx) const;
111   const tfeedback_candidate *find_candidate(gl_shader_program *prog,
112                                             hash_table *tfeedback_candidates);
113   void set_lowered_candidate(const tfeedback_candidate *candidate);
114
115   bool is_next_buffer_separator() const
116   {
117      return this->next_buffer_separator;
118   }
119
120   bool is_varying_written() const
121   {
122      if (this->next_buffer_separator || this->skip_components)
123         return false;
124
125      return this->matched_candidate->toplevel_var->data.assigned;
126   }
127
128   bool is_varying() const
129   {
130      return !this->next_buffer_separator && !this->skip_components;
131   }
132
133   bool subscripted() const
134   {
135      return this->is_subscripted;
136   }
137
138   const char *name() const
139   {
140      return this->orig_name;
141   }
142
143   unsigned get_stream_id() const
144   {
145      return this->stream_id;
146   }
147
148   unsigned get_buffer() const
149   {
150      return this->buffer;
151   }
152
153   unsigned get_offset() const
154   {
155      return this->offset;
156   }
157
158   /**
159    * The total number of varying components taken up by this variable.  Only
160    * valid if assign_location() has been called.
161    */
162   unsigned num_components() const
163   {
164      if (this->lowered_builtin_array_variable)
165         return this->size;
166      else
167         return this->vector_elements * this->matrix_columns * this->size *
168            (this->is_64bit() ? 2 : 1);
169   }
170
171   unsigned get_location() const {
172      return this->location;
173   }
174
175private:
176
177   bool is_64bit() const
178   {
179      return _mesa_gl_datatype_is_64bit(this->type);
180   }
181
182   /**
183    * The name that was supplied to glTransformFeedbackVaryings.  Used for
184    * error reporting and glGetTransformFeedbackVarying().
185    */
186   const char *orig_name;
187
188   /**
189    * The name of the variable, parsed from orig_name.
190    */
191   const char *var_name;
192
193   /**
194    * True if the declaration in orig_name represents an array.
195    */
196   bool is_subscripted;
197
198   /**
199    * If is_subscripted is true, the subscript that was specified in orig_name.
200    */
201   unsigned array_subscript;
202
203   /**
204    * Non-zero if the variable is gl_ClipDistance, glTessLevelOuter or
205    * gl_TessLevelInner and the driver lowers it to gl_*MESA.
206    */
207   enum {
208      none,
209      clip_distance,
210      cull_distance,
211      tess_level_outer,
212      tess_level_inner,
213   } lowered_builtin_array_variable;
214
215   /**
216    * The vertex shader output location that the linker assigned for this
217    * variable.  -1 if a location hasn't been assigned yet.
218    */
219   int location;
220
221   /**
222    * Used to store the buffer assigned by xfb_buffer.
223    */
224   unsigned buffer;
225
226   /**
227    * Used to store the offset assigned by xfb_offset.
228    */
229   unsigned offset;
230
231   /**
232    * If non-zero, then this variable may be packed along with other variables
233    * into a single varying slot, so this offset should be applied when
234    * accessing components.  For example, an offset of 1 means that the x
235    * component of this variable is actually stored in component y of the
236    * location specified by \c location.
237    *
238    * Only valid if location != -1.
239    */
240   unsigned location_frac;
241
242   /**
243    * If location != -1, the number of vector elements in this variable, or 1
244    * if this variable is a scalar.
245    */
246   unsigned vector_elements;
247
248   /**
249    * If location != -1, the number of matrix columns in this variable, or 1
250    * if this variable is not a matrix.
251    */
252   unsigned matrix_columns;
253
254   /** Type of the varying returned by glGetTransformFeedbackVarying() */
255   GLenum type;
256
257   /**
258    * If location != -1, the size that should be returned by
259    * glGetTransformFeedbackVarying().
260    */
261   unsigned size;
262
263   /**
264    * How many components to skip. If non-zero, this is
265    * gl_SkipComponents{1,2,3,4} from ARB_transform_feedback3.
266    */
267   unsigned skip_components;
268
269   /**
270    * Whether this is gl_NextBuffer from ARB_transform_feedback3.
271    */
272   bool next_buffer_separator;
273
274   /**
275    * If find_candidate() has been called, pointer to the tfeedback_candidate
276    * data structure that was found.  Otherwise NULL.
277    */
278   const tfeedback_candidate *matched_candidate;
279
280   /**
281    * StreamId assigned to this varying (defaults to 0). Can only be set to
282    * values other than 0 in geometry shaders that use the stream layout
283    * modifier. Accepted values must be in the range [0, MAX_VERTEX_STREAMS-1].
284    */
285   unsigned stream_id;
286};
287
288bool
289link_varyings(struct gl_shader_program *prog, unsigned first, unsigned last,
290              struct gl_context *ctx, void *mem_ctx);
291
292void
293validate_first_and_last_interface_explicit_locations(struct gl_context *ctx,
294                                                     struct gl_shader_program *prog,
295                                                     gl_shader_stage first,
296                                                     gl_shader_stage last);
297
298void
299cross_validate_outputs_to_inputs(struct gl_context *ctx,
300                                 struct gl_shader_program *prog,
301                                 gl_linked_shader *producer,
302                                 gl_linked_shader *consumer);
303
304#endif /* GLSL_LINK_VARYINGS_H */
305