Merge branch 'nir-spirv' into vulkan
[mesa.git] / src / glsl / ast_type.cpp
index 0ee2c495aa4fa4f5f8a45badfa9df3cfb96c0991..892122af03d04050bd24aa3dcb0275f5847c77a8 100644 (file)
@@ -40,7 +40,12 @@ ast_type_specifier::print(void) const
 bool
 ast_fully_specified_type::has_qualifiers() const
 {
-   return this->qualifier.flags.i != 0;
+   /* 'subroutine' isnt a real qualifier. */
+   ast_type_qualifier subroutine_only;
+   subroutine_only.flags.i = 0;
+   subroutine_only.flags.q.subroutine = 1;
+   subroutine_only.flags.q.subroutine_def = 1;
+   return (this->qualifier.flags.i & ~subroutine_only.flags.i) != 0;
 }
 
 bool ast_type_qualifier::has_interpolation() const
@@ -78,14 +83,16 @@ ast_type_qualifier::has_storage() const
           || this->flags.q.varying
           || this->flags.q.in
           || this->flags.q.out
-          || this->flags.q.uniform;
+          || this->flags.q.uniform
+          || this->flags.q.buffer;
 }
 
 bool
 ast_type_qualifier::has_auxiliary_storage() const
 {
    return this->flags.q.centroid
-          || this->flags.q.sample;
+          || this->flags.q.sample
+          || this->flags.q.patch;
 }
 
 const char*
@@ -122,14 +129,28 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
    ubo_binding_mask.flags.q.explicit_binding = 1;
    ubo_binding_mask.flags.q.explicit_offset = 1;
 
+   ast_type_qualifier stream_layout_mask;
+   stream_layout_mask.flags.i = 0;
+   stream_layout_mask.flags.q.stream = 1;
+
    /* Uniform block layout qualifiers get to overwrite each
     * other (rightmost having priority), while all other
     * qualifiers currently don't allow duplicates.
     */
+   ast_type_qualifier allowed_duplicates_mask;
+   allowed_duplicates_mask.flags.i =
+      ubo_mat_mask.flags.i |
+      ubo_layout_mask.flags.i |
+      ubo_binding_mask.flags.i;
+
+   /* Geometry shaders can have several layout qualifiers
+    * assigning different stream values.
+    */
+   if (state->stage == MESA_SHADER_GEOMETRY)
+      allowed_duplicates_mask.flags.i |=
+         stream_layout_mask.flags.i;
 
-   if ((this->flags.i & q.flags.i & ~(ubo_mat_mask.flags.i |
-                                     ubo_layout_mask.flags.i |
-                                      ubo_binding_mask.flags.i)) != 0) {
+   if ((this->flags.i & q.flags.i & ~allowed_duplicates_mask.flags.i) != 0) {
       _mesa_glsl_error(loc, state,
                       "duplicate layout qualifiers used");
       return false;
@@ -154,6 +175,87 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
       this->max_vertices = q.max_vertices;
    }
 
+   if (q.flags.q.invocations) {
+      if (this->flags.q.invocations && this->invocations != q.invocations) {
+         _mesa_glsl_error(loc, state,
+                          "geometry shader set conflicting invocations "
+                          "(%d and %d)", this->invocations, q.invocations);
+         return false;
+      }
+      this->invocations = q.invocations;
+   }
+
+   if (state->stage == MESA_SHADER_GEOMETRY &&
+       state->has_explicit_attrib_stream()) {
+      if (q.flags.q.stream && q.stream >= state->ctx->Const.MaxVertexStreams) {
+         _mesa_glsl_error(loc, state,
+                          "`stream' value is larger than MAX_VERTEX_STREAMS - 1 "
+                          "(%d > %d)",
+                          q.stream, state->ctx->Const.MaxVertexStreams - 1);
+      }
+      if (this->flags.q.explicit_stream &&
+          this->stream >= state->ctx->Const.MaxVertexStreams) {
+         _mesa_glsl_error(loc, state,
+                          "`stream' value is larger than MAX_VERTEX_STREAMS - 1 "
+                          "(%d > %d)",
+                          this->stream, state->ctx->Const.MaxVertexStreams - 1);
+      }
+
+      if (!this->flags.q.explicit_stream) {
+         if (q.flags.q.stream) {
+            this->flags.q.stream = 1;
+            this->stream = q.stream;
+         } else if (!this->flags.q.stream && this->flags.q.out) {
+            /* Assign default global stream value */
+            this->flags.q.stream = 1;
+            this->stream = state->out_qualifier->stream;
+         }
+      } else {
+         if (q.flags.q.explicit_stream) {
+            _mesa_glsl_error(loc, state,
+                             "duplicate layout `stream' qualifier");
+         }
+      }
+   }
+
+   if (q.flags.q.vertices) {
+      if (this->flags.q.vertices && this->vertices != q.vertices) {
+        _mesa_glsl_error(loc, state,
+                         "tessellation control shader set conflicting "
+                         "vertices (%d and %d)",
+                         this->vertices, q.vertices);
+        return false;
+      }
+      this->vertices = q.vertices;
+   }
+
+   if (q.flags.q.vertex_spacing) {
+      if (this->flags.q.vertex_spacing && this->vertex_spacing != q.vertex_spacing) {
+        _mesa_glsl_error(loc, state,
+                         "conflicting vertex spacing used");
+        return false;
+      }
+      this->vertex_spacing = q.vertex_spacing;
+   }
+
+   if (q.flags.q.ordering) {
+      if (this->flags.q.ordering && this->ordering != q.ordering) {
+        _mesa_glsl_error(loc, state,
+                         "conflicting ordering used");
+        return false;
+      }
+      this->ordering = q.ordering;
+   }
+
+   if (q.flags.q.point_mode) {
+      if (this->flags.q.point_mode && this->point_mode != q.point_mode) {
+        _mesa_glsl_error(loc, state,
+                         "conflicting point mode used");
+        return false;
+      }
+      this->point_mode = q.point_mode;
+   }
+
    if ((q.flags.i & ubo_mat_mask.flags.i) != 0)
       this->flags.i &= ~ubo_mat_mask.flags.i;
    if ((q.flags.i & ubo_layout_mask.flags.i) != 0)
@@ -195,9 +297,30 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
       this->image_base_type = q.image_base_type;
    }
 
+   if (q.flags.q.vk_set) {
+      this->set = q.set;
+      this->binding = q.binding;
+   }
+
    return true;
 }
 
+bool
+ast_type_qualifier::merge_out_qualifier(YYLTYPE *loc,
+                                        _mesa_glsl_parse_state *state,
+                                        ast_type_qualifier q,
+                                        ast_node* &node)
+{
+   void *mem_ctx = state;
+   const bool r = this->merge_qualifier(loc, state, q);
+
+   if (state->stage == MESA_SHADER_TESS_CTRL) {
+      node = new(mem_ctx) ast_tcs_output_layout(*loc, q.vertices);
+   }
+
+   return r;
+}
+
 bool
 ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
                                        _mesa_glsl_parse_state *state,
@@ -211,6 +334,27 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
    valid_in_mask.flags.i = 0;
 
    switch (state->stage) {
+   case MESA_SHADER_TESS_EVAL:
+      if (q.flags.q.prim_type) {
+         /* Make sure this is a valid input primitive type. */
+         switch (q.prim_type) {
+         case GL_TRIANGLES:
+         case GL_QUADS:
+         case GL_ISOLINES:
+            break;
+         default:
+            _mesa_glsl_error(loc, state,
+                             "invalid tessellation evaluation "
+                             "shader input primitive type");
+            break;
+         }
+      }
+
+      valid_in_mask.flags.q.prim_type = 1;
+      valid_in_mask.flags.q.vertex_spacing = 1;
+      valid_in_mask.flags.q.ordering = 1;
+      valid_in_mask.flags.q.point_mode = 1;
+      break;
    case MESA_SHADER_GEOMETRY:
       if (q.flags.q.prim_type) {
          /* Make sure this is a valid input primitive type. */
@@ -236,18 +380,14 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
       valid_in_mask.flags.q.invocations = 1;
       break;
    case MESA_SHADER_FRAGMENT:
-      if (q.flags.q.early_fragment_tests) {
-         state->early_fragment_tests = true;
-      } else {
-         _mesa_glsl_error(loc, state, "invalid input layout qualifier");
-      }
+      valid_in_mask.flags.q.early_fragment_tests = 1;
       break;
    case MESA_SHADER_COMPUTE:
       create_cs_ast |=
          q.flags.q.local_size != 0 &&
          state->in_qualifier->flags.q.local_size == 0;
 
-      valid_in_mask.flags.q.local_size = 1;
+      valid_in_mask.flags.q.local_size = 7;
       break;
    default:
       _mesa_glsl_error(loc, state,
@@ -270,7 +410,9 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
       if (q.flags.q.prim_type &&
           this->prim_type != q.prim_type) {
          _mesa_glsl_error(loc, state,
-                          "conflicting input primitive types specified");
+                          "conflicting input primitive %s specified",
+                          state->stage == MESA_SHADER_GEOMETRY ?
+                          "type" : "mode");
       }
    } else if (q.flags.q.prim_type) {
       state->in_qualifier->flags.q.prim_type = 1;
@@ -288,6 +430,43 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
       this->invocations = q.invocations;
    }
 
+   if (q.flags.q.early_fragment_tests) {
+      state->fs_early_fragment_tests = true;
+   }
+
+   if (this->flags.q.vertex_spacing) {
+      if (q.flags.q.vertex_spacing &&
+          this->vertex_spacing != q.vertex_spacing) {
+         _mesa_glsl_error(loc, state,
+                          "conflicting vertex spacing specified");
+      }
+   } else if (q.flags.q.vertex_spacing) {
+      this->flags.q.vertex_spacing = 1;
+      this->vertex_spacing = q.vertex_spacing;
+   }
+
+   if (this->flags.q.ordering) {
+      if (q.flags.q.ordering &&
+          this->ordering != q.ordering) {
+         _mesa_glsl_error(loc, state,
+                          "conflicting ordering specified");
+      }
+   } else if (q.flags.q.ordering) {
+      this->flags.q.ordering = 1;
+      this->ordering = q.ordering;
+   }
+
+   if (this->flags.q.point_mode) {
+      if (q.flags.q.point_mode &&
+          this->point_mode != q.point_mode) {
+         _mesa_glsl_error(loc, state,
+                          "conflicting point mode specified");
+      }
+   } else if (q.flags.q.point_mode) {
+      this->flags.q.point_mode = 1;
+      this->point_mode = q.point_mode;
+   }
+
    if (create_gs_ast) {
       node = new(mem_ctx) ast_gs_input_layout(*loc, q.prim_type);
    } else if (create_cs_ast) {