glsl: Move type_contains_sampler() into glsl_type for later reuse.
[mesa.git] / src / glsl / glsl_types.cpp
index ff157080ff6793019d9964110f8cb24c9a18df3a..a5e21bbb96c06ef319c1c12d6b220b790c71b8c9 100644 (file)
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include <cstdio>
+#include <stdio.h>
 #include <stdlib.h>
+#include "main/core.h" /* for Elements */
 #include "glsl_symbol_table.h"
 #include "glsl_parser_extras.h"
 #include "glsl_types.h"
 #include "builtin_types.h"
 extern "C" {
-#include "hash_table.h"
+#include "program/hash_table.h"
 }
 
 hash_table *glsl_type::array_types = NULL;
+hash_table *glsl_type::record_types = NULL;
+void *glsl_type::mem_ctx = NULL;
+
+void
+glsl_type::init_ralloc_type_ctx(void)
+{
+   if (glsl_type::mem_ctx == NULL) {
+      glsl_type::mem_ctx = ralloc_autofree_context();
+      assert(glsl_type::mem_ctx != NULL);
+   }
+}
+
+glsl_type::glsl_type(GLenum gl_type,
+                    glsl_base_type 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),
+   length(0)
+{
+   init_ralloc_type_ctx();
+   this->name = ralloc_strdup(this->mem_ctx, name);
+   /* 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),
+   length(0)
+{
+   init_ralloc_type_ctx();
+   this->name = ralloc_strdup(this->mem_ctx, name);
+   memset(& fields, 0, sizeof(fields));
+}
+
+glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
+                    const char *name) :
+   base_type(GLSL_TYPE_STRUCT),
+   sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
+   sampler_type(0),
+   vector_elements(0), matrix_columns(0),
+   length(num_fields)
+{
+   unsigned int i;
+
+   init_ralloc_type_ctx();
+   this->name = ralloc_strdup(this->mem_ctx, name);
+   this->fields.structure = ralloc_array(this->mem_ctx,
+                                        glsl_struct_field, length);
+   for (i = 0; i < length; i++) {
+      this->fields.structure[i].type = fields[i].type;
+      this->fields.structure[i].name = ralloc_strdup(this->fields.structure,
+                                                    fields[i].name);
+   }
+}
 
 static void
 add_types_to_symbol_table(glsl_symbol_table *symtab,
@@ -45,9 +111,24 @@ add_types_to_symbol_table(glsl_symbol_table *symtab,
    }
 }
 
+bool
+glsl_type::contains_sampler() const
+{
+   if (this->is_array()) {
+      return this->fields.array->contains_sampler();
+   } else if (this->is_record()) {
+      for (unsigned int i = 0; i < this->length; i++) {
+        if (this->fields.structure[i].type->contains_sampler())
+           return true;
+      }
+      return false;
+   } else {
+      return this->is_sampler();
+   }
+}
 
-static void
-generate_110_types(glsl_symbol_table *symtab)
+void
+glsl_type::generate_100ES_types(glsl_symbol_table *symtab)
 {
    add_types_to_symbol_table(symtab, builtin_core_types,
                             Elements(builtin_core_types),
@@ -55,15 +136,26 @@ generate_110_types(glsl_symbol_table *symtab)
    add_types_to_symbol_table(symtab, builtin_structure_types,
                             Elements(builtin_structure_types),
                             false);
+   add_types_to_symbol_table(symtab, void_type, 1, false);
+}
+
+void
+glsl_type::generate_110_types(glsl_symbol_table *symtab)
+{
+   generate_100ES_types(symtab);
+
+   add_types_to_symbol_table(symtab, builtin_110_types,
+                            Elements(builtin_110_types),
+                            false);
+   add_types_to_symbol_table(symtab, &_sampler3D_type, 1, false);
    add_types_to_symbol_table(symtab, builtin_110_deprecated_structure_types,
                             Elements(builtin_110_deprecated_structure_types),
                             false);
-   add_types_to_symbol_table(symtab, & void_type, 1, false);
 }
 
 
-static void
-generate_120_types(glsl_symbol_table *symtab)
+void
+glsl_type::generate_120_types(glsl_symbol_table *symtab)
 {
    generate_110_types(symtab);
 
@@ -72,18 +164,20 @@ 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);
 
    add_types_to_symbol_table(symtab, builtin_130_types,
                             Elements(builtin_130_types), false);
+   generate_EXT_texture_array_types(symtab, false);
 }
 
 
-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 +185,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),
@@ -100,18 +195,29 @@ generate_EXT_texture_array_types(glsl_symbol_table *symtab, bool warn)
 }
 
 
+void
+glsl_type::generate_OES_texture_3D_types(glsl_symbol_table *symtab, bool warn)
+{
+   add_types_to_symbol_table(symtab, &_sampler3D_type, 1, warn);
+}
+
+
 void
 _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state)
 {
    switch (state->language_version) {
+   case 100:
+      assert(state->es_shader);
+      glsl_type::generate_100ES_types(state->symbols);
+      break;
    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 +225,17 @@ _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->OES_texture_3D_enable && state->language_version == 100) {
+      glsl_type::generate_OES_texture_3D_types(state->symbols,
+                                              state->OES_texture_3D_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);
    }
 }
@@ -148,69 +258,22 @@ const glsl_type *glsl_type::get_base_type() const
 }
 
 
-ir_function *
-glsl_type::generate_constructor(glsl_symbol_table *symtab) const
+void
+_mesa_glsl_release_types(void)
 {
-   void *ctx = symtab;
-
-   /* Generate the function name and add it to the symbol table.
-    */
-   ir_function *const f = new(ctx) ir_function(name);
-
-   bool added = symtab->add_function(name, f);
-   assert(added);
-
-   ir_function_signature *const sig = new(ctx) ir_function_signature(this);
-   f->add_signature(sig);
-
-   ir_variable **declarations =
-      (ir_variable **) malloc(sizeof(ir_variable *) * this->length);
-   for (unsigned i = 0; i < length; i++) {
-      char *const param_name = (char *) malloc(10);
-
-      snprintf(param_name, 10, "p%08X", i);
-
-      ir_variable *var = (this->base_type == GLSL_TYPE_ARRAY)
-        ? new(ctx) ir_variable(fields.array, param_name)
-        : new(ctx) ir_variable(fields.structure[i].type, param_name);
-
-      var->mode = ir_var_in;
-      declarations[i] = var;
-      sig->parameters.push_tail(var);
+   if (glsl_type::array_types != NULL) {
+      hash_table_dtor(glsl_type::array_types);
+      glsl_type::array_types = NULL;
    }
 
-   /* Generate the body of the constructor.  The body assigns each of the
-    * parameters to a portion of a local variable called __retval that has
-    * the same type as the constructor.  After initializing __retval,
-    * __retval is returned.
-    */
-   ir_variable *retval = new(ctx) ir_variable(this, "__retval");
-   sig->body.push_tail(retval);
-
-   for (unsigned i = 0; i < length; i++) {
-      ir_dereference *const lhs = (this->base_type == GLSL_TYPE_ARRAY)
-        ? (ir_dereference *) new(ctx) ir_dereference_array(retval,
-                                                           new(ctx) ir_constant(i))
-        : (ir_dereference *) new(ctx) ir_dereference_record(retval,
-                                                            fields.structure[i].name);
-
-      ir_dereference *const rhs = new(ctx) ir_dereference_variable(declarations[i]);
-      ir_instruction *const assign = new(ctx) ir_assignment(lhs, rhs, NULL);
-
-      sig->body.push_tail(assign);
+   if (glsl_type::record_types != NULL) {
+      hash_table_dtor(glsl_type::record_types);
+      glsl_type::record_types = NULL;
    }
-
-   free(declarations);
-
-   ir_dereference *const retref = new(ctx) ir_dereference_variable(retval);
-   ir_instruction *const inst = new(ctx) ir_return(retref);
-   sig->body.push_tail(inst);
-
-   return f;
 }
 
 
-glsl_type::glsl_type(void *ctx, const glsl_type *array, unsigned length) :
+glsl_type::glsl_type(const glsl_type *array, unsigned length) :
    base_type(GLSL_TYPE_ARRAY),
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
    sampler_type(0),
@@ -218,13 +281,18 @@ glsl_type::glsl_type(void *ctx, const glsl_type *array, unsigned length) :
    name(NULL), length(length)
 {
    this->fields.array = array;
+   /* Inherit the gl type of the base. The GL type is used for
+    * uniform/statevar handling in Mesa and the arrayness of the type
+    * is represented by the size rather than the type.
+    */
+   this->gl_type = array->gl_type;
 
    /* Allow a maximum of 10 characters for the array size.  This is enough
     * for 32-bits of ~0.  The extra 3 are for the '[', ']', and terminating
     * NUL.
     */
    const unsigned name_length = strlen(array->name) + 10 + 3;
-   char *const n = (char *) talloc_size(ctx, name_length);
+   char *const n = (char *) ralloc_size(this->mem_ctx, name_length);
 
    if (length == 0)
       snprintf(n, name_length, "%s[]", array->name);
@@ -239,7 +307,7 @@ const glsl_type *
 glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns)
 {
    if (base_type == GLSL_TYPE_VOID)
-      return &void_type;
+      return void_type;
 
    if ((rows < 1) || (rows > 4) || (columns < 1) || (columns > 4))
       return error_type;
@@ -293,8 +361,40 @@ glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns)
 }
 
 
+const glsl_type *
+glsl_type::get_array_instance(const glsl_type *base, unsigned array_size)
+{
+
+   if (array_types == NULL) {
+      array_types = hash_table_ctor(64, hash_table_string_hash,
+                                   hash_table_string_compare);
+   }
+
+   /* Generate a name using the base type pointer in the key.  This is
+    * done because the name of the base type may not be unique across
+    * shaders.  For example, two shaders may have different record types
+    * named 'foo'.
+    */
+   char key[128];
+   snprintf(key, sizeof(key), "%p[%u]", (void *) base, array_size);
+
+   const glsl_type *t = (glsl_type *) hash_table_find(array_types, key);
+   if (t == NULL) {
+      t = new glsl_type(base, array_size);
+
+      hash_table_insert(array_types, (void *) t, ralloc_strdup(mem_ctx, key));
+   }
+
+   assert(t->base_type == GLSL_TYPE_ARRAY);
+   assert(t->length == array_size);
+   assert(t->fields.array == base);
+
+   return t;
+}
+
+
 int
-glsl_type::array_key_compare(const void *a, const void *b)
+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;
@@ -302,50 +402,66 @@ glsl_type::array_key_compare(const void *a, const void *b)
    /* Return zero is the types match (there is zero difference) or non-zero
     * otherwise.
     */
-   return ((key1->fields.array == key2->fields.array)
-          && (key1->length == key2->length)) ? 0 : 1;
+   if (strcmp(key1->name, key2->name) != 0)
+      return 1;
+
+   if (key1->length != key2->length)
+      return 1;
+
+   for (unsigned i = 0; i < key1->length; i++) {
+      if (key1->fields.structure[i].type != key2->fields.structure[i].type)
+        return 1;
+      if (strcmp(key1->fields.structure[i].name,
+                key2->fields.structure[i].name) != 0)
+        return 1;
+   }
+
+   return 0;
 }
 
 
 unsigned
-glsl_type::array_key_hash(const void *a)
+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);
 
-   const struct {
-      const glsl_type *t;
-      unsigned l;
-      char nul;
-   } hash_key = {
-      key->fields.array,
-      key->length,
-      '\0'
-   };
+   for (unsigned i = 0; i < key->length; i++) {
+      if (size >= sizeof(hash_key))
+        break;
+
+      size += snprintf(& hash_key[size], sizeof(hash_key) - size,
+                      "%p", (void *) key->fields.structure[i].type);
+   }
 
    return hash_table_string_hash(& hash_key);
 }
 
 
 const glsl_type *
-glsl_type::get_array_instance(void *ctx, const glsl_type *base,
-                             unsigned array_size)
+glsl_type::get_record_instance(const glsl_struct_field *fields,
+                              unsigned num_fields,
+                              const char *name)
 {
-   const glsl_type key(ctx, base, array_size);
+   const glsl_type key(fields, num_fields, name);
 
-   if (array_types == NULL) {
-      array_types = hash_table_ctor(64, array_key_hash, array_key_compare);
+   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(array_types, & key);
+   const glsl_type *t = (glsl_type *) hash_table_find(record_types, & key);
    if (t == NULL) {
-      t = new(ctx) glsl_type(ctx, base, array_size);
+      t = new glsl_type(fields, num_fields, name);
 
-      hash_table_insert(array_types, (void *) t, t);
+      hash_table_insert(record_types, (void *) t, t);
    }
 
-   assert(t->base_type == GLSL_TYPE_ARRAY);
-   assert(t->length == array_size);
-   assert(t->fields.array == base);
+   assert(t->base_type == GLSL_TYPE_STRUCT);
+   assert(t->length == num_fields);
+   assert(strcmp(t->name, name) == 0);
 
    return t;
 }