diff options
-rw-r--r-- | src/glsl/ast_to_hir.cpp | 4 | ||||
-rw-r--r-- | src/glsl/glsl_types.cpp | 72 | ||||
-rw-r--r-- | src/glsl/glsl_types.h | 12 |
3 files changed, 86 insertions, 2 deletions
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index 54a8e9e00a7..664e4687c4e 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -2383,7 +2383,6 @@ ir_rvalue * ast_struct_specifier::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { - void *ctx = talloc_parent(state); unsigned decl_count = 0; /* Make an initial pass over the list of structure fields to determine how @@ -2446,7 +2445,8 @@ ast_struct_specifier::hir(exec_list *instructions, name = this->name; } - glsl_type *t = new(ctx) glsl_type(fields, decl_count, name); + const glsl_type *t = + glsl_type::get_record_instance(fields, decl_count, name); YYLTYPE loc = this->get_location(); if (!state->symbols->add_type(name, t)) { diff --git a/src/glsl/glsl_types.cpp b/src/glsl/glsl_types.cpp index 158659c71e5..672a7f7cd17 100644 --- a/src/glsl/glsl_types.cpp +++ b/src/glsl/glsl_types.cpp @@ -32,6 +32,7 @@ extern "C" { } hash_table *glsl_type::array_types = NULL; +hash_table *glsl_type::record_types = NULL; glsl_type::glsl_type(GLenum gl_type, unsigned base_type, unsigned vector_elements, @@ -384,6 +385,77 @@ glsl_type::get_array_instance(void *ctx, const glsl_type *base, } +int +glsl_type::record_key_compare(const void *a, const void *b) +{ + const glsl_type *const key1 = (glsl_type *) a; + const glsl_type *const key2 = (glsl_type *) b; + + /* Return zero is the types match (there is zero difference) or non-zero + * otherwise. + */ + if (strcmp(key1->name, key2->name) != 0) + return 1; + + if (key1->length != key2->length) + return 1; + + for (unsigned i = 0; i < key1->length; i++) + /* FINISHME: Is the name of the structure field also significant? */ + if (key1->fields.structure[i].type != key2->fields.structure[i].type) + return 1; + + return 0; +} + + +unsigned +glsl_type::record_key_hash(const void *a) +{ + const glsl_type *const key = (glsl_type *) a; + char hash_key[128]; + unsigned size = 0; + + size = snprintf(hash_key, sizeof(hash_key), "%08x", key->length); + + for (unsigned i = 0; i < key->length; i++) { + if (size >= sizeof(hash_key)) + break; + + size += snprintf(& hash_key[size], sizeof(hash_key) - size, + "%p", key->fields.structure[i].type); + } + + return hash_table_string_hash(& hash_key); +} + + +const glsl_type * +glsl_type::get_record_instance(const glsl_struct_field *fields, + unsigned num_fields, + const char *name) +{ + const glsl_type key(fields, num_fields, name); + + if (record_types == NULL) { + record_types = hash_table_ctor(64, record_key_hash, record_key_compare); + } + + const glsl_type *t = (glsl_type *) hash_table_find(record_types, & key); + if (t == NULL) { + t = new(NULL) glsl_type(fields, num_fields, name); + + hash_table_insert(record_types, (void *) t, t); + } + + assert(t->base_type == GLSL_TYPE_STRUCT); + assert(t->length == num_fields); + assert(strcmp(t->name, name) == 0); + + return t; +} + + const glsl_type * glsl_type::field_type(const char *name) const { diff --git a/src/glsl/glsl_types.h b/src/glsl/glsl_types.h index e1bfd34f4ef..a1c9fae4f9f 100644 --- a/src/glsl/glsl_types.h +++ b/src/glsl/glsl_types.h @@ -206,6 +206,12 @@ struct glsl_type { unsigned elements); /** + * Get the instance of a record type + */ + static const glsl_type *get_record_instance(const glsl_struct_field *fields, + unsigned num_fields, + const char *name); + /** * Generate the constructor for this type and add it to the symbol table */ class ir_function *generate_constructor(class glsl_symbol_table *) const; @@ -407,6 +413,12 @@ private: static int array_key_compare(const void *a, const void *b); static unsigned array_key_hash(const void *key); + /** Hash table containing the known record types. */ + static struct hash_table *record_types; + + static int record_key_compare(const void *a, const void *b); + static unsigned record_key_hash(const void *key); + /** * \name Pointers to various type singletons */ |