v2: Dropped some unrelated reordering in glsl_parser.yy as Ken suggested. Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>tags/11.0-branchpoint
| @@ -434,6 +434,7 @@ struct ast_type_qualifier { | |||
| unsigned out:1; | |||
| unsigned centroid:1; | |||
| unsigned sample:1; | |||
| unsigned patch:1; | |||
| unsigned uniform:1; | |||
| unsigned buffer:1; | |||
| unsigned smooth:1; | |||
| @@ -2487,6 +2487,9 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, | |||
| var->data.stream = qual->stream; | |||
| } | |||
| if (qual->flags.q.patch) | |||
| var->data.patch = 1; | |||
| if (qual->flags.q.attribute && state->stage != MESA_SHADER_VERTEX) { | |||
| var->type = glsl_type::error_type; | |||
| _mesa_glsl_error(loc, state, | |||
| @@ -3209,6 +3212,17 @@ handle_tess_ctrl_shader_output_decl(struct _mesa_glsl_parse_state *state, | |||
| num_vertices = state->out_qualifier->vertices; | |||
| } | |||
| if (!var->type->is_array() && !var->data.patch) { | |||
| _mesa_glsl_error(&loc, state, | |||
| "tessellation control shader outputs must be arrays"); | |||
| /* To avoid cascading failures, short circuit the checks below. */ | |||
| return; | |||
| } | |||
| if (var->data.patch) | |||
| return; | |||
| validate_layout_qualifier_vertex_count(state, loc, var, num_vertices, | |||
| &state->tcs_output_size, | |||
| "geometry shader input"); | |||
| @@ -3958,6 +3972,33 @@ ast_declarator_list::hir(exec_list *instructions, | |||
| } | |||
| /* From section 4.3.4 of the GLSL 4.00 spec: | |||
| * "Input variables may not be declared using the patch in qualifier | |||
| * in tessellation control or geometry shaders." | |||
| * | |||
| * From section 4.3.6 of the GLSL 4.00 spec: | |||
| * "It is an error to use patch out in a vertex, tessellation | |||
| * evaluation, or geometry shader." | |||
| * | |||
| * This doesn't explicitly forbid using them in a fragment shader, but | |||
| * that's probably just an oversight. | |||
| */ | |||
| if (state->stage != MESA_SHADER_TESS_EVAL | |||
| && this->type->qualifier.flags.q.patch | |||
| && this->type->qualifier.flags.q.in) { | |||
| _mesa_glsl_error(&loc, state, "'patch in' can only be used in a " | |||
| "tessellation evaluation shader"); | |||
| } | |||
| if (state->stage != MESA_SHADER_TESS_CTRL | |||
| && this->type->qualifier.flags.q.patch | |||
| && this->type->qualifier.flags.q.out) { | |||
| _mesa_glsl_error(&loc, state, "'patch out' can only be used in a " | |||
| "tessellation control shader"); | |||
| } | |||
| /* Precision qualifiers exists only in GLSL versions 1.00 and >= 1.30. | |||
| */ | |||
| if (this->type->qualifier.precision != ast_precision_none) { | |||
| @@ -5481,6 +5522,7 @@ ast_process_structure_or_interface_block(exec_list *instructions, | |||
| interpret_interpolation_qualifier(qual, var_mode, state, &loc); | |||
| fields[i].centroid = qual->flags.q.centroid ? 1 : 0; | |||
| fields[i].sample = qual->flags.q.sample ? 1 : 0; | |||
| fields[i].patch = qual->flags.q.patch ? 1 : 0; | |||
| /* Only save explicitly defined streams in block's field */ | |||
| fields[i].stream = qual->flags.q.explicit_stream ? qual->stream : -1; | |||
| @@ -5815,6 +5857,8 @@ ast_interface_block::hir(exec_list *instructions, | |||
| earlier_per_vertex->fields.structure[j].centroid; | |||
| fields[i].sample = | |||
| earlier_per_vertex->fields.structure[j].sample; | |||
| fields[i].patch = | |||
| earlier_per_vertex->fields.structure[j].patch; | |||
| } | |||
| } | |||
| @@ -5994,6 +6038,7 @@ ast_interface_block::hir(exec_list *instructions, | |||
| var->data.interpolation = fields[i].interpolation; | |||
| var->data.centroid = fields[i].centroid; | |||
| var->data.sample = fields[i].sample; | |||
| var->data.patch = fields[i].patch; | |||
| var->init_interface_type(block_type); | |||
| if (var_mode == ir_var_shader_in || var_mode == ir_var_uniform) | |||
| @@ -86,7 +86,8 @@ 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* | |||
| @@ -883,10 +883,10 @@ builtin_variable_generator::generate_tcs_special_vars() | |||
| add_system_value(SYSTEM_VALUE_VERTICES_IN, int_t, "gl_PatchVerticesIn"); | |||
| add_system_value(SYSTEM_VALUE_INVOCATION_ID, int_t, "gl_InvocationID"); | |||
| add_output(VARYING_SLOT_TESS_LEVEL_OUTER, | |||
| array(float_t, 4), "gl_TessLevelOuter"); | |||
| add_output(VARYING_SLOT_TESS_LEVEL_INNER, | |||
| array(float_t, 2), "gl_TessLevelInner"); | |||
| add_output(VARYING_SLOT_TESS_LEVEL_OUTER, array(float_t, 4), | |||
| "gl_TessLevelOuter")->data.patch = 1; | |||
| add_output(VARYING_SLOT_TESS_LEVEL_INNER, array(float_t, 2), | |||
| "gl_TessLevelInner")->data.patch = 1; | |||
| } | |||
| @@ -315,6 +315,7 @@ invariant KEYWORD(120, 100, 120, 100, INVARIANT); | |||
| flat KEYWORD(130, 100, 130, 300, FLAT); | |||
| smooth KEYWORD(130, 300, 130, 300, SMOOTH); | |||
| noperspective KEYWORD(130, 300, 130, 0, NOPERSPECTIVE); | |||
| patch KEYWORD_WITH_ALT(0, 300, 400, 0, yyextra->ARB_tessellation_shader_enable, PATCH); | |||
| sampler1D DEPRECATED_ES_KEYWORD(SAMPLER1D); | |||
| sampler2D return SAMPLER2D; | |||
| @@ -576,7 +577,6 @@ usamplerBuffer KEYWORD(140, 300, 140, 0, USAMPLERBUFFER); | |||
| /* Additional reserved words in GLSL ES 3.00 */ | |||
| resource KEYWORD(0, 300, 0, 0, RESOURCE); | |||
| patch KEYWORD(0, 300, 0, 0, PATCH); | |||
| sample KEYWORD_WITH_ALT(400, 300, 400, 0, yyextra->ARB_gpu_shader5_enable, SAMPLE); | |||
| subroutine KEYWORD(0, 300, 0, 0, SUBROUTINE); | |||
| @@ -1866,7 +1866,11 @@ auxiliary_storage_qualifier: | |||
| memset(& $$, 0, sizeof($$)); | |||
| $$.flags.q.sample = 1; | |||
| } | |||
| /* TODO: "patch" also goes here someday. */ | |||
| | PATCH | |||
| { | |||
| memset(& $$, 0, sizeof($$)); | |||
| $$.flags.q.patch = 1; | |||
| } | |||
| storage_qualifier: | |||
| CONST_TOK | |||
| @@ -861,6 +861,8 @@ _mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q) | |||
| printf("centroid "); | |||
| if (q->flags.q.sample) | |||
| printf("sample "); | |||
| if (q->flags.q.patch) | |||
| printf("patch "); | |||
| if (q->flags.q.uniform) | |||
| printf("uniform "); | |||
| if (q->flags.q.buffer) | |||
| @@ -122,6 +122,7 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, | |||
| this->fields.structure[i].centroid = fields[i].centroid; | |||
| this->fields.structure[i].sample = fields[i].sample; | |||
| this->fields.structure[i].matrix_layout = fields[i].matrix_layout; | |||
| this->fields.structure[i].patch = fields[i].patch; | |||
| } | |||
| mtx_unlock(&glsl_type::mutex); | |||
| @@ -154,6 +155,7 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, | |||
| this->fields.structure[i].centroid = fields[i].centroid; | |||
| this->fields.structure[i].sample = fields[i].sample; | |||
| this->fields.structure[i].matrix_layout = fields[i].matrix_layout; | |||
| this->fields.structure[i].patch = fields[i].patch; | |||
| } | |||
| mtx_unlock(&glsl_type::mutex); | |||
| @@ -722,6 +724,9 @@ glsl_type::record_compare(const glsl_type *b) const | |||
| if (this->fields.structure[i].sample | |||
| != b->fields.structure[i].sample) | |||
| return false; | |||
| if (this->fields.structure[i].patch | |||
| != b->fields.structure[i].patch) | |||
| return false; | |||
| } | |||
| return true; | |||
| @@ -751,6 +751,12 @@ struct glsl_struct_field { | |||
| */ | |||
| unsigned matrix_layout:2; | |||
| /** | |||
| * For interface blocks, 1 if this variable is a per-patch input or output | |||
| * (as in ir_variable::patch). 0 otherwise. | |||
| */ | |||
| unsigned patch:1; | |||
| /** | |||
| * For interface blocks, it has a value if this variable uses multiple vertex | |||
| * streams (as in ir_variable::stream). -1 otherwise. | |||
| @@ -1643,6 +1643,7 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name, | |||
| this->data.read_only = false; | |||
| this->data.centroid = false; | |||
| this->data.sample = false; | |||
| this->data.patch = false; | |||
| this->data.invariant = false; | |||
| this->data.how_declared = ir_var_declared_normally; | |||
| this->data.mode = mode; | |||
| @@ -1785,6 +1786,7 @@ ir_function_signature::qualifiers_match(exec_list *params) | |||
| a->data.interpolation != b->data.interpolation || | |||
| a->data.centroid != b->data.centroid || | |||
| a->data.sample != b->data.sample || | |||
| a->data.patch != b->data.patch || | |||
| a->data.image_read_only != b->data.image_read_only || | |||
| a->data.image_write_only != b->data.image_write_only || | |||
| a->data.image_coherent != b->data.image_coherent || | |||
| @@ -622,6 +622,7 @@ public: | |||
| unsigned read_only:1; | |||
| unsigned centroid:1; | |||
| unsigned sample:1; | |||
| unsigned patch:1; | |||
| unsigned invariant:1; | |||
| unsigned precise:1; | |||
| @@ -167,6 +167,7 @@ void ir_print_visitor::visit(ir_variable *ir) | |||
| const char *const cent = (ir->data.centroid) ? "centroid " : ""; | |||
| const char *const samp = (ir->data.sample) ? "sample " : ""; | |||
| const char *const patc = (ir->data.patch) ? "patch " : ""; | |||
| const char *const inv = (ir->data.invariant) ? "invariant " : ""; | |||
| const char *const mode[] = { "", "uniform ", "shader_storage", | |||
| "shader_in ", "shader_out ", | |||
| @@ -177,8 +178,8 @@ void ir_print_visitor::visit(ir_variable *ir) | |||
| const char *const interp[] = { "", "smooth", "flat", "noperspective" }; | |||
| STATIC_ASSERT(ARRAY_SIZE(interp) == INTERP_QUALIFIER_COUNT); | |||
| fprintf(f, "(%s%s%s%s%s%s%s) ", | |||
| loc, cent, samp, inv, mode[ir->data.mode], | |||
| fprintf(f, "(%s%s%s%s%s%s%s%s) ", | |||
| loc, cent, samp, patc, inv, mode[ir->data.mode], | |||
| stream[ir->data.stream], | |||
| interp[ir->data.interpolation]); | |||
| @@ -417,6 +417,8 @@ ir_reader::read_declaration(s_expression *expr) | |||
| var->data.centroid = 1; | |||
| } else if (strcmp(qualifier->value(), "sample") == 0) { | |||
| var->data.sample = 1; | |||
| } else if (strcmp(qualifier->value(), "patch") == 0) { | |||
| var->data.patch = 1; | |||
| } else if (strcmp(qualifier->value(), "invariant") == 0) { | |||
| var->data.invariant = 1; | |||
| } else if (strcmp(qualifier->value(), "uniform") == 0) { | |||
| @@ -140,6 +140,24 @@ ir_set_program_inouts_visitor::mark_whole_variable(ir_variable *var) | |||
| type = type->fields.array; | |||
| } | |||
| if (this->shader_stage == MESA_SHADER_TESS_CTRL && | |||
| var->data.mode == ir_var_shader_in) { | |||
| assert(type->is_array()); | |||
| type = type->fields.array; | |||
| } | |||
| if (this->shader_stage == MESA_SHADER_TESS_CTRL && | |||
| var->data.mode == ir_var_shader_out && !var->data.patch) { | |||
| assert(type->is_array()); | |||
| type = type->fields.array; | |||
| } | |||
| if (this->shader_stage == MESA_SHADER_TESS_EVAL && | |||
| var->data.mode == ir_var_shader_in && !var->data.patch) { | |||
| assert(type->is_array()); | |||
| type = type->fields.array; | |||
| } | |||
| mark(this->prog, var, 0, type->count_attribute_slots(), | |||
| this->shader_stage == MESA_SHADER_FRAGMENT); | |||
| } | |||
| @@ -165,6 +183,9 @@ ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir) | |||
| * | |||
| * *Except gl_PrimitiveIDIn, as noted below. | |||
| * | |||
| * For tessellation control shaders all inputs and non-patch outputs are | |||
| * arrays. For tessellation evaluation shaders non-patch inputs are arrays. | |||
| * | |||
| * If the index can't be interpreted as a constant, or some other problem | |||
| * occurs, then nothing will be marked and false will be returned. | |||
| */ | |||
| @@ -184,6 +205,24 @@ ir_set_program_inouts_visitor::try_mark_partial_variable(ir_variable *var, | |||
| type = type->fields.array; | |||
| } | |||
| if (this->shader_stage == MESA_SHADER_TESS_CTRL && | |||
| var->data.mode == ir_var_shader_in) { | |||
| assert(type->is_array()); | |||
| type = type->fields.array; | |||
| } | |||
| if (this->shader_stage == MESA_SHADER_TESS_CTRL && | |||
| var->data.mode == ir_var_shader_out && !var->data.patch) { | |||
| assert(type->is_array()); | |||
| type = type->fields.array; | |||
| } | |||
| if (this->shader_stage == MESA_SHADER_TESS_EVAL && | |||
| var->data.mode == ir_var_shader_in && !var->data.patch) { | |||
| assert(type->is_array()); | |||
| type = type->fields.array; | |||
| } | |||
| /* The code below only handles: | |||
| * | |||
| * - Indexing into matrices | |||
| @@ -242,6 +281,22 @@ ir_set_program_inouts_visitor::try_mark_partial_variable(ir_variable *var, | |||
| return true; | |||
| } | |||
| static bool | |||
| is_multiple_vertices(gl_shader_stage stage, ir_variable *var) | |||
| { | |||
| if (var->data.patch) | |||
| return false; | |||
| if (var->data.mode == ir_var_shader_in) | |||
| return stage == MESA_SHADER_GEOMETRY || | |||
| stage == MESA_SHADER_TESS_CTRL || | |||
| stage == MESA_SHADER_TESS_EVAL; | |||
| if (var->data.mode == ir_var_shader_out) | |||
| return stage == MESA_SHADER_TESS_CTRL; | |||
| return false; | |||
| } | |||
| ir_visitor_status | |||
| ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir) | |||
| { | |||
| @@ -256,10 +311,9 @@ ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir) | |||
| */ | |||
| if (ir_dereference_variable * const deref_var = | |||
| inner_array->array->as_dereference_variable()) { | |||
| if (this->shader_stage == MESA_SHADER_GEOMETRY && | |||
| deref_var->var->data.mode == ir_var_shader_in) { | |||
| /* foo is a geometry shader input, so i is the vertex, and j the | |||
| * part of the input we're accessing. | |||
| if (is_multiple_vertices(this->shader_stage, deref_var->var)) { | |||
| /* foo is a geometry or tessellation shader input, so i is | |||
| * the vertex, and j the part of the input we're accessing. | |||
| */ | |||
| if (try_mark_partial_variable(deref_var->var, ir->array_index)) | |||
| { | |||
| @@ -275,10 +329,9 @@ ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir) | |||
| } else if (ir_dereference_variable * const deref_var = | |||
| ir->array->as_dereference_variable()) { | |||
| /* ir => foo[i], where foo is a variable. */ | |||
| if (this->shader_stage == MESA_SHADER_GEOMETRY && | |||
| deref_var->var->data.mode == ir_var_shader_in) { | |||
| /* foo is a geometry shader input, so i is the vertex, and we're | |||
| * accessing the entire input. | |||
| if (is_multiple_vertices(this->shader_stage, deref_var->var)) { | |||
| /* foo is a geometry or tessellation shader input, so i is | |||
| * the vertex, and we're accessing the entire input. | |||
| */ | |||
| mark_whole_variable(deref_var->var); | |||
| /* We've now taken care of foo, but i might contain a subexpression | |||
| @@ -116,6 +116,18 @@ cross_validate_types_and_qualifiers(struct gl_shader_program *prog, | |||
| return; | |||
| } | |||
| if (input->data.patch != output->data.patch) { | |||
| linker_error(prog, | |||
| "%s shader output `%s' %s patch qualifier, " | |||
| "but %s shader input %s patch qualifier\n", | |||
| _mesa_shader_stage_to_string(producer_stage), | |||
| output->name, | |||
| (output->data.patch) ? "has" : "lacks", | |||
| _mesa_shader_stage_to_string(consumer_stage), | |||
| (input->data.patch) ? "has" : "lacks"); | |||
| return; | |||
| } | |||
| if (!prog->IsES && input->data.invariant != output->data.invariant) { | |||
| linker_error(prog, | |||
| "%s shader output `%s' %s invariant qualifier, " | |||
| @@ -989,7 +1001,8 @@ varying_matches::compute_packing_class(const ir_variable *var) | |||
| * | |||
| * Therefore, the packing class depends only on the interpolation type. | |||
| */ | |||
| unsigned packing_class = var->data.centroid | (var->data.sample << 1); | |||
| unsigned packing_class = var->data.centroid | (var->data.sample << 1) | | |||
| (var->data.patch << 2); | |||
| packing_class *= 4; | |||
| packing_class += var->data.interpolation; | |||
| return packing_class; | |||
| @@ -159,6 +159,7 @@ flatten_named_interface_blocks_declarations::run(exec_list *instructions) | |||
| iface_t->fields.structure[i].interpolation; | |||
| new_var->data.centroid = iface_t->fields.structure[i].centroid; | |||
| new_var->data.sample = iface_t->fields.structure[i].sample; | |||
| new_var->data.patch = iface_t->fields.structure[i].patch; | |||
| new_var->init_interface_type(iface_t); | |||
| hash_table_insert(interface_namespace, new_var, | |||
| @@ -610,6 +610,7 @@ lower_packed_varyings_visitor::get_packed_varying_deref( | |||
| } | |||
| packed_var->data.centroid = unpacked_var->data.centroid; | |||
| packed_var->data.sample = unpacked_var->data.sample; | |||
| packed_var->data.patch = unpacked_var->data.patch; | |||
| packed_var->data.interpolation = unpacked_var->data.interpolation; | |||
| packed_var->data.location = location; | |||
| unpacked_var->insert_before(packed_var); | |||