2 * Copyright (c) 2013 Intel Corporation
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:
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
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.
25 * \file lower_named_interface_blocks.cpp
27 * This lowering pass converts all interface blocks with instance names
28 * into interface blocks without an instance name.
30 * For example, the following shader:
38 * inst_name.block_var = 0.0;
52 * This takes place after the shader code has already been verified with
53 * the interface name in place.
55 * The linking phase will use the interface block name rather than the
56 * interface's instance name when linking interfaces.
58 * This modification to the ir allows our currently existing dead code
59 * elimination to work with interface blocks without changes.
62 #include "glsl_symbol_table.h"
64 #include "ir_optimization.h"
65 #include "ir_rvalue_visitor.h"
66 #include "program/hash_table.h"
68 static const glsl_type *
69 process_array_type(const glsl_type *type, unsigned idx)
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);
76 return glsl_type::get_array_instance(
77 element_type->fields.structure[idx].type, type->length);
82 process_array_ir(void * const mem_ctx,
83 ir_dereference_array *deref_array_prev,
86 ir_dereference_array *deref_array =
87 deref_array_prev->array->as_dereference_array();
89 if (deref_array == NULL) {
90 return new(mem_ctx) ir_dereference_array(deref_var,
91 deref_array_prev->array_index);
93 deref_array = (ir_dereference_array *) process_array_ir(mem_ctx,
96 return new(mem_ctx) ir_dereference_array(deref_array,
97 deref_array_prev->array_index);
103 class flatten_named_interface_blocks_declarations : public ir_rvalue_visitor
106 void * const mem_ctx;
107 hash_table *interface_namespace;
109 flatten_named_interface_blocks_declarations(void *mem_ctx)
111 interface_namespace(NULL)
115 void run(exec_list *instructions);
117 virtual ir_visitor_status visit_leave(ir_assignment *);
118 virtual void handle_rvalue(ir_rvalue **rvalue);
121 } /* anonymous namespace */
124 flatten_named_interface_blocks_declarations::run(exec_list *instructions)
126 interface_namespace = hash_table_ctor(0, hash_table_string_hash,
127 hash_table_string_compare);
129 /* First pass: adjust instance block variables with an instance name
130 * to not have an instance name.
132 * The interface block variables are stored in the interface_namespace
133 * hash table so they can be used in the second pass.
135 foreach_in_list_safe(ir_instruction, node, instructions) {
136 ir_variable *var = node->as_variable();
137 if (!var || !var->is_interface_instance())
140 /* It should be possible to handle uniforms during this pass,
141 * but, this will require changes to the other uniform block
144 if (var->data.mode == ir_var_uniform ||
145 var->data.mode == ir_var_shader_storage)
148 const glsl_type * iface_t = var->type->without_array();
149 exec_node *insert_pos = var;
151 assert (iface_t->is_interface());
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);
160 ir_variable *found_var =
161 (ir_variable *) hash_table_find(interface_namespace,
164 ir_variable *new_var;
166 ralloc_strdup(mem_ctx, iface_t->fields.structure[i].name);
167 if (!var->type->is_array()) {
169 new(mem_ctx) ir_variable(iface_t->fields.structure[i].type,
171 (ir_variable_mode) var->data.mode);
173 const glsl_type *new_array_type =
174 process_array_type(var->type, i);
176 new(mem_ctx) ir_variable(new_array_type,
178 (ir_variable_mode) var->data.mode);
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;
198 new_var->init_interface_type(var->type);
199 hash_table_insert(interface_namespace, new_var,
201 insert_pos->insert_after(new_var);
202 insert_pos = new_var;
208 /* Second pass: visit all ir_dereference_record instances, and if they
209 * reference an interface block, then flatten the refererence out.
211 visit_list_elements(this, instructions);
212 hash_table_dtor(interface_namespace);
213 interface_namespace = NULL;
217 flatten_named_interface_blocks_declarations::visit_leave(ir_assignment *ir)
219 ir_dereference_record *lhs_rec = ir->lhs->as_dereference_record();
221 ir_variable *lhs_var = ir->lhs->variable_referenced();
222 if (lhs_var && lhs_var->get_interface_type()) {
223 lhs_var->data.assigned = 1;
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);
233 ir_variable *lhs_var = lhs_rec_tmp->variable_referenced();
235 lhs_var->data.assigned = 1;
238 return rvalue_visit(ir);
242 flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue **rvalue)
247 ir_dereference_record *ir = (*rvalue)->as_dereference_record();
251 ir_variable *var = ir->variable_referenced();
255 if (!var->is_interface_instance())
258 /* It should be possible to handle uniforms during this pass,
259 * but, this will require changes to the other uniform block
262 if (var->data.mode == ir_var_uniform || var->data.mode == ir_var_shader_storage)
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,
277 ir_dereference_variable *deref_var =
278 new(mem_ctx) ir_dereference_variable(found_var);
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);
292 lower_named_interface_blocks(void *mem_ctx, gl_shader *shader)
294 flatten_named_interface_blocks_declarations v_decl(mem_ctx);
295 v_decl.run(shader->ir);