1 /* 2 * Copyright 2010 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 ir_set_program_inouts.cpp 26 * 27 * Sets the InputsRead and OutputsWritten of Mesa programs. 28 * 29 * Mesa programs (gl_program, not gl_shader_program) have a set of 30 * flags indicating which varyings are read and written. Computing 31 * which are actually read from some sort of backend code can be 32 * tricky when variable array indexing involved. So this pass 33 * provides support for setting InputsRead and OutputsWritten right 34 * from the GLSL IR. 35 */ 36 37 extern "C" { 38 #include "main/core.h" /* for struct gl_program */ 39 #include "program/hash_table.h" 40 } 41 #include "ir.h" 42 #include "ir_visitor.h" 43 #include "glsl_types.h" 44 45 class ir_set_program_inouts_visitor : public ir_hierarchical_visitor { 46 public: 47 ir_set_program_inouts_visitor(struct gl_program *prog) 48 { 49 this->prog = prog; 50 this->ht = hash_table_ctor(0, 51 hash_table_pointer_hash, 52 hash_table_pointer_compare); 53 } 54 ~ir_set_program_inouts_visitor() 55 { 56 hash_table_dtor(this->ht); 57 } 58 59 virtual ir_visitor_status visit_enter(ir_dereference_array *); 60 virtual ir_visitor_status visit_enter(ir_function_signature *); 61 virtual ir_visitor_status visit(ir_dereference_variable *); 62 virtual ir_visitor_status visit(ir_variable *); 63 64 struct gl_program *prog; 65 struct hash_table *ht; 66 }; 67 68 static void 69 mark(struct gl_program *prog, ir_variable *var, int offset, int len) 70 { 71 /* As of GLSL 1.20, varyings can only be floats, floating-point 72 * vectors or matrices, or arrays of them. For Mesa programs using 73 * InputsRead/OutputsWritten, everything but matrices uses one 74 * slot, while matrices use a slot per column. Presumably 75 * something doing a more clever packing would use something other 76 * than InputsRead/OutputsWritten. 77 */ 78 79 for (int i = 0; i < len; i++) { 80 if (var->mode == ir_var_in) 81 prog->InputsRead |= BITFIELD64_BIT(var->location + offset + i); 82 else 83 prog->OutputsWritten |= BITFIELD64_BIT(var->location + offset + i); 84 } 85 } 86 87 /* Default handler: Mark all the locations in the variable as used. */ 88 ir_visitor_status 89 ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir) 90 { 91 if (hash_table_find(this->ht, ir->var) == NULL) 92 return visit_continue; 93 94 if (ir->type->is_array()) { 95 for (unsigned int i = 0; i < ir->type->length; i++) { 96 mark(this->prog, ir->var, i, 97 ir->type->length * ir->type->fields.array->matrix_columns); 98 } 99 } else { 100 mark(this->prog, ir->var, 0, ir->type->matrix_columns); 101 } 102 103 return visit_continue; 104 } 105 106 ir_visitor_status 107 ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir) 108 { 109 ir_dereference_variable *deref_var; 110 ir_constant *index = ir->array_index->as_constant(); 111 deref_var = ir->array->as_dereference_variable(); 112 ir_variable *var = NULL; 113 114 /* Check that we're dereferencing a shader in or out */ 115 if (deref_var) 116 var = (ir_variable *)hash_table_find(this->ht, deref_var->var); 117 118 if (index && var) { 119 int width = 1; 120 121 if (deref_var->type->is_array() && 122 deref_var->type->fields.array->is_matrix()) { 123 width = deref_var->type->fields.array->matrix_columns; 124 } 125 126 mark(this->prog, var, index->value.i[0] * width, width); 127 return visit_continue_with_parent; 128 } 129 130 return visit_continue; 131 } 132 133 ir_visitor_status 134 ir_set_program_inouts_visitor::visit(ir_variable *ir) 135 { 136 if (ir->mode == ir_var_in || 137 ir->mode == ir_var_out) { 138 hash_table_insert(this->ht, ir, ir); 139 } 140 141 return visit_continue; 142 } 143 144 ir_visitor_status 145 ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir) 146 { 147 /* We don't want to descend into the function parameters and 148 * consider them as shader inputs or outputs. 149 */ 150 visit_list_elements(this, &ir->body); 151 return visit_continue_with_parent; 152 } 153 154 void 155 do_set_program_inouts(exec_list *instructions, struct gl_program *prog) 156 { 157 ir_set_program_inouts_visitor v(prog); 158 159 prog->InputsRead = 0; 160 prog->OutputsWritten = 0; 161 visit_list_elements(&v, instructions); 162 } 163