Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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