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
* \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
* \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"
* \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;
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
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;
};
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);
}
struct _mesa_glsl_parse_state *state);
private:
- unsigned local_size[3];
+ ast_layout_expression *local_size[3];
};
/*@}*/
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) {
+ 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;
+ }
+
+ if (const_int->value.i[0] < 0) {
_mesa_glsl_error(loc, state, "%s layout qualifier is invalid (%d < 0)",
- qual_indentifier, qual_value);
+ qual_indentifier, const_int->value.u[0]);
return false;
}
- *value = (unsigned) qual_value;
+ /* 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;
}
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) {
*/
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()) {
{
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 "
{
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
* 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,
}
}
+ /* 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
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);
}
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 &&
}
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) {
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];
}
}
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;
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) {
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;
%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
}
;
-integer_constant:
- INTCONSTANT { $$ = $1; }
- | UINTCONSTANT { $$ = $1; }
- ;
-
layout_qualifier_id:
any_identifier
{
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;
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);
}
}
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",
YYERROR;
} else {
$$.flags.q.local_size |= (1 << i);
- $$.local_size[i] = $3;
+ $$.local_size[i] = new(ctx) ast_layout_expression(@1, $3);
}
break;
}
if (match_layout_qualifier("invocations", $1, state) == 0) {
$$.flags.q.invocations = 1;
-
- if ($3 <= 0) {
- _mesa_glsl_error(& @3, state,
- "invalid invocations %d specified", $3);
- YYERROR;
- } else if ($3 > MAX_GEOMETRY_SHADER_INVOCATIONS) {
+ $$.invocations = new(ctx) ast_layout_expression(@1, $3);
+ if (!state->is_version(400, 0) &&
+ !state->ARB_gpu_shader5_enable) {
_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");
}
}
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;
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;
}
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: