• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ir_set_program_inouts_visitor(struct gl_program * prog)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    }
~ir_set_program_inouts_visitor()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
mark(struct gl_program * prog,ir_variable * var,int offset,int len)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
visit(ir_dereference_variable * ir)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
visit_enter(ir_dereference_array * ir)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
visit(ir_variable * ir)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
visit_enter(ir_function_signature * ir)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
do_set_program_inouts(exec_list * instructions,struct gl_program * prog)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