[Mesa-dev] [PATCH 20/46] glsl: add tessellation shader parsing support.

Kenneth Graunke kenneth at whitecape.org
Fri Jun 19 03:24:50 PDT 2015


On Wednesday, June 17, 2015 01:01:16 AM Marek Olšák wrote:
> From: Fabian Bieler <fabianbieler at fastmail.fm>
> 
> ---
>  src/glsl/ast.h                  |  54 +++++++++++++++-
>  src/glsl/ast_to_hir.cpp         | 133 +++++++++++++++++++++++++++++++++++++++-
>  src/glsl/ast_type.cpp           | 112 ++++++++++++++++++++++++++++++++-
>  src/glsl/glsl_parser.yy         | 118 +++++++++++++++++++++++++++++++++--
>  src/glsl/glsl_parser_extras.cpp |  39 +++++++++++-
>  src/glsl/glsl_parser_extras.h   |  31 ++++++++--
>  6 files changed, 471 insertions(+), 16 deletions(-)
> 
> diff --git a/src/glsl/ast.h b/src/glsl/ast.h
> index ef74e51..26ad3bf 100644
> --- a/src/glsl/ast.h
> +++ b/src/glsl/ast.h
> @@ -514,6 +514,17 @@ struct ast_type_qualifier {
>           unsigned stream:1; /**< Has stream value assigned  */
>           unsigned explicit_stream:1; /**< stream value assigned explicitly by shader code */
>           /** \} */
> +
> +	 /** \name Layout qualifiers for GL_ARB_tessellation_shader */
> +	 /** \{ */
> +	 /* tess eval input layout */
> +	 /* gs prim_type reused for primitive mode */
> +	 unsigned vertex_spacing:1;
> +	 unsigned ordering:1;
> +	 unsigned point_mode:1;
> +	 /* tess control output layout */
> +	 unsigned vertices:1;
> +	 /** \} */
>        }
>        /** \brief Set of flags, accessed by name. */
>        q;
> @@ -549,7 +560,10 @@ struct ast_type_qualifier {
>     /** Stream in GLSL 1.50 geometry shaders. */
>     unsigned stream;
>  
> -   /** Input or output primitive type in GLSL 1.50 geometry shaders */
> +   /**
> +    * Input or output primitive type in GLSL 1.50 geometry shaders
> +    * and tessellation shaders.
> +    */
>     GLenum prim_type;
>  
>     /**
> @@ -576,6 +590,18 @@ struct ast_type_qualifier {
>      */
>     int local_size[3];
>  
> +   /** Tessellation evaluation shader: vertex spacing (equal, fractional even/odd) */
> +   GLenum vertex_spacing;
> +
> +   /** Tessellation evaluation shader: vertex ordering (CW or CCW) */
> +   GLenum ordering;
> +
> +   /** Tessellation evaluation shader: point mode */
> +   bool point_mode;
> +
> +   /** Tessellation control shader: number of output vertices */
> +   int vertices;
> +
>     /**
>      * Image format specified with an ARB_shader_image_load_store
>      * layout qualifier.
> @@ -631,6 +657,11 @@ struct ast_type_qualifier {
>  			_mesa_glsl_parse_state *state,
>  			ast_type_qualifier q);
>  
> +   bool merge_out_qualifier(YYLTYPE *loc,
> +                           _mesa_glsl_parse_state *state,
> +                           ast_type_qualifier q,
> +                           ast_node* &node);
> +
>     bool merge_in_qualifier(YYLTYPE *loc,
>                             _mesa_glsl_parse_state *state,
>                             ast_type_qualifier q,
> @@ -1031,6 +1062,27 @@ public:
>  
>  
>  /**
> + * AST node representing a declaration of the output layout for tessellation
> + * control shaders.
> + */
> +class ast_tcs_output_layout : public ast_node
> +{
> +public:
> +   ast_tcs_output_layout(const struct YYLTYPE &locp, int vertices)
> +      : vertices(vertices)
> +   {
> +      set_location(locp);
> +   }
> +
> +   virtual ir_rvalue *hir(exec_list *instructions,
> +                          struct _mesa_glsl_parse_state *state);
> +
> +private:
> +   const int vertices;
> +};
> +
> +
> +/**
>   * AST node representing a declaration of the input layout for geometry
>   * shaders.
>   */
> diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
> index 259e01e..53daf13 100644
> --- a/src/glsl/ast_to_hir.cpp
> +++ b/src/glsl/ast_to_hir.cpp
> @@ -79,6 +79,7 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
>     state->toplevel_ir = instructions;
>  
>     state->gs_input_prim_type_specified = false;
> +   state->tcs_output_vertices_specified = false;
>     state->cs_input_local_size_specified = false;
>  
>     /* Section 4.2 of the GLSL 1.20 specification states:
> @@ -2205,6 +2206,8 @@ validate_explicit_location(const struct ast_type_qualifier *qual,
>      *                     input            output
>      *                     -----            ------
>      * vertex              explicit_loc     sso
> +    * tess control        sso              sso
> +    * tess eval           sso              sso
>      * geometry            sso              sso
>      * fragment            sso              explicit_loc
>      */
> @@ -2227,6 +2230,8 @@ validate_explicit_location(const struct ast_type_qualifier *qual,
>        fail = true;
>        break;
>  
> +   case MESA_SHADER_TESS_CTRL:
> +   case MESA_SHADER_TESS_EVAL:
>     case MESA_SHADER_GEOMETRY:
>        if (var->data.mode == ir_var_shader_in || var->data.mode == ir_var_shader_out) {
>           if (!state->check_separate_shader_objects_allowed(loc, var))
> @@ -2286,6 +2291,8 @@ validate_explicit_location(const struct ast_type_qualifier *qual,
>                 : (qual->location + VARYING_SLOT_VAR0);
>              break;
>  
> +         case MESA_SHADER_TESS_CTRL:
> +         case MESA_SHADER_TESS_EVAL:
>           case MESA_SHADER_GEOMETRY:
>              var->data.location = qual->location + VARYING_SLOT_VAR0;
>              break;
> @@ -2564,7 +2571,9 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
>        case MESA_SHADER_VERTEX:
>           if (var->data.mode == ir_var_shader_out)
>              var->data.invariant = true;
> -	      break;
> +         break;
> +      case MESA_SHADER_TESS_CTRL:
> +      case MESA_SHADER_TESS_EVAL:
>        case MESA_SHADER_GEOMETRY:
>           if ((var->data.mode == ir_var_shader_in)
>               || (var->data.mode == ir_var_shader_out))
> @@ -3101,6 +3110,63 @@ process_initializer(ir_variable *var, ast_declaration *decl,
>   * (this covers both interface blocks arrays and bare input variables).
>   */
>  static void
> +handle_tess_ctrl_shader_output_decl(struct _mesa_glsl_parse_state *state,
> +                                       YYLTYPE loc, ir_variable *var)
> +{
> +   unsigned num_vertices = 0;
> +
> +   if (state->tcs_output_vertices_specified) {
> +      num_vertices = state->out_qualifier->vertices;
> +   }
> +
> +   if (var->type->is_unsized_array()) {
> +      if (num_vertices != 0)
> +         var->type = glsl_type::get_array_instance(var->type->fields.array,
> +                                                   num_vertices);
> +   } else {
> +      /* Section 4.3.8.1 (Input Layout Qualifiers) of the GLSL 1.50 spec
> +       * includes the following examples of compile-time errors:
> +       *
> +       *   // code sequence within one shader...
> +       *   in vec4 Color1[];    // size unknown
> +       *   ...Color1.length()...// illegal, length() unknown
> +       *   in vec4 Color2[2];   // size is 2
> +       *   ...Color1.length()...// illegal, Color1 still has no size
> +       *   in vec4 Color3[3];   // illegal, input sizes are inconsistent
> +       *   layout(lines) in;    // legal, input size is 2, matching
> +       *   in vec4 Color4[3];   // illegal, contradicts layout
> +       *   ...
> +       *
> +       * To detect the case illustrated by Color3, we verify that the size of
> +       * an explicitly-sized array matches the size of any previously declared
> +       * explicitly-sized array.  To detect the case illustrated by Color4, we
> +       * verify that the size of an explicitly-sized array is consistent with
> +       * any previously declared input layout.
> +       */
> +      if (num_vertices != 0 && var->type->length != num_vertices) {
> +         _mesa_glsl_error(&loc, state,
> +               "tessellation control shader output size contradicts "
> +               "previously declared layout (size is %u, but layout specifies "
> +               "a size of %u)", var->type->length, num_vertices);
> +      } else if (state->tcs_output_size != 0 &&
> +            var->type->length != state->tcs_output_size) {
> +         _mesa_glsl_error(&loc, state,
> +               "tessellation control shader output sizes are "
> +               "inconsistent (size is %u, but a previous "
> +               "declaration has size %u)",
> +               var->type->length, state->tcs_output_size);
> +      } else {
> +         state->tcs_output_size = var->type->length;
> +      }
> +   }
> +}

This is an unfortunate amount of copy and pasted code from
handle_geometry_shader_input_decl()...it seems like a better solution
would be to make a helper:

static void
validate_layout_qualifier_vertex_count(struct _mesa_glsl_parse_state *state,
                                       YYLTYPE loc, ir_variable *var,
                                       unsigned num_vertices,
                                       unsigned *size,
                                       const char *stage_name)
{
    ...the bulk of this code, but with *size instead of state->tcs_output_size or state->gs_input_size...
}

static void
handle_geometry_shader_input_decl(struct _mesa_glsl_parse_state *state,
                                  YYLTYPE loc, ir_variable *var)
{
   unsigned num_vertices = 0;
   if (state->gs_input_prim_type_specified) {
      num_vertices = vertices_per_prim(state->in_qualifier->prim_type);
   }

   /* Geometry shader input variables must be arrays.  Caller should have
    * reported an error for this.
    */
   if (!var->type->is_array()) {
      assert(state->error);

      /* To avoid cascading failures, short circuit the checks below. */
      return;
   }

   validate_layout_qualifier_vertex_count(state, loc, var, num_vertices,
                                          &state->gs_input_size, "geometry");
}

static void
handle_tess_ctrl_shader_output_decl(struct _mesa_glsl_parse_state *state,
                                       YYLTYPE loc, ir_variable *var)
{
   unsigned num_vertices = 0;

   if (state->tcs_output_vertices_specified) {
      num_vertices = state->out_qualifier->vertices;
   }

   validate_layout_qualifier_vertex_count(state, loc, var, num_vertices,
                                          &state->tcs_output_size,
                                          "tessellation control");
}

> +
> +
> +/**
> + * Do additional processing necessary for geometry shader input declarations
> + * (this covers both interface blocks arrays and bare input variables).
> + */
> +static void
>  handle_geometry_shader_input_decl(struct _mesa_glsl_parse_state *state,
>                                    YYLTYPE loc, ir_variable *var)
>  {
> @@ -3747,6 +3813,10 @@ ast_declarator_list::hir(exec_list *instructions,
>                 }
>              }
>           }
> +
> +         if (state->stage == MESA_SHADER_TESS_CTRL) {
> +            handle_tess_ctrl_shader_output_decl(state, loc, var);
> +         }
>        }
>  
>        /* Integer fragment inputs must be qualified with 'flat'.  In GLSL ES,
> @@ -6007,6 +6077,67 @@ ast_interface_block::hir(exec_list *instructions,
>  
>  
>  ir_rvalue *
> +ast_tcs_output_layout::hir(exec_list *instructions,
> +			  struct _mesa_glsl_parse_state *state)
> +{
> +   YYLTYPE loc = this->get_location();
> +
> +   /* If any tessellation control output layout declaration preceded this
> +    * one, make sure it was consistent with this one.
> +    */
> +   if (state->tcs_output_vertices_specified &&
> +       state->out_qualifier->vertices != this->vertices) {
> +      _mesa_glsl_error(&loc, state,
> +		       "tessellation control shader output layout does not "
> +		       "match previous declaration");
> +      return NULL;
> +   }
> +
> +   /* If any shader outputs occurred before this declaration and specified an
> +    * array size, make sure the size they specified is consistent with the
> +    * primitive type.
> +    */
> +   unsigned num_vertices = this->vertices;
> +   if (state->tcs_output_size != 0 && state->tcs_output_size != num_vertices) {
> +      _mesa_glsl_error(&loc, state,
> +		       "this tessellation control shader output layout "
> +		       "specifies %u vertices, but a previous output "
> +		       "is declared with size %u",
> +		       num_vertices, state->tcs_output_size);
> +      return NULL;
> +   }
> +
> +   state->tcs_output_vertices_specified = true;
> +
> +   /* If any shader outputs occurred before this declaration and did not
> +    * specify an array size, their size is determined now.
> +    */
> +   foreach_in_list (ir_instruction, node, instructions) {
> +      ir_variable *var = node->as_variable();
> +      if (var == NULL || var->data.mode != ir_var_shader_out)
> +	 continue;
> +
> +      /* Note: Not all tessellation control shader output are arrays. */
> +      if (!var->type->is_unsized_array())
> +	 continue;
> +
> +      if (var->data.max_array_access >= num_vertices) {
> +	 _mesa_glsl_error(&loc, state,
> +			  "this tessellation control shader output layout "
> +			  "specifies %u vertices, but an access to element "
> +			  "%u of output `%s' already exists", num_vertices,
> +			  var->data.max_array_access, var->name);
> +      } else {
> +	 var->type = glsl_type::get_array_instance(var->type->fields.array,
> +						   num_vertices);
> +      }
> +   }
> +
> +   return NULL;
> +}
> +
> +
> +ir_rvalue *
>  ast_gs_input_layout::hir(exec_list *instructions,
>                           struct _mesa_glsl_parse_state *state)
>  {
> diff --git a/src/glsl/ast_type.cpp b/src/glsl/ast_type.cpp
> index 1bcf6a2..5bebaab 100644
> --- a/src/glsl/ast_type.cpp
> +++ b/src/glsl/ast_type.cpp
> @@ -211,6 +211,44 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
>        }
>     }
>  
> +   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)
> @@ -256,6 +294,22 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
>  }
>  
>  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,
>                                         ast_type_qualifier q,
> @@ -268,6 +322,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. */
> @@ -323,7 +398,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;
> @@ -345,6 +422,39 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
>        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) {
> diff --git a/src/glsl/glsl_parser.yy b/src/glsl/glsl_parser.yy
> index 3ce9e10..eaf0dd6 100644
> --- a/src/glsl/glsl_parser.yy
> +++ b/src/glsl/glsl_parser.yy
> @@ -1385,6 +1385,85 @@ layout_qualifier_id:
>           }
>        }
>  
> +      /* Layout qualifiers for tessellation evaluation shaders. */
> +      if (!$$.flags.i) {
> +         struct {
> +            const char *s;
> +            GLenum e;
> +         } map[] = {
> +                 /* triangles already parsed by gs-specific code */

I suppose the point of this is to avoid hitting the "You need
ARB_tessellation_shader enabled in your" shader check when using
"triangles" for the GS.  Seems OK.  Alternatively, we could probably
handle it here for completeness, but move the GS block above this one.

I don't really have a preference.

> +                 { "quads", GL_QUADS },
> +                 { "isolines", GL_ISOLINES },
> +         };
> +         for (unsigned i = 0; i < ARRAY_SIZE(map); i++) {
> +            if (match_layout_qualifier($1, map[i].s, state) == 0) {
> +               $$.flags.q.prim_type = 1;
> +               $$.prim_type = map[i].e;
> +               break;
> +            }
> +         }
> +
> +         if (!state->ARB_tessellation_shader_enable &&

Won't this trigger regardless if whether we matched any qualifiers?
The existing geometry shader code does: if ($$.flags.i && ...)
i.e. it only triggers if we actually matched something in this block.

> +             !state->is_version(400, 0)) {
> +            _mesa_glsl_error(& @1, state,
> +                             "primitive mode qualifier `%s' requires "
> +                             "GLSL 4.00 or ARB_tessellation_shader", $1);
> +         }
> +      }
> +      if (!$$.flags.i) {
> +         struct {
> +            const char *s;
> +            GLenum e;
> +         } map[] = {
> +                 { "equal_spacing", GL_EQUAL },
> +                 { "fractional_odd_spacing", GL_FRACTIONAL_ODD },
> +                 { "fractional_even_spacing", GL_FRACTIONAL_EVEN },
> +         };
> +         for (unsigned i = 0; i < ARRAY_SIZE(map); i++) {
> +            if (match_layout_qualifier($1, map[i].s, state) == 0) {
> +               $$.flags.q.vertex_spacing = 1;
> +               $$.vertex_spacing = map[i].e;
> +               break;
> +            }
> +         }
> +
> +         if (!state->ARB_tessellation_shader_enable &&

Same concern here.

> +             !state->is_version(400, 0)) {
> +            _mesa_glsl_error(& @1, state,
> +                             "vertex spacing qualifier `%s' requires "
> +                             "GLSL 4.00 or ARB_tessellation_shader", $1);
> +         }
> +      }
> +      if (!$$.flags.i) {
> +         if (match_layout_qualifier($1, "cw", state) == 0) {
> +            $$.flags.q.ordering = 1;
> +            $$.ordering = GL_CW;
> +         } else if (match_layout_qualifier($1, "ccw", state) == 0) {
> +            $$.flags.q.ordering = 1;
> +            $$.ordering = GL_CCW;
> +         }
> +
> +         if (!state->ARB_tessellation_shader_enable &&

Same concern here.

> +             !state->is_version(400, 0)) {
> +            _mesa_glsl_error(& @1, state,
> +                             "ordering qualifier `%s' requires "
> +                             "GLSL 4.00 or ARB_tessellation_shader", $1);
> +         }
> +      }
> +      if (!$$.flags.i) {
> +         if (match_layout_qualifier($1, "point_mode", state) == 0) {
> +            $$.flags.q.point_mode = 1;
> +            $$.point_mode = true;
> +         }
> +
> +         if (!state->ARB_tessellation_shader_enable &&

Same concern here.

Otherwise, this patch looks OK to me.  ast_to_hir is generally a
horrible mess, so it's hard to tell, but I think Fabian's done basically
the right stuff.

> +             !state->is_version(400, 0)) {
> +            _mesa_glsl_error(& @1, state,
> +                             "qualifier `point_mode' requires "
> +                             "GLSL 4.00 or ARB_tessellation_shader");
> +         }
> +      }
> +
>        if (!$$.flags.i) {
>           _mesa_glsl_error(& @1, state, "unrecognized layout identifier "
>                            "`%s'", $1);
> @@ -1521,6 +1600,30 @@ layout_qualifier_id:
>           }
>        }
>  
> +      /* Layout qualifiers for tessellation control shaders. */
> +      if (match_layout_qualifier("vertices", $1, state) == 0) {
> +         $$.flags.q.vertices = 1;
> +
> +         if ($3 <= 0) {
> +            _mesa_glsl_error(& @3, state,
> +                             "invalid vertices (%d) specified", $3);
> +            YYERROR;
> +         } else if ($3 > (int)state->Const.MaxPatchVertices) {
> +            _mesa_glsl_error(& @3, state,
> +                             "vertices (%d) exceeds "
> +                             "GL_MAX_PATCH_VERTICES", $3);
> +            YYERROR;
> +         } else {
> +            $$.vertices = $3;
> +            if (!state->ARB_tessellation_shader_enable &&
> +                !state->is_version(400, 0)) {
> +               _mesa_glsl_error(& @1, state,
> +                                "vertices qualifier requires GLSL 4.00 or "
> +                                "ARB_tessellation_shader");
> +            }
> +         }
> +      }
> +
>        /* If the identifier didn't match any known layout identifiers,
>         * emit an error.
>         */
> @@ -2720,11 +2823,8 @@ layout_defaults:
>  
>     | layout_qualifier OUT_TOK ';'
>     {
> -      if (state->stage != MESA_SHADER_GEOMETRY) {
> -         _mesa_glsl_error(& @1, state,
> -                          "out layout qualifiers only valid in "
> -                          "geometry shaders");
> -      } else {
> +      $$ = NULL;
> +      if (state->stage == MESA_SHADER_GEOMETRY) {
>           if ($1.flags.q.prim_type) {
>              /* Make sure this is a valid output primitive type. */
>              switch ($1.prim_type) {
> @@ -2743,6 +2843,12 @@ layout_defaults:
>  
>           /* Allow future assigments of global out's stream id value */
>           state->out_qualifier->flags.q.explicit_stream = 0;
> +      } else if (state->stage == MESA_SHADER_TESS_CTRL) {
> +         if (!state->out_qualifier->merge_out_qualifier(& @1, state, $1, $$))
> +            YYERROR;
> +      } else {
> +         _mesa_glsl_error(& @1, state,
> +                          "out layout qualifiers only valid in "
> +                          "tessellation control or geometry shaders");
>        }
> -      $$ = NULL;
>     }
> diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp
> index 046d5d7..6f59022 100644
> --- a/src/glsl/glsl_parser_extras.cpp
> +++ b/src/glsl/glsl_parser_extras.cpp
> @@ -145,6 +145,9 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
>     /* ARB_viewport_array */
>     this->Const.MaxViewports = ctx->Const.MaxViewports;
>  
> +   /* tessellation shader constants */
> +   this->Const.MaxPatchVertices = ctx->Const.MaxPatchVertices;
> +
>     this->current_function = NULL;
>     this->toplevel_ir = NULL;
>     this->found_return = false;
> @@ -224,6 +227,7 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
>     this->fs_redeclares_gl_fragcoord_with_no_layout_qualifiers = false;
>  
>     this->gs_input_prim_type_specified = false;
> +   this->tcs_output_vertices_specified = false;
>     this->gs_input_size = 0;
>     this->in_qualifier = new(this) ast_type_qualifier();
>     this->out_qualifier = new(this) ast_type_qualifier();
> @@ -389,6 +393,8 @@ _mesa_shader_stage_to_string(unsigned stage)
>     case MESA_SHADER_FRAGMENT: return "fragment";
>     case MESA_SHADER_GEOMETRY: return "geometry";
>     case MESA_SHADER_COMPUTE:  return "compute";
> +   case MESA_SHADER_TESS_CTRL: return "tess ctrl";
> +   case MESA_SHADER_TESS_EVAL: return "tess eval";
>     }
>  
>     unreachable("Unknown shader stage.");
> @@ -406,6 +412,8 @@ _mesa_shader_stage_to_abbrev(unsigned stage)
>     case MESA_SHADER_FRAGMENT: return "FS";
>     case MESA_SHADER_GEOMETRY: return "GS";
>     case MESA_SHADER_COMPUTE:  return "CS";
> +   case MESA_SHADER_TESS_CTRL: return "TCS";
> +   case MESA_SHADER_TESS_EVAL: return "TES";
>     }
>  
>     unreachable("Unknown shader stage.");
> @@ -573,6 +581,7 @@ static const _mesa_glsl_extension _mesa_glsl_supported_extensions[] = {
>     EXT(ARB_shader_texture_lod,         true,  false,     ARB_shader_texture_lod),
>     EXT(ARB_shading_language_420pack,   true,  false,     ARB_shading_language_420pack),
>     EXT(ARB_shading_language_packing,   true,  false,     ARB_shading_language_packing),
> +   EXT(ARB_tessellation_shader,        true,  false,     ARB_tessellation_shader),
>     EXT(ARB_texture_cube_map_array,     true,  false,     ARB_texture_cube_map_array),
>     EXT(ARB_texture_gather,             true,  false,     ARB_texture_gather),
>     EXT(ARB_texture_multisample,        true,  false,     ARB_texture_multisample),
> @@ -1417,8 +1426,12 @@ static void
>  set_shader_inout_layout(struct gl_shader *shader,
>  		     struct _mesa_glsl_parse_state *state)
>  {
> -   if (shader->Stage != MESA_SHADER_GEOMETRY) {
> -      /* Should have been prevented by the parser. */
> +   /* Should have been prevented by the parser. */
> +   if (shader->Stage == MESA_SHADER_TESS_CTRL) {
> +      assert(!state->in_qualifier->flags.i);
> +   } else if (shader->Stage == MESA_SHADER_TESS_EVAL) {
> +      assert(!state->out_qualifier->flags.i);
> +   } else if (shader->Stage != MESA_SHADER_GEOMETRY) {
>        assert(!state->in_qualifier->flags.i);
>        assert(!state->out_qualifier->flags.i);
>     }
> @@ -1438,6 +1451,28 @@ set_shader_inout_layout(struct gl_shader *shader,
>     }
>  
>     switch (shader->Stage) {
> +   case MESA_SHADER_TESS_CTRL:
> +      shader->TessCtrl.VerticesOut = 0;
> +      if (state->tcs_output_vertices_specified)
> +         shader->TessCtrl.VerticesOut = state->out_qualifier->vertices;
> +      break;
> +   case MESA_SHADER_TESS_EVAL:
> +      shader->TessEval.PrimitiveMode = PRIM_UNKNOWN;
> +      if (state->in_qualifier->flags.q.prim_type)
> +         shader->TessEval.PrimitiveMode = state->in_qualifier->prim_type;
> +
> +      shader->TessEval.Spacing = 0;
> +      if (state->in_qualifier->flags.q.vertex_spacing)
> +         shader->TessEval.Spacing = state->in_qualifier->vertex_spacing;
> +
> +      shader->TessEval.VertexOrder = 0;
> +      if (state->in_qualifier->flags.q.ordering)
> +         shader->TessEval.VertexOrder = state->in_qualifier->ordering;
> +
> +      shader->TessEval.PointMode = -1;
> +      if (state->in_qualifier->flags.q.point_mode)
> +         shader->TessEval.PointMode = state->in_qualifier->point_mode;
> +      break;
>     case MESA_SHADER_GEOMETRY:
>        shader->Geom.VerticesOut = 0;
>        if (state->out_qualifier->flags.q.max_vertices)
> diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h
> index 9a0c24e..7226a55 100644
> --- a/src/glsl/glsl_parser_extras.h
> +++ b/src/glsl/glsl_parser_extras.h
> @@ -272,15 +272,19 @@ struct _mesa_glsl_parse_state {
>     bool fs_redeclares_gl_fragcoord_with_no_layout_qualifiers;
>  
>     /**
> -    * True if a geometry shader input primitive type was specified using a
> -    * layout directive.
> +    * True if a geometry shader input primitive type or tessellation control
> +    * output vertices were specified using a layout directive.
>      *
> -    * Note: this value is computed at ast_to_hir time rather than at parse
> +    * Note: these values are computed at ast_to_hir time rather than at parse
>      * time.
>      */
>     bool gs_input_prim_type_specified;
> +   bool tcs_output_vertices_specified;
>  
> -   /** Input layout qualifiers from GLSL 1.50. (geometry shader controls)*/
> +   /**
> +    * Input layout qualifiers from GLSL 1.50 (geometry shader controls),
> +    * and GLSL 4.00 (tessellation evaluation shader)
> +    */
>     struct ast_type_qualifier *in_qualifier;
>  
>     /**
> @@ -298,7 +302,10 @@ struct _mesa_glsl_parse_state {
>      */
>     unsigned cs_input_local_size[3];
>  
> -   /** Output layout qualifiers from GLSL 1.50. (geometry shader controls)*/
> +   /**
> +    * Output layout qualifiers from GLSL 1.50 (geometry shader controls),
> +    * and GLSL 4.00 (tessellation control shader).
> +    */
>     struct ast_type_qualifier *out_qualifier;
>  
>     /**
> @@ -378,6 +385,9 @@ struct _mesa_glsl_parse_state {
>  
>        /* ARB_viewport_array */
>        unsigned MaxViewports;
> +
> +      /* ARB_tessellation_shader */
> +      unsigned MaxPatchVertices;
>     } Const;
>  
>     /**
> @@ -468,6 +478,8 @@ struct _mesa_glsl_parse_state {
>     bool ARB_shading_language_420pack_warn;
>     bool ARB_shading_language_packing_enable;
>     bool ARB_shading_language_packing_warn;
> +   bool ARB_tessellation_shader_enable;
> +   bool ARB_tessellation_shader_warn;
>     bool ARB_texture_cube_map_array_enable;
>     bool ARB_texture_cube_map_array_warn;
>     bool ARB_texture_gather_enable;
> @@ -538,6 +550,15 @@ struct _mesa_glsl_parse_state {
>  
>     bool fs_early_fragment_tests;
>  
> +   /**
> +    * For tessellation control shaders, size of the most recently seen output
> +    * declaration that was a sized array, or 0 if no sized output array
> +    * declarations have been seen.
> +    *
> +    * Unused for other shader types.
> +    */
> +   unsigned tcs_output_size;
> +
>     /** Atomic counter offsets by binding */
>     unsigned atomic_counter_offsets[MAX_COMBINED_ATOMIC_BUFFERS];
>  
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20150619/3e05baf5/attachment-0001.sig>


More information about the mesa-dev mailing list