glsl: add support for complie-time constant expressions
This patch replaces the old interger constant qualifiers with either the new ast_layout_expression type if the qualifier requires merging or ast_expression if the qualifier can't have mulitple declarations or if all but the newest qualifier is simply ignored. We also update the process_qualifier_constant() helper to be similar to the one in the ast_layout_expression class, but in this case it will be used to process the ast_expression qualifiers. Global shader layout qualifier validation is moved out of the parser in this change as we now need to evaluate any constant expression before doing the validation. V2: Fix minimum value check for vertices (Emil) Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
This commit is contained in:
committed by
Timothy Arceri
parent
0954b813a3
commit
02d2ab2378
+16
-17
@@ -578,7 +578,7 @@ struct ast_type_qualifier {
|
||||
unsigned precision:2;
|
||||
|
||||
/** Geometry shader invocations for GL_ARB_gpu_shader5. */
|
||||
int invocations;
|
||||
ast_layout_expression *invocations;
|
||||
|
||||
/**
|
||||
* Location specified via GL_ARB_explicit_attrib_location layout
|
||||
@@ -586,20 +586,20 @@ struct ast_type_qualifier {
|
||||
* \note
|
||||
* This field is only valid if \c explicit_location is set.
|
||||
*/
|
||||
int location;
|
||||
ast_expression *location;
|
||||
/**
|
||||
* Index specified via GL_ARB_explicit_attrib_location layout
|
||||
*
|
||||
* \note
|
||||
* This field is only valid if \c explicit_index is set.
|
||||
*/
|
||||
int index;
|
||||
ast_expression *index;
|
||||
|
||||
/** Maximum output vertices in GLSL 1.50 geometry shaders. */
|
||||
int max_vertices;
|
||||
ast_layout_expression *max_vertices;
|
||||
|
||||
/** Stream in GLSL 1.50 geometry shaders. */
|
||||
unsigned stream;
|
||||
ast_expression *stream;
|
||||
|
||||
/**
|
||||
* Input or output primitive type in GLSL 1.50 geometry shaders
|
||||
@@ -613,7 +613,7 @@ struct ast_type_qualifier {
|
||||
* \note
|
||||
* This field is only valid if \c explicit_binding is set.
|
||||
*/
|
||||
int binding;
|
||||
ast_expression *binding;
|
||||
|
||||
/**
|
||||
* Offset specified via GL_ARB_shader_atomic_counter's "offset"
|
||||
@@ -622,14 +622,14 @@ struct ast_type_qualifier {
|
||||
* \note
|
||||
* This field is only valid if \c explicit_offset is set.
|
||||
*/
|
||||
int offset;
|
||||
ast_expression *offset;
|
||||
|
||||
/**
|
||||
* Local size specified via GL_ARB_compute_shader's "local_size_{x,y,z}"
|
||||
* layout qualifier. Element i of this array is only valid if
|
||||
* flags.q.local_size & (1 << i) is set.
|
||||
*/
|
||||
int local_size[3];
|
||||
ast_layout_expression *local_size[3];
|
||||
|
||||
/** Tessellation evaluation shader: vertex spacing (equal, fractional even/odd) */
|
||||
GLenum vertex_spacing;
|
||||
@@ -641,7 +641,7 @@ struct ast_type_qualifier {
|
||||
bool point_mode;
|
||||
|
||||
/** Tessellation control shader: number of output vertices */
|
||||
int vertices;
|
||||
ast_layout_expression *vertices;
|
||||
|
||||
/**
|
||||
* Image format specified with an ARB_shader_image_load_store
|
||||
@@ -1113,17 +1113,13 @@ public:
|
||||
class ast_tcs_output_layout : public ast_node
|
||||
{
|
||||
public:
|
||||
ast_tcs_output_layout(const struct YYLTYPE &locp, int vertices)
|
||||
: vertices(vertices)
|
||||
ast_tcs_output_layout(const struct YYLTYPE &locp)
|
||||
{
|
||||
set_location(locp);
|
||||
}
|
||||
|
||||
virtual ir_rvalue *hir(exec_list *instructions,
|
||||
struct _mesa_glsl_parse_state *state);
|
||||
|
||||
private:
|
||||
const int vertices;
|
||||
};
|
||||
|
||||
|
||||
@@ -1155,9 +1151,12 @@ private:
|
||||
class ast_cs_input_layout : public ast_node
|
||||
{
|
||||
public:
|
||||
ast_cs_input_layout(const struct YYLTYPE &locp, const unsigned *local_size)
|
||||
ast_cs_input_layout(const struct YYLTYPE &locp,
|
||||
ast_layout_expression **local_size)
|
||||
{
|
||||
memcpy(this->local_size, local_size, sizeof(this->local_size));
|
||||
for (int i = 0; i < 3; i++) {
|
||||
this->local_size[i] = local_size[i];
|
||||
}
|
||||
set_location(locp);
|
||||
}
|
||||
|
||||
@@ -1165,7 +1164,7 @@ public:
|
||||
struct _mesa_glsl_parse_state *state);
|
||||
|
||||
private:
|
||||
unsigned local_size[3];
|
||||
ast_layout_expression *local_size[3];
|
||||
};
|
||||
|
||||
/*@}*/
|
||||
|
||||
+91
-37
@@ -2508,16 +2508,40 @@ static bool
|
||||
process_qualifier_constant(struct _mesa_glsl_parse_state *state,
|
||||
YYLTYPE *loc,
|
||||
const char *qual_indentifier,
|
||||
int qual_value,
|
||||
ast_expression *const_expression,
|
||||
unsigned *value)
|
||||
{
|
||||
if (qual_value < 0) {
|
||||
_mesa_glsl_error(loc, state, "%s layout qualifier is invalid (%d < 0)",
|
||||
qual_indentifier, qual_value);
|
||||
exec_list dummy_instructions;
|
||||
|
||||
if (const_expression == NULL) {
|
||||
*value = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
ir_rvalue *const ir = const_expression->hir(&dummy_instructions, state);
|
||||
|
||||
ir_constant *const const_int = ir->constant_expression_value();
|
||||
if (const_int == NULL || !const_int->type->is_integer()) {
|
||||
_mesa_glsl_error(loc, state, "%s must be an integral constant "
|
||||
"expression", qual_indentifier);
|
||||
return false;
|
||||
}
|
||||
|
||||
*value = (unsigned) qual_value;
|
||||
if (const_int->value.i[0] < 0) {
|
||||
_mesa_glsl_error(loc, state, "%s layout qualifier is invalid (%d < 0)",
|
||||
qual_indentifier, const_int->value.u[0]);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If the location is const (and we've verified that
|
||||
* it is) then no instructions should have been emitted
|
||||
* when we converted it to HIR. If they were emitted,
|
||||
* then either the location isn't const after all, or
|
||||
* we are emitting unnecessary instructions.
|
||||
*/
|
||||
assert(dummy_instructions.is_empty());
|
||||
|
||||
*value = const_int->value.u[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3845,7 +3869,17 @@ handle_tess_ctrl_shader_output_decl(struct _mesa_glsl_parse_state *state,
|
||||
unsigned num_vertices = 0;
|
||||
|
||||
if (state->tcs_output_vertices_specified) {
|
||||
num_vertices = state->out_qualifier->vertices;
|
||||
if (!state->out_qualifier->vertices->
|
||||
process_qualifier_constant(state, "vertices",
|
||||
&num_vertices, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num_vertices > state->Const.MaxPatchVertices) {
|
||||
_mesa_glsl_error(&loc, state, "vertices (%d) exceeds "
|
||||
"GL_MAX_PATCH_VERTICES", num_vertices);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!var->type->is_array() && !var->data.patch) {
|
||||
@@ -4079,9 +4113,18 @@ ast_declarator_list::hir(exec_list *instructions,
|
||||
*/
|
||||
if (decl_type && decl_type->contains_atomic()) {
|
||||
if (type->qualifier.flags.q.explicit_binding &&
|
||||
type->qualifier.flags.q.explicit_offset)
|
||||
state->atomic_counter_offsets[type->qualifier.binding] =
|
||||
type->qualifier.offset;
|
||||
type->qualifier.flags.q.explicit_offset) {
|
||||
unsigned qual_binding;
|
||||
unsigned qual_offset;
|
||||
if (process_qualifier_constant(state, &loc, "binding",
|
||||
type->qualifier.binding,
|
||||
&qual_binding)
|
||||
&& process_qualifier_constant(state, &loc, "offset",
|
||||
type->qualifier.offset,
|
||||
&qual_offset)) {
|
||||
state->atomic_counter_offsets[qual_binding] = qual_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this->declarations.is_empty()) {
|
||||
@@ -7055,22 +7098,18 @@ ast_tcs_output_layout::hir(exec_list *instructions,
|
||||
{
|
||||
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;
|
||||
unsigned num_vertices;
|
||||
if (!state->out_qualifier->vertices->
|
||||
process_qualifier_constant(state, "vertices", &num_vertices,
|
||||
false)) {
|
||||
/* return here to stop cascading incorrect error messages */
|
||||
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 "
|
||||
@@ -7178,20 +7217,6 @@ ast_cs_input_layout::hir(exec_list *instructions,
|
||||
{
|
||||
YYLTYPE loc = this->get_location();
|
||||
|
||||
/* If any compute input layout declaration preceded this one, make sure it
|
||||
* was consistent with this one.
|
||||
*/
|
||||
if (state->cs_input_local_size_specified) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (state->cs_input_local_size[i] != this->local_size[i]) {
|
||||
_mesa_glsl_error(&loc, state,
|
||||
"compute shader input layout does not match"
|
||||
" previous declaration");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* From the ARB_compute_shader specification:
|
||||
*
|
||||
* If the local size of the shader in any dimension is greater
|
||||
@@ -7204,15 +7229,30 @@ ast_cs_input_layout::hir(exec_list *instructions,
|
||||
* report it at compile time as well.
|
||||
*/
|
||||
GLuint64 total_invocations = 1;
|
||||
unsigned qual_local_size[3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (this->local_size[i] > state->ctx->Const.MaxComputeWorkGroupSize[i]) {
|
||||
|
||||
char *local_size_str = ralloc_asprintf(NULL, "invalid local_size_%c",
|
||||
'x' + i);
|
||||
/* Infer a local_size of 1 for unspecified dimensions */
|
||||
if (this->local_size[i] == NULL) {
|
||||
qual_local_size[i] = 1;
|
||||
} else if (!this->local_size[i]->
|
||||
process_qualifier_constant(state, local_size_str,
|
||||
&qual_local_size[i], false)) {
|
||||
ralloc_free(local_size_str);
|
||||
return NULL;
|
||||
}
|
||||
ralloc_free(local_size_str);
|
||||
|
||||
if (qual_local_size[i] > state->ctx->Const.MaxComputeWorkGroupSize[i]) {
|
||||
_mesa_glsl_error(&loc, state,
|
||||
"local_size_%c exceeds MAX_COMPUTE_WORK_GROUP_SIZE"
|
||||
" (%d)", 'x' + i,
|
||||
state->ctx->Const.MaxComputeWorkGroupSize[i]);
|
||||
break;
|
||||
}
|
||||
total_invocations *= this->local_size[i];
|
||||
total_invocations *= qual_local_size[i];
|
||||
if (total_invocations >
|
||||
state->ctx->Const.MaxComputeWorkGroupInvocations) {
|
||||
_mesa_glsl_error(&loc, state,
|
||||
@@ -7223,9 +7263,23 @@ ast_cs_input_layout::hir(exec_list *instructions,
|
||||
}
|
||||
}
|
||||
|
||||
/* If any compute input layout declaration preceded this one, make sure it
|
||||
* was consistent with this one.
|
||||
*/
|
||||
if (state->cs_input_local_size_specified) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (state->cs_input_local_size[i] != qual_local_size[i]) {
|
||||
_mesa_glsl_error(&loc, state,
|
||||
"compute shader input layout does not match"
|
||||
" previous declaration");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state->cs_input_local_size_specified = true;
|
||||
for (int i = 0; i < 3; i++)
|
||||
state->cs_input_local_size[i] = this->local_size[i];
|
||||
state->cs_input_local_size[i] = qual_local_size[i];
|
||||
|
||||
/* We may now declare the built-in constant gl_WorkGroupSize (see
|
||||
* builtin_variable_generator::generate_constants() for why we didn't
|
||||
@@ -7240,7 +7294,7 @@ ast_cs_input_layout::hir(exec_list *instructions,
|
||||
ir_constant_data data;
|
||||
memset(&data, 0, sizeof(data));
|
||||
for (int i = 0; i < 3; i++)
|
||||
data.u[i] = this->local_size[i];
|
||||
data.u[i] = qual_local_size[i];
|
||||
var->constant_value = new(var) ir_constant(glsl_type::uvec3_type, &data);
|
||||
var->constant_initializer =
|
||||
new(var) ir_constant(glsl_type::uvec3_type, &data);
|
||||
|
||||
+24
-45
@@ -169,23 +169,19 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
|
||||
}
|
||||
|
||||
if (q.flags.q.max_vertices) {
|
||||
if (this->flags.q.max_vertices && this->max_vertices != q.max_vertices) {
|
||||
_mesa_glsl_error(loc, state,
|
||||
"geometry shader set conflicting max_vertices "
|
||||
"(%d and %d)", this->max_vertices, q.max_vertices);
|
||||
return false;
|
||||
if (this->max_vertices) {
|
||||
this->max_vertices->merge_qualifier(q.max_vertices);
|
||||
} else {
|
||||
this->max_vertices = q.max_vertices;
|
||||
}
|
||||
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;
|
||||
if (this->invocations) {
|
||||
this->invocations->merge_qualifier(q.invocations);
|
||||
} else {
|
||||
this->invocations = q.invocations;
|
||||
}
|
||||
this->invocations = q.invocations;
|
||||
}
|
||||
|
||||
if (state->stage == MESA_SHADER_GEOMETRY &&
|
||||
@@ -208,14 +204,11 @@ 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;
|
||||
if (this->vertices) {
|
||||
this->vertices->merge_qualifier(q.vertices);
|
||||
} else {
|
||||
this->vertices = q.vertices;
|
||||
}
|
||||
this->vertices = q.vertices;
|
||||
}
|
||||
|
||||
if (q.flags.q.vertex_spacing) {
|
||||
@@ -252,15 +245,11 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (q.flags.q.local_size & (1 << i)) {
|
||||
if ((this->flags.q.local_size & (1 << i)) &&
|
||||
this->local_size[i] != q.local_size[i]) {
|
||||
_mesa_glsl_error(loc, state,
|
||||
"compute shader set conflicting values for "
|
||||
"local_size_%c (%d and %d)", 'x' + i,
|
||||
this->local_size[i], q.local_size[i]);
|
||||
return false;
|
||||
if (this->local_size[i]) {
|
||||
this->local_size[i]->merge_qualifier(q.local_size[i]);
|
||||
} else {
|
||||
this->local_size[i] = q.local_size[i];
|
||||
}
|
||||
this->local_size[i] = q.local_size[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,7 +288,7 @@ ast_type_qualifier::merge_out_qualifier(YYLTYPE *loc,
|
||||
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);
|
||||
node = new(mem_ctx) ast_tcs_output_layout(*loc);
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -403,15 +392,13 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
|
||||
state->in_qualifier->prim_type = q.prim_type;
|
||||
}
|
||||
|
||||
if (this->flags.q.invocations &&
|
||||
q.flags.q.invocations &&
|
||||
this->invocations != q.invocations) {
|
||||
_mesa_glsl_error(loc, state,
|
||||
"conflicting invocations counts specified");
|
||||
return false;
|
||||
} else if (q.flags.q.invocations) {
|
||||
if (q.flags.q.invocations) {
|
||||
this->flags.q.invocations = 1;
|
||||
this->invocations = q.invocations;
|
||||
if (this->invocations) {
|
||||
this->invocations->merge_qualifier(q.invocations);
|
||||
} else {
|
||||
this->invocations = q.invocations;
|
||||
}
|
||||
}
|
||||
|
||||
if (q.flags.q.early_fragment_tests) {
|
||||
@@ -454,15 +441,7 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
|
||||
if (create_gs_ast) {
|
||||
node = new(mem_ctx) ast_gs_input_layout(*loc, q.prim_type);
|
||||
} else if (create_cs_ast) {
|
||||
/* Infer a local_size of 1 for every unspecified dimension */
|
||||
unsigned local_size[3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (q.flags.q.local_size & (1 << i))
|
||||
local_size[i] = q.local_size[i];
|
||||
else
|
||||
local_size[i] = 1;
|
||||
}
|
||||
node = new(mem_ctx) ast_cs_input_layout(*loc, local_size);
|
||||
node = new(mem_ctx) ast_cs_input_layout(*loc, q.local_size);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+27
-60
@@ -298,7 +298,6 @@ static bool match_layout_qualifier(const char *s1, const char *s2,
|
||||
%type <node> conditionopt
|
||||
%type <node> for_init_statement
|
||||
%type <for_rest_statement> for_rest_statement
|
||||
%type <n> integer_constant
|
||||
%type <node> layout_defaults
|
||||
|
||||
%right THEN ELSE
|
||||
@@ -1152,11 +1151,6 @@ layout_qualifier_id_list:
|
||||
}
|
||||
;
|
||||
|
||||
integer_constant:
|
||||
INTCONSTANT { $$ = $1; }
|
||||
| UINTCONSTANT { $$ = $1; }
|
||||
;
|
||||
|
||||
layout_qualifier_id:
|
||||
any_identifier
|
||||
{
|
||||
@@ -1453,9 +1447,18 @@ layout_qualifier_id:
|
||||
YYERROR;
|
||||
}
|
||||
}
|
||||
| any_identifier '=' integer_constant
|
||||
| any_identifier '=' constant_expression
|
||||
{
|
||||
memset(& $$, 0, sizeof($$));
|
||||
void *ctx = state;
|
||||
|
||||
if ($3->oper != ast_int_constant &&
|
||||
$3->oper != ast_uint_constant &&
|
||||
!state->has_enhanced_layouts()) {
|
||||
_mesa_glsl_error(& @1, state,
|
||||
"compile-time constant expressions require "
|
||||
"GLSL 4.40 or ARB_enhanced_layouts");
|
||||
}
|
||||
|
||||
if (match_layout_qualifier("location", $1, state) == 0) {
|
||||
$$.flags.q.explicit_location = 1;
|
||||
@@ -1495,18 +1498,11 @@ layout_qualifier_id:
|
||||
|
||||
if (match_layout_qualifier("max_vertices", $1, state) == 0) {
|
||||
$$.flags.q.max_vertices = 1;
|
||||
|
||||
if ($3 < 0) {
|
||||
$$.max_vertices = new(ctx) ast_layout_expression(@1, $3);
|
||||
if (!state->is_version(150, 0)) {
|
||||
_mesa_glsl_error(& @3, state,
|
||||
"invalid max_vertices %d specified", $3);
|
||||
YYERROR;
|
||||
} else {
|
||||
$$.max_vertices = $3;
|
||||
if (!state->is_version(150, 0)) {
|
||||
_mesa_glsl_error(& @3, state,
|
||||
"#version 150 max_vertices qualifier "
|
||||
"specified", $3);
|
||||
}
|
||||
"#version 150 max_vertices qualifier "
|
||||
"specified", $3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1527,12 +1523,7 @@ layout_qualifier_id:
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (match_layout_qualifier(local_size_qualifiers[i], $1,
|
||||
state) == 0) {
|
||||
if ($3 <= 0) {
|
||||
_mesa_glsl_error(& @3, state,
|
||||
"invalid %s of %d specified",
|
||||
local_size_qualifiers[i], $3);
|
||||
YYERROR;
|
||||
} else if (!state->has_compute_shader()) {
|
||||
if (!state->has_compute_shader()) {
|
||||
_mesa_glsl_error(& @3, state,
|
||||
"%s qualifier requires GLSL 4.30 or "
|
||||
"GLSL ES 3.10 or ARB_compute_shader",
|
||||
@@ -1540,7 +1531,7 @@ layout_qualifier_id:
|
||||
YYERROR;
|
||||
} else {
|
||||
$$.flags.q.local_size |= (1 << i);
|
||||
$$.local_size[i] = $3;
|
||||
$$.local_size[i] = new(ctx) ast_layout_expression(@1, $3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1548,48 +1539,24 @@ layout_qualifier_id:
|
||||
|
||||
if (match_layout_qualifier("invocations", $1, state) == 0) {
|
||||
$$.flags.q.invocations = 1;
|
||||
|
||||
if ($3 <= 0) {
|
||||
$$.invocations = new(ctx) ast_layout_expression(@1, $3);
|
||||
if (!state->is_version(400, 0) &&
|
||||
!state->ARB_gpu_shader5_enable) {
|
||||
_mesa_glsl_error(& @3, state,
|
||||
"invalid invocations %d specified", $3);
|
||||
YYERROR;
|
||||
} else if ($3 > MAX_GEOMETRY_SHADER_INVOCATIONS) {
|
||||
_mesa_glsl_error(& @3, state,
|
||||
"invocations (%d) exceeds "
|
||||
"GL_MAX_GEOMETRY_SHADER_INVOCATIONS", $3);
|
||||
YYERROR;
|
||||
} else {
|
||||
$$.invocations = $3;
|
||||
if (!state->is_version(400, 0) &&
|
||||
!state->ARB_gpu_shader5_enable) {
|
||||
_mesa_glsl_error(& @3, state,
|
||||
"GL_ARB_gpu_shader5 invocations "
|
||||
"qualifier specified", $3);
|
||||
}
|
||||
"GL_ARB_gpu_shader5 invocations "
|
||||
"qualifier specified", $3);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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");
|
||||
}
|
||||
$$.vertices = new(ctx) ast_layout_expression(@1, $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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1648,8 +1648,20 @@ 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;
|
||||
if (state->tcs_output_vertices_specified) {
|
||||
unsigned vertices;
|
||||
if (state->out_qualifier->vertices->
|
||||
process_qualifier_constant(state, "vertices", &vertices,
|
||||
false)) {
|
||||
|
||||
YYLTYPE loc = state->out_qualifier->vertices->get_location();
|
||||
if (vertices > state->Const.MaxPatchVertices) {
|
||||
_mesa_glsl_error(&loc, state, "vertices (%d) exceeds "
|
||||
"GL_MAX_PATCH_VERTICES", vertices);
|
||||
}
|
||||
shader->TessCtrl.VerticesOut = vertices;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MESA_SHADER_TESS_EVAL:
|
||||
shader->TessEval.PrimitiveMode = PRIM_UNKNOWN;
|
||||
@@ -1670,8 +1682,14 @@ set_shader_inout_layout(struct gl_shader *shader,
|
||||
break;
|
||||
case MESA_SHADER_GEOMETRY:
|
||||
shader->Geom.VerticesOut = 0;
|
||||
if (state->out_qualifier->flags.q.max_vertices)
|
||||
shader->Geom.VerticesOut = state->out_qualifier->max_vertices;
|
||||
if (state->out_qualifier->flags.q.max_vertices) {
|
||||
unsigned qual_max_vertices;
|
||||
if (state->out_qualifier->max_vertices->
|
||||
process_qualifier_constant(state, "max_vertices",
|
||||
&qual_max_vertices, true)) {
|
||||
shader->Geom.VerticesOut = qual_max_vertices;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->gs_input_prim_type_specified) {
|
||||
shader->Geom.InputType = state->in_qualifier->prim_type;
|
||||
@@ -1686,8 +1704,22 @@ set_shader_inout_layout(struct gl_shader *shader,
|
||||
}
|
||||
|
||||
shader->Geom.Invocations = 0;
|
||||
if (state->in_qualifier->flags.q.invocations)
|
||||
shader->Geom.Invocations = state->in_qualifier->invocations;
|
||||
if (state->in_qualifier->flags.q.invocations) {
|
||||
unsigned invocations;
|
||||
if (state->in_qualifier->invocations->
|
||||
process_qualifier_constant(state, "invocations",
|
||||
&invocations, false)) {
|
||||
|
||||
YYLTYPE loc = state->in_qualifier->invocations->get_location();
|
||||
if (invocations > MAX_GEOMETRY_SHADER_INVOCATIONS) {
|
||||
_mesa_glsl_error(&loc, state,
|
||||
"invocations (%d) exceeds "
|
||||
"GL_MAX_GEOMETRY_SHADER_INVOCATIONS",
|
||||
invocations);
|
||||
}
|
||||
shader->Geom.Invocations = invocations;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MESA_SHADER_COMPUTE:
|
||||
|
||||
Reference in New Issue
Block a user