glsl_type: Add get_record_instance method
[mesa.git] / src / glsl / glsl_types.cpp
index ff157080ff6793019d9964110f8cb24c9a18df3a..672a7f7cd17e34006d48245c07c39e79c173f630 100644 (file)
@@ -32,6 +32,38 @@ 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,
+                    unsigned matrix_columns, const char *name) :
+   gl_type(gl_type),
+   base_type(base_type),
+   sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
+   sampler_type(0),
+   vector_elements(vector_elements), matrix_columns(matrix_columns),
+   name(name),
+   length(0)
+{
+   /* Neither dimension is zero or both dimensions are zero.
+    */
+   assert((vector_elements == 0) == (matrix_columns == 0));
+   memset(& fields, 0, sizeof(fields));
+}
+
+glsl_type::glsl_type(GLenum gl_type,
+                    enum glsl_sampler_dim dim, bool shadow, bool array,
+                    unsigned type, const char *name) :
+   gl_type(gl_type),
+   base_type(GLSL_TYPE_SAMPLER),
+   sampler_dimensionality(dim), sampler_shadow(shadow),
+   sampler_array(array), sampler_type(type),
+   vector_elements(0), matrix_columns(0),
+   name(name),
+   length(0)
+{
+   memset(& fields, 0, sizeof(fields));
+}
 
 static void
 add_types_to_symbol_table(glsl_symbol_table *symtab,
@@ -46,8 +78,8 @@ add_types_to_symbol_table(glsl_symbol_table *symtab,
 }
 
 
-static void
-generate_110_types(glsl_symbol_table *symtab)
+void
+glsl_type::generate_110_types(glsl_symbol_table *symtab)
 {
    add_types_to_symbol_table(symtab, builtin_core_types,
                             Elements(builtin_core_types),
@@ -62,8 +94,8 @@ generate_110_types(glsl_symbol_table *symtab)
 }
 
 
-static void
-generate_120_types(glsl_symbol_table *symtab)
+void
+glsl_type::generate_120_types(glsl_symbol_table *symtab)
 {
    generate_110_types(symtab);
 
@@ -72,8 +104,8 @@ generate_120_types(glsl_symbol_table *symtab)
 }
 
 
-static void
-generate_130_types(glsl_symbol_table *symtab)
+void
+glsl_type::generate_130_types(glsl_symbol_table *symtab)
 {
    generate_120_types(symtab);
 
@@ -82,8 +114,9 @@ generate_130_types(glsl_symbol_table *symtab)
 }
 
 
-static void
-generate_ARB_texture_rectangle_types(glsl_symbol_table *symtab, bool warn)
+void
+glsl_type::generate_ARB_texture_rectangle_types(glsl_symbol_table *symtab,
+                                               bool warn)
 {
    add_types_to_symbol_table(symtab, builtin_ARB_texture_rectangle_types,
                             Elements(builtin_ARB_texture_rectangle_types),
@@ -91,8 +124,9 @@ generate_ARB_texture_rectangle_types(glsl_symbol_table *symtab, bool warn)
 }
 
 
-static void
-generate_EXT_texture_array_types(glsl_symbol_table *symtab, bool warn)
+void
+glsl_type::generate_EXT_texture_array_types(glsl_symbol_table *symtab,
+                                           bool warn)
 {
    add_types_to_symbol_table(symtab, builtin_EXT_texture_array_types,
                             Elements(builtin_EXT_texture_array_types),
@@ -105,13 +139,13 @@ _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state)
 {
    switch (state->language_version) {
    case 110:
-      generate_110_types(state->symbols);
+      glsl_type::generate_110_types(state->symbols);
       break;
    case 120:
-      generate_120_types(state->symbols);
+      glsl_type::generate_120_types(state->symbols);
       break;
    case 130:
-      generate_130_types(state->symbols);
+      glsl_type::generate_130_types(state->symbols);
       break;
    default:
       /* error */
@@ -119,13 +153,13 @@ _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state)
    }
 
    if (state->ARB_texture_rectangle_enable) {
-      generate_ARB_texture_rectangle_types(state->symbols,
+      glsl_type::generate_ARB_texture_rectangle_types(state->symbols,
                                           state->ARB_texture_rectangle_warn);
    }
 
    if (state->EXT_texture_array_enable && state->language_version < 130) {
       // These are already included in 130; don't create twice.
-      generate_EXT_texture_array_types(state->symbols,
+      glsl_type::generate_EXT_texture_array_types(state->symbols,
                                       state->EXT_texture_array_warn);
    }
 }
@@ -351,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
 {