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 "main/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
37namespace linker {
38void
39populate_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
44ir_variable *
45get_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
52class link_varyings : public ::testing::Test {
53public:
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_TESS_MAX];
74};
75
76link_varyings::link_varyings()
77{
78   static const glsl_struct_field f[] = {
79      glsl_struct_field(glsl_type::vec(4), "v")
80   };
81
82   this->simple_interface =
83      glsl_type::get_interface_instance(f,
84                                        ARRAY_SIZE(f),
85                                        GLSL_INTERFACE_PACKING_STD140,
86                                        false,
87                                        "simple_interface");
88}
89
90void
91link_varyings::SetUp()
92{
93   this->mem_ctx = ralloc_context(NULL);
94   this->ir.make_empty();
95
96   this->consumer_inputs =
97         _mesa_hash_table_create(NULL, _mesa_key_hash_string,
98                                 _mesa_key_string_equal);
99
100   this->consumer_interface_inputs =
101         _mesa_hash_table_create(NULL, _mesa_key_hash_string,
102                                 _mesa_key_string_equal);
103}
104
105void
106link_varyings::TearDown()
107{
108   ralloc_free(this->mem_ctx);
109   this->mem_ctx = NULL;
110
111   _mesa_hash_table_destroy(this->consumer_inputs, NULL);
112   this->consumer_inputs = NULL;
113   _mesa_hash_table_destroy(this->consumer_interface_inputs, NULL);
114   this->consumer_interface_inputs = NULL;
115}
116
117TEST_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
139TEST_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
166TEST_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
193TEST_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
218TEST_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
255TEST_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
294TEST_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