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 <gtest/gtest.h>
24 #include "util/compiler.h"
25 #include "main/mtypes.h"
26 #include "main/macros.h"
27 #include "util/ralloc.h"
28 #include "ir.h"
29 #include "util/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 void
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    virtual void SetUp();
55    virtual void TearDown();
56 
interface_field_name(const glsl_type * iface,unsigned field=0)57    char *interface_field_name(const glsl_type *iface, unsigned field = 0)
58    {
59       return ralloc_asprintf(mem_ctx,
60                              "%s.%s",
61                              iface->name,
62                              iface->fields.structure[field].name);
63    }
64 
65    void *mem_ctx;
66    exec_list ir;
67    hash_table *consumer_inputs;
68    hash_table *consumer_interface_inputs;
69 
70    const glsl_type *simple_interface;
71    ir_variable *junk[VARYING_SLOT_TESS_MAX];
72 };
73 
74 void
SetUp()75 link_varyings::SetUp()
76 {
77    glsl_type_singleton_init_or_ref();
78 
79    this->mem_ctx = ralloc_context(NULL);
80    this->ir.make_empty();
81 
82    this->consumer_inputs =
83          _mesa_hash_table_create(NULL, _mesa_hash_string,
84                                  _mesa_key_string_equal);
85 
86    this->consumer_interface_inputs =
87          _mesa_hash_table_create(NULL, _mesa_hash_string,
88                                  _mesa_key_string_equal);
89 
90    /* Needs to happen after glsl type initialization */
91    static const glsl_struct_field f[] = {
92       glsl_struct_field(glsl_type::vec(4), "v")
93    };
94 
95    this->simple_interface =
96       glsl_type::get_interface_instance(f,
97                                         ARRAY_SIZE(f),
98                                         GLSL_INTERFACE_PACKING_STD140,
99                                         false,
100                                         "simple_interface");
101 }
102 
103 void
TearDown()104 link_varyings::TearDown()
105 {
106    ralloc_free(this->mem_ctx);
107    this->mem_ctx = NULL;
108 
109    _mesa_hash_table_destroy(this->consumer_inputs, NULL);
110    this->consumer_inputs = NULL;
111    _mesa_hash_table_destroy(this->consumer_interface_inputs, NULL);
112    this->consumer_interface_inputs = NULL;
113 
114    glsl_type_singleton_decref();
115 }
116 
TEST_F(link_varyings,single_simple_input)117 TEST_F(link_varyings, single_simple_input)
118 {
119    ir_variable *const v =
120       new(mem_ctx) ir_variable(glsl_type::vec(4),
121                                "a",
122                                ir_var_shader_in);
123 
124 
125    ir.push_tail(v);
126 
127    linker::populate_consumer_input_sets(mem_ctx,
128                                         &ir,
129                                         consumer_inputs,
130                                         consumer_interface_inputs,
131                                         junk);
132 
133    hash_entry *entry = _mesa_hash_table_search(consumer_inputs, "a");
134    EXPECT_EQ((void *) v, entry->data);
135    EXPECT_EQ(1u, consumer_inputs->entries);
136    EXPECT_TRUE(consumer_interface_inputs->entries == 0);
137 }
138 
TEST_F(link_varyings,gl_ClipDistance)139 TEST_F(link_varyings, gl_ClipDistance)
140 {
141    const glsl_type *const array_8_of_float =
142       glsl_type::get_array_instance(glsl_type::vec(1), 8);
143 
144    ir_variable *const clipdistance =
145       new(mem_ctx) ir_variable(array_8_of_float,
146                                "gl_ClipDistance",
147                                ir_var_shader_in);
148 
149    clipdistance->data.explicit_location = true;
150    clipdistance->data.location = VARYING_SLOT_CLIP_DIST0;
151    clipdistance->data.explicit_index = 0;
152 
153    ir.push_tail(clipdistance);
154 
155    linker::populate_consumer_input_sets(mem_ctx,
156                                         &ir,
157                                         consumer_inputs,
158                                         consumer_interface_inputs,
159                                         junk);
160 
161    EXPECT_EQ(clipdistance, junk[VARYING_SLOT_CLIP_DIST0]);
162    EXPECT_TRUE(consumer_inputs->entries == 0);
163    EXPECT_TRUE(consumer_interface_inputs->entries == 0);
164 }
165 
TEST_F(link_varyings,gl_CullDistance)166 TEST_F(link_varyings, gl_CullDistance)
167 {
168    const glsl_type *const array_8_of_float =
169       glsl_type::get_array_instance(glsl_type::vec(1), 8);
170 
171    ir_variable *const culldistance =
172       new(mem_ctx) ir_variable(array_8_of_float,
173                                "gl_CullDistance",
174                                ir_var_shader_in);
175 
176    culldistance->data.explicit_location = true;
177    culldistance->data.location = VARYING_SLOT_CULL_DIST0;
178    culldistance->data.explicit_index = 0;
179 
180    ir.push_tail(culldistance);
181 
182    linker::populate_consumer_input_sets(mem_ctx,
183                                         &ir,
184                                         consumer_inputs,
185                                         consumer_interface_inputs,
186                                         junk);
187 
188    EXPECT_EQ(culldistance, junk[VARYING_SLOT_CULL_DIST0]);
189    EXPECT_TRUE(consumer_inputs->entries == 0);
190    EXPECT_TRUE(consumer_interface_inputs->entries == 0);
191 }
192 
TEST_F(link_varyings,single_interface_input)193 TEST_F(link_varyings, single_interface_input)
194 {
195    ir_variable *const v =
196       new(mem_ctx) ir_variable(simple_interface->fields.structure[0].type,
197                                simple_interface->fields.structure[0].name,
198                                ir_var_shader_in);
199 
200    v->init_interface_type(simple_interface);
201 
202    ir.push_tail(v);
203 
204    linker::populate_consumer_input_sets(mem_ctx,
205                                         &ir,
206                                         consumer_inputs,
207                                         consumer_interface_inputs,
208                                         junk);
209    char *const full_name = interface_field_name(simple_interface);
210 
211    hash_entry *entry = _mesa_hash_table_search(consumer_interface_inputs,
212                                                full_name);
213    EXPECT_EQ((void *) v, entry->data);
214    EXPECT_EQ(1u, consumer_interface_inputs->entries);
215    EXPECT_TRUE(consumer_inputs->entries == 0);
216 }
217 
TEST_F(link_varyings,one_interface_and_one_simple_input)218 TEST_F(link_varyings, one_interface_and_one_simple_input)
219 {
220    ir_variable *const v =
221       new(mem_ctx) ir_variable(glsl_type::vec(4),
222                                "a",
223                                ir_var_shader_in);
224 
225 
226    ir.push_tail(v);
227 
228    ir_variable *const iface =
229       new(mem_ctx) ir_variable(simple_interface->fields.structure[0].type,
230                                simple_interface->fields.structure[0].name,
231                                ir_var_shader_in);
232 
233    iface->init_interface_type(simple_interface);
234 
235    ir.push_tail(iface);
236 
237    linker::populate_consumer_input_sets(mem_ctx,
238                                         &ir,
239                                         consumer_inputs,
240                                         consumer_interface_inputs,
241                                         junk);
242 
243    char *const iface_field_name = interface_field_name(simple_interface);
244 
245    hash_entry *entry = _mesa_hash_table_search(consumer_interface_inputs,
246                                                iface_field_name);
247    EXPECT_EQ((void *) iface, entry->data);
248    EXPECT_EQ(1u, consumer_interface_inputs->entries);
249 
250    entry = _mesa_hash_table_search(consumer_inputs, "a");
251    EXPECT_EQ((void *) v, entry->data);
252    EXPECT_EQ(1u, consumer_inputs->entries);
253 }
254 
TEST_F(link_varyings,interface_field_doesnt_match_noninterface)255 TEST_F(link_varyings, interface_field_doesnt_match_noninterface)
256 {
257    char *const iface_field_name = interface_field_name(simple_interface);
258 
259    /* The input shader has a single input variable name "a.v"
260     */
261    ir_variable *const in_v =
262       new(mem_ctx) ir_variable(glsl_type::vec(4),
263                                iface_field_name,
264                                ir_var_shader_in);
265 
266    ir.push_tail(in_v);
267 
268    linker::populate_consumer_input_sets(mem_ctx,
269                                         &ir,
270                                         consumer_inputs,
271                                         consumer_interface_inputs,
272                                         junk);
273 
274    /* Create an output variable, "v", that is part of an interface block named
275     * "a".  They should not match.
276     */
277    ir_variable *const out_v =
278       new(mem_ctx) ir_variable(simple_interface->fields.structure[0].type,
279                                simple_interface->fields.structure[0].name,
280                                ir_var_shader_in);
281 
282    out_v->init_interface_type(simple_interface);
283 
284    ir_variable *const match =
285       linker::get_matching_input(mem_ctx,
286                                  out_v,
287                                  consumer_inputs,
288                                  consumer_interface_inputs,
289                                  junk);
290 
291    EXPECT_EQ(NULL, match);
292 }
293 
TEST_F(link_varyings,interface_field_doesnt_match_noninterface_vice_versa)294 TEST_F(link_varyings, interface_field_doesnt_match_noninterface_vice_versa)
295 {
296    char *const iface_field_name = interface_field_name(simple_interface);
297 
298    /* In input shader has a single variable, "v", that is part of an interface
299     * block named "a".
300     */
301    ir_variable *const in_v =
302       new(mem_ctx) ir_variable(simple_interface->fields.structure[0].type,
303                                simple_interface->fields.structure[0].name,
304                                ir_var_shader_in);
305 
306    in_v->init_interface_type(simple_interface);
307 
308    ir.push_tail(in_v);
309 
310    linker::populate_consumer_input_sets(mem_ctx,
311                                         &ir,
312                                         consumer_inputs,
313                                         consumer_interface_inputs,
314                                         junk);
315 
316    /* Create an output variable "a.v".  They should not match.
317     */
318    ir_variable *const out_v =
319       new(mem_ctx) ir_variable(glsl_type::vec(4),
320                                iface_field_name,
321                                ir_var_shader_out);
322 
323    ir_variable *const match =
324       linker::get_matching_input(mem_ctx,
325                                  out_v,
326                                  consumer_inputs,
327                                  consumer_interface_inputs,
328                                  junk);
329 
330    EXPECT_EQ(NULL, match);
331 }
332