[Mesa-dev] [PATCH 20/46] glsl: add tessellation shader parsing support.
Marek Olšák
maraeo at gmail.com
Tue Jun 16 16:01:16 PDT 2015
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;
+ }
+ }
+}
+
+
+/**
+ * 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 */
+ { "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 &&
+ !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 &&
+ !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 &&
+ !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 &&
+ !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];
--
2.1.0
More information about the mesa-dev
mailing list