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 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 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 76 link_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 90 void 91 link_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 105 void 106 link_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 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 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 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 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 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 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 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