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 69static const glsl_type * 70process_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 82static ir_rvalue * 83process_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 102namespace { 103 104class flatten_named_interface_blocks_declarations : public ir_rvalue_visitor 105{ 106public: 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 125void 126flatten_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 223ir_visitor_status 224flatten_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 248ir_visitor_status 249flatten_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 265void 266flatten_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 317void 318lower_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 324