~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/compiler/glsl/lower_named_interface_blocks.cpp

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 2013 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 lower_named_interface_blocks.cpp
26
 
 *
27
 
 * This lowering pass converts all interface blocks with instance names
28
 
 * into interface blocks without an instance name.
29
 
 *
30
 
 * For example, the following shader:
31
 
 *
32
 
 *   out block {
33
 
 *     float block_var;
34
 
 *   } inst_name;
35
 
 *
36
 
 *   main()
37
 
 *   {
38
 
 *     inst_name.block_var = 0.0;
39
 
 *   }
40
 
 *
41
 
 * Is rewritten to:
42
 
 *
43
 
 *   out block {
44
 
 *     float block_var;
45
 
 *   };
46
 
 *
47
 
 *   main()
48
 
 *   {
49
 
 *     block_var = 0.0;
50
 
 *   }
51
 
 *
52
 
 * This takes place after the shader code has already been verified with
53
 
 * the interface name in place.
54
 
 *
55
 
 * The linking phase will use the interface block name rather than the
56
 
 * interface's instance name when linking interfaces.
57
 
 *
58
 
 * This modification to the ir allows our currently existing dead code
59
 
 * elimination to work with interface blocks without changes.
60
 
 */
61
 
 
62
 
#include "glsl_symbol_table.h"
63
 
#include "ir.h"
64
 
#include "ir_optimization.h"
65
 
#include "ir_rvalue_visitor.h"
66
 
#include "util/hash_table.h"
67
 
#include "main/shader_types.h"
68
 
 
69
 
static const glsl_type *
70
 
process_array_type(const glsl_type *type, unsigned idx)
71
 
{
72
 
   const glsl_type *element_type = type->fields.array;
73
 
   if (element_type->is_array()) {
74
 
      const glsl_type *new_array_type = process_array_type(element_type, idx);
75
 
      return glsl_type::get_array_instance(new_array_type, type->length);
76
 
   } else {
77
 
      return glsl_type::get_array_instance(
78
 
         element_type->fields.structure[idx].type, type->length);
79
 
   }
80
 
}
81
 
 
82
 
static ir_rvalue *
83
 
process_array_ir(void * const mem_ctx,
84
 
                 ir_dereference_array *deref_array_prev,
85
 
                 ir_rvalue *deref_var)
86
 
{
87
 
   ir_dereference_array *deref_array =
88
 
      deref_array_prev->array->as_dereference_array();
89
 
 
90
 
   if (deref_array == NULL) {
91
 
      return new(mem_ctx) ir_dereference_array(deref_var,
92
 
                                               deref_array_prev->array_index);
93
 
   } else {
94
 
      deref_array = (ir_dereference_array *) process_array_ir(mem_ctx,
95
 
                                                              deref_array,
96
 
                                                              deref_var);
97
 
      return new(mem_ctx) ir_dereference_array(deref_array,
98
 
                                               deref_array_prev->array_index);
99
 
   }
100
 
}
101
 
 
102
 
namespace {
103
 
 
104
 
class flatten_named_interface_blocks_declarations : public ir_rvalue_visitor
105
 
{
106
 
public:
107
 
   void * const mem_ctx;
108
 
   hash_table *interface_namespace;
109
 
 
110
 
   flatten_named_interface_blocks_declarations(void *mem_ctx)
111
 
      : mem_ctx(mem_ctx),
112
 
        interface_namespace(NULL)
113
 
   {
114
 
   }
115
 
 
116
 
   void run(exec_list *instructions);
117
 
 
118
 
   virtual ir_visitor_status visit_leave(ir_assignment *);
119
 
   virtual ir_visitor_status visit_leave(ir_expression *);
120
 
   virtual void handle_rvalue(ir_rvalue **rvalue);
121
 
};
122
 
 
123
 
} /* anonymous namespace */
124
 
 
125
 
void
126
 
flatten_named_interface_blocks_declarations::run(exec_list *instructions)
127
 
{
128
 
   interface_namespace = _mesa_hash_table_create(NULL, _mesa_hash_string,
129
 
                                                 _mesa_key_string_equal);
130
 
 
131
 
   /* First pass: adjust instance block variables with an instance name
132
 
    * to not have an instance name.
133
 
    *
134
 
    * The interface block variables are stored in the interface_namespace
135
 
    * hash table so they can be used in the second pass.
136
 
    */
137
 
   foreach_in_list_safe(ir_instruction, node, instructions) {
138
 
      ir_variable *var = node->as_variable();
139
 
      if (!var || !var->is_interface_instance())
140
 
         continue;
141
 
 
142
 
      /* It should be possible to handle uniforms during this pass,
143
 
       * but, this will require changes to the other uniform block
144
 
       * support code.
145
 
       */
146
 
      if (var->data.mode == ir_var_uniform ||
147
 
          var->data.mode == ir_var_shader_storage)
148
 
         continue;
149
 
 
150
 
      const glsl_type * iface_t = var->type->without_array();
151
 
      exec_node *insert_pos = var;
152
 
 
153
 
      assert (iface_t->is_interface());
154
 
 
155
 
      for (unsigned i = 0; i < iface_t->length; i++) {
156
 
         const char * field_name = iface_t->fields.structure[i].name;
157
 
         char *iface_field_name =
158
 
            ralloc_asprintf(mem_ctx, "%s %s.%s.%s",
159
 
                            var->data.mode == ir_var_shader_in ? "in" : "out",
160
 
                            iface_t->name, var->name, field_name);
161
 
 
162
 
         hash_entry *entry = _mesa_hash_table_search(interface_namespace,
163
 
                                                     iface_field_name);
164
 
         ir_variable *found_var = entry ? (ir_variable *) entry->data : NULL;
165
 
         if (!found_var) {
166
 
            ir_variable *new_var;
167
 
            char *var_name =
168
 
               ralloc_strdup(mem_ctx, iface_t->fields.structure[i].name);
169
 
            if (!var->type->is_array()) {
170
 
               new_var =
171
 
                  new(mem_ctx) ir_variable(iface_t->fields.structure[i].type,
172
 
                                           var_name,
173
 
                                           (ir_variable_mode) var->data.mode);
174
 
            } else {
175
 
               const glsl_type *new_array_type =
176
 
                  process_array_type(var->type, i);
177
 
               new_var =
178
 
                  new(mem_ctx) ir_variable(new_array_type,
179
 
                                           var_name,
180
 
                                           (ir_variable_mode) var->data.mode);
181
 
            }
182
 
            new_var->data.location = iface_t->fields.structure[i].location;
183
 
            new_var->data.location_frac =
184
 
               iface_t->fields.structure[i].component >= 0 ?
185
 
                  iface_t->fields.structure[i].component : 0;
186
 
            new_var->data.explicit_location = (new_var->data.location >= 0);
187
 
            new_var->data.explicit_component =
188
 
               (iface_t->fields.structure[i].component >= 0);
189
 
            new_var->data.offset = iface_t->fields.structure[i].offset;
190
 
            new_var->data.explicit_xfb_offset =
191
 
               (iface_t->fields.structure[i].offset >= 0);
192
 
            new_var->data.xfb_buffer =
193
 
               iface_t->fields.structure[i].xfb_buffer;
194
 
            new_var->data.explicit_xfb_buffer =
195
 
               iface_t->fields.structure[i].explicit_xfb_buffer;
196
 
            new_var->data.interpolation =
197
 
               iface_t->fields.structure[i].interpolation;
198
 
            new_var->data.centroid = iface_t->fields.structure[i].centroid;
199
 
            new_var->data.sample = iface_t->fields.structure[i].sample;
200
 
            new_var->data.patch = iface_t->fields.structure[i].patch;
201
 
            new_var->data.stream = var->data.stream;
202
 
            new_var->data.how_declared = var->data.how_declared;
203
 
            new_var->data.from_named_ifc_block = 1;
204
 
 
205
 
            new_var->init_interface_type(var->type);
206
 
            _mesa_hash_table_insert(interface_namespace, iface_field_name,
207
 
                                    new_var);
208
 
            insert_pos->insert_after(new_var);
209
 
            insert_pos = new_var;
210
 
         }
211
 
      }
212
 
      var->remove();
213
 
   }
214
 
 
215
 
   /* Second pass: visit all ir_dereference_record instances, and if they
216
 
    * reference an interface block, then flatten the refererence out.
217
 
    */
218
 
   visit_list_elements(this, instructions);
219
 
   _mesa_hash_table_destroy(interface_namespace, NULL);
220
 
   interface_namespace = NULL;
221
 
}
222
 
 
223
 
ir_visitor_status
224
 
flatten_named_interface_blocks_declarations::visit_leave(ir_assignment *ir)
225
 
{
226
 
   ir_dereference_record *lhs_rec = ir->lhs->as_dereference_record();
227
 
 
228
 
   ir_variable *lhs_var =  ir->lhs->variable_referenced();
229
 
   if (lhs_var && lhs_var->get_interface_type()) {
230
 
      lhs_var->data.assigned = 1;
231
 
   }
232
 
 
233
 
   if (lhs_rec) {
234
 
      ir_rvalue *lhs_rec_tmp = lhs_rec;
235
 
      handle_rvalue(&lhs_rec_tmp);
236
 
      if (lhs_rec_tmp != lhs_rec) {
237
 
         ir->set_lhs(lhs_rec_tmp);
238
 
      }
239
 
 
240
 
      ir_variable *lhs_var =  lhs_rec_tmp->variable_referenced();
241
 
      if (lhs_var) {
242
 
         lhs_var->data.assigned = 1;
243
 
      }
244
 
   }
245
 
   return rvalue_visit(ir);
246
 
}
247
 
 
248
 
ir_visitor_status
249
 
flatten_named_interface_blocks_declarations::visit_leave(ir_expression *ir)
250
 
{
251
 
   ir_visitor_status status = rvalue_visit(ir);
252
 
 
253
 
   if (ir->operation == ir_unop_interpolate_at_centroid ||
254
 
       ir->operation == ir_binop_interpolate_at_offset ||
255
 
       ir->operation == ir_binop_interpolate_at_sample) {
256
 
      const ir_rvalue *val = ir->operands[0];
257
 
 
258
 
      /* This disables varying packing for this input. */
259
 
      val->variable_referenced()->data.must_be_shader_input = 1;
260
 
   }
261
 
 
262
 
   return status;
263
 
}
264
 
 
265
 
void
266
 
flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue **rvalue)
267
 
{
268
 
   if (*rvalue == NULL)
269
 
      return;
270
 
 
271
 
   ir_dereference_record *ir = (*rvalue)->as_dereference_record();
272
 
   if (ir == NULL)
273
 
      return;
274
 
 
275
 
   ir_variable *var = ir->variable_referenced();
276
 
   if (var == NULL)
277
 
      return;
278
 
 
279
 
   if (!var->is_interface_instance())
280
 
      return;
281
 
 
282
 
   /* It should be possible to handle uniforms during this pass,
283
 
    * but, this will require changes to the other uniform block
284
 
    * support code.
285
 
    */
286
 
   if (var->data.mode == ir_var_uniform || var->data.mode == ir_var_shader_storage)
287
 
      return;
288
 
 
289
 
   if (var->get_interface_type() != NULL) {
290
 
      char *iface_field_name =
291
 
         ralloc_asprintf(mem_ctx, "%s %s.%s.%s",
292
 
                         var->data.mode == ir_var_shader_in ? "in" : "out",
293
 
                         var->get_interface_type()->name,
294
 
                         var->name,
295
 
                         ir->record->type->fields.structure[ir->field_idx].name);
296
 
 
297
 
      /* Find the variable in the set of flattened interface blocks */
298
 
      hash_entry *entry = _mesa_hash_table_search(interface_namespace,
299
 
                                                  iface_field_name);
300
 
      assert(entry);
301
 
      ir_variable *found_var = (ir_variable *) entry->data;
302
 
 
303
 
      ir_dereference_variable *deref_var =
304
 
         new(mem_ctx) ir_dereference_variable(found_var);
305
 
 
306
 
      ir_dereference_array *deref_array =
307
 
         ir->record->as_dereference_array();
308
 
      if (deref_array != NULL) {
309
 
         *rvalue = process_array_ir(mem_ctx, deref_array,
310
 
                                    (ir_rvalue *)deref_var);
311
 
      } else {
312
 
         *rvalue = deref_var;
313
 
      }
314
 
   }
315
 
}
316
 
 
317
 
void
318
 
lower_named_interface_blocks(void *mem_ctx, gl_linked_shader *shader)
319
 
{
320
 
   flatten_named_interface_blocks_declarations v_decl(mem_ctx);
321
 
   v_decl.run(shader->ir);
322
 
}
323