Merge ../mesa into vulkan
[mesa.git] / src / glsl / glsl_types.cpp
index 435b86673306e580af767155f1fd6fa0ab5142ef..9ef2fbf2525c38b2b735e4a41dbbeb8075112fe7 100644 (file)
 #include "main/core.h" /* for Elements, MAX2 */
 #include "glsl_parser_extras.h"
 #include "glsl_types.h"
-extern "C" {
-#include "program/hash_table.h"
-}
+#include "util/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;
+hash_table *glsl_type::function_types = NULL;
+hash_table *glsl_type::subroutine_types = NULL;
 void *glsl_type::mem_ctx = NULL;
 
 void
@@ -44,8 +46,8 @@ glsl_type::init_ralloc_type_ctx(void)
 }
 
 glsl_type::glsl_type(GLenum gl_type,
-                    glsl_base_type base_type, unsigned vector_elements,
-                    unsigned matrix_columns, const char *name) :
+                     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),
@@ -53,9 +55,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));
@@ -63,17 +70,22 @@ glsl_type::glsl_type(GLenum gl_type,
 }
 
 glsl_type::glsl_type(GLenum gl_type, glsl_base_type base_type,
-                    enum glsl_sampler_dim dim, bool shadow, bool array,
-                    unsigned type, const char *name) :
+                     enum glsl_sampler_dim dim, bool shadow, bool array,
+                     unsigned type, const char *name) :
    gl_type(gl_type),
    base_type(base_type),
    sampler_dimensionality(dim), sampler_shadow(shadow),
    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) {
@@ -85,7 +97,7 @@ glsl_type::glsl_type(GLenum gl_type, glsl_base_type base_type,
 }
 
 glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
-                    const char *name) :
+                     const char *name) :
    gl_type(0),
    base_type(GLSL_TYPE_STRUCT),
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
@@ -95,25 +107,36 @@ 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);
+                                         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);
+                                                     fields[i].name);
       this->fields.structure[i].location = fields[i].location;
       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].matrix_layout = fields[i].matrix_layout;
+      this->fields.structure[i].patch = fields[i].patch;
+      this->fields.structure[i].image_read_only = fields[i].image_read_only;
+      this->fields.structure[i].image_write_only = fields[i].image_write_only;
+      this->fields.structure[i].image_coherent = fields[i].image_coherent;
+      this->fields.structure[i].image_volatile = fields[i].image_volatile;
+      this->fields.structure[i].image_restrict = fields[i].image_restrict;
    }
+
+   mtx_unlock(&glsl_type::mutex);
 }
 
 glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
-                    enum glsl_interface_packing packing, const char *name) :
+                     enum glsl_interface_packing packing, const char *name) :
    gl_type(0),
    base_type(GLSL_TYPE_INTERFACE),
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
@@ -123,23 +146,76 @@ 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);
+                                         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);
+                                                     fields[i].name);
       this->fields.structure[i].location = fields[i].location;
       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].matrix_layout = fields[i].matrix_layout;
+      this->fields.structure[i].patch = fields[i].patch;
+   }
+
+   mtx_unlock(&glsl_type::mutex);
+}
+
+glsl_type::glsl_type(const glsl_type *return_type,
+                     const glsl_function_param *params, unsigned num_params) :
+   gl_type(0),
+   base_type(GLSL_TYPE_FUNCTION),
+   sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
+   sampler_type(0), interface_packing(0),
+   vector_elements(0), matrix_columns(0),
+   length(num_params)
+{
+   unsigned int i;
+
+   mtx_lock(&glsl_type::mutex);
+
+   init_ralloc_type_ctx();
+
+   this->fields.parameters = rzalloc_array(this->mem_ctx,
+                                           glsl_function_param, num_params + 1);
+
+   /* We store the return type as the first parameter */
+   this->fields.parameters[0].type = return_type;
+   this->fields.parameters[0].in = false;
+   this->fields.parameters[0].out = true;
+
+   /* We store the i'th parameter in slot i+1 */
+   for (i = 0; i < length; i++) {
+      this->fields.parameters[i + 1].type = params[i].type;
+      this->fields.parameters[i + 1].in = params[i].in;
+      this->fields.parameters[i + 1].out = params[i].out;
    }
+
+   mtx_unlock(&glsl_type::mutex);
 }
 
+glsl_type::glsl_type(const char *subroutine_name) :
+   gl_type(0),
+   base_type(GLSL_TYPE_SUBROUTINE),
+   sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
+   sampler_type(0), interface_packing(0),
+   vector_elements(1), matrix_columns(1),
+   length(0)
+{
+   mtx_lock(&glsl_type::mutex);
+
+   init_ralloc_type_ctx();
+   assert(subroutine_name != NULL);
+   this->name = ralloc_strdup(this->mem_ctx, subroutine_name);
+   mtx_unlock(&glsl_type::mutex);
+}
 
 bool
 glsl_type::contains_sampler() const
@@ -148,8 +224,8 @@ glsl_type::contains_sampler() const
       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;
+         if (this->fields.structure[i].type->contains_sampler())
+            return true;
       }
       return false;
    } else {
@@ -165,8 +241,8 @@ glsl_type::contains_integer() const
       return this->fields.array->contains_integer();
    } else if (this->is_record()) {
       for (unsigned int i = 0; i < this->length; i++) {
-        if (this->fields.structure[i].type->contains_integer())
-           return true;
+         if (this->fields.structure[i].type->contains_integer())
+            return true;
       }
       return false;
    } else {
@@ -174,6 +250,22 @@ glsl_type::contains_integer() const
    }
 }
 
+bool
+glsl_type::contains_double() const
+{
+   if (this->is_array()) {
+      return this->fields.array->contains_double();
+   } else if (this->is_record()) {
+      for (unsigned int i = 0; i < this->length; i++) {
+         if (this->fields.structure[i].type->contains_double())
+            return true;
+      }
+      return false;
+   } else {
+      return this->is_double();
+   }
+}
+
 bool
 glsl_type::contains_opaque() const {
    switch (base_type) {
@@ -182,7 +274,7 @@ glsl_type::contains_opaque() const {
    case GLSL_TYPE_ATOMIC_UINT:
       return true;
    case GLSL_TYPE_ARRAY:
-      return element_type()->contains_opaque();
+      return fields.array->contains_opaque();
    case GLSL_TYPE_STRUCT:
       for (unsigned int i = 0; i < length; i++) {
          if (fields.structure[i].type->contains_opaque())
@@ -194,6 +286,22 @@ glsl_type::contains_opaque() const {
    }
 }
 
+bool
+glsl_type::contains_subroutine() const
+{
+   if (this->is_array()) {
+      return this->fields.array->contains_subroutine();
+   } else if (this->is_record()) {
+      for (unsigned int i = 0; i < this->length; i++) {
+         if (this->fields.structure[i].type->contains_subroutine())
+            return true;
+      }
+      return false;
+   } else {
+      return this->is_subroutine();
+   }
+}
+
 gl_texture_index
 glsl_type::sampler_index() const
 {
@@ -231,8 +339,8 @@ glsl_type::contains_image() const
       return this->fields.array->contains_image();
    } else if (this->is_record()) {
       for (unsigned int i = 0; i < this->length; i++) {
-        if (this->fields.structure[i].type->contains_image())
-           return true;
+         if (this->fields.structure[i].type->contains_image())
+            return true;
       }
       return false;
    } else {
@@ -249,6 +357,8 @@ const glsl_type *glsl_type::get_base_type() const
       return int_type;
    case GLSL_TYPE_FLOAT:
       return float_type;
+   case GLSL_TYPE_DOUBLE:
+      return double_type;
    case GLSL_TYPE_BOOL:
       return bool_type;
    default:
@@ -273,6 +383,8 @@ const glsl_type *glsl_type::get_scalar_type() const
       return int_type;
    case GLSL_TYPE_FLOAT:
       return float_type;
+   case GLSL_TYPE_DOUBLE:
+      return double_type;
    case GLSL_TYPE_BOOL:
       return bool_type;
    default:
@@ -285,15 +397,24 @@ const glsl_type *glsl_type::get_scalar_type() const
 void
 _mesa_glsl_release_types(void)
 {
+   /* Should only be called during atexit (either when unloading shared
+    * object, or if process terminates), so no mutex-locking should be
+    * necessary.
+    */
    if (glsl_type::array_types != NULL) {
-      hash_table_dtor(glsl_type::array_types);
+      _mesa_hash_table_destroy(glsl_type::array_types, NULL);
       glsl_type::array_types = NULL;
    }
 
    if (glsl_type::record_types != NULL) {
-      hash_table_dtor(glsl_type::record_types);
+      _mesa_hash_table_destroy(glsl_type::record_types, NULL);
       glsl_type::record_types = NULL;
    }
+
+   if (glsl_type::interface_types != NULL) {
+      _mesa_hash_table_destroy(glsl_type::interface_types, NULL);
+      glsl_type::interface_types = NULL;
+   }
 }
 
 
@@ -302,7 +423,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
@@ -316,7 +437,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);
@@ -351,6 +475,17 @@ glsl_type::vec(unsigned components)
    return ts[components - 1];
 }
 
+const glsl_type *
+glsl_type::dvec(unsigned components)
+{
+   if (components == 0 || components > 4)
+      return error_type;
+
+   static const glsl_type *const ts[] = {
+      double_type, dvec2_type, dvec3_type, dvec4_type
+   };
+   return ts[components - 1];
+}
 
 const glsl_type *
 glsl_type::ivec(unsigned components)
@@ -405,19 +540,21 @@ glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns)
    if (columns == 1) {
       switch (base_type) {
       case GLSL_TYPE_UINT:
-        return uvec(rows);
+         return uvec(rows);
       case GLSL_TYPE_INT:
-        return ivec(rows);
+         return ivec(rows);
       case GLSL_TYPE_FLOAT:
-        return vec(rows);
+         return vec(rows);
+      case GLSL_TYPE_DOUBLE:
+         return dvec(rows);
       case GLSL_TYPE_BOOL:
-        return bvec(rows);
+         return bvec(rows);
       default:
-        return error_type;
+         return error_type;
       }
    } else {
-      if ((base_type != GLSL_TYPE_FLOAT) || (rows == 1))
-        return error_type;
+      if ((base_type != GLSL_TYPE_FLOAT && base_type != GLSL_TYPE_DOUBLE) || (rows == 1))
+         return error_type;
 
       /* GLSL matrix types are named mat{COLUMNS}x{ROWS}.  Only the following
        * combinations are valid:
@@ -430,17 +567,32 @@ glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns)
        */
 #define IDX(c,r) (((c-1)*3) + (r-1))
 
-      switch (IDX(columns, rows)) {
-      case IDX(2,2): return mat2_type;
-      case IDX(2,3): return mat2x3_type;
-      case IDX(2,4): return mat2x4_type;
-      case IDX(3,2): return mat3x2_type;
-      case IDX(3,3): return mat3_type;
-      case IDX(3,4): return mat3x4_type;
-      case IDX(4,2): return mat4x2_type;
-      case IDX(4,3): return mat4x3_type;
-      case IDX(4,4): return mat4_type;
-      default: return error_type;
+      if (base_type == GLSL_TYPE_DOUBLE) {
+         switch (IDX(columns, rows)) {
+         case IDX(2,2): return dmat2_type;
+         case IDX(2,3): return dmat2x3_type;
+         case IDX(2,4): return dmat2x4_type;
+         case IDX(3,2): return dmat3x2_type;
+         case IDX(3,3): return dmat3_type;
+         case IDX(3,4): return dmat3x4_type;
+         case IDX(4,2): return dmat4x2_type;
+         case IDX(4,3): return dmat4x3_type;
+         case IDX(4,4): return dmat4_type;
+         default: return error_type;
+         }
+      } else {
+         switch (IDX(columns, rows)) {
+         case IDX(2,2): return mat2_type;
+         case IDX(2,3): return mat2x3_type;
+         case IDX(2,4): return mat2x4_type;
+         case IDX(3,2): return mat3x2_type;
+         case IDX(3,3): return mat3_type;
+         case IDX(3,4): return mat3x4_type;
+         case IDX(4,2): return mat4x2_type;
+         case IDX(4,3): return mat4x3_type;
+         case IDX(4,4): return mat4_type;
+         default: return error_type;
+         }
       }
    }
 
@@ -448,16 +600,121 @@ glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns)
    return error_type;
 }
 
-
 const glsl_type *
-glsl_type::get_array_instance(const glsl_type *base, unsigned array_size)
+glsl_type::get_sampler_instance(enum glsl_sampler_dim dim,
+                                bool shadow,
+                                bool array,
+                                glsl_base_type type)
 {
-
-   if (array_types == NULL) {
-      array_types = hash_table_ctor(64, hash_table_string_hash,
-                                   hash_table_string_compare);
+   switch (type) {
+   case GLSL_TYPE_FLOAT:
+      switch (dim) {
+      case GLSL_SAMPLER_DIM_1D:
+         if (shadow)
+            return (array ? sampler1DArrayShadow_type : sampler1DShadow_type);
+         else
+            return (array ? sampler1DArray_type : sampler1D_type);
+      case GLSL_SAMPLER_DIM_2D:
+         if (shadow)
+            return (array ? sampler2DArrayShadow_type : sampler2DShadow_type);
+         else
+            return (array ? sampler2DArray_type : sampler2D_type);
+      case GLSL_SAMPLER_DIM_3D:
+         if (shadow || array)
+            return error_type;
+         else
+            return sampler3D_type;
+      case GLSL_SAMPLER_DIM_CUBE:
+         if (shadow)
+            return (array ? samplerCubeArrayShadow_type : samplerCubeShadow_type);
+         else
+            return (array ? samplerCubeArray_type : samplerCube_type);
+      case GLSL_SAMPLER_DIM_RECT:
+         if (array)
+            return error_type;
+         if (shadow)
+            return sampler2DRectShadow_type;
+         else
+            return sampler2DRect_type;
+      case GLSL_SAMPLER_DIM_BUF:
+         if (shadow || array)
+            return error_type;
+         else
+            return samplerBuffer_type;
+      case GLSL_SAMPLER_DIM_MS:
+         if (shadow)
+            return error_type;
+         return (array ? sampler2DMSArray_type : sampler2DMS_type);
+      case GLSL_SAMPLER_DIM_EXTERNAL:
+         if (shadow || array)
+            return error_type;
+         else
+            return samplerExternalOES_type;
+      }
+   case GLSL_TYPE_INT:
+      if (shadow)
+         return error_type;
+      switch (dim) {
+      case GLSL_SAMPLER_DIM_1D:
+         return (array ? isampler1DArray_type : isampler1D_type);
+      case GLSL_SAMPLER_DIM_2D:
+         return (array ? isampler2DArray_type : isampler2D_type);
+      case GLSL_SAMPLER_DIM_3D:
+         if (array)
+            return error_type;
+         return isampler3D_type;
+      case GLSL_SAMPLER_DIM_CUBE:
+         return (array ? isamplerCubeArray_type : isamplerCube_type);
+      case GLSL_SAMPLER_DIM_RECT:
+         if (array)
+            return error_type;
+         return isampler2DRect_type;
+      case GLSL_SAMPLER_DIM_BUF:
+         if (array)
+            return error_type;
+         return isamplerBuffer_type;
+      case GLSL_SAMPLER_DIM_MS:
+         return (array ? isampler2DMSArray_type : isampler2DMS_type);
+      case GLSL_SAMPLER_DIM_EXTERNAL:
+         return error_type;
+      }
+   case GLSL_TYPE_UINT:
+      if (shadow)
+         return error_type;
+      switch (dim) {
+      case GLSL_SAMPLER_DIM_1D:
+         return (array ? usampler1DArray_type : usampler1D_type);
+      case GLSL_SAMPLER_DIM_2D:
+         return (array ? usampler2DArray_type : usampler2D_type);
+      case GLSL_SAMPLER_DIM_3D:
+         if (array)
+            return error_type;
+         return usampler3D_type;
+      case GLSL_SAMPLER_DIM_CUBE:
+         return (array ? usamplerCubeArray_type : usamplerCube_type);
+      case GLSL_SAMPLER_DIM_RECT:
+         if (array)
+            return error_type;
+         return usampler2DRect_type;
+      case GLSL_SAMPLER_DIM_BUF:
+         if (array)
+            return error_type;
+         return usamplerBuffer_type;
+      case GLSL_SAMPLER_DIM_MS:
+         return (array ? usampler2DMSArray_type : usampler2DMS_type);
+      case GLSL_SAMPLER_DIM_EXTERNAL:
+         return error_type;
+      }
+   default:
+      return error_type;
    }
 
+   unreachable("switch statement above should be complete");
+}
+
+const glsl_type *
+glsl_type::get_array_instance(const glsl_type *base, unsigned array_size)
+{
    /* 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
@@ -466,18 +723,31 @@ 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);
 
-   const glsl_type *t = (glsl_type *) hash_table_find(array_types, key);
-   if (t == NULL) {
-      t = new glsl_type(base, array_size);
+   mtx_lock(&glsl_type::mutex);
 
-      hash_table_insert(array_types, (void *) t, ralloc_strdup(mem_ctx, key));
+   if (array_types == NULL) {
+      array_types = _mesa_hash_table_create(NULL, _mesa_key_hash_string,
+                                            _mesa_key_string_equal);
    }
 
-   assert(t->base_type == GLSL_TYPE_ARRAY);
-   assert(t->length == array_size);
-   assert(t->fields.array == base);
+   const struct hash_entry *entry = _mesa_hash_table_search(array_types, key);
+   if (entry == NULL) {
+      mtx_unlock(&glsl_type::mutex);
+      const glsl_type *t = new glsl_type(base, array_size);
+      mtx_lock(&glsl_type::mutex);
 
-   return t;
+      entry = _mesa_hash_table_insert(array_types,
+                                      ralloc_strdup(mem_ctx, key),
+                                      (void *) t);
+   }
+
+   assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_ARRAY);
+   assert(((glsl_type *) entry->data)->length == array_size);
+   assert(((glsl_type *) entry->data)->fields.array == base);
+
+   mtx_unlock(&glsl_type::mutex);
+
+   return (glsl_type *) entry->data;
 }
 
 
@@ -506,10 +776,10 @@ glsl_type::record_compare(const glsl_type *b) const
 
    for (unsigned i = 0; i < this->length; i++) {
       if (this->fields.structure[i].type != b->fields.structure[i].type)
-        return false;
+         return false;
       if (strcmp(this->fields.structure[i].name,
-                b->fields.structure[i].name) != 0)
-        return false;
+                 b->fields.structure[i].name) != 0)
+         return false;
       if (this->fields.structure[i].matrix_layout
          != b->fields.structure[i].matrix_layout)
         return false;
@@ -525,102 +795,299 @@ glsl_type::record_compare(const glsl_type *b) const
       if (this->fields.structure[i].sample
           != b->fields.structure[i].sample)
          return false;
+      if (this->fields.structure[i].patch
+          != b->fields.structure[i].patch)
+         return false;
+      if (this->fields.structure[i].image_read_only
+          != b->fields.structure[i].image_read_only)
+         return false;
+      if (this->fields.structure[i].image_write_only
+          != b->fields.structure[i].image_write_only)
+         return false;
+      if (this->fields.structure[i].image_coherent
+          != b->fields.structure[i].image_coherent)
+         return false;
+      if (this->fields.structure[i].image_volatile
+          != b->fields.structure[i].image_volatile)
+         return false;
+      if (this->fields.structure[i].image_restrict
+          != b->fields.structure[i].image_restrict)
+         return false;
    }
 
    return true;
 }
 
 
-int
+bool
 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;
-
-   return !key1->record_compare(key2);
+   return strcmp(key1->name, key2->name) == 0 && key1->record_compare(key2);
 }
 
 
+/**
+ * Generate an integer hash value for a glsl_type structure type.
+ */
 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);
+   uintptr_t hash = key->length;
+   unsigned retval;
 
    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);
+      /* casting pointer to uintptr_t */
+      hash = (hash * 13 ) + (uintptr_t) key->fields.structure[i].type;
    }
 
-   return hash_table_string_hash(& hash_key);
+   if (sizeof(hash) == 8)
+      retval = (hash & 0xffffffff) ^ ((uint64_t) hash >> 32);
+   else
+      retval = hash;
+
+   return retval;
 }
 
 
 const glsl_type *
 glsl_type::get_record_instance(const glsl_struct_field *fields,
-                              unsigned num_fields,
-                              const char *name)
+                               unsigned num_fields,
+                               const char *name)
 {
    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);
+      record_types = _mesa_hash_table_create(NULL, record_key_hash,
+                                             record_key_compare);
    }
 
-   const glsl_type *t = (glsl_type *) hash_table_find(record_types, & key);
-   if (t == NULL) {
-      t = new glsl_type(fields, num_fields, name);
+   const struct hash_entry *entry = _mesa_hash_table_search(record_types,
+                                                            &key);
+   if (entry == NULL) {
+      mtx_unlock(&glsl_type::mutex);
+      const glsl_type *t = new glsl_type(fields, num_fields, name);
+      mtx_lock(&glsl_type::mutex);
 
-      hash_table_insert(record_types, (void *) t, t);
+      entry = _mesa_hash_table_insert(record_types, t, (void *) t);
    }
 
-   assert(t->base_type == GLSL_TYPE_STRUCT);
-   assert(t->length == num_fields);
-   assert(strcmp(t->name, name) == 0);
+   assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_STRUCT);
+   assert(((glsl_type *) entry->data)->length == num_fields);
+   assert(strcmp(((glsl_type *) entry->data)->name, name) == 0);
 
-   return t;
+   mtx_unlock(&glsl_type::mutex);
+
+   return (glsl_type *) entry->data;
 }
 
 
 const glsl_type *
 glsl_type::get_interface_instance(const glsl_struct_field *fields,
-                                 unsigned num_fields,
-                                 enum glsl_interface_packing packing,
-                                 const char *block_name)
+                                  unsigned num_fields,
+                                  enum glsl_interface_packing packing,
+                                  const char *block_name)
 {
    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);
+      interface_types = _mesa_hash_table_create(NULL, record_key_hash,
+                                                record_key_compare);
+   }
+
+   const struct hash_entry *entry = _mesa_hash_table_search(interface_types,
+                                                            &key);
+   if (entry == NULL) {
+      mtx_unlock(&glsl_type::mutex);
+      const glsl_type *t = new glsl_type(fields, num_fields,
+                                         packing, block_name);
+      mtx_lock(&glsl_type::mutex);
+
+      entry = _mesa_hash_table_insert(interface_types, t, (void *) t);
+   }
+
+   assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_INTERFACE);
+   assert(((glsl_type *) entry->data)->length == num_fields);
+   assert(strcmp(((glsl_type *) entry->data)->name, block_name) == 0);
+
+   mtx_unlock(&glsl_type::mutex);
+
+   return (glsl_type *) entry->data;
+}
+
+const glsl_type *
+glsl_type::get_subroutine_instance(const char *subroutine_name)
+{
+   const glsl_type key(subroutine_name);
+
+   mtx_lock(&glsl_type::mutex);
+
+   if (subroutine_types == NULL) {
+      subroutine_types = _mesa_hash_table_create(NULL, record_key_hash,
+                                                 record_key_compare);
+   }
+
+   const struct hash_entry *entry = _mesa_hash_table_search(subroutine_types,
+                                                            &key);
+   if (entry == NULL) {
+      mtx_unlock(&glsl_type::mutex);
+      const glsl_type *t = new glsl_type(subroutine_name);
+      mtx_lock(&glsl_type::mutex);
+
+      entry = _mesa_hash_table_insert(subroutine_types, t, (void *) t);
+   }
+
+   assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_SUBROUTINE);
+   assert(strcmp(((glsl_type *) entry->data)->name, subroutine_name) == 0);
+
+   mtx_unlock(&glsl_type::mutex);
+
+   return (glsl_type *) entry->data;
+}
+
+
+static bool
+function_key_compare(const void *a, const void *b)
+{
+   const glsl_type *const key1 = (glsl_type *) a;
+   const glsl_type *const key2 = (glsl_type *) b;
+
+   if (key1->length != key2->length)
+      return 1;
+
+   return memcmp(key1->fields.parameters, key2->fields.parameters,
+                 (key1->length + 1) * sizeof(*key1->fields.parameters));
+}
+
+
+static uint32_t
+function_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", (void *) key->fields.structure[i].type);
+   }
+
+   return _mesa_hash_string(hash_key);
+}
+
+const glsl_type *
+glsl_type::get_function_instance(const glsl_type *return_type,
+                                 const glsl_function_param *params,
+                                 unsigned num_params)
+{
+   const glsl_type key(return_type, params, num_params);
+
+   mtx_lock(&glsl_type::mutex);
+
+   if (function_types == NULL) {
+      function_types = _mesa_hash_table_create(NULL, function_key_hash,
+                                               function_key_compare);
    }
 
-   const glsl_type *t = (glsl_type *) hash_table_find(interface_types, & key);
-   if (t == NULL) {
-      t = new glsl_type(fields, num_fields, packing, block_name);
+   struct hash_entry *entry = _mesa_hash_table_search(function_types, &key);
+   if (entry == NULL) {
+      mtx_unlock(&glsl_type::mutex);
+      const glsl_type *t = new glsl_type(return_type, params, num_params);
+      mtx_lock(&glsl_type::mutex);
 
-      hash_table_insert(interface_types, (void *) t, t);
+      entry = _mesa_hash_table_insert(function_types, t, (void *) t);
    }
 
-   assert(t->base_type == GLSL_TYPE_INTERFACE);
-   assert(t->length == num_fields);
-   assert(strcmp(t->name, block_name) == 0);
+   const glsl_type *t = (const glsl_type *)entry->data;
+
+   assert(t->base_type == GLSL_TYPE_FUNCTION);
+   assert(t->length == num_params);
+
+   mtx_unlock(&glsl_type::mutex);
 
    return t;
 }
 
 
+const glsl_type *
+glsl_type::get_mul_type(const glsl_type *type_a, const glsl_type *type_b)
+{
+   if (type_a == type_b) {
+      return type_a;
+   } else if (type_a->is_matrix() && type_b->is_matrix()) {
+      /* Matrix multiply.  The columns of A must match the rows of B.  Given
+       * the other previously tested constraints, this means the vector type
+       * of a row from A must be the same as the vector type of a column from
+       * B.
+       */
+      if (type_a->row_type() == type_b->column_type()) {
+         /* The resulting matrix has the number of columns of matrix B and
+          * the number of rows of matrix A.  We get the row count of A by
+          * looking at the size of a vector that makes up a column.  The
+          * transpose (size of a row) is done for B.
+          */
+         const glsl_type *const type =
+            get_instance(type_a->base_type,
+                         type_a->column_type()->vector_elements,
+                         type_b->row_type()->vector_elements);
+         assert(type != error_type);
+
+         return type;
+      }
+   } else if (type_a->is_matrix()) {
+      /* A is a matrix and B is a column vector.  Columns of A must match
+       * rows of B.  Given the other previously tested constraints, this
+       * means the vector type of a row from A must be the same as the
+       * vector the type of B.
+       */
+      if (type_a->row_type() == type_b) {
+         /* The resulting vector has a number of elements equal to
+          * the number of rows of matrix A. */
+         const glsl_type *const type =
+            get_instance(type_a->base_type,
+                         type_a->column_type()->vector_elements,
+                         1);
+         assert(type != error_type);
+
+         return type;
+      }
+   } else {
+      assert(type_b->is_matrix());
+
+      /* A is a row vector and B is a matrix.  Columns of A must match rows
+       * of B.  Given the other previously tested constraints, this means
+       * the type of A must be the same as the vector type of a column from
+       * B.
+       */
+      if (type_a == type_b->column_type()) {
+         /* The resulting vector has a number of elements equal to
+          * the number of columns of matrix B. */
+         const glsl_type *const type =
+            get_instance(type_a->base_type,
+                         type_b->row_type()->vector_elements,
+                         1);
+         assert(type != error_type);
+
+         return type;
+      }
+   }
+
+   return error_type;
+}
+
+
 const glsl_type *
 glsl_type::field_type(const char *name) const
 {
@@ -630,7 +1097,7 @@ glsl_type::field_type(const char *name) const
 
    for (unsigned i = 0; i < this->length; i++) {
       if (strcmp(name, this->fields.structure[i].name) == 0)
-        return this->fields.structure[i].type;
+         return this->fields.structure[i].type;
    }
 
    return error_type;
@@ -646,7 +1113,7 @@ glsl_type::field_index(const char *name) const
 
    for (unsigned i = 0; i < this->length; i++) {
       if (strcmp(name, this->fields.structure[i].name) == 0)
-        return i;
+         return i;
    }
 
    return -1;
@@ -663,12 +1130,15 @@ glsl_type::component_slots() const
    case GLSL_TYPE_BOOL:
       return this->components();
 
+   case GLSL_TYPE_DOUBLE:
+      return 2 * this->components();
+
    case GLSL_TYPE_STRUCT:
    case GLSL_TYPE_INTERFACE: {
       unsigned size = 0;
 
       for (unsigned i = 0; i < this->length; i++)
-        size += this->fields.structure[i].type->component_slots();
+         size += this->fields.structure[i].type->component_slots();
 
       return size;
    }
@@ -678,7 +1148,10 @@ glsl_type::component_slots() const
 
    case GLSL_TYPE_IMAGE:
       return 1;
+   case GLSL_TYPE_SUBROUTINE:
+     return 1;
 
+   case GLSL_TYPE_FUNCTION:
    case GLSL_TYPE_SAMPLER:
    case GLSL_TYPE_ATOMIC_UINT:
    case GLSL_TYPE_VOID:
@@ -689,6 +1162,32 @@ glsl_type::component_slots() const
    return 0;
 }
 
+unsigned
+glsl_type::record_location_offset(unsigned length) const
+{
+   unsigned offset = 0;
+   const glsl_type *t = this->without_array();
+   if (t->is_record()) {
+      assert(length <= t->length);
+
+      for (unsigned i = 0; i < length; i++) {
+         const glsl_type *st = t->fields.structure[i].type;
+         const glsl_type *wa = st->without_array();
+         if (wa->is_record()) {
+            unsigned r_offset = wa->record_location_offset(wa->length);
+            offset += st->is_array() ? st->length * r_offset : r_offset;
+         } else {
+            /* We dont worry about arrays here because unless the array
+             * contains a structure or another array it only takes up a single
+             * uniform slot.
+             */
+            offset += 1;
+         }
+      }
+   }
+   return offset;
+}
+
 unsigned
 glsl_type::uniform_locations() const
 {
@@ -698,9 +1197,11 @@ glsl_type::uniform_locations() const
    case GLSL_TYPE_UINT:
    case GLSL_TYPE_INT:
    case GLSL_TYPE_FLOAT:
+   case GLSL_TYPE_DOUBLE:
    case GLSL_TYPE_BOOL:
    case GLSL_TYPE_SAMPLER:
    case GLSL_TYPE_IMAGE:
+   case GLSL_TYPE_SUBROUTINE:
       return 1;
 
    case GLSL_TYPE_STRUCT:
@@ -742,12 +1243,26 @@ glsl_type::can_implicitly_convert_to(const glsl_type *desired,
          desired->base_type == GLSL_TYPE_UINT && this->base_type == GLSL_TYPE_INT)
       return true;
 
+   /* No implicit conversions from double. */
+   if ((!state || state->has_double()) && this->is_double())
+      return false;
+
+   /* Conversions from different types to double. */
+   if ((!state || state->has_double()) && desired->is_double()) {
+      if (this->is_float())
+         return true;
+      if (this->is_integer())
+         return true;
+   }
+
    return false;
 }
 
 unsigned
 glsl_type::std140_base_alignment(bool row_major) const
 {
+   unsigned N = is_double() ? 8 : 4;
+
    /* (1) If the member is a scalar consuming <N> basic machine units, the
     *     base alignment is <N>.
     *
@@ -761,12 +1276,12 @@ glsl_type::std140_base_alignment(bool row_major) const
    if (this->is_scalar() || this->is_vector()) {
       switch (this->vector_elements) {
       case 1:
-        return 4;
+         return N;
       case 2:
-        return 8;
+         return 2 * N;
       case 3:
       case 4:
-        return 16;
+         return 4 * N;
       }
    }
 
@@ -791,12 +1306,13 @@ glsl_type::std140_base_alignment(bool row_major) const
     */
    if (this->is_array()) {
       if (this->fields.array->is_scalar() ||
-         this->fields.array->is_vector() ||
-         this->fields.array->is_matrix()) {
-        return MAX2(this->fields.array->std140_base_alignment(row_major), 16);
+          this->fields.array->is_vector() ||
+          this->fields.array->is_matrix()) {
+         return MAX2(this->fields.array->std140_base_alignment(row_major), 16);
       } else {
-        assert(this->fields.array->is_record());
-        return this->fields.array->std140_base_alignment(row_major);
+         assert(this->fields.array->is_record() ||
+                this->fields.array->is_array());
+         return this->fields.array->std140_base_alignment(row_major);
       }
    }
 
@@ -815,11 +1331,11 @@ glsl_type::std140_base_alignment(bool row_major) const
       int r = this->vector_elements;
 
       if (row_major) {
-        vec_type = get_instance(GLSL_TYPE_FLOAT, c, 1);
-        array_type = glsl_type::get_array_instance(vec_type, r);
+         vec_type = get_instance(base_type, c, 1);
+         array_type = glsl_type::get_array_instance(vec_type, r);
       } else {
-        vec_type = get_instance(GLSL_TYPE_FLOAT, r, 1);
-        array_type = glsl_type::get_array_instance(vec_type, c);
+         vec_type = get_instance(base_type, r, 1);
+         array_type = glsl_type::get_array_instance(vec_type, c);
       }
 
       return array_type->std140_base_alignment(false);
@@ -849,9 +1365,9 @@ glsl_type::std140_base_alignment(bool row_major) const
             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(field_row_major));
+         const struct glsl_type *field_type = this->fields.structure[i].type;
+         base_alignment = MAX2(base_alignment,
+                               field_type->std140_base_alignment(field_row_major));
       }
       return base_alignment;
    }
@@ -863,6 +1379,8 @@ glsl_type::std140_base_alignment(bool row_major) const
 unsigned
 glsl_type::std140_size(bool row_major) const
 {
+   unsigned N = is_double() ? 8 : 4;
+
    /* (1) If the member is a scalar consuming <N> basic machine units, the
     *     base alignment is <N>.
     *
@@ -874,7 +1392,7 @@ glsl_type::std140_size(bool row_major) const
     *     <N> basic machine units, the base alignment is 4<N>.
     */
    if (this->is_scalar() || this->is_vector()) {
-      return this->vector_elements * 4;
+      return this->vector_elements * N;
    }
 
    /* (5) If the member is a column-major matrix with <C> columns and
@@ -901,24 +1419,25 @@ glsl_type::std140_size(bool row_major) const
       unsigned int array_len;
 
       if (this->is_array()) {
-        element_type = this->fields.array;
-        array_len = this->length;
+         element_type = this->fields.array;
+         array_len = this->length;
       } else {
-        element_type = this;
-        array_len = 1;
+         element_type = this;
+         array_len = 1;
       }
 
       if (row_major) {
-        vec_type = get_instance(GLSL_TYPE_FLOAT,
-                                element_type->matrix_columns, 1);
-        array_len *= element_type->vector_elements;
+         vec_type = get_instance(element_type->base_type,
+                                 element_type->matrix_columns, 1);
+
+         array_len *= element_type->vector_elements;
       } else {
-        vec_type = get_instance(GLSL_TYPE_FLOAT,
-                                element_type->vector_elements, 1);
-        array_len *= element_type->matrix_columns;
+         vec_type = get_instance(element_type->base_type,
+                                 element_type->vector_elements, 1);
+         array_len *= element_type->matrix_columns;
       }
       const glsl_type *array_type = glsl_type::get_array_instance(vec_type,
-                                                                 array_len);
+                                                                  array_len);
 
       return array_type->std140_size(false);
    }
@@ -935,11 +1454,11 @@ glsl_type::std140_size(bool row_major) const
     */
    if (this->is_array()) {
       if (this->fields.array->is_record()) {
-        return this->length * this->fields.array->std140_size(row_major);
+         return this->length * this->fields.array->std140_size(row_major);
       } else {
-        unsigned element_base_align =
-           this->fields.array->std140_base_alignment(row_major);
-        return this->length * MAX2(element_base_align, 16);
+         unsigned element_base_align =
+            this->fields.array->std140_base_alignment(row_major);
+         return this->length * MAX2(element_base_align, 16);
       }
    }
 
@@ -955,7 +1474,7 @@ glsl_type::std140_size(bool row_major) const
     *     rounded up to the next multiple of the base alignment of the
     *     structure.
     */
-   if (this->is_record()) {
+   if (this->is_record() || this->is_interface()) {
       unsigned size = 0;
       unsigned max_align = 0;
 
@@ -969,17 +1488,22 @@ glsl_type::std140_size(bool row_major) const
             field_row_major = false;
          }
 
-        const struct glsl_type *field_type = this->fields.structure[i].type;
-        unsigned align = field_type->std140_base_alignment(field_row_major);
-        size = glsl_align(size, align);
-        size += field_type->std140_size(field_row_major);
+         const struct glsl_type *field_type = this->fields.structure[i].type;
+         unsigned align = field_type->std140_base_alignment(field_row_major);
+
+         /* Ignore unsized arrays when calculating size */
+         if (field_type->is_unsized_array())
+            continue;
+
+         size = glsl_align(size, align);
+         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, max_align);
+      size = glsl_align(size, MAX2(max_align, 16));
       return size;
    }
 
@@ -987,6 +1511,216 @@ glsl_type::std140_size(bool row_major) const
    return -1;
 }
 
+unsigned
+glsl_type::std430_base_alignment(bool row_major) const
+{
+
+   unsigned N = is_double() ? 8 : 4;
+
+   /* (1) If the member is a scalar consuming <N> basic machine units, the
+    *     base alignment is <N>.
+    *
+    * (2) If the member is a two- or four-component vector with components
+    *     consuming <N> basic machine units, the base alignment is 2<N> or
+    *     4<N>, respectively.
+    *
+    * (3) If the member is a three-component vector with components consuming
+    *     <N> basic machine units, the base alignment is 4<N>.
+    */
+   if (this->is_scalar() || this->is_vector()) {
+      switch (this->vector_elements) {
+      case 1:
+         return N;
+      case 2:
+         return 2 * N;
+      case 3:
+      case 4:
+         return 4 * N;
+      }
+   }
+
+   /* OpenGL 4.30 spec, section 7.6.2.2 "Standard Uniform Block Layout":
+    *
+    * "When using the std430 storage layout, shader storage blocks will be
+    * laid out in buffer storage identically to uniform and shader storage
+    * blocks using the std140 layout, except that the base alignment and
+    * stride of arrays of scalars and vectors in rule 4 and of structures
+    * in rule 9 are not rounded up a multiple of the base alignment of a vec4.
+    */
+
+   /* (1) If the member is a scalar consuming <N> basic machine units, the
+    *     base alignment is <N>.
+    *
+    * (2) If the member is a two- or four-component vector with components
+    *     consuming <N> basic machine units, the base alignment is 2<N> or
+    *     4<N>, respectively.
+    *
+    * (3) If the member is a three-component vector with components consuming
+    *     <N> basic machine units, the base alignment is 4<N>.
+    */
+   if (this->is_array())
+      return this->fields.array->std430_base_alignment(row_major);
+
+   /* (5) If the member is a column-major matrix with <C> columns and
+    *     <R> rows, the matrix is stored identically to an array of
+    *     <C> column vectors with <R> components each, according to
+    *     rule (4).
+    *
+    * (7) If the member is a row-major matrix with <C> columns and <R>
+    *     rows, the matrix is stored identically to an array of <R>
+    *     row vectors with <C> components each, according to rule (4).
+    */
+   if (this->is_matrix()) {
+      const struct glsl_type *vec_type, *array_type;
+      int c = this->matrix_columns;
+      int r = this->vector_elements;
+
+      if (row_major) {
+         vec_type = get_instance(base_type, c, 1);
+         array_type = glsl_type::get_array_instance(vec_type, r);
+      } else {
+         vec_type = get_instance(base_type, r, 1);
+         array_type = glsl_type::get_array_instance(vec_type, c);
+      }
+
+      return array_type->std430_base_alignment(false);
+   }
+
+      /* (9) If the member is a structure, the base alignment of the
+    *     structure is <N>, where <N> is the largest base alignment
+    *     value of any of its members, and rounded up to the base
+    *     alignment of a vec4. The individual members of this
+    *     sub-structure are then assigned offsets by applying this set
+    *     of rules recursively, where the base offset of the first
+    *     member of the sub-structure is equal to the aligned offset
+    *     of the structure. The structure may have padding at the end;
+    *     the base offset of the member following the sub-structure is
+    *     rounded up to the next multiple of the base alignment of the
+    *     structure.
+    */
+   if (this->is_record()) {
+      unsigned base_alignment = 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;
+         base_alignment = MAX2(base_alignment,
+                               field_type->std430_base_alignment(field_row_major));
+      }
+      assert(base_alignment > 0);
+      return base_alignment;
+   }
+   assert(!"not reached");
+   return -1;
+}
+
+unsigned
+glsl_type::std430_array_stride(bool row_major) const
+{
+   unsigned N = is_double() ? 8 : 4;
+
+   /* Notice that the array stride of a vec3 is not 3 * N but 4 * N.
+    * See OpenGL 4.30 spec, section 7.6.2.2 "Standard Uniform Block Layout"
+    *
+    * (3) If the member is a three-component vector with components consuming
+    *     <N> basic machine units, the base alignment is 4<N>.
+    */
+   if (this->is_vector() && this->vector_elements == 3)
+      return 4 * N;
+
+   /* By default use std430_size(row_major) */
+   return this->std430_size(row_major);
+}
+
+unsigned
+glsl_type::std430_size(bool row_major) const
+{
+   unsigned N = is_double() ? 8 : 4;
+
+   /* OpenGL 4.30 spec, section 7.6.2.2 "Standard Uniform Block Layout":
+    *
+    * "When using the std430 storage layout, shader storage blocks will be
+    * laid out in buffer storage identically to uniform and shader storage
+    * blocks using the std140 layout, except that the base alignment and
+    * stride of arrays of scalars and vectors in rule 4 and of structures
+    * in rule 9 are not rounded up a multiple of the base alignment of a vec4.
+    */
+   if (this->is_scalar() || this->is_vector())
+         return this->vector_elements * N;
+
+   if (this->without_array()->is_matrix()) {
+      const struct glsl_type *element_type;
+      const struct glsl_type *vec_type;
+      unsigned int array_len;
+
+      if (this->is_array()) {
+         element_type = this->without_array();
+         array_len = this->arrays_of_arrays_size();
+      } else {
+         element_type = this;
+         array_len = 1;
+      }
+
+      if (row_major) {
+         vec_type = get_instance(element_type->base_type,
+                                 element_type->matrix_columns, 1);
+
+         array_len *= element_type->vector_elements;
+      } else {
+         vec_type = get_instance(element_type->base_type,
+                                 element_type->vector_elements, 1);
+         array_len *= element_type->matrix_columns;
+      }
+      const glsl_type *array_type = glsl_type::get_array_instance(vec_type,
+                                                                  array_len);
+
+      return array_type->std430_size(false);
+   }
+
+   if (this->is_array()) {
+      if (this->without_array()->is_record())
+         return this->arrays_of_arrays_size() *
+            this->without_array()->std430_size(row_major);
+      else
+         return this->arrays_of_arrays_size() *
+            this->without_array()->std430_base_alignment(row_major);
+   }
+
+   if (this->is_record() || this->is_interface()) {
+      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->std430_base_alignment(field_row_major);
+         size = glsl_align(size, align);
+         size += field_type->std430_size(field_row_major);
+
+         max_align = MAX2(align, max_align);
+      }
+      size = glsl_align(size, max_align);
+      return size;
+   }
+
+   assert(!"not reached");
+   return -1;
+}
 
 unsigned
 glsl_type::count_attribute_slots() const
@@ -1016,6 +1750,7 @@ glsl_type::count_attribute_slots() const
    case GLSL_TYPE_INT:
    case GLSL_TYPE_FLOAT:
    case GLSL_TYPE_BOOL:
+   case GLSL_TYPE_DOUBLE:
       return this->matrix_columns;
 
    case GLSL_TYPE_STRUCT:
@@ -1031,10 +1766,12 @@ glsl_type::count_attribute_slots() const
    case GLSL_TYPE_ARRAY:
       return this->length * this->fields.array->count_attribute_slots();
 
+   case GLSL_TYPE_FUNCTION:
    case GLSL_TYPE_SAMPLER:
    case GLSL_TYPE_IMAGE:
    case GLSL_TYPE_ATOMIC_UINT:
    case GLSL_TYPE_VOID:
+   case GLSL_TYPE_SUBROUTINE:
    case GLSL_TYPE_ERROR:
       break;
    }
@@ -1070,8 +1807,13 @@ glsl_type::coordinate_components() const
       break;
    }
 
-   /* Array textures need an additional component for the array index. */
-   if (sampler_array)
+   /* Array textures need an additional component for the array index, except
+    * for cubemap array images that behave like a 2D array of interleaved
+    * cubemap faces.
+    */
+   if (sampler_array &&
+       !(base_type == GLSL_TYPE_IMAGE &&
+         sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE))
       size += 1;
 
    return size;