glsl: add tessellation shader parsing support (v2)
v2: Fixed things that Ken suggested. Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
This commit is contained in:
parent
206af9d049
commit
497eb29583
|
@ -515,6 +515,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;
|
||||
|
@ -550,7 +561,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;
|
||||
|
||||
/**
|
||||
|
@ -577,6 +591,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.
|
||||
|
@ -632,6 +658,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.
|
||||
|
|
|
@ -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:
|
||||
|
@ -2231,6 +2232,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
|
||||
*/
|
||||
|
@ -2253,6 +2256,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))
|
||||
|
@ -2312,6 +2317,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;
|
||||
|
@ -2592,7 +2599,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))
|
||||
|
@ -3132,30 +3141,13 @@ process_initializer(ir_variable *var, ast_declaration *decl,
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
validate_layout_qualifier_vertex_count(struct _mesa_glsl_parse_state *state,
|
||||
YYLTYPE loc, ir_variable *var,
|
||||
unsigned num_vertices,
|
||||
unsigned *size,
|
||||
const char *var_category)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (var->type->is_unsized_array()) {
|
||||
/* Section 4.3.8.1 (Input Layout Qualifiers) of the GLSL 1.50 spec says:
|
||||
*
|
||||
|
@ -3165,6 +3157,8 @@ handle_geometry_shader_input_decl(struct _mesa_glsl_parse_state *state,
|
|||
*
|
||||
* Followed by a table mapping each allowed input layout qualifier to
|
||||
* the corresponding input length.
|
||||
*
|
||||
* Similarly for tessellation control shader outputs.
|
||||
*/
|
||||
if (num_vertices != 0)
|
||||
var->type = glsl_type::get_array_instance(var->type->fields.array,
|
||||
|
@ -3191,22 +3185,63 @@ handle_geometry_shader_input_decl(struct _mesa_glsl_parse_state *state,
|
|||
*/
|
||||
if (num_vertices != 0 && var->type->length != num_vertices) {
|
||||
_mesa_glsl_error(&loc, state,
|
||||
"geometry shader input size contradicts previously"
|
||||
" declared layout (size is %u, but layout requires a"
|
||||
" size of %u)", var->type->length, num_vertices);
|
||||
} else if (state->gs_input_size != 0 &&
|
||||
var->type->length != state->gs_input_size) {
|
||||
"%s size contradicts previously declared layout "
|
||||
"(size is %u, but layout requires a size of %u)",
|
||||
var_category, var->type->length, num_vertices);
|
||||
} else if (*size != 0 && var->type->length != *size) {
|
||||
_mesa_glsl_error(&loc, state,
|
||||
"geometry shader input sizes are "
|
||||
"inconsistent (size is %u, but a previous "
|
||||
"declaration has size %u)",
|
||||
var->type->length, state->gs_input_size);
|
||||
"%s sizes are inconsistent (size is %u, but a "
|
||||
"previous declaration has size %u)",
|
||||
var_category, var->type->length, *size);
|
||||
} else {
|
||||
state->gs_input_size = var->type->length;
|
||||
*size = var->type->length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
"geometry shader input");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
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 shader input");
|
||||
}
|
||||
|
||||
void
|
||||
validate_identifier(const char *identifier, YYLTYPE loc,
|
||||
|
@ -3796,6 +3831,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,
|
||||
|
@ -6058,6 +6097,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)
|
||||
|
|
|
@ -212,6 +212,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,
|
|||
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,
|
||||
|
@ -269,6 +323,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. */
|
||||
|
@ -324,7 +399,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;
|
||||
|
@ -346,6 +423,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) {
|
||||
|
|
|
@ -1385,6 +1385,89 @@ 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 ($$.flags.i &&
|
||||
!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 ($$.flags.i &&
|
||||
!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 ($$.flags.i &&
|
||||
!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 ($$.flags.i &&
|
||||
!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);
|
||||
|
@ -1522,6 +1605,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.
|
||||
*/
|
||||
|
@ -2743,11 +2850,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) {
|
||||
|
@ -2766,6 +2870,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;
|
||||
}
|
||||
|
|
|
@ -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.");
|
||||
|
@ -574,6 +582,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),
|
||||
|
@ -1420,8 +1429,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);
|
||||
}
|
||||
|
@ -1441,6 +1454,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)
|
||||
|
|
|
@ -277,15 +277,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;
|
||||
|
||||
/**
|
||||
|
@ -303,7 +307,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;
|
||||
|
||||
/**
|
||||
|
@ -383,6 +390,9 @@ struct _mesa_glsl_parse_state {
|
|||
|
||||
/* ARB_viewport_array */
|
||||
unsigned MaxViewports;
|
||||
|
||||
/* ARB_tessellation_shader */
|
||||
unsigned MaxPatchVertices;
|
||||
} Const;
|
||||
|
||||
/**
|
||||
|
@ -475,6 +485,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;
|
||||
|
@ -545,6 +557,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];
|
||||
|
||||
|
|
Loading…
Reference in New Issue