glsl_type: Add get_record_instance method
authorIan Romanick <ian.d.romanick@intel.com>
Mon, 28 Jun 2010 18:54:57 +0000 (11:54 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Tue, 29 Jun 2010 18:15:39 +0000 (11:15 -0700)
src/glsl/ast_to_hir.cpp
src/glsl/glsl_types.cpp
src/glsl/glsl_types.h

index 54a8e9e..664e468 100644 (file)
@@ -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)) {
index 158659c..672a7f7 100644 (file)
@@ -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
 {
index e1bfd34..a1c9fae 100644 (file)
@@ -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
     */