Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 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 | #include |
||
24 | #include "main/compiler.h" |
||
25 | #include "main/mtypes.h" |
||
26 | #include "main/macros.h" |
||
27 | #include "util/ralloc.h" |
||
28 | #include "ir.h" |
||
29 | #include "program/hash_table.h" |
||
30 | |||
31 | /** |
||
32 | * \file varyings_test.cpp |
||
33 | * |
||
34 | * Test various aspects of linking shader stage inputs and outputs. |
||
35 | */ |
||
36 | |||
37 | namespace linker { |
||
38 | bool |
||
39 | populate_consumer_input_sets(void *mem_ctx, exec_list *ir, |
||
40 | hash_table *consumer_inputs, |
||
41 | hash_table *consumer_interface_inputs, |
||
42 | ir_variable *consumer_inputs_with_locations[VARYING_SLOT_MAX]); |
||
43 | |||
44 | ir_variable * |
||
45 | get_matching_input(void *mem_ctx, |
||
46 | const ir_variable *output_var, |
||
47 | hash_table *consumer_inputs, |
||
48 | hash_table *consumer_interface_inputs, |
||
49 | ir_variable *consumer_inputs_with_locations[VARYING_SLOT_MAX]); |
||
50 | } |
||
51 | |||
52 | class link_varyings : public ::testing::Test { |
||
53 | public: |
||
54 | link_varyings(); |
||
55 | |||
56 | virtual void SetUp(); |
||
57 | virtual void TearDown(); |
||
58 | |||
59 | char *interface_field_name(const glsl_type *iface, unsigned field = 0) |
||
60 | { |
||
61 | return ralloc_asprintf(mem_ctx, |
||
62 | "%s.%s", |
||
63 | iface->name, |
||
64 | iface->fields.structure[field].name); |
||
65 | } |
||
66 | |||
67 | void *mem_ctx; |
||
68 | exec_list ir; |
||
69 | hash_table *consumer_inputs; |
||
70 | hash_table *consumer_interface_inputs; |
||
71 | |||
72 | const glsl_type *simple_interface; |
||
73 | ir_variable *junk[VARYING_SLOT_MAX]; |
||
74 | }; |
||
75 | |||
76 | link_varyings::link_varyings() |
||
77 | { |
||
78 | static const glsl_struct_field f[] = { |
||
79 | { |
||
80 | glsl_type::vec(4), |
||
81 | "v", |
||
82 | false, |
||
83 | 0, |
||
84 | 0, |
||
85 | 0, |
||
86 | |||
87 | } |
||
88 | }; |
||
89 | |||
90 | this->simple_interface = |
||
91 | glsl_type::get_interface_instance(f, |
||
92 | ARRAY_SIZE(f), |
||
93 | GLSL_INTERFACE_PACKING_STD140, |
||
94 | "simple_interface"); |
||
95 | } |
||
96 | |||
97 | void |
||
98 | link_varyings::SetUp() |
||
99 | { |
||
100 | this->mem_ctx = ralloc_context(NULL); |
||
101 | this->ir.make_empty(); |
||
102 | |||
103 | this->consumer_inputs |
||
104 | = hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare); |
||
105 | |||
106 | this->consumer_interface_inputs |
||
107 | = hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare); |
||
108 | } |
||
109 | |||
110 | void |
||
111 | link_varyings::TearDown() |
||
112 | { |
||
113 | ralloc_free(this->mem_ctx); |
||
114 | this->mem_ctx = NULL; |
||
115 | |||
116 | hash_table_dtor(this->consumer_inputs); |
||
117 | this->consumer_inputs = NULL; |
||
118 | hash_table_dtor(this->consumer_interface_inputs); |
||
119 | this->consumer_interface_inputs = NULL; |
||
120 | } |
||
121 | |||
122 | /** |
||
123 | * Hash table callback function that counts the elements in the table |
||
124 | * |
||
125 | * \sa num_elements |
||
126 | */ |
||
127 | static void |
||
128 | ht_count_callback(const void *, void *, void *closure) |
||
129 | { |
||
130 | unsigned int *counter = (unsigned int *) closure; |
||
131 | |||
132 | (*counter)++; |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * Helper function to count the number of elements in a hash table. |
||
137 | */ |
||
138 | static unsigned |
||
139 | num_elements(hash_table *ht) |
||
140 | { |
||
141 | unsigned int counter = 0; |
||
142 | |||
143 | hash_table_call_foreach(ht, ht_count_callback, (void *) &counter); |
||
144 | |||
145 | return counter; |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Helper function to determine whether a hash table is empty. |
||
150 | */ |
||
151 | static bool |
||
152 | is_empty(hash_table *ht) |
||
153 | { |
||
154 | return num_elements(ht) == 0; |
||
155 | } |
||
156 | |||
157 | TEST_F(link_varyings, single_simple_input) |
||
158 | { |
||
159 | ir_variable *const v = |
||
160 | new(mem_ctx) ir_variable(glsl_type::vec(4), |
||
161 | "a", |
||
162 | ir_var_shader_in); |
||
163 | |||
164 | |||
165 | ir.push_tail(v); |
||
166 | |||
167 | ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, |
||
168 | &ir, |
||
169 | consumer_inputs, |
||
170 | consumer_interface_inputs, |
||
171 | junk)); |
||
172 | |||
173 | EXPECT_EQ((void *) v, hash_table_find(consumer_inputs, "a")); |
||
174 | EXPECT_EQ(1u, num_elements(consumer_inputs)); |
||
175 | EXPECT_TRUE(is_empty(consumer_interface_inputs)); |
||
176 | } |
||
177 | |||
178 | TEST_F(link_varyings, gl_ClipDistance) |
||
179 | { |
||
180 | const glsl_type *const array_8_of_float = |
||
181 | glsl_type::get_array_instance(glsl_type::vec(1), 8); |
||
182 | |||
183 | ir_variable *const clipdistance = |
||
184 | new(mem_ctx) ir_variable(array_8_of_float, |
||
185 | "gl_ClipDistance", |
||
186 | ir_var_shader_in); |
||
187 | |||
188 | clipdistance->data.explicit_location = true; |
||
189 | clipdistance->data.location = VARYING_SLOT_CLIP_DIST0; |
||
190 | clipdistance->data.explicit_index = 0; |
||
191 | |||
192 | ir.push_tail(clipdistance); |
||
193 | |||
194 | ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, |
||
195 | &ir, |
||
196 | consumer_inputs, |
||
197 | consumer_interface_inputs, |
||
198 | junk)); |
||
199 | |||
200 | EXPECT_EQ(clipdistance, junk[VARYING_SLOT_CLIP_DIST0]); |
||
201 | EXPECT_TRUE(is_empty(consumer_inputs)); |
||
202 | EXPECT_TRUE(is_empty(consumer_interface_inputs)); |
||
203 | } |
||
204 | |||
205 | TEST_F(link_varyings, single_interface_input) |
||
206 | { |
||
207 | ir_variable *const v = |
||
208 | new(mem_ctx) ir_variable(simple_interface->fields.structure[0].type, |
||
209 | simple_interface->fields.structure[0].name, |
||
210 | ir_var_shader_in); |
||
211 | |||
212 | v->init_interface_type(simple_interface); |
||
213 | |||
214 | ir.push_tail(v); |
||
215 | |||
216 | ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, |
||
217 | &ir, |
||
218 | consumer_inputs, |
||
219 | consumer_interface_inputs, |
||
220 | junk)); |
||
221 | char *const full_name = interface_field_name(simple_interface); |
||
222 | |||
223 | EXPECT_EQ((void *) v, hash_table_find(consumer_interface_inputs, full_name)); |
||
224 | EXPECT_EQ(1u, num_elements(consumer_interface_inputs)); |
||
225 | EXPECT_TRUE(is_empty(consumer_inputs)); |
||
226 | } |
||
227 | |||
228 | TEST_F(link_varyings, one_interface_and_one_simple_input) |
||
229 | { |
||
230 | ir_variable *const v = |
||
231 | new(mem_ctx) ir_variable(glsl_type::vec(4), |
||
232 | "a", |
||
233 | ir_var_shader_in); |
||
234 | |||
235 | |||
236 | ir.push_tail(v); |
||
237 | |||
238 | ir_variable *const iface = |
||
239 | new(mem_ctx) ir_variable(simple_interface->fields.structure[0].type, |
||
240 | simple_interface->fields.structure[0].name, |
||
241 | ir_var_shader_in); |
||
242 | |||
243 | iface->init_interface_type(simple_interface); |
||
244 | |||
245 | ir.push_tail(iface); |
||
246 | |||
247 | ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, |
||
248 | &ir, |
||
249 | consumer_inputs, |
||
250 | consumer_interface_inputs, |
||
251 | junk)); |
||
252 | |||
253 | char *const iface_field_name = interface_field_name(simple_interface); |
||
254 | |||
255 | EXPECT_EQ((void *) iface, hash_table_find(consumer_interface_inputs, |
||
256 | iface_field_name)); |
||
257 | EXPECT_EQ(1u, num_elements(consumer_interface_inputs)); |
||
258 | |||
259 | EXPECT_EQ((void *) v, hash_table_find(consumer_inputs, "a")); |
||
260 | EXPECT_EQ(1u, num_elements(consumer_inputs)); |
||
261 | } |
||
262 | |||
263 | TEST_F(link_varyings, invalid_interface_input) |
||
264 | { |
||
265 | ir_variable *const v = |
||
266 | new(mem_ctx) ir_variable(simple_interface, |
||
267 | "named_interface", |
||
268 | ir_var_shader_in); |
||
269 | |||
270 | ASSERT_EQ(simple_interface, v->get_interface_type()); |
||
271 | |||
272 | ir.push_tail(v); |
||
273 | |||
274 | EXPECT_FALSE(linker::populate_consumer_input_sets(mem_ctx, |
||
275 | &ir, |
||
276 | consumer_inputs, |
||
277 | consumer_interface_inputs, |
||
278 | junk)); |
||
279 | } |
||
280 | |||
281 | TEST_F(link_varyings, interface_field_doesnt_match_noninterface) |
||
282 | { |
||
283 | char *const iface_field_name = interface_field_name(simple_interface); |
||
284 | |||
285 | /* The input shader has a single input variable name "a.v" |
||
286 | */ |
||
287 | ir_variable *const in_v = |
||
288 | new(mem_ctx) ir_variable(glsl_type::vec(4), |
||
289 | iface_field_name, |
||
290 | ir_var_shader_in); |
||
291 | |||
292 | ir.push_tail(in_v); |
||
293 | |||
294 | ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, |
||
295 | &ir, |
||
296 | consumer_inputs, |
||
297 | consumer_interface_inputs, |
||
298 | junk)); |
||
299 | |||
300 | /* Create an output variable, "v", that is part of an interface block named |
||
301 | * "a". They should not match. |
||
302 | */ |
||
303 | ir_variable *const out_v = |
||
304 | new(mem_ctx) ir_variable(simple_interface->fields.structure[0].type, |
||
305 | simple_interface->fields.structure[0].name, |
||
306 | ir_var_shader_in); |
||
307 | |||
308 | out_v->init_interface_type(simple_interface); |
||
309 | |||
310 | ir_variable *const match = |
||
311 | linker::get_matching_input(mem_ctx, |
||
312 | out_v, |
||
313 | consumer_inputs, |
||
314 | consumer_interface_inputs, |
||
315 | junk); |
||
316 | |||
317 | EXPECT_EQ(NULL, match); |
||
318 | } |
||
319 | |||
320 | TEST_F(link_varyings, interface_field_doesnt_match_noninterface_vice_versa) |
||
321 | { |
||
322 | char *const iface_field_name = interface_field_name(simple_interface); |
||
323 | |||
324 | /* In input shader has a single variable, "v", that is part of an interface |
||
325 | * block named "a". |
||
326 | */ |
||
327 | ir_variable *const in_v = |
||
328 | new(mem_ctx) ir_variable(simple_interface->fields.structure[0].type, |
||
329 | simple_interface->fields.structure[0].name, |
||
330 | ir_var_shader_in); |
||
331 | |||
332 | in_v->init_interface_type(simple_interface); |
||
333 | |||
334 | ir.push_tail(in_v); |
||
335 | |||
336 | ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, |
||
337 | &ir, |
||
338 | consumer_inputs, |
||
339 | consumer_interface_inputs, |
||
340 | junk)); |
||
341 | |||
342 | /* Create an output variable "a.v". They should not match. |
||
343 | */ |
||
344 | ir_variable *const out_v = |
||
345 | new(mem_ctx) ir_variable(glsl_type::vec(4), |
||
346 | iface_field_name, |
||
347 | ir_var_shader_out); |
||
348 | |||
349 | ir_variable *const match = |
||
350 | linker::get_matching_input(mem_ctx, |
||
351 | out_v, |
||
352 | consumer_inputs, |
||
353 | consumer_interface_inputs, |
||
354 | junk); |
||
355 | |||
356 | EXPECT_EQ(NULL, match); |
||
357 | } |