glsl: add support for explicit locations inside interface blocks
authorTimothy Arceri <timothy.arceri@collabora.com>
Mon, 30 Nov 2015 23:34:18 +0000 (10:34 +1100)
committerTimothy Arceri <timothy.arceri@collabora.com>
Tue, 15 Dec 2015 02:10:44 +0000 (13:10 +1100)
This change also adds explicit location support for structs and interfaces which
is currently missing in Mesa but is allowed with SSO and GLSL 1.50+.

Reviewed-by: Edward O'Callaghan <eocallaghan@alterapraxis.com>
src/glsl/ast.h
src/glsl/ast_to_hir.cpp
src/glsl/glsl_parser.yy
src/glsl/link_interface_blocks.cpp

index adfc7938bffbe183a428b9f3b8c65e6c7457ffb5..f8ab0b71b7bb2b34b367c1b791f853f4c91bfde5 100644 (file)
@@ -726,6 +726,7 @@ public:
                          struct _mesa_glsl_parse_state *state);
 
    const char *name;
+   ast_type_qualifier *layout;
    /* List of ast_declarator_list * */
    exec_list declarations;
    bool is_declaration;
index 35a1e134dfa0f0d9458ab3e29e4bd660a3edecdc..1091c0227035a7abd32539c0cbfa694878461c0e 100644 (file)
@@ -6179,7 +6179,8 @@ ast_process_struct_or_iface_block_members(exec_list *instructions,
                                           bool allow_reserved_names,
                                           ir_variable_mode var_mode,
                                           ast_type_qualifier *layout,
-                                          unsigned block_stream)
+                                          unsigned block_stream,
+                                          unsigned expl_location)
 {
    unsigned decl_count = 0;
 
@@ -6200,6 +6201,9 @@ ast_process_struct_or_iface_block_members(exec_list *instructions,
    glsl_struct_field *const fields = ralloc_array(state, glsl_struct_field,
                                                   decl_count);
 
+   bool first_member = true;
+   bool first_member_has_explicit_location;
+
    unsigned i = 0;
    foreach_list_typed (ast_declarator_list, decl_list, link, declarations) {
       const char *type_name;
@@ -6264,6 +6268,27 @@ ast_process_struct_or_iface_block_members(exec_list *instructions,
                           "to struct or interface block members");
       }
 
+      if (is_interface) {
+         if (!first_member) {
+            if (!layout->flags.q.explicit_location &&
+                ((first_member_has_explicit_location &&
+                  !qual->flags.q.explicit_location) ||
+                 (!first_member_has_explicit_location &&
+                  qual->flags.q.explicit_location))) {
+               _mesa_glsl_error(&loc, state,
+                                "when block-level location layout qualifier "
+                                "is not supplied either all members must "
+                                "have a location layout qualifier or all "
+                                "members must not have a location layout "
+                                "qualifier");
+            }
+         } else {
+            first_member = false;
+            first_member_has_explicit_location =
+               qual->flags.q.explicit_location;
+         }
+      }
+
       if (qual->flags.q.std140 ||
           qual->flags.q.std430 ||
           qual->flags.q.packed ||
@@ -6338,7 +6363,6 @@ ast_process_struct_or_iface_block_members(exec_list *instructions,
          validate_array_dimensions(field_type, state, &loc);
          fields[i].type = field_type;
          fields[i].name = decl->identifier;
-         fields[i].location = -1;
          fields[i].interpolation =
             interpret_interpolation_qualifier(qual, var_mode, state, &loc);
          fields[i].centroid = qual->flags.q.centroid ? 1 : 0;
@@ -6346,6 +6370,22 @@ ast_process_struct_or_iface_block_members(exec_list *instructions,
          fields[i].patch = qual->flags.q.patch ? 1 : 0;
          fields[i].precision = qual->precision;
 
+         if (qual->flags.q.explicit_location) {
+            unsigned qual_location;
+            if (process_qualifier_constant(state, &loc, "location",
+                                           qual->location, &qual_location)) {
+               fields[i].location = VARYING_SLOT_VAR0 + qual_location;
+               expl_location = fields[i].location + 1;
+            }
+         } else {
+            if (layout && layout->flags.q.explicit_location) {
+               fields[i].location = expl_location;
+               expl_location = expl_location + 1;
+            } else {
+               fields[i].location = -1;
+            }
+         }
+
          /* Propogate row- / column-major information down the fields of the
           * structure or interface block.  Structures need this data because
           * the structure may contain a structure that contains ... a matrix
@@ -6444,6 +6484,16 @@ ast_struct_specifier::hir(exec_list *instructions,
 
    state->struct_specifier_depth++;
 
+   unsigned expl_location = -1;
+   if (layout && layout->flags.q.explicit_location) {
+      if (!process_qualifier_constant(state, &loc, "location",
+                                      layout->location, &expl_location)) {
+         return NULL;
+      } else {
+         expl_location = VARYING_SLOT_VAR0 + expl_location;
+      }
+   }
+
    glsl_struct_field *fields;
    unsigned decl_count =
       ast_process_struct_or_iface_block_members(instructions,
@@ -6454,8 +6504,9 @@ ast_struct_specifier::hir(exec_list *instructions,
                                                 GLSL_MATRIX_LAYOUT_INHERITED,
                                                 false /* allow_reserved_names */,
                                                 ir_var_auto,
-                                                NULL,
-                                                0 /* for interface only */);
+                                                layout,
+                                                0, /* for interface only */
+                                                expl_location);
 
    validate_identifier(this->name, loc, state);
 
@@ -6620,6 +6671,16 @@ ast_interface_block::hir(exec_list *instructions,
       return NULL;
    }
 
+   unsigned expl_location = -1;
+   if (layout.flags.q.explicit_location) {
+      if (!process_qualifier_constant(state, &loc, "location",
+                                      layout.location, &expl_location)) {
+         return NULL;
+      } else {
+         expl_location = VARYING_SLOT_VAR0 + expl_location;
+      }
+   }
+
    unsigned int num_variables =
       ast_process_struct_or_iface_block_members(&declared_variables,
                                                 state,
@@ -6630,7 +6691,8 @@ ast_interface_block::hir(exec_list *instructions,
                                                 redeclaring_per_vertex,
                                                 var_mode,
                                                 &this->layout,
-                                                qual_stream);
+                                                qual_stream,
+                                                expl_location);
 
    state->struct_specifier_depth--;
 
@@ -6969,6 +7031,10 @@ ast_interface_block::hir(exec_list *instructions,
          }
 
          var->data.stream = qual_stream;
+         if (layout.flags.q.explicit_location) {
+            var->data.location = expl_location;
+            var->data.explicit_location = true;
+         }
 
          state->symbols->add_variable(var);
          instructions->push_tail(var);
@@ -6989,6 +7055,9 @@ ast_interface_block::hir(exec_list *instructions,
          var->data.sample = fields[i].sample;
          var->data.patch = fields[i].patch;
          var->data.stream = qual_stream;
+         var->data.location = fields[i].location;
+         if (fields[i].location != -1)
+            var->data.explicit_location = true;
          var->init_interface_type(block_type);
 
          if (var_mode == ir_var_shader_in || var_mode == ir_var_uniform)
index 7eb383ac60ca6b064698375bb4cff31f49bb292b..51796a65df99c6dca2918725e5a1b93ac5ebdaf7 100644 (file)
@@ -1130,6 +1130,10 @@ fully_specified_type:
       $$->set_location_range(@1, @2);
       $$->qualifier = $1;
       $$->specifier = $2;
+      if ($$->specifier->structure != NULL &&
+          $$->specifier->structure->is_declaration) {
+            $$->specifier->structure->layout = &$$->qualifier;
+      }
    }
    ;
 
index 61ba0785d6359230402c93fb65a98a19376ca36f..64c30fea9a3c7aae5086247aca598abe05c3aae7 100644 (file)
@@ -166,9 +166,19 @@ public:
     */
    ir_variable *lookup(ir_variable *var)
    {
-      const struct hash_entry *entry =
-         _mesa_hash_table_search(ht, var->get_interface_type()->name);
-      return entry ? (ir_variable *) entry->data : NULL;
+      if (var->data.explicit_location &&
+          var->data.location >= VARYING_SLOT_VAR0) {
+         char location_str[11];
+         snprintf(location_str, 11, "%d", var->data.location);
+
+         const struct hash_entry *entry =
+            _mesa_hash_table_search(ht, location_str);
+         return entry ? (ir_variable *) entry->data : NULL;
+      } else {
+         const struct hash_entry *entry =
+            _mesa_hash_table_search(ht, var->get_interface_type()->name);
+         return entry ? (ir_variable *) entry->data : NULL;
+      }
    }
 
    /**
@@ -176,7 +186,19 @@ public:
     */
    void store(ir_variable *var)
    {
-      _mesa_hash_table_insert(ht, var->get_interface_type()->name, var);
+      if (var->data.explicit_location &&
+          var->data.location >= VARYING_SLOT_VAR0) {
+         /* If explicit location is given then lookup the variable by location.
+          * We turn the location into a string and use this as the hash key
+          * rather than the name. Note: We allocate enough space for a 32-bit
+          * unsigned location value which is overkill but future proof.
+          */
+         char location_str[11];
+         snprintf(location_str, 11, "%d", var->data.location);
+         _mesa_hash_table_insert(ht, ralloc_strdup(mem_ctx, location_str), var);
+      } else {
+         _mesa_hash_table_insert(ht, var->get_interface_type()->name, var);
+      }
    }
 
 private: