X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fglsl%2Fast_type.cpp;h=8643b7bfb761df00bb8cad3746099c7afe9649c8;hb=a108e14d1c11140def8e2207ce42d8b54660607b;hp=b596cd59ecf8ce7d614f63fc823fd19ea412dd5d;hpb=4087d9ec0b601465261da5d3bc06412d1ac3e445;p=mesa.git diff --git a/src/glsl/ast_type.cpp b/src/glsl/ast_type.cpp index b596cd59ecf..8643b7bfb76 100644 --- a/src/glsl/ast_type.cpp +++ b/src/glsl/ast_type.cpp @@ -38,9 +38,17 @@ ast_type_specifier::print(void) const } bool -ast_fully_specified_type::has_qualifiers() const +ast_fully_specified_type::has_qualifiers(_mesa_glsl_parse_state *state) const { - return this->qualifier.flags.i != 0; + /* 'subroutine' isnt a real qualifier. */ + ast_type_qualifier subroutine_only; + subroutine_only.flags.i = 0; + subroutine_only.flags.q.subroutine = 1; + subroutine_only.flags.q.subroutine_def = 1; + if (state->has_explicit_uniform_location()) { + subroutine_only.flags.q.explicit_index = 1; + } + return (this->qualifier.flags.i & ~subroutine_only.flags.i) != 0; } bool ast_type_qualifier::has_interpolation() const @@ -60,6 +68,7 @@ ast_type_qualifier::has_layout() const || this->flags.q.depth_less || this->flags.q.depth_unchanged || this->flags.q.std140 + || this->flags.q.std430 || this->flags.q.shared || this->flags.q.column_major || this->flags.q.row_major @@ -78,14 +87,17 @@ ast_type_qualifier::has_storage() const || this->flags.q.varying || this->flags.q.in || this->flags.q.out - || this->flags.q.uniform; + || this->flags.q.uniform + || this->flags.q.buffer + || this->flags.q.shared_storage; } bool ast_type_qualifier::has_auxiliary_storage() const { return this->flags.q.centroid - || this->flags.q.sample; + || this->flags.q.sample + || this->flags.q.patch; } const char* @@ -104,7 +116,7 @@ ast_type_qualifier::interpolation_string() const bool ast_type_qualifier::merge_qualifier(YYLTYPE *loc, _mesa_glsl_parse_state *state, - ast_type_qualifier q) + const ast_type_qualifier &q) { ast_type_qualifier ubo_mat_mask; ubo_mat_mask.flags.i = 0; @@ -116,6 +128,7 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc, ubo_layout_mask.flags.q.std140 = 1; ubo_layout_mask.flags.q.packed = 1; ubo_layout_mask.flags.q.shared = 1; + ubo_layout_mask.flags.q.std430 = 1; ast_type_qualifier ubo_binding_mask; ubo_binding_mask.flags.i = 0; @@ -159,41 +172,32 @@ 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) { + if (this->max_vertices) { + this->max_vertices->merge_qualifier(q.max_vertices); + } else { + this->max_vertices = q.max_vertices; + } + } + + if (q.flags.q.subroutine_def) { + if (this->flags.q.subroutine_def) { _mesa_glsl_error(loc, state, - "geometry shader set conflicting max_vertices " - "(%d and %d)", this->max_vertices, q.max_vertices); - return false; + "conflicting subroutine qualifiers used"); + } else { + this->subroutine_list = q.subroutine_list; } - 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 && state->has_explicit_attrib_stream()) { - if (q.flags.q.stream && q.stream >= state->ctx->Const.MaxVertexStreams) { - _mesa_glsl_error(loc, state, - "`stream' value is larger than MAX_VERTEX_STREAMS - 1 " - "(%d > %d)", - q.stream, state->ctx->Const.MaxVertexStreams - 1); - } - if (this->flags.q.explicit_stream && - this->stream >= state->ctx->Const.MaxVertexStreams) { - _mesa_glsl_error(loc, state, - "`stream' value is larger than MAX_VERTEX_STREAMS - 1 " - "(%d > %d)", - this->stream, state->ctx->Const.MaxVertexStreams - 1); - } - if (!this->flags.q.explicit_stream) { if (q.flags.q.stream) { this->flags.q.stream = 1; @@ -211,6 +215,41 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc, } } + if (q.flags.q.vertices) { + if (this->vertices) { + this->vertices->merge_qualifier(q.vertices); + } else { + 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) @@ -218,15 +257,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]; } } @@ -255,10 +290,26 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc, return true; } +bool +ast_type_qualifier::merge_out_qualifier(YYLTYPE *loc, + _mesa_glsl_parse_state *state, + const 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); + } + + return r; +} + bool ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc, _mesa_glsl_parse_state *state, - ast_type_qualifier q, + const ast_type_qualifier &q, ast_node* &node) { void *mem_ctx = state; @@ -268,6 +319,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. */ @@ -293,11 +365,7 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc, valid_in_mask.flags.q.invocations = 1; break; case MESA_SHADER_FRAGMENT: - if (q.flags.q.early_fragment_tests) { - state->early_fragment_tests = true; - } else { - _mesa_glsl_error(loc, state, "invalid input layout qualifier"); - } + valid_in_mask.flags.q.early_fragment_tests = 1; break; case MESA_SHADER_COMPUTE: create_cs_ast |= @@ -327,36 +395,125 @@ 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; 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) { + 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) { - /* 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, q.local_size); + } + + return true; +} + +bool +ast_layout_expression::process_qualifier_constant(struct _mesa_glsl_parse_state *state, + const char *qual_indentifier, + unsigned *value, + bool can_be_zero) +{ + int min_value = 0; + bool first_pass = true; + *value = 0; + + if (!can_be_zero) + min_value = 1; + + for (exec_node *node = layout_const_expressions.head; + !node->is_tail_sentinel(); node = node->next) { + + exec_list dummy_instructions; + ast_node *const_expression = exec_node_data(ast_node, node, link); + + 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()) { + YYLTYPE loc = const_expression->get_location(); + _mesa_glsl_error(&loc, state, "%s must be an integral constant " + "expression", qual_indentifier); + return false; + } + + if (const_int->value.i[0] < min_value) { + YYLTYPE loc = const_expression->get_location(); + _mesa_glsl_error(&loc, state, "%s layout qualifier is invalid " + "(%d < %d)", qual_indentifier, + const_int->value.i[0], min_value); + return false; + } + + if (!first_pass && *value != const_int->value.u[0]) { + YYLTYPE loc = const_expression->get_location(); + _mesa_glsl_error(&loc, state, "%s layout qualifier does not " + "match previous declaration (%d vs %d)", + qual_indentifier, *value, const_int->value.i[0]); + return false; + } else { + first_pass = false; + *value = const_int->value.u[0]; } - node = new(mem_ctx) ast_cs_input_layout(*loc, local_size); + + /* 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()); } return true;