nv50,nvc0: buffer resources can be bound as other things down the line
[mesa.git] / src / glsl / link_uniform_block_active_visitor.cpp
1 /*
2 * Copyright © 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 #include "link_uniform_block_active_visitor.h"
25 #include "program.h"
26
27 link_uniform_block_active *
28 process_block(void *mem_ctx, struct hash_table *ht, ir_variable *var)
29 {
30 const uint32_t h = _mesa_hash_string(var->get_interface_type()->name);
31 const hash_entry *const existing_block =
32 _mesa_hash_table_search(ht, h, var->get_interface_type()->name);
33
34 const glsl_type *const block_type = var->is_interface_instance()
35 ? var->type : var->get_interface_type();
36
37
38 /* If a block with this block-name has not previously been seen, add it.
39 * If a block with this block-name has been seen, it must be identical to
40 * the block currently being examined.
41 */
42 if (existing_block == NULL) {
43 link_uniform_block_active *const b =
44 rzalloc(mem_ctx, struct link_uniform_block_active);
45
46 b->type = block_type;
47 b->has_instance_name = var->is_interface_instance();
48
49 if (var->data.explicit_binding) {
50 b->has_binding = true;
51 b->binding = var->data.binding;
52 } else {
53 b->has_binding = false;
54 b->binding = 0;
55 }
56
57 _mesa_hash_table_insert(ht, h, var->get_interface_type()->name,
58 (void *) b);
59 return b;
60 } else {
61 link_uniform_block_active *const b =
62 (link_uniform_block_active *) existing_block->data;
63
64 if (b->type != block_type
65 || b->has_instance_name != var->is_interface_instance())
66 return NULL;
67 else
68 return b;
69 }
70
71 assert(!"Should not get here.");
72 return NULL;
73 }
74
75 ir_visitor_status
76 link_uniform_block_active_visitor::visit(ir_variable *var)
77 {
78 if (!var->is_in_uniform_block())
79 return visit_continue;
80
81 const glsl_type *const block_type = var->is_interface_instance()
82 ? var->type : var->get_interface_type();
83
84 /* Section 2.11.6 (Uniform Variables) of the OpenGL ES 3.0.3 spec says:
85 *
86 * "All members of a named uniform block declared with a shared or
87 * std140 layout qualifier are considered active, even if they are not
88 * referenced in any shader in the program. The uniform block itself is
89 * also considered active, even if no member of the block is
90 * referenced."
91 */
92 if (block_type->interface_packing == GLSL_INTERFACE_PACKING_PACKED)
93 return visit_continue;
94
95 /* Process the block. Bail if there was an error.
96 */
97 link_uniform_block_active *const b =
98 process_block(this->mem_ctx, this->ht, var);
99 if (b == NULL) {
100 linker_error(this->prog,
101 "uniform block `%s' has mismatching definitions",
102 var->get_interface_type()->name);
103 this->success = false;
104 return visit_stop;
105 }
106
107 assert(b->num_array_elements == 0);
108 assert(b->array_elements == NULL);
109 assert(b->type != NULL);
110
111 return visit_continue;
112 }
113
114 ir_visitor_status
115 link_uniform_block_active_visitor::visit_enter(ir_dereference_array *ir)
116 {
117 ir_dereference_variable *const d = ir->array->as_dereference_variable();
118 ir_variable *const var = (d == NULL) ? NULL : d->var;
119
120 /* If the r-value being dereferenced is not a variable (e.g., a field of a
121 * structure) or is not a uniform block instance, continue.
122 *
123 * WARNING: It is not enough for the variable to be part of uniform block.
124 * It must represent the entire block. Arrays (or matrices) inside blocks
125 * that lack an instance name are handled by the ir_dereference_variable
126 * function.
127 */
128 if (var == NULL
129 || !var->is_in_uniform_block()
130 || !var->is_interface_instance())
131 return visit_continue;
132
133 /* Process the block. Bail if there was an error.
134 */
135 link_uniform_block_active *const b =
136 process_block(this->mem_ctx, this->ht, var);
137 if (b == NULL) {
138 linker_error(prog,
139 "uniform block `%s' has mismatching definitions",
140 var->get_interface_type()->name);
141 this->success = false;
142 return visit_stop;
143 }
144
145 /* Block arrays must be declared with an instance name.
146 */
147 assert(b->has_instance_name);
148 assert((b->num_array_elements == 0) == (b->array_elements == NULL));
149 assert(b->type != NULL);
150
151 ir_constant *c = ir->array_index->as_constant();
152
153 if (c) {
154 /* Index is a constant, so mark just that element used, if not already */
155 const unsigned idx = c->get_uint_component(0);
156
157 unsigned i;
158 for (i = 0; i < b->num_array_elements; i++) {
159 if (b->array_elements[i] == idx)
160 break;
161 }
162
163 assert(i <= b->num_array_elements);
164
165 if (i == b->num_array_elements) {
166 b->array_elements = reralloc(this->mem_ctx,
167 b->array_elements,
168 unsigned,
169 b->num_array_elements + 1);
170
171 b->array_elements[b->num_array_elements] = idx;
172
173 b->num_array_elements++;
174 }
175 } else {
176 /* The array index is not a constant, so mark the entire array used. */
177 assert(b->type->is_array());
178 if (b->num_array_elements < b->type->length) {
179 b->num_array_elements = b->type->length;
180 b->array_elements = reralloc(this->mem_ctx,
181 b->array_elements,
182 unsigned,
183 b->num_array_elements);
184
185 for (unsigned i = 0; i < b->num_array_elements; i++) {
186 b->array_elements[i] = i;
187 }
188 }
189 }
190
191 return visit_continue_with_parent;
192 }
193
194 ir_visitor_status
195 link_uniform_block_active_visitor::visit(ir_dereference_variable *ir)
196 {
197 ir_variable *var = ir->var;
198
199 if (!var->is_in_uniform_block())
200 return visit_continue;
201
202 assert(!var->is_interface_instance() || !var->type->is_array());
203
204 /* Process the block. Bail if there was an error.
205 */
206 link_uniform_block_active *const b =
207 process_block(this->mem_ctx, this->ht, var);
208 if (b == NULL) {
209 linker_error(this->prog,
210 "uniform block `%s' has mismatching definitions",
211 var->get_interface_type()->name);
212 this->success = false;
213 return visit_stop;
214 }
215
216 assert(b->num_array_elements == 0);
217 assert(b->array_elements == NULL);
218 assert(b->type != NULL);
219
220 return visit_continue;
221 }