OSDN Git Service

glsl: when lowering named interface set assigned flag
[android-x86/external-mesa.git] / src / compiler / glsl / lower_named_interface_blocks.cpp
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 static const glsl_type *
69 process_array_type(const glsl_type *type, unsigned idx)
70 {
71    const glsl_type *element_type = type->fields.array;
72    if (element_type->is_array()) {
73       const glsl_type *new_array_type = process_array_type(element_type, idx);
74       return glsl_type::get_array_instance(new_array_type, type->length);
75    } else {
76       return glsl_type::get_array_instance(
77          element_type->fields.structure[idx].type, type->length);
78    }
79 }
80
81 static ir_rvalue *
82 process_array_ir(void * const mem_ctx,
83                  ir_dereference_array *deref_array_prev,
84                  ir_rvalue *deref_var)
85 {
86    ir_dereference_array *deref_array =
87       deref_array_prev->array->as_dereference_array();
88
89    if (deref_array == NULL) {
90       return new(mem_ctx) ir_dereference_array(deref_var,
91                                                deref_array_prev->array_index);
92    } else {
93       deref_array = (ir_dereference_array *) process_array_ir(mem_ctx,
94                                                               deref_array,
95                                                               deref_var);
96       return new(mem_ctx) ir_dereference_array(deref_array,
97                                                deref_array_prev->array_index);
98    }
99 }
100
101 namespace {
102
103 class flatten_named_interface_blocks_declarations : public ir_rvalue_visitor
104 {
105 public:
106    void * const mem_ctx;
107    hash_table *interface_namespace;
108
109    flatten_named_interface_blocks_declarations(void *mem_ctx)
110       : mem_ctx(mem_ctx),
111         interface_namespace(NULL)
112    {
113    }
114
115    void run(exec_list *instructions);
116
117    virtual ir_visitor_status visit_leave(ir_assignment *);
118    virtual void handle_rvalue(ir_rvalue **rvalue);
119 };
120
121 } /* anonymous namespace */
122
123 void
124 flatten_named_interface_blocks_declarations::run(exec_list *instructions)
125 {
126    interface_namespace = hash_table_ctor(0, hash_table_string_hash,
127                                          hash_table_string_compare);
128
129    /* First pass: adjust instance block variables with an instance name
130     * to not have an instance name.
131     *
132     * The interface block variables are stored in the interface_namespace
133     * hash table so they can be used in the second pass.
134     */
135    foreach_in_list_safe(ir_instruction, node, instructions) {
136       ir_variable *var = node->as_variable();
137       if (!var || !var->is_interface_instance())
138          continue;
139
140       /* It should be possible to handle uniforms during this pass,
141        * but, this will require changes to the other uniform block
142        * support code.
143        */
144       if (var->data.mode == ir_var_uniform ||
145           var->data.mode == ir_var_shader_storage)
146          continue;
147
148       const glsl_type * iface_t = var->type->without_array();
149       exec_node *insert_pos = var;
150
151       assert (iface_t->is_interface());
152
153       for (unsigned i = 0; i < iface_t->length; i++) {
154          const char * field_name = iface_t->fields.structure[i].name;
155          char *iface_field_name =
156             ralloc_asprintf(mem_ctx, "%s %s.%s.%s",
157                             var->data.mode == ir_var_shader_in ? "in" : "out",
158                             iface_t->name, var->name, field_name);
159
160          ir_variable *found_var =
161             (ir_variable *) hash_table_find(interface_namespace,
162                                             iface_field_name);
163          if (!found_var) {
164             ir_variable *new_var;
165             char *var_name =
166                ralloc_strdup(mem_ctx, iface_t->fields.structure[i].name);
167             if (!var->type->is_array()) {
168                new_var =
169                   new(mem_ctx) ir_variable(iface_t->fields.structure[i].type,
170                                            var_name,
171                                            (ir_variable_mode) var->data.mode);
172             } else {
173                const glsl_type *new_array_type =
174                   process_array_type(var->type, i);
175                new_var =
176                   new(mem_ctx) ir_variable(new_array_type,
177                                            var_name,
178                                            (ir_variable_mode) var->data.mode);
179             }
180             new_var->data.location = iface_t->fields.structure[i].location;
181             new_var->data.explicit_location = (new_var->data.location >= 0);
182             new_var->data.offset = iface_t->fields.structure[i].offset;
183             new_var->data.explicit_xfb_offset =
184                (iface_t->fields.structure[i].offset >= 0);
185             new_var->data.xfb_buffer =
186                iface_t->fields.structure[i].xfb_buffer;
187             new_var->data.explicit_xfb_buffer =
188                iface_t->fields.structure[i].explicit_xfb_buffer;
189             new_var->data.interpolation =
190                iface_t->fields.structure[i].interpolation;
191             new_var->data.centroid = iface_t->fields.structure[i].centroid;
192             new_var->data.sample = iface_t->fields.structure[i].sample;
193             new_var->data.patch = iface_t->fields.structure[i].patch;
194             new_var->data.stream = var->data.stream;
195             new_var->data.how_declared = var->data.how_declared;
196             new_var->data.from_named_ifc_block = 1;
197
198             new_var->init_interface_type(var->type);
199             hash_table_insert(interface_namespace, new_var,
200                               iface_field_name);
201             insert_pos->insert_after(new_var);
202             insert_pos = new_var;
203          }
204       }
205       var->remove();
206    }
207
208    /* Second pass: visit all ir_dereference_record instances, and if they
209     * reference an interface block, then flatten the refererence out.
210     */
211    visit_list_elements(this, instructions);
212    hash_table_dtor(interface_namespace);
213    interface_namespace = NULL;
214 }
215
216 ir_visitor_status
217 flatten_named_interface_blocks_declarations::visit_leave(ir_assignment *ir)
218 {
219    ir_dereference_record *lhs_rec = ir->lhs->as_dereference_record();
220
221    ir_variable *lhs_var =  ir->lhs->variable_referenced();
222    if (lhs_var && lhs_var->get_interface_type()) {
223       lhs_var->data.assigned = 1;
224    }
225
226    if (lhs_rec) {
227       ir_rvalue *lhs_rec_tmp = lhs_rec;
228       handle_rvalue(&lhs_rec_tmp);
229       if (lhs_rec_tmp != lhs_rec) {
230          ir->set_lhs(lhs_rec_tmp);
231       }
232
233       ir_variable *lhs_var =  lhs_rec_tmp->variable_referenced();
234       if (lhs_var) {
235          lhs_var->data.assigned = 1;
236       }
237    }
238    return rvalue_visit(ir);
239 }
240
241 void
242 flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue **rvalue)
243 {
244    if (*rvalue == NULL)
245       return;
246
247    ir_dereference_record *ir = (*rvalue)->as_dereference_record();
248    if (ir == NULL)
249       return;
250
251    ir_variable *var = ir->variable_referenced();
252    if (var == NULL)
253       return;
254
255    if (!var->is_interface_instance())
256       return;
257
258    /* It should be possible to handle uniforms during this pass,
259     * but, this will require changes to the other uniform block
260     * support code.
261     */
262    if (var->data.mode == ir_var_uniform || var->data.mode == ir_var_shader_storage)
263       return;
264
265    if (var->get_interface_type() != NULL) {
266       char *iface_field_name =
267          ralloc_asprintf(mem_ctx, "%s %s.%s.%s",
268                          var->data.mode == ir_var_shader_in ? "in" : "out",
269                          var->get_interface_type()->name,
270                          var->name, ir->field);
271       /* Find the variable in the set of flattened interface blocks */
272       ir_variable *found_var =
273          (ir_variable *) hash_table_find(interface_namespace,
274                                          iface_field_name);
275       assert(found_var);
276
277       ir_dereference_variable *deref_var =
278          new(mem_ctx) ir_dereference_variable(found_var);
279
280       ir_dereference_array *deref_array =
281          ir->record->as_dereference_array();
282       if (deref_array != NULL) {
283          *rvalue = process_array_ir(mem_ctx, deref_array,
284                                     (ir_rvalue *)deref_var);
285       } else {
286          *rvalue = deref_var;
287       }
288    }
289 }
290
291 void
292 lower_named_interface_blocks(void *mem_ctx, gl_shader *shader)
293 {
294    flatten_named_interface_blocks_declarations v_decl(mem_ctx);
295    v_decl.run(shader->ir);
296 }
297