diff options
Diffstat (limited to 'src/compiler/glsl/tests/varyings_test.cpp')
-rw-r--r-- | src/compiler/glsl/tests/varyings_test.cpp | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/src/compiler/glsl/tests/varyings_test.cpp b/src/compiler/glsl/tests/varyings_test.cpp new file mode 100644 index 00000000000..0c4e0a471b8 --- /dev/null +++ b/src/compiler/glsl/tests/varyings_test.cpp @@ -0,0 +1,349 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <gtest/gtest.h> +#include "main/compiler.h" +#include "main/mtypes.h" +#include "main/macros.h" +#include "util/ralloc.h" +#include "ir.h" +#include "program/hash_table.h" + +/** + * \file varyings_test.cpp + * + * Test various aspects of linking shader stage inputs and outputs. + */ + +namespace linker { +bool +populate_consumer_input_sets(void *mem_ctx, exec_list *ir, + hash_table *consumer_inputs, + hash_table *consumer_interface_inputs, + ir_variable *consumer_inputs_with_locations[VARYING_SLOT_MAX]); + +ir_variable * +get_matching_input(void *mem_ctx, + const ir_variable *output_var, + hash_table *consumer_inputs, + hash_table *consumer_interface_inputs, + ir_variable *consumer_inputs_with_locations[VARYING_SLOT_MAX]); +} + +class link_varyings : public ::testing::Test { +public: + link_varyings(); + + virtual void SetUp(); + virtual void TearDown(); + + char *interface_field_name(const glsl_type *iface, unsigned field = 0) + { + return ralloc_asprintf(mem_ctx, + "%s.%s", + iface->name, + iface->fields.structure[field].name); + } + + void *mem_ctx; + exec_list ir; + hash_table *consumer_inputs; + hash_table *consumer_interface_inputs; + + const glsl_type *simple_interface; + ir_variable *junk[VARYING_SLOT_TESS_MAX]; +}; + +link_varyings::link_varyings() +{ + static const glsl_struct_field f[] = { + glsl_struct_field(glsl_type::vec(4), "v") + }; + + this->simple_interface = + glsl_type::get_interface_instance(f, + ARRAY_SIZE(f), + GLSL_INTERFACE_PACKING_STD140, + "simple_interface"); +} + +void +link_varyings::SetUp() +{ + this->mem_ctx = ralloc_context(NULL); + this->ir.make_empty(); + + this->consumer_inputs + = hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare); + + this->consumer_interface_inputs + = hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare); +} + +void +link_varyings::TearDown() +{ + ralloc_free(this->mem_ctx); + this->mem_ctx = NULL; + + hash_table_dtor(this->consumer_inputs); + this->consumer_inputs = NULL; + hash_table_dtor(this->consumer_interface_inputs); + this->consumer_interface_inputs = NULL; +} + +/** + * Hash table callback function that counts the elements in the table + * + * \sa num_elements + */ +static void +ht_count_callback(const void *, void *, void *closure) +{ + unsigned int *counter = (unsigned int *) closure; + + (*counter)++; +} + +/** + * Helper function to count the number of elements in a hash table. + */ +static unsigned +num_elements(hash_table *ht) +{ + unsigned int counter = 0; + + hash_table_call_foreach(ht, ht_count_callback, (void *) &counter); + + return counter; +} + +/** + * Helper function to determine whether a hash table is empty. + */ +static bool +is_empty(hash_table *ht) +{ + return num_elements(ht) == 0; +} + +TEST_F(link_varyings, single_simple_input) +{ + ir_variable *const v = + new(mem_ctx) ir_variable(glsl_type::vec(4), + "a", + ir_var_shader_in); + + + ir.push_tail(v); + + ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, + &ir, + consumer_inputs, + consumer_interface_inputs, + junk)); + + EXPECT_EQ((void *) v, hash_table_find(consumer_inputs, "a")); + EXPECT_EQ(1u, num_elements(consumer_inputs)); + EXPECT_TRUE(is_empty(consumer_interface_inputs)); +} + +TEST_F(link_varyings, gl_ClipDistance) +{ + const glsl_type *const array_8_of_float = + glsl_type::get_array_instance(glsl_type::vec(1), 8); + + ir_variable *const clipdistance = + new(mem_ctx) ir_variable(array_8_of_float, + "gl_ClipDistance", + ir_var_shader_in); + + clipdistance->data.explicit_location = true; + clipdistance->data.location = VARYING_SLOT_CLIP_DIST0; + clipdistance->data.explicit_index = 0; + + ir.push_tail(clipdistance); + + ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, + &ir, + consumer_inputs, + consumer_interface_inputs, + junk)); + + EXPECT_EQ(clipdistance, junk[VARYING_SLOT_CLIP_DIST0]); + EXPECT_TRUE(is_empty(consumer_inputs)); + EXPECT_TRUE(is_empty(consumer_interface_inputs)); +} + +TEST_F(link_varyings, single_interface_input) +{ + ir_variable *const v = + new(mem_ctx) ir_variable(simple_interface->fields.structure[0].type, + simple_interface->fields.structure[0].name, + ir_var_shader_in); + + v->init_interface_type(simple_interface); + + ir.push_tail(v); + + ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, + &ir, + consumer_inputs, + consumer_interface_inputs, + junk)); + char *const full_name = interface_field_name(simple_interface); + + EXPECT_EQ((void *) v, hash_table_find(consumer_interface_inputs, full_name)); + EXPECT_EQ(1u, num_elements(consumer_interface_inputs)); + EXPECT_TRUE(is_empty(consumer_inputs)); +} + +TEST_F(link_varyings, one_interface_and_one_simple_input) +{ + ir_variable *const v = + new(mem_ctx) ir_variable(glsl_type::vec(4), + "a", + ir_var_shader_in); + + + ir.push_tail(v); + + ir_variable *const iface = + new(mem_ctx) ir_variable(simple_interface->fields.structure[0].type, + simple_interface->fields.structure[0].name, + ir_var_shader_in); + + iface->init_interface_type(simple_interface); + + ir.push_tail(iface); + + ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, + &ir, + consumer_inputs, + consumer_interface_inputs, + junk)); + + char *const iface_field_name = interface_field_name(simple_interface); + + EXPECT_EQ((void *) iface, hash_table_find(consumer_interface_inputs, + iface_field_name)); + EXPECT_EQ(1u, num_elements(consumer_interface_inputs)); + + EXPECT_EQ((void *) v, hash_table_find(consumer_inputs, "a")); + EXPECT_EQ(1u, num_elements(consumer_inputs)); +} + +TEST_F(link_varyings, invalid_interface_input) +{ + ir_variable *const v = + new(mem_ctx) ir_variable(simple_interface, + "named_interface", + ir_var_shader_in); + + ASSERT_EQ(simple_interface, v->get_interface_type()); + + ir.push_tail(v); + + EXPECT_FALSE(linker::populate_consumer_input_sets(mem_ctx, + &ir, + consumer_inputs, + consumer_interface_inputs, + junk)); +} + +TEST_F(link_varyings, interface_field_doesnt_match_noninterface) +{ + char *const iface_field_name = interface_field_name(simple_interface); + + /* The input shader has a single input variable name "a.v" + */ + ir_variable *const in_v = + new(mem_ctx) ir_variable(glsl_type::vec(4), + iface_field_name, + ir_var_shader_in); + + ir.push_tail(in_v); + + ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, + &ir, + consumer_inputs, + consumer_interface_inputs, + junk)); + + /* Create an output variable, "v", that is part of an interface block named + * "a". They should not match. + */ + ir_variable *const out_v = + new(mem_ctx) ir_variable(simple_interface->fields.structure[0].type, + simple_interface->fields.structure[0].name, + ir_var_shader_in); + + out_v->init_interface_type(simple_interface); + + ir_variable *const match = + linker::get_matching_input(mem_ctx, + out_v, + consumer_inputs, + consumer_interface_inputs, + junk); + + EXPECT_EQ(NULL, match); +} + +TEST_F(link_varyings, interface_field_doesnt_match_noninterface_vice_versa) +{ + char *const iface_field_name = interface_field_name(simple_interface); + + /* In input shader has a single variable, "v", that is part of an interface + * block named "a". + */ + ir_variable *const in_v = + new(mem_ctx) ir_variable(simple_interface->fields.structure[0].type, + simple_interface->fields.structure[0].name, + ir_var_shader_in); + + in_v->init_interface_type(simple_interface); + + ir.push_tail(in_v); + + ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, + &ir, + consumer_inputs, + consumer_interface_inputs, + junk)); + + /* Create an output variable "a.v". They should not match. + */ + ir_variable *const out_v = + new(mem_ctx) ir_variable(glsl_type::vec(4), + iface_field_name, + ir_var_shader_out); + + ir_variable *const match = + linker::get_matching_input(mem_ctx, + out_v, + consumer_inputs, + consumer_interface_inputs, + junk); + + EXPECT_EQ(NULL, match); +} |