• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 inputs_read and outputs_written of Mesa programs.
28  *
29  * Mesa programs (gl_program, not gl_shader_program) have a set of
30  * flags indicating which varyings are read and written.  Computing
31  * which are actually read from some sort of backend code can be
32  * tricky when variable array indexing involved.  So this pass
33  * provides support for setting inputs_read and outputs_written right
34  * from the GLSL IR.
35  */
36 
37 #include "main/core.h" /* for struct gl_program */
38 #include "ir.h"
39 #include "ir_visitor.h"
40 #include "compiler/glsl_types.h"
41 
42 namespace {
43 
44 class ir_set_program_inouts_visitor : public ir_hierarchical_visitor {
45 public:
ir_set_program_inouts_visitor(struct gl_program * prog,gl_shader_stage shader_stage)46    ir_set_program_inouts_visitor(struct gl_program *prog,
47                                  gl_shader_stage shader_stage)
48    {
49       this->prog = prog;
50       this->shader_stage = shader_stage;
51    }
~ir_set_program_inouts_visitor()52    ~ir_set_program_inouts_visitor()
53    {
54    }
55 
56    virtual ir_visitor_status visit_enter(ir_dereference_array *);
57    virtual ir_visitor_status visit_enter(ir_function_signature *);
58    virtual ir_visitor_status visit_enter(ir_discard *);
59    virtual ir_visitor_status visit_enter(ir_texture *);
60    virtual ir_visitor_status visit(ir_dereference_variable *);
61 
62 private:
63    void mark_whole_variable(ir_variable *var);
64    bool try_mark_partial_variable(ir_variable *var, ir_rvalue *index);
65 
66    struct gl_program *prog;
67    gl_shader_stage shader_stage;
68 };
69 
70 } /* anonymous namespace */
71 
72 static inline bool
is_shader_inout(ir_variable * var)73 is_shader_inout(ir_variable *var)
74 {
75    return var->data.mode == ir_var_shader_in ||
76           var->data.mode == ir_var_shader_out ||
77           var->data.mode == ir_var_system_value;
78 }
79 
80 static void
mark(struct gl_program * prog,ir_variable * var,int offset,int len,gl_shader_stage stage)81 mark(struct gl_program *prog, ir_variable *var, int offset, int len,
82      gl_shader_stage stage)
83 {
84    /* As of GLSL 1.20, varyings can only be floats, floating-point
85     * vectors or matrices, or arrays of them.  For Mesa programs using
86     * inputs_read/outputs_written, everything but matrices uses one
87     * slot, while matrices use a slot per column.  Presumably
88     * something doing a more clever packing would use something other
89     * than inputs_read/outputs_written.
90     */
91 
92    for (int i = 0; i < len; i++) {
93       assert(var->data.location != -1);
94 
95       int idx = var->data.location + offset + i;
96       bool is_patch_generic = var->data.patch &&
97                               idx != VARYING_SLOT_TESS_LEVEL_INNER &&
98                               idx != VARYING_SLOT_TESS_LEVEL_OUTER &&
99                               idx != VARYING_SLOT_BOUNDING_BOX0 &&
100                               idx != VARYING_SLOT_BOUNDING_BOX1;
101       GLbitfield64 bitfield;
102 
103       if (is_patch_generic) {
104          assert(idx >= VARYING_SLOT_PATCH0 && idx < VARYING_SLOT_TESS_MAX);
105          bitfield = BITFIELD64_BIT(idx - VARYING_SLOT_PATCH0);
106       }
107       else {
108          assert(idx < VARYING_SLOT_MAX);
109          bitfield = BITFIELD64_BIT(idx);
110       }
111 
112       if (var->data.mode == ir_var_shader_in) {
113          if (is_patch_generic)
114             prog->info.patch_inputs_read |= bitfield;
115          else
116             prog->info.inputs_read |= bitfield;
117 
118          /* double inputs read is only for vertex inputs */
119          if (stage == MESA_SHADER_VERTEX &&
120              var->type->without_array()->is_dual_slot())
121             prog->info.double_inputs_read |= bitfield;
122 
123          if (stage == MESA_SHADER_FRAGMENT) {
124             prog->info.fs.uses_sample_qualifier |= var->data.sample;
125          }
126       } else if (var->data.mode == ir_var_system_value) {
127          prog->info.system_values_read |= bitfield;
128       } else {
129          assert(var->data.mode == ir_var_shader_out);
130          if (is_patch_generic) {
131             prog->info.patch_outputs_written |= bitfield;
132          } else if (!var->data.read_only) {
133             prog->info.outputs_written |= bitfield;
134             if (var->data.index > 0)
135                prog->SecondaryOutputsWritten |= bitfield;
136          }
137 
138          if (var->data.fb_fetch_output)
139             prog->info.outputs_read |= bitfield;
140       }
141    }
142 }
143 
144 /**
145  * Mark an entire variable as used.  Caller must ensure that the variable
146  * represents a shader input or output.
147  */
148 void
mark_whole_variable(ir_variable * var)149 ir_set_program_inouts_visitor::mark_whole_variable(ir_variable *var)
150 {
151    const glsl_type *type = var->type;
152    bool is_vertex_input = false;
153    if (this->shader_stage == MESA_SHADER_GEOMETRY &&
154        var->data.mode == ir_var_shader_in && type->is_array()) {
155       type = type->fields.array;
156    }
157 
158    if (this->shader_stage == MESA_SHADER_TESS_CTRL &&
159        var->data.mode == ir_var_shader_in) {
160       assert(type->is_array());
161       type = type->fields.array;
162    }
163 
164    if (this->shader_stage == MESA_SHADER_TESS_CTRL &&
165        var->data.mode == ir_var_shader_out && !var->data.patch) {
166       assert(type->is_array());
167       type = type->fields.array;
168    }
169 
170    if (this->shader_stage == MESA_SHADER_TESS_EVAL &&
171        var->data.mode == ir_var_shader_in && !var->data.patch) {
172       assert(type->is_array());
173       type = type->fields.array;
174    }
175 
176    if (this->shader_stage == MESA_SHADER_VERTEX &&
177        var->data.mode == ir_var_shader_in)
178       is_vertex_input = true;
179 
180    mark(this->prog, var, 0, type->count_attribute_slots(is_vertex_input),
181         this->shader_stage);
182 }
183 
184 /* Default handler: Mark all the locations in the variable as used. */
185 ir_visitor_status
visit(ir_dereference_variable * ir)186 ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir)
187 {
188    if (!is_shader_inout(ir->var))
189       return visit_continue;
190 
191    mark_whole_variable(ir->var);
192 
193    return visit_continue;
194 }
195 
196 /**
197  * Try to mark a portion of the given variable as used.  Caller must ensure
198  * that the variable represents a shader input or output which can be indexed
199  * into in array fashion (an array or matrix).  For the purpose of geometry
200  * shader inputs (which are always arrays*), this means that the array element
201  * must be something that can be indexed into in array fashion.
202  *
203  * *Except gl_PrimitiveIDIn, as noted below.
204  *
205  * For tessellation control shaders all inputs and non-patch outputs are
206  * arrays. For tessellation evaluation shaders non-patch inputs are arrays.
207  *
208  * If the index can't be interpreted as a constant, or some other problem
209  * occurs, then nothing will be marked and false will be returned.
210  */
211 bool
try_mark_partial_variable(ir_variable * var,ir_rvalue * index)212 ir_set_program_inouts_visitor::try_mark_partial_variable(ir_variable *var,
213                                                          ir_rvalue *index)
214 {
215    const glsl_type *type = var->type;
216 
217    if (this->shader_stage == MESA_SHADER_GEOMETRY &&
218        var->data.mode == ir_var_shader_in) {
219       /* The only geometry shader input that is not an array is
220        * gl_PrimitiveIDIn, and in that case, this code will never be reached,
221        * because gl_PrimitiveIDIn can't be indexed into in array fashion.
222        */
223       assert(type->is_array());
224       type = type->fields.array;
225    }
226 
227    if (this->shader_stage == MESA_SHADER_TESS_CTRL &&
228        var->data.mode == ir_var_shader_in) {
229       assert(type->is_array());
230       type = type->fields.array;
231    }
232 
233    if (this->shader_stage == MESA_SHADER_TESS_CTRL &&
234        var->data.mode == ir_var_shader_out && !var->data.patch) {
235       assert(type->is_array());
236       type = type->fields.array;
237    }
238 
239    if (this->shader_stage == MESA_SHADER_TESS_EVAL &&
240        var->data.mode == ir_var_shader_in && !var->data.patch) {
241       assert(type->is_array());
242       type = type->fields.array;
243    }
244 
245    /* TODO: implement proper arrays of arrays support
246     * for now let the caller mark whole variable as used.
247     */
248    if (type->is_array() && type->fields.array->is_array())
249       return false;
250 
251    /* The code below only handles:
252     *
253     * - Indexing into matrices
254     * - Indexing into arrays of (matrices, vectors, or scalars)
255     *
256     * All other possibilities are either prohibited by GLSL (vertex inputs and
257     * fragment outputs can't be structs) or should have been eliminated by
258     * lowering passes (do_vec_index_to_swizzle() gets rid of indexing into
259     * vectors, and lower_packed_varyings() gets rid of structs that occur in
260     * varyings).
261     *
262     * However, we don't use varying packing in all cases - tessellation
263     * shaders bypass it.  This means we'll see varying structs and arrays
264     * of structs here.  For now, we just give up so the caller marks the
265     * entire variable as used.
266     */
267    if (!(type->is_matrix() ||
268         (type->is_array() &&
269          (type->fields.array->is_numeric() ||
270           type->fields.array->is_boolean())))) {
271 
272       /* If we don't know how to handle this case, give up and let the
273        * caller mark the whole variable as used.
274        */
275       return false;
276    }
277 
278    ir_constant *index_as_constant = index->as_constant();
279    if (!index_as_constant)
280       return false;
281 
282    unsigned elem_width;
283    unsigned num_elems;
284    if (type->is_array()) {
285       num_elems = type->length;
286       if (type->fields.array->is_matrix())
287          elem_width = type->fields.array->matrix_columns;
288       else
289          elem_width = 1;
290    } else {
291       num_elems = type->matrix_columns;
292       elem_width = 1;
293    }
294 
295    if (index_as_constant->value.u[0] >= num_elems) {
296       /* Constant index outside the bounds of the matrix/array.  This could
297        * arise as a result of constant folding of a legal GLSL program.
298        *
299        * Even though the spec says that indexing outside the bounds of a
300        * matrix/array results in undefined behaviour, we don't want to pass
301        * out-of-range values to mark() (since this could result in slots that
302        * don't exist being marked as used), so just let the caller mark the
303        * whole variable as used.
304        */
305       return false;
306    }
307 
308    /* double element width for double types that takes two slots */
309    if (this->shader_stage != MESA_SHADER_VERTEX ||
310        var->data.mode != ir_var_shader_in) {
311       if (type->without_array()->is_dual_slot())
312 	 elem_width *= 2;
313    }
314 
315    mark(this->prog, var, index_as_constant->value.u[0] * elem_width,
316         elem_width, this->shader_stage);
317    return true;
318 }
319 
320 static bool
is_multiple_vertices(gl_shader_stage stage,ir_variable * var)321 is_multiple_vertices(gl_shader_stage stage, ir_variable *var)
322 {
323    if (var->data.patch)
324       return false;
325 
326    if (var->data.mode == ir_var_shader_in)
327       return stage == MESA_SHADER_GEOMETRY ||
328              stage == MESA_SHADER_TESS_CTRL ||
329              stage == MESA_SHADER_TESS_EVAL;
330    if (var->data.mode == ir_var_shader_out)
331       return stage == MESA_SHADER_TESS_CTRL;
332 
333    return false;
334 }
335 
336 ir_visitor_status
visit_enter(ir_dereference_array * ir)337 ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir)
338 {
339    /* Note: for geometry shader inputs, lower_named_interface_blocks may
340     * create 2D arrays, so we need to be able to handle those.  2D arrays
341     * shouldn't be able to crop up for any other reason.
342     */
343    if (ir_dereference_array * const inner_array =
344        ir->array->as_dereference_array()) {
345       /*          ir => foo[i][j]
346        * inner_array => foo[i]
347        */
348       if (ir_dereference_variable * const deref_var =
349           inner_array->array->as_dereference_variable()) {
350          if (is_multiple_vertices(this->shader_stage, deref_var->var)) {
351             /* foo is a geometry or tessellation shader input, so i is
352              * the vertex, and j the part of the input we're accessing.
353              */
354             if (try_mark_partial_variable(deref_var->var, ir->array_index))
355             {
356                /* We've now taken care of foo and j, but i might contain a
357                 * subexpression that accesses shader inputs.  So manually
358                 * visit i and then continue with the parent.
359                 */
360                inner_array->array_index->accept(this);
361                return visit_continue_with_parent;
362             }
363          }
364       }
365    } else if (ir_dereference_variable * const deref_var =
366               ir->array->as_dereference_variable()) {
367       /* ir => foo[i], where foo is a variable. */
368       if (is_multiple_vertices(this->shader_stage, deref_var->var)) {
369          /* foo is a geometry or tessellation shader input, so i is
370           * the vertex, and we're accessing the entire input.
371           */
372          mark_whole_variable(deref_var->var);
373          /* We've now taken care of foo, but i might contain a subexpression
374           * that accesses shader inputs.  So manually visit i and then
375           * continue with the parent.
376           */
377          ir->array_index->accept(this);
378          return visit_continue_with_parent;
379       } else if (is_shader_inout(deref_var->var)) {
380          /* foo is a shader input/output, but not a geometry shader input,
381           * so i is the part of the input we're accessing.
382           */
383          if (try_mark_partial_variable(deref_var->var, ir->array_index))
384             return visit_continue_with_parent;
385       }
386    }
387 
388    /* The expression is something we don't recognize.  Just visit its
389     * subexpressions.
390     */
391    return visit_continue;
392 }
393 
394 ir_visitor_status
visit_enter(ir_function_signature * ir)395 ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir)
396 {
397    /* We don't want to descend into the function parameters and
398     * consider them as shader inputs or outputs.
399     */
400    visit_list_elements(this, &ir->body);
401    return visit_continue_with_parent;
402 }
403 
404 ir_visitor_status
visit_enter(ir_discard *)405 ir_set_program_inouts_visitor::visit_enter(ir_discard *)
406 {
407    /* discards are only allowed in fragment shaders. */
408    assert(this->shader_stage == MESA_SHADER_FRAGMENT);
409 
410    prog->info.fs.uses_discard = true;
411 
412    return visit_continue;
413 }
414 
415 ir_visitor_status
visit_enter(ir_texture * ir)416 ir_set_program_inouts_visitor::visit_enter(ir_texture *ir)
417 {
418    if (ir->op == ir_tg4)
419       prog->info.uses_texture_gather = true;
420    return visit_continue;
421 }
422 
423 void
do_set_program_inouts(exec_list * instructions,struct gl_program * prog,gl_shader_stage shader_stage)424 do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
425                       gl_shader_stage shader_stage)
426 {
427    ir_set_program_inouts_visitor v(prog, shader_stage);
428 
429    prog->info.inputs_read = 0;
430    prog->info.outputs_written = 0;
431    prog->SecondaryOutputsWritten = 0;
432    prog->info.outputs_read = 0;
433    prog->info.patch_inputs_read = 0;
434    prog->info.patch_outputs_written = 0;
435    prog->info.system_values_read = 0;
436    if (shader_stage == MESA_SHADER_FRAGMENT) {
437       prog->info.fs.uses_sample_qualifier = false;
438       prog->info.fs.uses_discard = false;
439    }
440    visit_list_elements(&v, instructions);
441 }
442