etnaviv: Add libdrm code as of 922d92994267743266024ecceb734ce0ebbca808
[mesa.git] / src / compiler / glsl_types.cpp
index 042f45a926db291f17385d8b4503059332cfd853..8e5087e2e1ab61d03767e63e36975a657806e26f 100644 (file)
 mtx_t glsl_type::hash_mutex = _MTX_INITIALIZER_NP;
 hash_table *glsl_type::explicit_matrix_types = NULL;
 hash_table *glsl_type::array_types = NULL;
-hash_table *glsl_type::record_types = NULL;
+hash_table *glsl_type::struct_types = NULL;
 hash_table *glsl_type::interface_types = NULL;
 hash_table *glsl_type::function_types = NULL;
 hash_table *glsl_type::subroutine_types = NULL;
 
+/* There might be multiple users for types (e.g. application using OpenGL
+ * and Vulkan simultanously or app using multiple Vulkan instances). Counter
+ * is used to make sure we don't release the types if a user is still present.
+ */
+static uint32_t glsl_type_users = 0;
+
 glsl_type::glsl_type(GLenum gl_type,
                      glsl_base_type base_type, unsigned vector_elements,
                      unsigned matrix_columns, const char *name,
@@ -44,7 +50,7 @@ glsl_type::glsl_type(GLenum gl_type,
    gl_type(gl_type),
    base_type(base_type), sampled_type(GLSL_TYPE_VOID),
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
-   interface_packing(0), interface_row_major(row_major),
+   interface_packing(0), interface_row_major(row_major), packed(0),
    vector_elements(vector_elements), matrix_columns(matrix_columns),
    length(0), explicit_stride(explicit_stride)
 {
@@ -79,7 +85,7 @@ glsl_type::glsl_type(GLenum gl_type, glsl_base_type base_type,
    base_type(base_type), sampled_type(type),
    sampler_dimensionality(dim), sampler_shadow(shadow),
    sampler_array(array), interface_packing(0),
-   interface_row_major(0),
+   interface_row_major(0), packed(0),
    length(0), explicit_stride(0)
 {
    this->mem_ctx = ralloc_context(NULL);
@@ -94,11 +100,11 @@ 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, bool packed) :
    gl_type(0),
    base_type(GLSL_TYPE_STRUCT), sampled_type(GLSL_TYPE_VOID),
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
-   interface_packing(0), interface_row_major(0),
+   interface_packing(0), interface_row_major(0), packed(packed),
    vector_elements(0), matrix_columns(0),
    length(num_fields), explicit_stride(0)
 {
@@ -128,7 +134,7 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
    base_type(GLSL_TYPE_INTERFACE), sampled_type(GLSL_TYPE_VOID),
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
    interface_packing((unsigned) packing),
-   interface_row_major((unsigned) row_major),
+   interface_row_major((unsigned) row_major), packed(0),
    vector_elements(0), matrix_columns(0),
    length(num_fields), explicit_stride(0)
 {
@@ -153,7 +159,7 @@ glsl_type::glsl_type(const glsl_type *return_type,
    gl_type(0),
    base_type(GLSL_TYPE_FUNCTION), sampled_type(GLSL_TYPE_VOID),
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
-   interface_packing(0), interface_row_major(0),
+   interface_packing(0), interface_row_major(0), packed(0),
    vector_elements(0), matrix_columns(0),
    length(num_params), explicit_stride(0)
 {
@@ -182,7 +188,7 @@ glsl_type::glsl_type(const char *subroutine_name) :
    gl_type(0),
    base_type(GLSL_TYPE_SUBROUTINE), sampled_type(GLSL_TYPE_VOID),
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
-   interface_packing(0), interface_row_major(0),
+   interface_packing(0), interface_row_major(0), packed(0),
    vector_elements(1), matrix_columns(1),
    length(0), explicit_stride(0)
 {
@@ -203,7 +209,7 @@ glsl_type::contains_sampler() const
 {
    if (this->is_array()) {
       return this->fields.array->contains_sampler();
-   } else if (this->is_record() || this->is_interface()) {
+   } else if (this->is_struct() || this->is_interface()) {
       for (unsigned int i = 0; i < this->length; i++) {
          if (this->fields.structure[i].type->contains_sampler())
             return true;
@@ -217,7 +223,7 @@ glsl_type::contains_sampler() const
 bool
 glsl_type::contains_array() const
 {
-   if (this->is_record() || this->is_interface()) {
+   if (this->is_struct() || this->is_interface()) {
       for (unsigned int i = 0; i < this->length; i++) {
          if (this->fields.structure[i].type->contains_array())
             return true;
@@ -233,7 +239,7 @@ glsl_type::contains_integer() const
 {
    if (this->is_array()) {
       return this->fields.array->contains_integer();
-   } else if (this->is_record() || this->is_interface()) {
+   } else if (this->is_struct() || this->is_interface()) {
       for (unsigned int i = 0; i < this->length; i++) {
          if (this->fields.structure[i].type->contains_integer())
             return true;
@@ -249,7 +255,7 @@ glsl_type::contains_double() const
 {
    if (this->is_array()) {
       return this->fields.array->contains_double();
-   } else if (this->is_record() || this->is_interface()) {
+   } else if (this->is_struct() || this->is_interface()) {
       for (unsigned int i = 0; i < this->length; i++) {
          if (this->fields.structure[i].type->contains_double())
             return true;
@@ -265,7 +271,7 @@ glsl_type::contains_64bit() const
 {
    if (this->is_array()) {
       return this->fields.array->contains_64bit();
-   } else if (this->is_record() || this->is_interface()) {
+   } else if (this->is_struct() || this->is_interface()) {
       for (unsigned int i = 0; i < this->length; i++) {
          if (this->fields.structure[i].type->contains_64bit())
             return true;
@@ -302,7 +308,7 @@ glsl_type::contains_subroutine() const
 {
    if (this->is_array()) {
       return this->fields.array->contains_subroutine();
-   } else if (this->is_record() || this->is_interface()) {
+   } else if (this->is_struct() || this->is_interface()) {
       for (unsigned int i = 0; i < this->length; i++) {
          if (this->fields.structure[i].type->contains_subroutine())
             return true;
@@ -348,7 +354,7 @@ glsl_type::contains_image() const
 {
    if (this->is_array()) {
       return this->fields.array->contains_image();
-   } else if (this->is_record() || this->is_interface()) {
+   } else if (this->is_struct() || this->is_interface()) {
       for (unsigned int i = 0; i < this->length; i++) {
          if (this->fields.structure[i].type->contains_image())
             return true;
@@ -434,7 +440,7 @@ const glsl_type *glsl_type::get_bare_type() const
          bare_fields[i].name = this->fields.structure[i].name;
       }
       const glsl_type *bare_type =
-         get_record_instance(bare_fields, this->length, this->name);
+         get_struct_instance(bare_fields, this->length, this->name);
       delete[] bare_fields;
       return bare_type;
    }
@@ -469,12 +475,26 @@ hash_free_type_function(struct hash_entry *entry)
 }
 
 void
-_mesa_glsl_release_types(void)
+glsl_type_singleton_init_or_ref()
 {
-   /* Should only be called during atexit (either when unloading shared
-    * object, or if process terminates), so no mutex-locking should be
-    * necessary.
-    */
+   mtx_lock(&glsl_type::hash_mutex);
+   glsl_type_users++;
+   mtx_unlock(&glsl_type::hash_mutex);
+}
+
+void
+glsl_type_singleton_decref()
+{
+   mtx_lock(&glsl_type::hash_mutex);
+
+   assert(glsl_type_users > 0);
+
+   /* Do not release glsl_types if they are still used. */
+   if (--glsl_type_users) {
+      mtx_unlock(&glsl_type::hash_mutex);
+      return;
+   }
+
    if (glsl_type::explicit_matrix_types != NULL) {
       _mesa_hash_table_destroy(glsl_type::explicit_matrix_types,
                                hash_free_type_function);
@@ -486,9 +506,9 @@ _mesa_glsl_release_types(void)
       glsl_type::array_types = NULL;
    }
 
-   if (glsl_type::record_types != NULL) {
-      _mesa_hash_table_destroy(glsl_type::record_types, hash_free_type_function);
-      glsl_type::record_types = NULL;
+   if (glsl_type::struct_types != NULL) {
+      _mesa_hash_table_destroy(glsl_type::struct_types, hash_free_type_function);
+      glsl_type::struct_types = NULL;
    }
 
    if (glsl_type::interface_types != NULL) {
@@ -505,6 +525,8 @@ _mesa_glsl_release_types(void)
       _mesa_hash_table_destroy(glsl_type::subroutine_types, hash_free_type_function);
       glsl_type::subroutine_types = NULL;
    }
+
+   mtx_unlock(&glsl_type::hash_mutex);
 }
 
 
@@ -512,7 +534,7 @@ glsl_type::glsl_type(const glsl_type *array, unsigned length,
                      unsigned explicit_stride) :
    base_type(GLSL_TYPE_ARRAY), sampled_type(GLSL_TYPE_VOID),
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
-   interface_packing(0), interface_row_major(0),
+   interface_packing(0), interface_row_major(0), packed(0),
    vector_elements(0), matrix_columns(0),
    length(length), name(NULL), explicit_stride(explicit_stride)
 {
@@ -1008,7 +1030,8 @@ glsl_type::get_array_instance(const glsl_type *base,
 
 
 bool
-glsl_type::record_compare(const glsl_type *b, bool match_locations) const
+glsl_type::record_compare(const glsl_type *b, bool match_name,
+                          bool match_locations) const
 {
    if (this->length != b->length)
       return false;
@@ -1025,9 +1048,16 @@ glsl_type::record_compare(const glsl_type *b, bool match_locations) const
     *     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).
+    *
+    * Section 7.4.1 (Shader Interface Matching) of the OpenGL 4.30 spec says:
+    *
+    *     "Variables or block members declared as structures are considered
+    *     to match in type if and only if structure members match in name,
+    *     type, qualification, and declaration order."
     */
-   if (strcmp(this->name, b->name) != 0)
-      return false;
+   if (match_name)
+      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)
@@ -1098,7 +1128,8 @@ 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 strcmp(key1->name, key2->name) == 0 && key1->record_compare(key2);
+   return strcmp(key1->name, key2->name) == 0 &&
+                 key1->record_compare(key2, true);
 }
 
 
@@ -1127,30 +1158,32 @@ glsl_type::record_key_hash(const void *a)
 
 
 const glsl_type *
-glsl_type::get_record_instance(const glsl_struct_field *fields,
+glsl_type::get_struct_instance(const glsl_struct_field *fields,
                                unsigned num_fields,
-                               const char *name)
+                               const char *name,
+                               bool packed)
 {
-   const glsl_type key(fields, num_fields, name);
+   const glsl_type key(fields, num_fields, name, packed);
 
    mtx_lock(&glsl_type::hash_mutex);
 
-   if (record_types == NULL) {
-      record_types = _mesa_hash_table_create(NULL, record_key_hash,
+   if (struct_types == NULL) {
+      struct_types = _mesa_hash_table_create(NULL, record_key_hash,
                                              record_key_compare);
    }
 
-   const struct hash_entry *entry = _mesa_hash_table_search(record_types,
+   const struct hash_entry *entry = _mesa_hash_table_search(struct_types,
                                                             &key);
    if (entry == NULL) {
-      const glsl_type *t = new glsl_type(fields, num_fields, name);
+      const glsl_type *t = new glsl_type(fields, num_fields, name, packed);
 
-      entry = _mesa_hash_table_insert(record_types, t, (void *) t);
+      entry = _mesa_hash_table_insert(struct_types, t, (void *) t);
    }
 
    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);
+   assert(((glsl_type *) entry->data)->packed == packed);
 
    mtx_unlock(&glsl_type::hash_mutex);
 
@@ -1425,18 +1458,18 @@ glsl_type::component_slots() const
 }
 
 unsigned
-glsl_type::record_location_offset(unsigned length) const
+glsl_type::struct_location_offset(unsigned length) const
 {
    unsigned offset = 0;
    const glsl_type *t = this->without_array();
-   if (t->is_record()) {
+   if (t->is_struct()) {
       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);
+         if (wa->is_struct()) {
+            unsigned r_offset = wa->struct_location_offset(wa->length);
             offset += st->is_array() ?
                st->arrays_of_arrays_size() * r_offset : r_offset;
          } else if (st->is_array() && st->fields.array->is_array()) {
@@ -1527,7 +1560,7 @@ glsl_type::varying_count() const
       return size;
    case GLSL_TYPE_ARRAY:
       /* Don't count innermost array elements */
-      if (this->without_array()->is_record() ||
+      if (this->without_array()->is_struct() ||
           this->without_array()->is_interface() ||
           this->fields.array->is_array())
          return this->length * this->fields.array->varying_count();
@@ -1642,7 +1675,7 @@ glsl_type::std140_base_alignment(bool row_major) const
           this->fields.array->is_matrix()) {
          return MAX2(this->fields.array->std140_base_alignment(row_major), 16);
       } else {
-         assert(this->fields.array->is_record() ||
+         assert(this->fields.array->is_struct() ||
                 this->fields.array->is_array());
          return this->fields.array->std140_base_alignment(row_major);
       }
@@ -1685,7 +1718,7 @@ glsl_type::std140_base_alignment(bool row_major) const
     *     rounded up to the next multiple of the base alignment of the
     *     structure.
     */
-   if (this->is_record()) {
+   if (this->is_struct()) {
       unsigned base_alignment = 16;
       for (unsigned i = 0; i < this->length; i++) {
          bool field_row_major = row_major;
@@ -1759,8 +1792,6 @@ glsl_type::std140_size(bool row_major) const
          array_len = 1;
       }
 
-      assert(element_type->explicit_stride == 0);
-
       if (row_major) {
          vec_type = get_instance(element_type->base_type,
                                  element_type->matrix_columns, 1);
@@ -1788,15 +1819,19 @@ glsl_type::std140_size(bool row_major) const
     *      the array are laid out in order, according to rule (9).
     */
    if (this->is_array()) {
-      assert(this->explicit_stride == 0);
-      if (this->without_array()->is_record()) {
-        return this->arrays_of_arrays_size() *
-            this->without_array()->std140_size(row_major);
+      unsigned stride;
+      if (this->without_array()->is_struct()) {
+        stride = this->without_array()->std140_size(row_major);
       } else {
         unsigned element_base_align =
            this->without_array()->std140_base_alignment(row_major);
-        return this->arrays_of_arrays_size() * MAX2(element_base_align, 16);
+         stride = MAX2(element_base_align, 16);
       }
+
+      unsigned size = this->arrays_of_arrays_size() * stride;
+      assert(this->explicit_stride == 0 ||
+             size == this->length * this->explicit_stride);
+      return size;
    }
 
    /* (9) If the member is a structure, the base alignment of the
@@ -1811,7 +1846,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() || this->is_interface()) {
+   if (this->is_struct() || this->is_interface()) {
       unsigned size = 0;
       unsigned max_align = 0;
 
@@ -1837,7 +1872,7 @@ glsl_type::std140_size(bool row_major) const
 
          max_align = MAX2(align, max_align);
 
-         if (field_type->is_record() && (i + 1 < this->length))
+         if (field_type->is_struct() && (i + 1 < this->length))
             size = glsl_align(size, 16);
       }
       size = glsl_align(size, MAX2(max_align, 16));
@@ -1848,6 +1883,79 @@ glsl_type::std140_size(bool row_major) const
    return -1;
 }
 
+const glsl_type *
+glsl_type::get_explicit_std140_type(bool row_major) const
+{
+   if (this->is_vector() || this->is_scalar()) {
+      return this;
+   } else if (this->is_matrix()) {
+      const glsl_type *vec_type;
+      if (row_major)
+         vec_type = get_instance(this->base_type, this->matrix_columns, 1);
+      else
+         vec_type = get_instance(this->base_type, this->vector_elements, 1);
+      unsigned elem_size = vec_type->std140_size(false);
+      unsigned stride = glsl_align(elem_size, 16);
+      return get_instance(this->base_type, this->vector_elements,
+                          this->matrix_columns, stride, row_major);
+   } else if (this->is_array()) {
+      unsigned elem_size = this->fields.array->std140_size(row_major);
+      const glsl_type *elem_type =
+         this->fields.array->get_explicit_std140_type(row_major);
+      unsigned stride = glsl_align(elem_size, 16);
+      return get_array_instance(elem_type, this->length, stride);
+   } else if (this->is_struct() || this->is_interface()) {
+      glsl_struct_field *fields = new glsl_struct_field[this->length];
+      unsigned offset = 0;
+      for (unsigned i = 0; i < length; i++) {
+         fields[i] = this->fields.structure[i];
+
+         bool field_row_major = row_major;
+         if (fields[i].matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) {
+            field_row_major = false;
+         } else if (fields[i].matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) {
+            field_row_major = true;
+         }
+         fields[i].type =
+            fields[i].type->get_explicit_std140_type(field_row_major);
+
+         unsigned fsize = fields[i].type->std140_size(field_row_major);
+         unsigned falign = fields[i].type->std140_base_alignment(field_row_major);
+         /* From the GLSL 460 spec section "Uniform and Shader Storage Block
+          * Layout Qualifiers":
+          *
+          *    "The actual offset of a member is computed as follows: If
+          *    offset was declared, start with that offset, otherwise start
+          *    with the next available offset. If the resulting offset is not
+          *    a multiple of the actual alignment, increase it to the first
+          *    offset that is a multiple of the actual alignment. This results
+          *    in the actual offset the member will have."
+          */
+         if (fields[i].offset >= 0) {
+            assert((unsigned)fields[i].offset >= offset);
+            offset = fields[i].offset;
+         }
+         offset = glsl_align(offset, falign);
+         fields[i].offset = offset;
+         offset += fsize;
+      }
+
+      const glsl_type *type;
+      if (this->is_struct())
+         type = get_struct_instance(fields, this->length, this->name);
+      else
+         type = get_interface_instance(fields, this->length,
+                                       (enum glsl_interface_packing)this->interface_packing,
+                                       this->interface_row_major,
+                                       this->name);
+
+      delete[] fields;
+      return type;
+   } else {
+      unreachable("Invalid type for UBO or SSBO");
+   }
+}
+
 unsigned
 glsl_type::std430_base_alignment(bool row_major) const
 {
@@ -1935,7 +2043,7 @@ glsl_type::std430_base_alignment(bool row_major) const
     *     rounded up to the next multiple of the base alignment of the
     *     structure.
     */
-   if (this->is_record()) {
+   if (this->is_struct()) {
       unsigned base_alignment = 0;
       for (unsigned i = 0; i < this->length; i++) {
          bool field_row_major = row_major;
@@ -1963,8 +2071,6 @@ glsl_type::std430_array_stride(bool row_major) const
 {
    unsigned N = is_64bit() ? 8 : 4;
 
-   assert(explicit_stride == 0);
-
    /* 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"
     *
@@ -1975,7 +2081,9 @@ glsl_type::std430_array_stride(bool row_major) const
       return 4 * N;
 
    /* By default use std430_size(row_major) */
-   return this->std430_size(row_major);
+   unsigned stride = this->std430_size(row_major);
+   assert(this->explicit_stride == 0 || this->explicit_stride == stride);
+   return stride;
 }
 
 unsigned
@@ -2009,8 +2117,6 @@ glsl_type::std430_size(bool row_major) const
          array_len = 1;
       }
 
-      assert(element_type->explicit_stride == 0);
-
       if (row_major) {
          vec_type = get_instance(element_type->base_type,
                                  element_type->matrix_columns, 1);
@@ -2028,16 +2134,19 @@ glsl_type::std430_size(bool row_major) const
    }
 
    if (this->is_array()) {
-      assert(this->explicit_stride == 0);
-      if (this->without_array()->is_record())
-         return this->arrays_of_arrays_size() *
-            this->without_array()->std430_size(row_major);
+      unsigned stride;
+      if (this->without_array()->is_struct())
+         stride = this->without_array()->std430_size(row_major);
       else
-         return this->arrays_of_arrays_size() *
-            this->without_array()->std430_base_alignment(row_major);
+         stride = this->without_array()->std430_base_alignment(row_major);
+
+      unsigned size = this->arrays_of_arrays_size() * stride;
+      assert(this->explicit_stride == 0 ||
+             size == this->length * this->explicit_stride);
+      return size;
    }
 
-   if (this->is_record() || this->is_interface()) {
+   if (this->is_struct() || this->is_interface()) {
       unsigned size = 0;
       unsigned max_align = 0;
 
@@ -2066,6 +2175,90 @@ glsl_type::std430_size(bool row_major) const
    return -1;
 }
 
+const glsl_type *
+glsl_type::get_explicit_std430_type(bool row_major) const
+{
+   if (this->is_vector() || this->is_scalar()) {
+      return this;
+   } else if (this->is_matrix()) {
+      const glsl_type *vec_type;
+      if (row_major)
+         vec_type = get_instance(this->base_type, this->matrix_columns, 1);
+      else
+         vec_type = get_instance(this->base_type, this->vector_elements, 1);
+      unsigned stride = vec_type->std430_array_stride(false);
+      return get_instance(this->base_type, this->vector_elements,
+                          this->matrix_columns, stride, row_major);
+   } else if (this->is_array()) {
+      const glsl_type *elem_type =
+         this->fields.array->get_explicit_std430_type(row_major);
+      unsigned stride = this->fields.array->std430_array_stride(row_major);
+      return get_array_instance(elem_type, this->length, stride);
+   } else if (this->is_struct() || this->is_interface()) {
+      glsl_struct_field *fields = new glsl_struct_field[this->length];
+      unsigned offset = 0;
+      for (unsigned i = 0; i < length; i++) {
+         fields[i] = this->fields.structure[i];
+
+         bool field_row_major = row_major;
+         if (fields[i].matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) {
+            field_row_major = false;
+         } else if (fields[i].matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) {
+            field_row_major = true;
+         }
+         fields[i].type =
+            fields[i].type->get_explicit_std430_type(field_row_major);
+
+         unsigned fsize = fields[i].type->std430_size(field_row_major);
+         unsigned falign = fields[i].type->std430_base_alignment(field_row_major);
+         /* From the GLSL 460 spec section "Uniform and Shader Storage Block
+          * Layout Qualifiers":
+          *
+          *    "The actual offset of a member is computed as follows: If
+          *    offset was declared, start with that offset, otherwise start
+          *    with the next available offset. If the resulting offset is not
+          *    a multiple of the actual alignment, increase it to the first
+          *    offset that is a multiple of the actual alignment. This results
+          *    in the actual offset the member will have."
+          */
+         if (fields[i].offset >= 0) {
+            assert((unsigned)fields[i].offset >= offset);
+            offset = fields[i].offset;
+         }
+         offset = glsl_align(offset, falign);
+         fields[i].offset = offset;
+         offset += fsize;
+      }
+
+      const glsl_type *type;
+      if (this->is_struct())
+         type = get_struct_instance(fields, this->length, this->name);
+      else
+         type = get_interface_instance(fields, this->length,
+                                       (enum glsl_interface_packing)this->interface_packing,
+                                       this->interface_row_major,
+                                       this->name);
+
+      delete[] fields;
+      return type;
+   } else {
+      unreachable("Invalid type for SSBO");
+   }
+}
+
+const glsl_type *
+glsl_type::get_explicit_interface_type(bool supports_std430) const
+{
+   enum glsl_interface_packing packing =
+      this->get_internal_ifc_packing(supports_std430);
+   if (packing == GLSL_INTERFACE_PACKING_STD140) {
+      return this->get_explicit_std140_type(this->interface_row_major);
+   } else {
+      assert(packing == GLSL_INTERFACE_PACKING_STD430);
+      return this->get_explicit_std430_type(this->interface_row_major);
+   }
+}
+
 unsigned
 glsl_type::count_attribute_slots(bool is_gl_vertex_input) const
 {
@@ -2287,6 +2480,8 @@ encode_type_to_blob(struct blob *blob, const glsl_type *type)
       if (type->is_interface()) {
          blob_write_uint32(blob, type->interface_packing);
          blob_write_uint32(blob, type->interface_row_major);
+      } else {
+         blob_write_uint32(blob, type->packed);
       }
       return;
    case GLSL_TYPE_VOID:
@@ -2375,7 +2570,8 @@ decode_type_from_blob(struct blob_reader *blob)
          t = glsl_type::get_interface_instance(fields, num_fields, packing,
                                                row_major, name);
       } else {
-         t = glsl_type::get_record_instance(fields, num_fields, name);
+         unsigned packed = blob_read_uint32(blob);
+         t = glsl_type::get_struct_instance(fields, num_fields, name, packed);
       }
 
       free(fields);
@@ -2389,3 +2585,51 @@ decode_type_from_blob(struct blob_reader *blob)
       return NULL;
    }
 }
+
+unsigned
+glsl_type::cl_alignment() const
+{
+   /* vectors unlike arrays are aligned to their size */
+   if (this->is_scalar() || this->is_vector())
+      return this->cl_size();
+   else if (this->is_array())
+      return this->without_array()->cl_alignment();
+   else if (this->is_struct()) {
+      /* Packed Structs are 0x1 aligned despite their size. */
+      if (this->packed)
+         return 1;
+
+      unsigned res = 1;
+      for (unsigned i = 0; i < this->length; ++i) {
+         struct glsl_struct_field &field = this->fields.structure[i];
+         res = MAX2(res, field.type->cl_alignment());
+      }
+      return res;
+   }
+   return 1;
+}
+
+unsigned
+glsl_type::cl_size() const
+{
+   if (this->is_scalar()) {
+      return glsl_base_type_get_bit_size(this->base_type) / 8;
+   } else if (this->is_vector()) {
+      unsigned vec_elemns = this->vector_elements == 3 ? 4 : this->vector_elements;
+      return vec_elemns * glsl_base_type_get_bit_size(this->base_type) / 8;
+   } else if (this->is_array()) {
+      unsigned size = this->without_array()->cl_size();
+      return size * this->length;
+   } else if (this->is_struct()) {
+      unsigned size = 0;
+      for (unsigned i = 0; i < this->length; ++i) {
+         struct glsl_struct_field &field = this->fields.structure[i];
+         /* if a struct is packed, members don't get aligned */
+         if (!this->packed)
+            size = align(size, field.type->cl_alignment());
+         size += field.type->cl_size();
+      }
+      return size;
+   }
+   return 1;
+}