summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Romanick <[email protected]>2010-06-28 11:54:57 -0700
committerIan Romanick <[email protected]>2010-06-29 11:15:39 -0700
commit49e3577b91f44013746f7a3db411e7041b7d899e (patch)
treed1a496d1e38b7a26e6bcac0c3eded20101510072
parent31bcce04b1f9c8c5e33370e26a3a9d6e60049aa8 (diff)
glsl_type: Add get_record_instance method
-rw-r--r--src/glsl/ast_to_hir.cpp4
-rw-r--r--src/glsl/glsl_types.cpp72
-rw-r--r--src/glsl/glsl_types.h12
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
*/