gtest: Update to 1.7.0.
[mesa.git] / src / glsl / ir_set_program_inouts.cpp
1 /*
2 * Copyright © 2010 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 /**
25 * \file ir_set_program_inouts.cpp
26 *
27 * Sets the InputsRead and OutputsWritten of Mesa programs.
28 *
29 * Additionally, for fragment shaders, sets the InterpQualifier array, the
30 * IsCentroid and IsSample bitfields, and the UsesDFdy flag.
31 *
32 * Mesa programs (gl_program, not gl_shader_program) have a set of
33 * flags indicating which varyings are read and written. Computing
34 * which are actually read from some sort of backend code can be
35 * tricky when variable array indexing involved. So this pass
36 * provides support for setting InputsRead and OutputsWritten right
37 * from the GLSL IR.
38 */
39
40 #include "main/core.h" /* for struct gl_program */
41 #include "ir.h"
42 #include "ir_visitor.h"
43 #include "glsl_types.h"
44
45 namespace {
46
47 class ir_set_program_inouts_visitor : public ir_hierarchical_visitor {
48 public:
49 ir_set_program_inouts_visitor(struct gl_program *prog,
50 gl_shader_stage shader_stage)
51 {
52 this->prog = prog;
53 this->shader_stage = shader_stage;
54 }
55 ~ir_set_program_inouts_visitor()
56 {
57 }
58
59 virtual ir_visitor_status visit_enter(ir_dereference_array *);
60 virtual ir_visitor_status visit_enter(ir_function_signature *);
61 virtual ir_visitor_status visit_enter(ir_expression *);
62 virtual ir_visitor_status visit_enter(ir_discard *);
63 virtual ir_visitor_status visit_enter(ir_texture *);
64 virtual ir_visitor_status visit(ir_dereference_variable *);
65
66 private:
67 void mark_whole_variable(ir_variable *var);
68 bool try_mark_partial_variable(ir_variable *var, ir_rvalue *index);
69
70 struct gl_program *prog;
71 gl_shader_stage shader_stage;
72 };
73
74 } /* anonymous namespace */
75
76 static inline bool
77 is_shader_inout(ir_variable *var)
78 {
79 return var->data.mode == ir_var_shader_in ||
80 var->data.mode == ir_var_shader_out ||
81 var->data.mode == ir_var_system_value;
82 }
83
84 static void
85 mark(struct gl_program *prog, ir_variable *var, int offset, int len,
86 bool is_fragment_shader)
87 {
88 /* As of GLSL 1.20, varyings can only be floats, floating-point
89 * vectors or matrices, or arrays of them. For Mesa programs using
90 * InputsRead/OutputsWritten, everything but matrices uses one
91 * slot, while matrices use a slot per column. Presumably
92 * something doing a more clever packing would use something other
93 * than InputsRead/OutputsWritten.
94 */
95
96 for (int i = 0; i < len; i++) {
97 GLbitfield64 bitfield =
98 BITFIELD64_BIT(var->data.location + var->data.index + offset + i);
99 if (var->data.mode == ir_var_shader_in) {
100 prog->InputsRead |= bitfield;
101 if (is_fragment_shader) {
102 gl_fragment_program *fprog = (gl_fragment_program *) prog;
103 fprog->InterpQualifier[var->data.location +
104 var->data.index + offset + i] =
105 (glsl_interp_qualifier) var->data.interpolation;
106 if (var->data.centroid)
107 fprog->IsCentroid |= bitfield;
108 if (var->data.sample)
109 fprog->IsSample |= bitfield;
110 }
111 } else if (var->data.mode == ir_var_system_value) {
112 prog->SystemValuesRead |= bitfield;
113 } else {
114 assert(var->data.mode == ir_var_shader_out);
115 prog->OutputsWritten |= bitfield;
116 }
117 }
118 }
119
120 /**
121 * Mark an entire variable as used. Caller must ensure that the variable
122 * represents a shader input or output.
123 */
124 void
125 ir_set_program_inouts_visitor::mark_whole_variable(ir_variable *var)
126 {
127 const glsl_type *type = var->type;
128 if (this->shader_stage == MESA_SHADER_GEOMETRY &&
129 var->data.mode == ir_var_shader_in && type->is_array()) {
130 type = type->fields.array;
131 }
132
133 mark(this->prog, var, 0, type->count_attribute_slots(),
134 this->shader_stage == MESA_SHADER_FRAGMENT);
135 }
136
137 /* Default handler: Mark all the locations in the variable as used. */
138 ir_visitor_status
139 ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir)
140 {
141 if (!is_shader_inout(ir->var))
142 return visit_continue;
143
144 mark_whole_variable(ir->var);
145
146 return visit_continue;
147 }
148
149 /**
150 * Try to mark a portion of the given variable as used. Caller must ensure
151 * that the variable represents a shader input or output which can be indexed
152 * into in array fashion (an array or matrix). For the purpose of geometry
153 * shader inputs (which are always arrays*), this means that the array element
154 * must be something that can be indexed into in array fashion.
155 *
156 * *Except gl_PrimitiveIDIn, as noted below.
157 *
158 * If the index can't be interpreted as a constant, or some other problem
159 * occurs, then nothing will be marked and false will be returned.
160 */
161 bool
162 ir_set_program_inouts_visitor::try_mark_partial_variable(ir_variable *var,
163 ir_rvalue *index)
164 {
165 const glsl_type *type = var->type;
166
167 if (this->shader_stage == MESA_SHADER_GEOMETRY &&
168 var->data.mode == ir_var_shader_in) {
169 /* The only geometry shader input that is not an array is
170 * gl_PrimitiveIDIn, and in that case, this code will never be reached,
171 * because gl_PrimitiveIDIn can't be indexed into in array fashion.
172 */
173 assert(type->is_array());
174 type = type->fields.array;
175 }
176
177 /* The code below only handles:
178 *
179 * - Indexing into matrices
180 * - Indexing into arrays of (matrices, vectors, or scalars)
181 *
182 * All other possibilities are either prohibited by GLSL (vertex inputs and
183 * fragment outputs can't be structs) or should have been eliminated by
184 * lowering passes (do_vec_index_to_swizzle() gets rid of indexing into
185 * vectors, and lower_packed_varyings() gets rid of structs that occur in
186 * varyings).
187 */
188 if (!(type->is_matrix() ||
189 (type->is_array() &&
190 (type->fields.array->is_numeric() ||
191 type->fields.array->is_boolean())))) {
192 assert(!"Unexpected indexing in ir_set_program_inouts");
193
194 /* For safety in release builds, in case we ever encounter unexpected
195 * indexing, give up and let the caller mark the whole variable as used.
196 */
197 return false;
198 }
199
200 ir_constant *index_as_constant = index->as_constant();
201 if (!index_as_constant)
202 return false;
203
204 unsigned elem_width;
205 unsigned num_elems;
206 if (type->is_array()) {
207 num_elems = type->length;
208 if (type->fields.array->is_matrix())
209 elem_width = type->fields.array->matrix_columns;
210 else
211 elem_width = 1;
212 } else {
213 num_elems = type->matrix_columns;
214 elem_width = 1;
215 }
216
217 if (index_as_constant->value.u[0] >= num_elems) {
218 /* Constant index outside the bounds of the matrix/array. This could
219 * arise as a result of constant folding of a legal GLSL program.
220 *
221 * Even though the spec says that indexing outside the bounds of a
222 * matrix/array results in undefined behaviour, we don't want to pass
223 * out-of-range values to mark() (since this could result in slots that
224 * don't exist being marked as used), so just let the caller mark the
225 * whole variable as used.
226 */
227 return false;
228 }
229
230 mark(this->prog, var, index_as_constant->value.u[0] * elem_width,
231 elem_width, this->shader_stage == MESA_SHADER_FRAGMENT);
232 return true;
233 }
234
235 ir_visitor_status
236 ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir)
237 {
238 /* Note: for geometry shader inputs, lower_named_interface_blocks may
239 * create 2D arrays, so we need to be able to handle those. 2D arrays
240 * shouldn't be able to crop up for any other reason.
241 */
242 if (ir_dereference_array * const inner_array =
243 ir->array->as_dereference_array()) {
244 /* ir => foo[i][j]
245 * inner_array => foo[i]
246 */
247 if (ir_dereference_variable * const deref_var =
248 inner_array->array->as_dereference_variable()) {
249 if (this->shader_stage == MESA_SHADER_GEOMETRY &&
250 deref_var->var->data.mode == ir_var_shader_in) {
251 /* foo is a geometry shader input, so i is the vertex, and j the
252 * part of the input we're accessing.
253 */
254 if (try_mark_partial_variable(deref_var->var, ir->array_index))
255 {
256 /* We've now taken care of foo and j, but i might contain a
257 * subexpression that accesses shader inputs. So manually
258 * visit i and then continue with the parent.
259 */
260 inner_array->array_index->accept(this);
261 return visit_continue_with_parent;
262 }
263 }
264 }
265 } else if (ir_dereference_variable * const deref_var =
266 ir->array->as_dereference_variable()) {
267 /* ir => foo[i], where foo is a variable. */
268 if (this->shader_stage == MESA_SHADER_GEOMETRY &&
269 deref_var->var->data.mode == ir_var_shader_in) {
270 /* foo is a geometry shader input, so i is the vertex, and we're
271 * accessing the entire input.
272 */
273 mark_whole_variable(deref_var->var);
274 /* We've now taken care of foo, but i might contain a subexpression
275 * that accesses shader inputs. So manually visit i and then
276 * continue with the parent.
277 */
278 ir->array_index->accept(this);
279 return visit_continue_with_parent;
280 } else if (is_shader_inout(deref_var->var)) {
281 /* foo is a shader input/output, but not a geometry shader input,
282 * so i is the part of the input we're accessing.
283 */
284 if (try_mark_partial_variable(deref_var->var, ir->array_index))
285 return visit_continue_with_parent;
286 }
287 }
288
289 /* The expression is something we don't recognize. Just visit its
290 * subexpressions.
291 */
292 return visit_continue;
293 }
294
295 ir_visitor_status
296 ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir)
297 {
298 /* We don't want to descend into the function parameters and
299 * consider them as shader inputs or outputs.
300 */
301 visit_list_elements(this, &ir->body);
302 return visit_continue_with_parent;
303 }
304
305 ir_visitor_status
306 ir_set_program_inouts_visitor::visit_enter(ir_expression *ir)
307 {
308 if (this->shader_stage == MESA_SHADER_FRAGMENT &&
309 ir->operation == ir_unop_dFdy) {
310 gl_fragment_program *fprog = (gl_fragment_program *) prog;
311 fprog->UsesDFdy = true;
312 }
313 return visit_continue;
314 }
315
316 ir_visitor_status
317 ir_set_program_inouts_visitor::visit_enter(ir_discard *)
318 {
319 /* discards are only allowed in fragment shaders. */
320 assert(this->shader_stage == MESA_SHADER_FRAGMENT);
321
322 gl_fragment_program *fprog = (gl_fragment_program *) prog;
323 fprog->UsesKill = true;
324
325 return visit_continue;
326 }
327
328 ir_visitor_status
329 ir_set_program_inouts_visitor::visit_enter(ir_texture *ir)
330 {
331 if (ir->op == ir_tg4)
332 prog->UsesGather = true;
333 return visit_continue;
334 }
335
336 void
337 do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
338 gl_shader_stage shader_stage)
339 {
340 ir_set_program_inouts_visitor v(prog, shader_stage);
341
342 prog->InputsRead = 0;
343 prog->OutputsWritten = 0;
344 prog->SystemValuesRead = 0;
345 if (shader_stage == MESA_SHADER_FRAGMENT) {
346 gl_fragment_program *fprog = (gl_fragment_program *) prog;
347 memset(fprog->InterpQualifier, 0, sizeof(fprog->InterpQualifier));
348 fprog->IsCentroid = 0;
349 fprog->IsSample = 0;
350 fprog->UsesDFdy = false;
351 fprog->UsesKill = false;
352 }
353 visit_list_elements(&v, instructions);
354 }