Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
4358 Serge 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 "program/hash_table.h"
67
 
68
class flatten_named_interface_blocks_declarations : public ir_rvalue_visitor
69
{
70
public:
71
   void * const mem_ctx;
72
   hash_table *interface_namespace;
73
 
74
   flatten_named_interface_blocks_declarations(void *mem_ctx)
75
      : mem_ctx(mem_ctx),
76
        interface_namespace(NULL)
77
   {
78
   }
79
 
80
   void run(exec_list *instructions);
81
 
82
   virtual ir_visitor_status visit_leave(ir_assignment *);
83
   virtual void handle_rvalue(ir_rvalue **rvalue);
84
};
85
 
86
void
87
flatten_named_interface_blocks_declarations::run(exec_list *instructions)
88
{
89
   interface_namespace = hash_table_ctor(0, hash_table_string_hash,
90
                                         hash_table_string_compare);
91
 
92
   /* First pass: adjust instance block variables with an instance name
93
    * to not have an instance name.
94
    *
95
    * The interface block variables are stored in the interface_namespace
96
    * hash table so they can be used in the second pass.
97
    */
98
   foreach_list_safe(node, instructions) {
99
      ir_variable *var = ((ir_instruction *) node)->as_variable();
100
      if (!var || !var->is_interface_instance())
101
         continue;
102
 
103
      /* It should be possible to handle uniforms during this pass,
104
       * but, this will require changes to the other uniform block
105
       * support code.
106
       */
107
      if (var->mode == ir_var_uniform)
108
         continue;
109
 
110
      const glsl_type * iface_t = var->type;
111
      const glsl_type * array_t = NULL;
112
      exec_node *insert_pos = var;
113
 
114
      if (iface_t->is_array()) {
115
         array_t = iface_t;
116
         iface_t = array_t->fields.array;
117
      }
118
 
119
      assert (iface_t->is_interface());
120
 
121
      for (unsigned i = 0; i < iface_t->length; i++) {
122
         const char * field_name = iface_t->fields.structure[i].name;
123
         char *iface_field_name =
124
            ralloc_asprintf(mem_ctx, "%s.%s",
125
                            iface_t->name, field_name);
126
 
127
         ir_variable *found_var =
128
            (ir_variable *) hash_table_find(interface_namespace,
129
                                            iface_field_name);
130
         if (!found_var) {
131
            ir_variable *new_var;
132
            if (array_t == NULL) {
133
               char *var_name =
134
                  ralloc_strdup(mem_ctx, iface_t->fields.structure[i].name);
135
               new_var =
136
                  new(mem_ctx) ir_variable(iface_t->fields.structure[i].type,
137
                                           var_name,
138
                                           (ir_variable_mode) var->mode);
139
            } else {
140
               const glsl_type *new_array_type =
141
                  glsl_type::get_array_instance(
142
                     iface_t->fields.structure[i].type,
143
                     array_t->length);
144
               char *var_name =
145
                  ralloc_asprintf(mem_ctx, "%s[%d]",
146
                                  iface_t->fields.structure[i].name,
147
                                  array_t->length);
148
               new_var =
149
                  new(mem_ctx) ir_variable(new_array_type,
150
                                           var_name,
151
                                           (ir_variable_mode) var->mode);
152
            }
153
 
154
            new_var->interface_type = iface_t;
155
            hash_table_insert(interface_namespace, new_var,
156
                              iface_field_name);
157
            insert_pos->insert_after(new_var);
158
            insert_pos = new_var;
159
         }
160
      }
161
      var->remove();
162
   }
163
 
164
   /* Second pass: visit all ir_dereference_record instances, and if they
165
    * reference an interface block, then flatten the refererence out.
166
    */
167
   visit_list_elements(this, instructions);
168
   hash_table_dtor(interface_namespace);
169
   interface_namespace = NULL;
170
}
171
 
172
ir_visitor_status
173
flatten_named_interface_blocks_declarations::visit_leave(ir_assignment *ir)
174
{
175
   ir_dereference_record *lhs_rec = ir->lhs->as_dereference_record();
176
   if (lhs_rec) {
177
      ir_rvalue *lhs_rec_tmp = lhs_rec;
178
      handle_rvalue(&lhs_rec_tmp);
179
      if (lhs_rec_tmp != lhs_rec) {
180
         ir->set_lhs(lhs_rec_tmp);
181
      }
182
   }
183
   return rvalue_visit(ir);
184
}
185
 
186
void
187
flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue **rvalue)
188
{
189
   if (*rvalue == NULL)
190
      return;
191
 
192
   ir_dereference_record *ir = (*rvalue)->as_dereference_record();
193
   if (ir == NULL)
194
      return;
195
 
196
   ir_variable *var = ir->variable_referenced();
197
   if (var == NULL)
198
      return;
199
 
200
   if (!var->is_interface_instance())
201
      return;
202
 
203
   /* It should be possible to handle uniforms during this pass,
204
    * but, this will require changes to the other uniform block
205
    * support code.
206
    */
207
   if (var->mode == ir_var_uniform)
208
      return;
209
 
210
   if (var->interface_type != NULL) {
211
      char *iface_field_name =
212
         ralloc_asprintf(mem_ctx, "%s.%s", var->interface_type->name,
213
                         ir->field);
214
      /* Find the variable in the set of flattened interface blocks */
215
      ir_variable *found_var =
216
         (ir_variable *) hash_table_find(interface_namespace,
217
                                         iface_field_name);
218
      assert(found_var);
219
 
220
      ir_dereference_variable *deref_var =
221
         new(mem_ctx) ir_dereference_variable(found_var);
222
 
223
      ir_dereference_array *deref_array =
224
         ir->record->as_dereference_array();
225
      if (deref_array != NULL) {
226
         *rvalue =
227
            new(mem_ctx) ir_dereference_array(deref_var,
228
                                              deref_array->array_index);
229
      } else {
230
         *rvalue = deref_var;
231
      }
232
   }
233
}
234
 
235
void
236
lower_named_interface_blocks(void *mem_ctx, gl_shader *shader)
237
{
238
   flatten_named_interface_blocks_declarations v_decl(mem_ctx);
239
   v_decl.run(shader->ir);
240
}
241