glsl: Fix locations of variables in patch qualified interface blocks.
[mesa.git] / src / compiler / glsl / ast_type.cpp
index c3d38cbbf8afbc0221b20a7c3f3521b3cbb778d9..f3f6b29369b070bad4c40d5145456aedebeef29e 100644 (file)
@@ -74,6 +74,7 @@ ast_type_qualifier::has_layout() const
           || this->flags.q.row_major
           || this->flags.q.packed
           || this->flags.q.explicit_align
+          || this->flags.q.explicit_component
           || this->flags.q.explicit_location
           || this->flags.q.explicit_image_format
           || this->flags.q.explicit_index
@@ -146,6 +147,7 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
    input_layout_mask.flags.q.centroid = 1;
    /* Function params can have constant */
    input_layout_mask.flags.q.constant = 1;
+   input_layout_mask.flags.q.explicit_component = 1;
    input_layout_mask.flags.q.explicit_location = 1;
    input_layout_mask.flags.q.flat = 1;
    input_layout_mask.flags.q.in = 1;
@@ -173,9 +175,10 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
    /* Geometry shaders can have several layout qualifiers
     * assigning different stream values.
     */
-   if (state->stage == MESA_SHADER_GEOMETRY)
+   if (state->stage == MESA_SHADER_GEOMETRY) {
       allowed_duplicates_mask.flags.i |=
          stream_layout_mask.flags.i;
+   }
 
    if (is_single_layout_merge && !state->has_enhanced_layouts() &&
        (this->flags.i & q.flags.i & ~allowed_duplicates_mask.flags.i) != 0) {
@@ -224,7 +227,8 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
          if (q.flags.q.stream) {
             this->flags.q.stream = 1;
             this->stream = q.stream;
-         } else if (!this->flags.q.stream && this->flags.q.out) {
+         } else if (!this->flags.q.stream && this->flags.q.out &&
+                    !this->flags.q.in) {
             /* Assign default global stream value */
             this->flags.q.stream = 1;
             this->stream = state->out_qualifier->stream;
@@ -237,7 +241,8 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
          if (q.flags.q.xfb_buffer) {
             this->flags.q.xfb_buffer = 1;
             this->xfb_buffer = q.xfb_buffer;
-         } else if (!this->flags.q.xfb_buffer && this->flags.q.out) {
+         } else if (!this->flags.q.xfb_buffer && this->flags.q.out &&
+                    !this->flags.q.in) {
             /* Assign global xfb_buffer value */
             this->flags.q.xfb_buffer = 1;
             this->xfb_buffer = state->out_qualifier->xfb_buffer;
@@ -337,6 +342,9 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
    if (q.flags.q.explicit_index)
       this->index = q.index;
 
+  if (q.flags.q.explicit_component)
+      this->component = q.component;
+
    if (q.flags.q.explicit_binding)
       this->binding = q.binding;
 
@@ -406,6 +414,8 @@ ast_type_qualifier::merge_out_qualifier(YYLTYPE *loc,
       valid_out_mask.flags.q.xfb_buffer = 1;
       valid_out_mask.flags.q.explicit_xfb_stride = 1;
       valid_out_mask.flags.q.xfb_stride = 1;
+   } else if (state->stage == MESA_SHADER_FRAGMENT) {
+      valid_out_mask.flags.q.blend_support = 1;
    } else {
       _mesa_glsl_error(loc, state, "out layout qualifiers only valid in "
                        "geometry, tessellation and vertex shaders");
@@ -581,11 +591,98 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
    return true;
 }
 
+/**
+ * Check if the current type qualifier has any illegal flags.
+ *
+ * If so, print an error message, followed by a list of illegal flags.
+ *
+ * \param message        The error message to print.
+ * \param allowed_flags  A list of valid flags.
+ */
+bool
+ast_type_qualifier::validate_flags(YYLTYPE *loc,
+                                   _mesa_glsl_parse_state *state,
+                                   const ast_type_qualifier &allowed_flags,
+                                   const char *message, const char *name)
+{
+   ast_type_qualifier bad;
+   bad.flags.i = this->flags.i & ~allowed_flags.flags.i;
+   if (bad.flags.i == 0)
+      return true;
+
+   _mesa_glsl_error(loc, state,
+                    "%s '%s':"
+                    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
+                    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
+                    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+                    message, name,
+                    bad.flags.q.invariant ? " invariant" : "",
+                    bad.flags.q.precise ? " precise" : "",
+                    bad.flags.q.constant ? " constant" : "",
+                    bad.flags.q.attribute ? " attribute" : "",
+                    bad.flags.q.varying ? " varying" : "",
+                    bad.flags.q.in ? " in" : "",
+                    bad.flags.q.out ? " out" : "",
+                    bad.flags.q.centroid ? " centroid" : "",
+                    bad.flags.q.sample ? " sample" : "",
+                    bad.flags.q.patch ? " patch" : "",
+                    bad.flags.q.uniform ? " uniform" : "",
+                    bad.flags.q.buffer ? " buffer" : "",
+                    bad.flags.q.shared_storage ? " shared_storage" : "",
+                    bad.flags.q.smooth ? " smooth" : "",
+                    bad.flags.q.flat ? " flat" : "",
+                    bad.flags.q.noperspective ? " noperspective" : "",
+                    bad.flags.q.origin_upper_left ? " origin_upper_left" : "",
+                    bad.flags.q.pixel_center_integer ? " pixel_center_integer" : "",
+                    bad.flags.q.explicit_align ? " align" : "",
+                    bad.flags.q.explicit_component ? " component" : "",
+                    bad.flags.q.explicit_location ? " location" : "",
+                    bad.flags.q.explicit_index ? " index" : "",
+                    bad.flags.q.explicit_binding ? " binding" : "",
+                    bad.flags.q.explicit_offset ? " offset" : "",
+                    bad.flags.q.depth_any ? " depth_any" : "",
+                    bad.flags.q.depth_greater ? " depth_greater" : "",
+                    bad.flags.q.depth_less ? " depth_less" : "",
+                    bad.flags.q.depth_unchanged ? " depth_unchanged" : "",
+                    bad.flags.q.std140 ? " std140" : "",
+                    bad.flags.q.std430 ? " std430" : "",
+                    bad.flags.q.shared ? " shared" : "",
+                    bad.flags.q.packed ? " packed" : "",
+                    bad.flags.q.column_major ? " column_major" : "",
+                    bad.flags.q.row_major ? " row_major" : "",
+                    bad.flags.q.prim_type ? " prim_type" : "",
+                    bad.flags.q.max_vertices ? " max_vertices" : "",
+                    bad.flags.q.local_size ? " local_size" : "",
+                    bad.flags.q.early_fragment_tests ? " early_fragment_tests" : "",
+                    bad.flags.q.explicit_image_format ? " image_format" : "",
+                    bad.flags.q.coherent ? " coherent" : "",
+                    bad.flags.q._volatile ? " _volatile" : "",
+                    bad.flags.q.restrict_flag ? " restrict_flag" : "",
+                    bad.flags.q.read_only ? " read_only" : "",
+                    bad.flags.q.write_only ? " write_only" : "",
+                    bad.flags.q.invocations ? " invocations" : "",
+                    bad.flags.q.stream ? " stream" : "",
+                    bad.flags.q.explicit_stream ? " stream" : "",
+                    bad.flags.q.explicit_xfb_offset ? " xfb_offset" : "",
+                    bad.flags.q.xfb_buffer ? " xfb_buffer" : "",
+                    bad.flags.q.explicit_xfb_buffer ? " xfb_buffer" : "",
+                    bad.flags.q.xfb_stride ? " xfb_stride" : "",
+                    bad.flags.q.explicit_xfb_stride ? " xfb_stride" : "",
+                    bad.flags.q.vertex_spacing ? " vertex_spacing" : "",
+                    bad.flags.q.ordering ? " ordering" : "",
+                    bad.flags.q.point_mode ? " point_mode" : "",
+                    bad.flags.q.vertices ? " vertices" : "",
+                    bad.flags.q.subroutine ? " subroutine" : "",
+                    bad.flags.q.subroutine_def ? " subroutine_def" : "");
+   return false;
+}
+
 bool
 ast_layout_expression::process_qualifier_constant(struct _mesa_glsl_parse_state *state,
                                                   const char *qual_indentifier,
                                                   unsigned *value,
-                                                  bool can_be_zero)
+                                                  bool can_be_zero,
+                                                  bool must_match)
 {
    int min_value = 0;
    bool first_pass = true;
@@ -594,8 +691,8 @@ ast_layout_expression::process_qualifier_constant(struct _mesa_glsl_parse_state
    if (!can_be_zero)
       min_value = 1;
 
-   for (exec_node *node = layout_const_expressions.head;
-           !node->is_tail_sentinel(); node = node->next) {
+   for (exec_node *node = layout_const_expressions.get_head_raw();
+        !node->is_tail_sentinel(); node = node->next) {
 
       exec_list dummy_instructions;
       ast_node *const_expression = exec_node_data(ast_node, node, link);
@@ -618,12 +715,19 @@ ast_layout_expression::process_qualifier_constant(struct _mesa_glsl_parse_state
          return false;
       }
 
-      if (!first_pass && *value != const_int->value.u[0]) {
-         YYLTYPE loc = const_expression->get_location();
-         _mesa_glsl_error(&loc, state, "%s layout qualifier does not "
-                         "match previous declaration (%d vs %d)",
-                          qual_indentifier, *value, const_int->value.i[0]);
-         return false;
+      /* From section 4.4 "Layout Qualifiers" of the GLSL 4.50 spec:
+       * "When the same layout-qualifier-name occurs multiple times,
+       *  in a single declaration, the last occurrence overrides the
+       *  former occurrence(s)."
+       */
+      if (!first_pass) {
+         if ((must_match || !state->has_420pack()) && *value != const_int->value.u[0]) {
+            YYLTYPE loc = const_expression->get_location();
+            _mesa_glsl_error(&loc, state, "%s layout qualifier does not "
+                             "match previous declaration (%d vs %d)",
+                             qual_indentifier, *value, const_int->value.i[0]);
+            return false;
+         }
       } else {
          first_pass = false;
          *value = const_int->value.u[0];