nir: Add a function to detect if a block is immediately followed by an if
[mesa.git] / src / glsl / glsl_types.cpp
index e77146cdf0ac68f38903d12e80a91905585083ea..0d2eb7cec0980093fdbabdffcec1e70af818056c 100644 (file)
  */
 
 #include <stdio.h>
-#include <stdlib.h>
-#include "main/core.h" /* for Elements */
-#include "glsl_symbol_table.h"
+#include "main/core.h" /* for Elements, MAX2 */
 #include "glsl_parser_extras.h"
 #include "glsl_types.h"
-extern "C" {
 #include "program/hash_table.h"
-}
 
+
+mtx_t glsl_type::mutex = _MTX_INITIALIZER_NP;
 hash_table *glsl_type::array_types = NULL;
 hash_table *glsl_type::record_types = NULL;
 hash_table *glsl_type::interface_types = NULL;
@@ -55,9 +53,14 @@ glsl_type::glsl_type(GLenum gl_type,
    vector_elements(vector_elements), matrix_columns(matrix_columns),
    length(0)
 {
+   mtx_lock(&glsl_type::mutex);
+
    init_ralloc_type_ctx();
    assert(name != NULL);
    this->name = ralloc_strdup(this->mem_ctx, name);
+
+   mtx_unlock(&glsl_type::mutex);
+
    /* Neither dimension is zero or both dimensions are zero.
     */
    assert((vector_elements == 0) == (matrix_columns == 0));
@@ -73,9 +76,14 @@ glsl_type::glsl_type(GLenum gl_type, glsl_base_type base_type,
    sampler_array(array), sampler_type(type), interface_packing(0),
    length(0)
 {
+   mtx_lock(&glsl_type::mutex);
+
    init_ralloc_type_ctx();
    assert(name != NULL);
    this->name = ralloc_strdup(this->mem_ctx, name);
+
+   mtx_unlock(&glsl_type::mutex);
+
    memset(& fields, 0, sizeof(fields));
 
    if (base_type == GLSL_TYPE_SAMPLER) {
@@ -97,11 +105,14 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
 {
    unsigned int i;
 
+   mtx_lock(&glsl_type::mutex);
+
    init_ralloc_type_ctx();
    assert(name != NULL);
    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,
@@ -110,8 +121,10 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
       this->fields.structure[i].interpolation = fields[i].interpolation;
       this->fields.structure[i].centroid = fields[i].centroid;
       this->fields.structure[i].sample = fields[i].sample;
-      this->fields.structure[i].row_major = fields[i].row_major;
+      this->fields.structure[i].matrix_layout = fields[i].matrix_layout;
    }
+
+   mtx_unlock(&glsl_type::mutex);
 }
 
 glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
@@ -125,6 +138,8 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
 {
    unsigned int i;
 
+   mtx_lock(&glsl_type::mutex);
+
    init_ralloc_type_ctx();
    assert(name != NULL);
    this->name = ralloc_strdup(this->mem_ctx, name);
@@ -138,8 +153,10 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
       this->fields.structure[i].interpolation = fields[i].interpolation;
       this->fields.structure[i].centroid = fields[i].centroid;
       this->fields.structure[i].sample = fields[i].sample;
-      this->fields.structure[i].row_major = fields[i].row_major;
+      this->fields.structure[i].matrix_layout = fields[i].matrix_layout;
    }
+
+   mtx_unlock(&glsl_type::mutex);
 }
 
 
@@ -287,6 +304,8 @@ const glsl_type *glsl_type::get_scalar_type() const
 void
 _mesa_glsl_release_types(void)
 {
+   mtx_lock(&glsl_type::mutex);
+
    if (glsl_type::array_types != NULL) {
       hash_table_dtor(glsl_type::array_types);
       glsl_type::array_types = NULL;
@@ -296,6 +315,8 @@ _mesa_glsl_release_types(void)
       hash_table_dtor(glsl_type::record_types);
       glsl_type::record_types = NULL;
    }
+
+   mtx_unlock(&glsl_type::mutex);
 }
 
 
@@ -304,7 +325,7 @@ glsl_type::glsl_type(const glsl_type *array, unsigned length) :
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
    sampler_type(0), interface_packing(0),
    vector_elements(0), matrix_columns(0),
-   name(NULL), length(length)
+   length(length), name(NULL)
 {
    this->fields.array = array;
    /* Inherit the gl type of the base. The GL type is used for
@@ -318,7 +339,10 @@ glsl_type::glsl_type(const glsl_type *array, unsigned length) :
     * NUL.
     */
    const unsigned name_length = strlen(array->name) + 10 + 3;
+
+   mtx_lock(&glsl_type::mutex);
    char *const n = (char *) ralloc_size(this->mem_ctx, name_length);
+   mtx_unlock(&glsl_type::mutex);
 
    if (length == 0)
       snprintf(n, name_length, "%s[]", array->name);
@@ -454,12 +478,6 @@ 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
@@ -468,9 +486,19 @@ glsl_type::get_array_instance(const glsl_type *base, unsigned array_size)
    char key[128];
    snprintf(key, sizeof(key), "%p[%u]", (void *) base, array_size);
 
+   mtx_lock(&glsl_type::mutex);
+
+   if (array_types == NULL) {
+      array_types = hash_table_ctor(64, hash_table_string_hash,
+                                   hash_table_string_compare);
+   }
+
    const glsl_type *t = (glsl_type *) hash_table_find(array_types, key);
+
    if (t == NULL) {
+      mtx_unlock(&glsl_type::mutex);
       t = new glsl_type(base, array_size);
+      mtx_lock(&glsl_type::mutex);
 
       hash_table_insert(array_types, (void *) t, ralloc_strdup(mem_ctx, key));
    }
@@ -479,6 +507,8 @@ glsl_type::get_array_instance(const glsl_type *base, unsigned array_size)
    assert(t->length == array_size);
    assert(t->fields.array == base);
 
+   mtx_unlock(&glsl_type::mutex);
+
    return t;
 }
 
@@ -492,14 +522,28 @@ glsl_type::record_compare(const glsl_type *b) const
    if (this->interface_packing != b->interface_packing)
       return false;
 
+   /* From the GLSL 4.20 specification (Sec 4.2):
+    *
+    *     "Structures must have the same name, sequence of type names, and
+    *     type definitions, and field names to be considered the same type."
+    *
+    * GLSL ES behaves the same (Ver 1.00 Sec 4.2.4, Ver 3.00 Sec 4.2.5).
+    *
+    * Note that we cannot force type name check when comparing unnamed
+    * structure types, these have a unique name assigned during parsing.
+    */
+   if (!this->is_anonymous() && !b->is_anonymous())
+      if (strcmp(this->name, b->name) != 0)
+         return false;
+
    for (unsigned i = 0; i < this->length; i++) {
       if (this->fields.structure[i].type != b->fields.structure[i].type)
         return false;
       if (strcmp(this->fields.structure[i].name,
                 b->fields.structure[i].name) != 0)
         return false;
-      if (this->fields.structure[i].row_major
-         != b->fields.structure[i].row_major)
+      if (this->fields.structure[i].matrix_layout
+         != b->fields.structure[i].matrix_layout)
         return false;
       if (this->fields.structure[i].location
           != b->fields.structure[i].location)
@@ -563,13 +607,17 @@ glsl_type::get_record_instance(const glsl_struct_field *fields,
 {
    const glsl_type key(fields, num_fields, name);
 
+   mtx_lock(&glsl_type::mutex);
+
    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) {
+      mtx_unlock(&glsl_type::mutex);
       t = new glsl_type(fields, num_fields, name);
+      mtx_lock(&glsl_type::mutex);
 
       hash_table_insert(record_types, (void *) t, t);
    }
@@ -578,6 +626,8 @@ glsl_type::get_record_instance(const glsl_struct_field *fields,
    assert(t->length == num_fields);
    assert(strcmp(t->name, name) == 0);
 
+   mtx_unlock(&glsl_type::mutex);
+
    return t;
 }
 
@@ -590,13 +640,17 @@ glsl_type::get_interface_instance(const glsl_struct_field *fields,
 {
    const glsl_type key(fields, num_fields, packing, block_name);
 
+   mtx_lock(&glsl_type::mutex);
+
    if (interface_types == NULL) {
       interface_types = hash_table_ctor(64, record_key_hash, record_key_compare);
    }
 
    const glsl_type *t = (glsl_type *) hash_table_find(interface_types, & key);
    if (t == NULL) {
+      mtx_unlock(&glsl_type::mutex);
       t = new glsl_type(fields, num_fields, packing, block_name);
+      mtx_lock(&glsl_type::mutex);
 
       hash_table_insert(interface_types, (void *) t, t);
    }
@@ -605,6 +659,8 @@ glsl_type::get_interface_instance(const glsl_struct_field *fields,
    assert(t->length == num_fields);
    assert(strcmp(t->name, block_name) == 0);
 
+   mtx_unlock(&glsl_type::mutex);
+
    return t;
 }
 
@@ -677,6 +733,32 @@ glsl_type::component_slots() const
    return 0;
 }
 
+unsigned
+glsl_type::uniform_locations() const
+{
+   unsigned size = 0;
+
+   switch (this->base_type) {
+   case GLSL_TYPE_UINT:
+   case GLSL_TYPE_INT:
+   case GLSL_TYPE_FLOAT:
+   case GLSL_TYPE_BOOL:
+   case GLSL_TYPE_SAMPLER:
+   case GLSL_TYPE_IMAGE:
+      return 1;
+
+   case GLSL_TYPE_STRUCT:
+   case GLSL_TYPE_INTERFACE:
+      for (unsigned i = 0; i < this->length; i++)
+         size += this->fields.structure[i].type->uniform_locations();
+      return size;
+   case GLSL_TYPE_ARRAY:
+      return this->length * this->fields.array->uniform_locations();
+   default:
+      return 0;
+   }
+}
+
 bool
 glsl_type::can_implicitly_convert_to(const glsl_type *desired,
                                      _mesa_glsl_parse_state *state) const
@@ -802,9 +884,18 @@ glsl_type::std140_base_alignment(bool row_major) const
    if (this->is_record()) {
       unsigned base_alignment = 16;
       for (unsigned i = 0; i < this->length; i++) {
+         bool field_row_major = row_major;
+         const enum glsl_matrix_layout matrix_layout =
+            glsl_matrix_layout(this->fields.structure[i].matrix_layout);
+         if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) {
+            field_row_major = true;
+         } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) {
+            field_row_major = false;
+         }
+
         const struct glsl_type *field_type = this->fields.structure[i].type;
         base_alignment = MAX2(base_alignment,
-                              field_type->std140_base_alignment(row_major));
+                              field_type->std140_base_alignment(field_row_major));
       }
       return base_alignment;
    }
@@ -848,8 +939,7 @@ glsl_type::std140_size(bool row_major) const
     *     and <R> rows, the matrix is stored identically to a row of <S>*<R>
     *     row vectors with <C> components each, according to rule (4).
     */
-   if (this->is_matrix() || (this->is_array() &&
-                            this->fields.array->is_matrix())) {
+   if (this->without_array()->is_matrix()) {
       const struct glsl_type *element_type;
       const struct glsl_type *vec_type;
       unsigned int array_len;
@@ -911,14 +1001,29 @@ glsl_type::std140_size(bool row_major) const
     */
    if (this->is_record()) {
       unsigned size = 0;
+      unsigned max_align = 0;
+
       for (unsigned i = 0; i < this->length; i++) {
+         bool field_row_major = row_major;
+         const enum glsl_matrix_layout matrix_layout =
+            glsl_matrix_layout(this->fields.structure[i].matrix_layout);
+         if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) {
+            field_row_major = true;
+         } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) {
+            field_row_major = false;
+         }
+
         const struct glsl_type *field_type = this->fields.structure[i].type;
-        unsigned align = field_type->std140_base_alignment(row_major);
+        unsigned align = field_type->std140_base_alignment(field_row_major);
         size = glsl_align(size, align);
-        size += field_type->std140_size(row_major);
+        size += field_type->std140_size(field_row_major);
+
+         max_align = MAX2(align, max_align);
+
+         if (field_type->is_record() && (i + 1 < this->length))
+            size = glsl_align(size, 16);
       }
-      size = glsl_align(size,
-                       this->fields.structure[0].type->std140_base_alignment(row_major));
+      size = glsl_align(size, MAX2(max_align, 16));
       return size;
    }